diff --git a/.cursor/rules/error-collector.mdc b/.cursor/rules/error-collector.mdc new file mode 100644 index 0000000..31d49fb --- /dev/null +++ b/.cursor/rules/error-collector.mdc @@ -0,0 +1,300 @@ +--- +alwaysApply: true +description: Flutter UI Error Prevention and Layout Best Practices Guide +--- + +# Error Collector - Flutter UI Error Prevention Guide + +## ๐Ÿšจ Overflow Error Analysis (2025.09.27) + +### Root Cause Analysis + +#### 1. **Fixed Size Container Misuse** + +```dart +// โŒ Wrong - Forcing fixed dimensions +Container( + width: 402, // Ignores device screen size + height: 874, // Ignores device screen size + child: Column(...) // Content can overflow +) +``` + +**Problems:** + +- Ignores different device screen sizes +- Doesn't consider SafeArea, keyboard, and other dynamic elements +- Fails to calculate total height of Column children + +#### 2. **Unnecessary StatusBar Widget Implementation** + +```dart +// โŒ Wrong - Duplicating native functionality +const StatusBar(), // iOS/Android already provides this +``` + +**Problems:** + +- Conflicts with platform-specific status bar styles +- Takes up unnecessary layout space +- Duplicates native SafeArea functionality + +#### 3. **Layout Constraint Ignorance** + +```dart +// โŒ Wrong - Non-scrollable fixed layout +Column( + children: [ + // Widgets whose total height can exceed screen + Widget1(), Widget2(), Widget3()... + ] +) +``` + +## ๐Ÿ›ก๏ธ Error Prevention Rules + +### 1. **Layout Design Principles** + +#### โœ… DO: Use Responsive Layouts + +```dart +// Correct example +SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Column(...) + ) +) +``` + +#### โŒ DON'T: Fixed Size Containers + +```dart +// Forbidden pattern +Container( + width: 402, // Absolute size forbidden + height: 874, // Absolute size forbidden + child: Column(...) +) +``` + +### 2. **SafeArea and Platform Considerations** + +#### โœ… DO: Utilize Native Features + +```dart +Scaffold( + body: SafeArea( // Automatically handles iOS notch, Android status bar + child: YourContent() + ) +) +``` + +#### โŒ DON'T: Duplicate Platform Features + +```dart +// Forbidden pattern - Creating StatusBar widget +const StatusBar() // iOS/Android already provides this +``` + +### 3. **Container Size Rules** + +#### โœ… DO: Dynamic Size Calculation + +```dart +Container( + width: MediaQuery.of(context).size.width * 0.85, // Screen ratio based + child: Column( + mainAxisSize: MainAxisSize.min, // Adjust size to content + children: [...] + ) +) +``` + +#### โŒ DON'T: Arbitrary Fixed Values + +```dart +Container( + width: 342, // Ignores device differences + height: 120, // Ignores content changes +) +``` + +### 4. **Scroll Handling Rules** + +#### โœ… DO: Prevent Overflow + +```dart +// When content might exceed screen +SingleChildScrollView( + child: Column(children: [...]) +) + +// Or use ListView +ListView(children: [...]) +``` + +#### โŒ DON'T: Long Column Without Scroll + +```dart +Column( // Overflow risk + children: [ + // Many widgets... + ] +) +``` + +### 5. **Button Structure Design Principles** + +#### โœ… DO: Simple Button Structure + +```dart +// Correct - Direct button implementation +SizedBox( + width: 50, + height: 50, + child: ElevatedButton( + onPressed: onPressed, + style: ElevatedButton.styleFrom( + backgroundColor: color, + padding: EdgeInsets.zero, // Important! + shape: RoundedRectangleBorder(...), + ), + child: Icon(...), + ), +) +``` + +#### โŒ DON'T: Double Container Structure + +```dart +// Forbidden pattern - Causes button distortion +Container( // Outer container + decoration: BoxDecoration(...), + child: ElevatedButton( // Inner button - gets distorted! + child: content, + ), +) +``` + +### 6. **Alignment and Layout Principles** + +#### โœ… DO: Explicit Alignment Settings + +```dart +Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, // Essential! + children: [...] +) +``` + +#### โŒ DON'T: Missing Alignment Properties + +```dart +Column( // Missing alignment causes left bias + children: [...] +) +``` + +### 7. **Development Workflow Principles** + +#### โœ… DO: Utilize Hot Reload + +```dart +// After code changes: +// 1. Save file (Cmd+S) +// 2. Press 'r' in terminal +// 3. Instantly see changes +``` + +#### โŒ DON'T: Unnecessary App Restarts + +```dart +// Forbidden patterns: +// - Complete app shutdown and restart +// - Emulator reboot +// - flutter clean (only when necessary) +``` + +## ๐Ÿ” Development Checklists + +### Pre-Layout Development Checklist + +- [ ] Works on various screen sizes? +- [ ] Considers SafeArea? +- [ ] No possibility of content exceeding screen? +- [ ] Doesn't duplicate native features? + +### Widget Implementation Prohibitions + +- [ ] No fixed width/height values (without special reason) +- [ ] No platform feature reimplementation +- [ ] No screen size assumptions without MediaQuery +- [ ] No missing overflow handling in Column/Row + +### Button Distortion Prevention Checklist + +- [ ] No Container + ElevatedButton double structure +- [ ] Set ElevatedButton padding: EdgeInsets.zero +- [ ] Handle background/border directly in ElevatedButton.styleFrom +- [ ] Use SizedBox for size constraints, handle decoration in style + +### Alignment Issue Prevention Checklist + +- [ ] Specify mainAxisAlignment in Column/Row +- [ ] Always set crossAxisAlignment +- [ ] Use CrossAxisAlignment.center for center alignment +- [ ] Clearly define layout alignment intent + +### Development Efficiency Checklist + +- [ ] Prioritize Hot Reload (r key) +- [ ] Use Hot Restart only when state reset needed (R key) +- [ ] App restart only as last resort +- [ ] Emulator reboot only for system issues + +### Testing Requirements + +- [ ] Test on various device sizes +- [ ] Check layout when keyboard appears +- [ ] Test portrait/landscape mode switching +- [ ] Test long text/large data scenarios + +## ๐Ÿ“š References + +### Flutter Layout Widget Priority + +1. **SingleChildScrollView** - Overflow prevention +2. **MediaQuery** - Screen size information +3. **SafeArea** - Platform-specific safe areas +4. **ConstrainedBox/Flexible/Expanded** - Dynamic size adjustment +5. **LayoutBuilder** - Parent constraint-based layout + +### Debugging Tools + +```dart +// Display layout boundaries during development +import 'package:flutter/rendering.dart'; +debugPaintSizeEnabled = true; // Set in main() +``` + +## ๐ŸŽฏ Core Lessons + +**"All UI elements must be designed responsively, considering device sizes and platform characteristics. Buttons should have simple structures, alignment should be explicit, and development should utilize Hot Reload efficiently."** + +### Key Principles: + +1. **No Absolute Sizes** - All sizes must be relative +2. **Respect Platforms** - Don't duplicate native functionality +3. **Prepare for Overflow** - Always consider scroll possibilities +4. **Simple Button Structure** - Avoid double container structures +5. **Explicit Alignment** - Always set crossAxisAlignment +6. **Utilize Hot Reload** - Maximize development efficiency +7. **Test First** - Verify in various environments + +Follow these rules to prevent future layout errors and provide consistent user experience. diff --git a/.cursor/rules/error_collector.mdc b/.cursor/rules/error_collector.mdc new file mode 100644 index 0000000..673ec38 --- /dev/null +++ b/.cursor/rules/error_collector.mdc @@ -0,0 +1,304 @@ +--- +alwaysApply: true +description: Collection of error patterns to avoid repetition in UI/UX design and Flutter development +--- + +# Error Collector - Concise Rules + +Authoritative, deduplicated rules to prevent recurring UI/UX and Flutter code mistakes. Follow these every time. + +## 1) Layout & Responsiveness + +### โŒ Never use fixed positioning; use relative sizing + +**Error Pattern**: Using fixed-width containers and Row widgets that constrains input field widths instead of allowing them to span the full available width. + +**Example of WRONG approach**: + +```dart +Row( + children: [ + Expanded( + child: LabeledInputField(...), // โœ… This part is correct + ), + const SizedBox(width: 12), // โŒ Fixed spacing + SizedBox( + width: 90, // โŒ FIXED WIDTH - This breaks responsive design + child: ElevatedButton(...), + ), + ], +) +``` + +Pattern to follow: + +```dart +Row( + children: [ + Expanded( + flex: 7, // โœ… Relative sizing, lets input field span reasonable width + child: Column(...), // Contains label + input + error message + ), + const SizedBox(width: 12), // โœ… Fixed spacing between elements is OK + Expanded( + flex: 3, // โœ… Relative sizing, proportionally sized button + child: Container( + height: 50, // โœ… Fixed height is OK for consistency + child: ElevatedButton(...), + ), + ), + ], +) +``` + +Why: + +- Fixed widths break responsiveness. +- Inputs should span full available width to stay centered. +- Buttons must be proportional to inputs (use `Expanded` with `flex`). + +### โœ… Keep input widths consistent + +- Inputs use identical container width and height 50. +- Buttons sized proportionally via `Expanded(flex: ratio)`. + +### โœ… Match visual spec precisely + +- Verify: horizontal centering, right-side button placement, vertical/horizontal spacing, and overall balance. + +## 2) Async UI Safety & State + +### โŒ Never call setState() after dispose() + +**Error Pattern**: Using setState() in async operations without checking mounted state. + +**Wrong**: + +```dart +Future apiCall() async { + setState(() { + _isLoading = true; + }); + + final response = await http.get(...); + + setState(() { // โŒ Could be called after dispose() + _isLoading = false; + }); +} +``` + +Correct: + +```dart +Future apiCall() async { + setState(() { + _isLoading = true; + }); + + final response = await http.get(...); + + if (mounted) { // โœ… Always check mounted state + setState(() { + _isLoading = false; + }); + } +} +``` + +### โœ… Do not assume widget parameters exist + +Read the widget definition first; if missing, compose a custom layout. + +## 3) Team Memory Hygiene + +- After critical fixes, document root cause, solution, and prevention here. + +--- + +## Next Error Patterns Will Be Added Here + +As new critical errors are discovered during development, they will be added to this file to prevent repetition. + +## 4) Imports Hygiene + +### โŒ Unnecessary imports overlapping with `material.dart` + +Error Pattern: + +- Importing `package:flutter/services.dart` while all used symbols are already exposed via `package:flutter/material.dart`, triggering โ€œunnecessary_importโ€. + +Prevention: + +- Prefer `material.dart` for UI. +- Use โ€œOrganize Importsโ€ and keep `unnecessary_import` lint on. +- If auto-complete works without a new import, donโ€™t add it. + +## 5) Using BuildContext Across Async Gaps (`use_build_context_synchronously`) + +Error Pattern: + +- Calling `setState`, `Navigator` (e.g., `pushNamed`), or `ScaffoldMessenger.of(context)` after an `await` without verifying the widget is still mounted. If the widget is disposed, these calls will crash or misbehave. + +Prevention: + +- Immediately after any awaited async call, guard UI interactions with `if (!mounted) return;` or `if (mounted) { ... }`. +- Prefer early returns to keep flow clear: + +```dart +final response = await http.post(...); +if (!mounted) return; +setState(() { _isLoading = false; }); +Navigator.pushNamed(context, '/route'); +``` + +- Guard snackbars/navigation in success/else/catch with `if (mounted)`. +- Avoid capturing `context` in long-lived futures. +- In `finally`, wrap `setState` with `if (mounted)`. + +## 6) Constructors (`use_super_parameters`) + +Error Pattern: + +- Declaring constructors with an explicit `Key? key` parameter and forwarding it manually (`: super(key: key)`) instead of using Dart's super parameter feature, which triggers the `use_super_parameters` lint. + +Prevention: + +- Prefer `const MyWidget({super.key});` +- Keep `super.key` first among named params. +- Run `dart fix --apply` periodically. + +Wrong: + +```dart +class MyWidget extends StatelessWidget { + const MyWidget({Key? key}) : super(key: key); +} +``` + +Correct: + +```dart +class MyWidget extends StatelessWidget { + const MyWidget({super.key}); +} +``` + +## 7) Widget Tree Integrity + +Error Pattern: + +- Deeply nested Flutter widget trees (e.g., `Row` โ†’ `Expanded` โ†’ `Padding` โ†’ `SizedBox` โ†’ `ElevatedButton`) were missing one or more closing parentheses, producing analyzer errors like โ€œExpected to find ')'.โ€ +- Typical failure points happen right after multi-line widget constructors, especially when adding/removing wrappers such as `Expanded` or `Padding`. + +Prevention: + +- Use trailing commas to help formatter balance parentheses. +- Verify each wrapper has a closing `),`. +- Extract subtrees to keep depth โ‰ค 2โ€“3 levels. +- Fix the first โ€œExpected to find ')'โ€ before moving on. + +### โŒ Unnecessary Imports Overlapping With `material.dart` + +Error Pattern: + +- Importing `package:flutter/services.dart` while all used symbols are already exposed via `package:flutter/material.dart`, triggering โ€œunnecessary_importโ€. + +Prevention: + +- Prefer importing `material.dart` for UI layers unless a symbol is strictly outside Material (then import the narrow package explicitly). +- Use IDE โ€œOrganize Importsโ€ regularly and keep the `unnecessary_import` lint enabled. +- Before adding a new import, attempt auto-complete; if it resolves without the new import, do not add it. + +## 8) Test Imports + +Error Pattern: + +- Tests importing `package:flutter/material.dart` without using any of its symbols, causing โ€œunused_importโ€. + +Prevention: + +- In tests, import only the packages actually used (`flutter_test`, app `main.dart`, or specific widgets/helpers). +- Run `dart analyze` as part of pre-commit to surface unused imports early. + +## 9) Implementation Tips + +- Use trailing commas consistently in Flutter widget trees; rely on formatter to layout and reveal missing parentheses. +- After wrapping existing code with a new widget, immediately add its closing `),` and format before editing inner content. +- Keep widget trees shallow by extracting components; aim for โ‰ค 2โ€“3 nesting levels per method. +- Maintain a quick โ€œwrapper checklistโ€ when editing: Row โ†’ Expanded โ†’ Padding โ†’ SizedBox โ†’ Child โ†’ close in reverse order. + +## 10) Whitespace Containers (sized_box_for_whitespace) + +- Do not use `Container(width/height)` only for spacing. +- Use `SizedBox(width: ..., height: ...)` for whitespace. + +## 11) Logging Hygiene (avoid_print) + +- Do not use `print` in app code; prefer `dart:developer` (`developer.log`) or a logging package. +- Keep user-facing feedback via `ScaffoldMessenger`, developer diagnostics via logs. + +## 12) String Interpolation Cleanliness + +- Avoid unnecessary braces in string interpolation: use `$value` instead of `${value}` for simple identifiers. +- Use `${...}` only when evaluating expressions. + +## 13) Deprecated API Replacements + +- Avoid deprecated `ColorScheme` members such as `background`/`onBackground`. +- Prefer Material 3 fields like `surface`/`onSurface` and verify with analyzer. + +### โŒ Missing `super` Parameters in Widget Constructors + +Error Pattern: + +- Declaring constructors with an explicit `Key? key` parameter and forwarding it manually (`: super(key: key)`) instead of using Dart's super parameter feature, which triggers the `use_super_parameters` lint. + +Prevention: + +- Prefer super parameters in Flutter widgets: `const MyWidget({super.key});` +- When adding new optional parameters, keep `super.key` as the first positional named parameter for consistency. +- Run `dart fix --apply` periodically to catch and migrate remaining constructors. + +Wrong: + +```dart +class MyWidget extends StatelessWidget { + const MyWidget({Key? key}) : super(key: key); +} +``` + +Correct: + +```dart +class MyWidget extends StatelessWidget { + const MyWidget({super.key}); +} +``` + +### โŒ Using BuildContext Across Async Gaps (`use_build_context_synchronously`) + +Error Pattern: + +- Calling `Navigator`, `ScaffoldMessenger`, or `setState` after an `await` without verifying the widget is still mounted, leading to crashes or undefined behavior. + +Prevention: + +- Immediately after any awaited async call, guard UI interactions with `if (!mounted) return;` or wrap calls in `if (mounted) { ... }`. +- Avoid capturing `context` into long-lived futures. Pass data, not `BuildContext`, and centralize navigation in small helpers that check `mounted`. +- Handle all branches (success, 4xx/5xx, catch) consistently with a mounted guard before using `context`. + +Wrong: + +```dart +final resp = await http.post(...); +Navigator.pushNamed(context, '/next'); // โŒ may run after dispose +``` + +Correct: + +```dart +final resp = await http.post(...); +if (!mounted) return; // โœ… guard after async gap +Navigator.pushNamed(context, '/next'); +``` diff --git a/.cursor/rules/flutter-widgets.mdc b/.cursor/rules/flutter-widgets.mdc new file mode 100644 index 0000000..5a71c4c --- /dev/null +++ b/.cursor/rules/flutter-widgets.mdc @@ -0,0 +1,310 @@ +--- +alwaysApply: true +description: Flutter widget library and reuse guidelines +--- + +# Flutter Widget Library - Gradi Project + +This project has a comprehensive set of reusable Flutter widgets that should be used instead of creating new ones. Always check existing widgets before creating new ones. + +## Core Widgets + +### StatusBar Widget + +- **File**: [frontend/lib/widgets/status_bar.dart](mdc:frontend/lib/widgets/status_bar.dart) +- **Purpose**: Mobile status bar with time, battery, WiFi, and signal indicators +- **Usage**: `const StatusBar()` +- **Features**: Custom painter for icons, configurable time and battery level + +### AppLogo Widget + +- **File**: [frontend/lib/widgets/app_logo.dart](mdc:frontend/lib/widgets/app_logo.dart) +- **Purpose**: GRADI app logo with gradient text effect +- **Usage**: `const AppLogo()` +- **Features**: ShaderMask gradient, AppleSDGothicNeoH00 font, 88.98px size + +### InputField Widget + +- **File**: [frontend/lib/widgets/input_field.dart](mdc:frontend/lib/widgets/input_field.dart) +- **Purpose**: Standard text input field with Figma styling +- **Usage**: `InputField(placeholder: 'text', controller: controller)` +- **Features**: #F3F3F3 background, #A0A0A0 text, 342x50 size, rounded corners + +### LabeledInputField Widget + +- **File**: [frontend/lib/widgets/labeled_input_field.dart](mdc:frontend/lib/widgets/labeled_input_field.dart) +- **Purpose**: Input field with label above (for forms) +- **Usage**: `LabeledInputField(label: 'Label*', placeholder: 'placeholder')` +- **Features**: Label + input field combination, 342x76 total size + +### LoginButton Widget + +- **File**: [frontend/lib/widgets/login_button.dart](mdc:frontend/lib/widgets/login_button.dart) +- **Purpose**: Primary action button with gradient background +- **Usage**: `LoginButton(text: '๋กœ๊ทธ์ธ', onPressed: callback)` +- **Features**: AC5BF8โ†’636ACF gradient, 144ยฐ angle, 342x50 size + +### NextButton Widget + +- **File**: [frontend/lib/widgets/next_button.dart](mdc:frontend/lib/widgets/next_button.dart) +- **Purpose**: Secondary action button with gradient background +- **Usage**: `NextButton(text: '๋‹ค์Œ', onPressed: callback)` +- **Features**: Same gradient as LoginButton, reusable for navigation + +### SNSButton Widget + +- **File**: [frontend/lib/widgets/sns_button.dart](mdc:frontend/lib/widgets/sns_button.dart) +- **Purpose**: Social login buttons (Kakao, Google) +- **Usage**: `SNSButton(provider: SNSProvider.kakao, onPressed: callback)` +- **Features**: Brand colors, custom icons, 50x50 size + +### CustomBackButton Widget + +- **File**: [frontend/lib/widgets/back_button.dart](mdc:frontend/lib/widgets/back_button.dart) +- **Purpose**: Custom back navigation button +- **Usage**: `custom.CustomBackButton(onPressed: callback)` +- **Features**: Custom arrow icon, 38x38 size, #5C5C5C color +- **Note**: Use `as custom` prefix to avoid conflict with Flutter's BackButton + +### PageTitle Widget + +- **File**: [frontend/lib/widgets/page_title.dart](mdc:frontend/lib/widgets/page_title.dart) +- **Purpose**: Page title text with consistent styling +- **Usage**: `PageTitle(text: 'Title', width: 92, height: 24)` +- **Features**: Pretendard font, 20px size, #5C5C5C color + +### LinksSection Widget + +- **File**: [frontend/lib/widgets/links_section.dart](mdc:frontend/lib/widgets/links_section.dart) +- **Purpose**: Horizontal links with separators +- **Usage**: `LinksSection(onSignUp: callback, onFindID: callback, onFindPW: callback)` +- **Features**: Three links with dividers, different colors for emphasis + +### SNSDivider Widget + +- **File**: [frontend/lib/widgets/sns_divider.dart](mdc:frontend/lib/widgets/sns_divider.dart) +- **Purpose**: Divider with text for SNS login section +- **Usage**: `SNSDivider(text: 'SNS ๊ฐ„ํŽธ ๋กœ๊ทธ์ธ')` +- **Features**: Horizontal lines with centered text, 339x17 size + +### ErrorInputField Widget + +- **File**: [frontend/lib/widgets/error_input_field.dart](mdc:frontend/lib/widgets/error_input_field.dart) +- **Purpose**: Input field with error state and error message +- **Usage**: `ErrorInputField(label: 'Label*', placeholder: 'placeholder', hasError: true, errorText: 'Error message')` +- **Features**: Error border (gradient color), error text, dynamic height (102px with error, 76px normal) + +### VerificationCodeInput Widget + +- **File**: [frontend/lib/widgets/verification_code_input.dart](mdc:frontend/lib/widgets/verification_code_input.dart) +- **Purpose**: 4-digit verification code input with individual boxes +- **Usage**: `VerificationCodeInput(length: 4, onChanged: (code) => print(code))` +- **Features**: Auto-focus navigation, number-only input, visual feedback for filled boxes + +### UserIDCard Widget + +- **File**: [frontend/lib/widgets/user_id_card.dart](mdc:frontend/lib/widgets/user_id_card.dart) +- **Purpose**: Display user ID result with personalized message +- **Usage**: `UserIDCard(userName: '์ตœ์œค์ •', userId: '0311yjung')` +- **Features**: Two-line text display, personalized greeting, 24px font size + +## Screen Components + +### LoginPage Screen + +- **File**: [frontend/lib/screens/login_page.dart](mdc:frontend/lib/screens/login_page.dart) +- **Purpose**: Complete login screen implementation +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => LoginPage()))` +- **Features**: Full login flow with all components integrated + +### FindIDPage Screen + +- **File**: [frontend/lib/screens/find_id_page.dart](mdc:frontend/lib/screens/find_id_page.dart) +- **Purpose**: Find ID form screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => FindIDPage()))` +- **Features**: Name and email input with validation + +### FindIDErrorPage Screen + +- **File**: [frontend/lib/screens/find_id_error_page.dart](mdc:frontend/lib/screens/find_id_error_page.dart) +- **Purpose**: Find ID form screen with error state +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => FindIDErrorPage()))` +- **Features**: Name input (normal) and email input (error state) with error message + +### FindPasswordPage Screen + +- **File**: [frontend/lib/screens/find_password_page.dart](mdc:frontend/lib/screens/find_password_page.dart) +- **Purpose**: Find password form screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => FindPasswordPage()))` +- **Features**: Name, email, and ID input fields with validation + +### FindIDVerificationPage Screen + +- **File**: [frontend/lib/screens/find_id_verification_page.dart](mdc:frontend/lib/screens/find_id_verification_page.dart) +- **Purpose**: Find ID verification code input screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => FindIDVerificationPage(userName: '์ตœ์œค์ •')))` +- **Features**: 4-digit verification code input, personalized welcome message, resend code link + +### FindIDResultPage Screen + +- **File**: [frontend/lib/screens/find_id_result_page.dart](mdc:frontend/lib/screens/find_id_result_page.dart) +- **Purpose**: Find ID result display screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => FindIDResultPage(userName: '์ตœ์œค์ •', userId: '0311yjung')))` +- **Features**: User ID result display, login redirect button, personalized message + +### FindPasswordPage Screen + +- **File**: [frontend/lib/screens/find_password_page.dart](mdc:frontend/lib/screens/find_password_page.dart) +- **Purpose**: Find password form screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => FindPasswordPage()))` +- **Features**: Name, email, and ID input fields with validation + +### FindPasswordVerificationPage Screen + +- **File**: [frontend/lib/screens/find_password_verification_page.dart](mdc:frontend/lib/screens/find_password_verification_page.dart) +- **Purpose**: Find password verification code input screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => FindPasswordVerificationPage(userName: '์ตœ์œค์ •')))` +- **Features**: 4-digit verification code input, personalized welcome message, resend code link + +### SignUpPage Screen + +- **File**: [frontend/lib/screens/signup_page.dart](mdc:frontend/lib/screens/signup_page.dart) +- **Purpose**: User registration form screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => SignUpPage()))` +- **Features**: Name, ID, email, phone, password, and confirm password input fields with validation + +### FindIDErrorPage Screen + +- **File**: [frontend/lib/screens/find_id_error_page.dart](mdc:frontend/lib/screens/find_id_error_page.dart) +- **Purpose**: Find ID error display screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => FindIDErrorPage()))` +- **Features**: Error message display, retry button, back to login link + +### FindPasswordErrorPage Screen + +- **File**: [frontend/lib/screens/find_password_error_page.dart](mdc:frontend/lib/screens/find_password_error_page.dart) +- **Purpose**: Find password error display screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => FindPasswordErrorPage()))` +- **Features**: Error message display, retry button, back to login link + +### ResetPasswordPage Screen + +- **File**: [frontend/lib/screens/reset_password_page.dart](mdc:frontend/lib/screens/reset_password_page.dart) +- **Purpose**: Password reset form screen +- **Usage**: `Navigator.push(context, MaterialPageRoute(builder: (context) => ResetPasswordPage()))` +- **Features**: New password and confirm password input fields with validation + +## App Architecture + +### Routing System + +- **File**: [frontend/lib/routes/app_routes.dart](mdc:frontend/lib/routes/app_routes.dart) +- **Purpose**: Centralized routing configuration +- **Features**: Named routes, route generation for parameterized routes, comprehensive navigation flow + +### Theme System + +- **File**: [frontend/lib/theme/app_theme.dart](mdc:frontend/lib/theme/app_theme.dart) +- **Purpose**: Centralized theme configuration matching Figma design system +- **Features**: Colors, typography, input decorations, button styles, consistent theming + +### Main Application + +- **File**: [frontend/lib/main.dart](mdc:frontend/lib/main.dart) +- **Purpose**: App entry point with routing and theme configuration +- **Features**: System UI styling, route handling, error pages + +## Navigation Flow + +``` +LoginPage +โ”œโ”€โ”€ SignUpPage +โ”œโ”€โ”€ FindIDPage +โ”‚ โ”œโ”€โ”€ FindIDErrorPage +โ”‚ โ””โ”€โ”€ FindIDVerificationPage +โ”‚ โ””โ”€โ”€ FindIDResultPage +โ””โ”€โ”€ FindPasswordPage + โ”œโ”€โ”€ FindPasswordErrorPage + โ””โ”€โ”€ FindPasswordVerificationPage + โ””โ”€โ”€ ResetPasswordPage +``` + +## Design System Guidelines + +### Colors + +- **Primary Gradient**: AC5BF8 โ†’ 636ACF (144ยฐ) +- **Background**: #F3F3F3 (input fields) +- **Text Primary**: #5C5C5C (labels, titles) +- **Text Secondary**: #A0A0A0 (placeholders, hints) +- **Accent**: #666EDE (links) +- **White**: #FFFFFF (backgrounds) + +### Typography + +- **Primary Font**: Pretendard +- **Logo Font**: AppleSDGothicNeoH00 +- **Title Size**: 20px, FontWeight.w600 +- **Body Size**: 15px, FontWeight.w500 +- **Label Size**: 15px, FontWeight.w600 + +### Spacing + +- **Standard Padding**: 30px horizontal +- **Input Field Size**: 342x50 +- **Button Size**: 342x50 +- **Labeled Input**: 342x76 +- **Standard Gap**: 20-24px between elements + +## Usage Rules + +1. **Always import existing widgets** before creating new ones +2. **Use the exact widget names** as specified above +3. **Follow the established design system** for colors, fonts, and spacing +4. **Maintain consistent sizing** across all components +5. **Use proper import prefixes** to avoid naming conflicts (e.g., `as custom` for CustomBackButton) +6. **Test widgets in isolation** before integrating into screens +7. **Follow the established file structure** in `lib/widgets/` and `lib/screens/` + +## Common Patterns + +### Form Input Pattern + +```dart +final TextEditingController _controller = TextEditingController(); + +// In build method: +LabeledInputField( + label: 'Label*', + placeholder: 'Placeholder text', + controller: _controller, + keyboardType: TextInputType.text, +) +``` + +### Button Pattern + +```dart +void _handleAction() { + // Handle action logic +} + +// In build method: +LoginButton( + text: 'Button Text', + onPressed: _handleAction, +) +``` + +### Navigation Pattern + +```dart +void _handleNavigation() { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => TargetScreen()), + ); +} +``` + +Always reference these existing widgets before creating new ones to maintain consistency and avoid duplication. diff --git a/.gitignore b/.gitignore index b1e775f..bfcca9b 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,8 @@ ai-service/models/*.pkl ai-service/models/*.joblib ai-service/models/*.h5 ai-service/models/*.pb +ai-service/models/*.jpg +ai-service/test/*.jpg # Database database/*.sql.bak @@ -90,3 +92,17 @@ secrets/ tmp/ temp/ *.tmp + + +# images +*.jpg +*.jpeg +*.png +*.webp + +# video +*.mp4 +*.mov +# Cursor (local AI assistant rules and cache) +.cursor/ + diff --git a/ai-service/DB/__pycache__/create_db.cpython-311.pyc b/ai-service/DB/__pycache__/create_db.cpython-311.pyc new file mode 100644 index 0000000..d6fb6ae Binary files /dev/null and b/ai-service/DB/__pycache__/create_db.cpython-311.pyc differ diff --git a/ai-service/DB/__pycache__/create_db.cpython-312.pyc b/ai-service/DB/__pycache__/create_db.cpython-312.pyc new file mode 100644 index 0000000..81ac840 Binary files /dev/null and b/ai-service/DB/__pycache__/create_db.cpython-312.pyc differ diff --git a/ai-service/DB/__pycache__/crop_images.cpython-311.pyc b/ai-service/DB/__pycache__/crop_images.cpython-311.pyc new file mode 100644 index 0000000..c7bc706 Binary files /dev/null and b/ai-service/DB/__pycache__/crop_images.cpython-311.pyc differ diff --git a/ai-service/DB/__pycache__/crop_images.cpython-312.pyc b/ai-service/DB/__pycache__/crop_images.cpython-312.pyc new file mode 100644 index 0000000..6d3a690 Binary files /dev/null and b/ai-service/DB/__pycache__/crop_images.cpython-312.pyc differ diff --git a/ai-service/DB/__pycache__/ocr_images.cpython-311.pyc b/ai-service/DB/__pycache__/ocr_images.cpython-311.pyc new file mode 100644 index 0000000..33a7ec3 Binary files /dev/null and b/ai-service/DB/__pycache__/ocr_images.cpython-311.pyc differ diff --git a/ai-service/DB/__pycache__/ocr_images.cpython-312.pyc b/ai-service/DB/__pycache__/ocr_images.cpython-312.pyc new file mode 100644 index 0000000..50e6bb1 Binary files /dev/null and b/ai-service/DB/__pycache__/ocr_images.cpython-312.pyc differ diff --git a/ai-service/DB/answer.txt b/ai-service/DB/answer.txt new file mode 100644 index 0000000..0c64a58 --- /dev/null +++ b/ai-service/DB/answer.txt @@ -0,0 +1,290 @@ +9, 01, 4 +10, 02, 4 +11, 03, 3 +12, 04, 5 +13, 05, 4 +15, 01, 1 +16, 02, 3 +17, 03, 5 +18, 04, 5 +19, 05, 5 +21, 01, 3 +22, 02, 1 +23, 03, 1 +24, 04, 5 +25, 05, 5 +27, 01, 1 +28, 02, 5 +29, 03, 5 +30, 04, 1 +31, 05, 3 +33, 01, 3 +34, 02, 4 +35, 03, 3 +36, 04, 5 +37, 05, 2 +39, 01, 4 +40, 02, 4 +41, 03, 4 +42, 04, 3 +43, 05, 3 +45, 01, 3 +46, 02, 1 +47, 03, 4 +48, 04, 2 +49, 05, 2 +51, 01, 1 +52, 02, 3 +53, 03, 1 +54, 04, 2 +55, 05, 4 +57, 01, 4 +58, 02, 3 +59, 03, 4 +60, 04, 4 +61, 05, 3 +63, 01, 4 +64, 02, 3 +65, 03, 2 +66, 04, 4 +67, 05, 4 +69, 01, 3 +70, 02, 5 +71, 03, 5 +72, 04, 4 +73, 05, 3 +75, 01, 4 +76, 02, 4 +77, 03, 2 +78, 04, 3 +79, 05, 2 +83, 01, 5 +83, 02, 1 +85, 03, 4 +85, 04, 5 +85, 05, 2 +88, 01, 1 +88, 02, 3 +88, 03, 2 +88, 04, 5 +88, 05, 2 +89, 06, 3 +89, 07, 2 +89, 08, 3 +89, 09, 2 +89, 10, 4 +90, 11, 5 +90, 12, 1 +90, 13, 1 +90, 14, 3 +90, 15, 4 +91, 16, 5 +91, 17, 3 +91, 18, 5 +92, 19, 1 +92, 20, 2 +93, 21, 1 +93, 22, 1 +94, 23, 2 +94, 24, 1 +95, 25, 5 +95, 26, 4 +96, 27, 4 +96, 28, 5 +97, 29, 4 +97, 30, 3 +98, 31, 1 +98, 32, 3 +99, 33, 2 +99, 34, 1 +100, 35, 3 +100, 36, 4 +101, 37, 5 +101, 38, 4 +102, 39, 4 +102, 40, 1 +103, 41, 4 +103, 42, 5 +104, 43, 5 +104, 44, 3 +104, 45, 2 +105, 01, 2 +105, 02, 3 +105, 03, 3 +105, 04, 4 +105, 05, 2 +106, 06, 4 +106, 07, 5 +106, 08, 3 +106, 09, 5 +106, 10, 4 +107, 11, 2 +107, 12, 1 +107, 13, 1 +107, 14, 1 +107, 15, 3 +108, 16, 4 +108, 17, 4 +108, 18, 5 +109, 19, 1 +109, 20, 3 +110, 21, 5 +110, 22, 1 +111, 23, 5 +111, 24, 2 +112, 25, 4 +112, 26, 2 +113, 27, 4 +113, 28, 4 +114, 29, 3 +114, 30, 4 +115, 31, 2 +115, 32, 2 +116, 33, 1 +116, 34, 1 +117, 35, 3 +117, 36, 2 +118, 37, 5 +118, 38, 3 +119, 39, 3 +119, 40, 4 +120, 41, 4 +120, 42, 4 +121, 43, 4 +121, 44, 2 +121, 45, 5 +122, 01, 5 +122, 02, 3 +122, 03, 2 +122, 04, 5 +122, 05, 3 +123, 06, 3 +123, 07, 1 +123, 08, 4 +123, 09, 4 +123, 10, 3 +124, 11, 5 +124, 12, 4 +124, 13, 5 +124, 14, 3 +124, 15, 5 +125, 16, 3 +125, 17, 4 +125, 18, 1 +126, 19, 2 +126, 20, 1 +127, 21, 2 +127, 22, 1 +128, 23, 1 +128, 24, 1 +129, 25, 5 +129, 26, 4 +130, 27, 4 +130, 28, 5 +131, 29, 3 +131, 30, 4 +132, 31, 2 +132, 32, 2 +133, 33, 3 +133, 34, 1 +134, 35, 4 +134, 36, 4 +135, 37, 2 +135, 38, 5 +136, 39, 4 +136, 40, 1 +137, 41, 2 +137, 42, 5 +138, 43, 5 +138, 44, 3 +138, 45, 4 +139, 01, 1 +139, 02, 2 +139, 03, 5 +139, 04, 3 +139, 05, 1 +140, 06, 5 +140, 07, 2 +140, 08, 5 +140, 09, 5 +140, 10, 1 +141, 11, 1 +141, 12, 2 +141, 13, 4 +141, 14, 5 +141, 15, 2 +142, 16, 1 +142, 17, 3 +142, 18, 3 +143, 19, 2 +143, 20, 4 +144, 21, 4 +144, 22, 1 +145, 23, 4 +145, 24, 2 +146, 25, 5 +146, 26, 5 +147, 27, 4 +147, 28, 3 +148, 29, 4 +148, 30, 3 +149, 31, 4 +149, 32, 2 +150, 33, 4 +150, 34, 2 +151, 35, 4 +151, 36, 4 +152, 37, 3 +152, 38, 3 +153, 39, 3 +153, 40, 1 +154, 41, 1 +154, 42, 5 +155, 43, 2 +155, 44, 2 +155, 45, 2 +156, 01, 1 +156, 02, 1 +156, 03, 3 +156, 04, 3 +156, 05, 3 +157, 06, 2 +157, 07, 4 +157, 08, 4 +157, 09, 4 +157, 10, 4 +158, 11, 1 +158, 12, 2 +158, 13, 4 +158, 14, 5 +158, 15, 5 +159, 16, 4 +159, 17, 3 +159, 18, 5 +160, 19, 3 +160, 20, 1 +161, 21, 3 +161, 22, 2 +162, 23, 1 +162, 24, 1 +163, 25, 3 +163, 26, 4 +164, 27, 4 +164, 28, 5 +165, 29, 4 +165, 30, 5 +166, 31, 2 +166, 32, 5 +167, 33, 3 +167, 34, 2 +168, 35, 4 +168, 36, 5 +169, 37, 1 +169, 38, 3 +170, 39, 2 +170, 40, 2 +171, 41, 5 +171, 42, 5 +172, 43, 2 +172, 44, 2 +172, 45, 3 \ No newline at end of file diff --git a/ai-service/DB/chapter.txt b/ai-service/DB/chapter.txt new file mode 100644 index 0000000..319c72a --- /dev/null +++ b/ai-service/DB/chapter.txt @@ -0,0 +1,18 @@ +101, 9, 13 +102, 15, 19 +103, 21, 25 +104, 27, 31 +105, 33, 37 +106, 39, 43 +107, 45, 49 +108, 51, 55 +109, 57, 61 +110, 63, 67 +111, 69, 73 +112, 75, 79 +113, 82, 85 +201, 88, 104 +202, 105, 121 +203, 122, 138 +204, 139, 155 +205, 156, 172 \ No newline at end of file diff --git a/ai-service/DB/files/crop_images.py b/ai-service/DB/files/crop_images.py new file mode 100644 index 0000000..af77ff5 --- /dev/null +++ b/ai-service/DB/files/crop_images.py @@ -0,0 +1,277 @@ +import os +from dotenv import load_dotenv +import logging +import json +from pathlib import Path +from typing import Dict, List, Optional, Tuple +import cv2 +import numpy as np +from datetime import datetime + +# --- ์™ธ๋ถ€ ๋ชจ๋“ˆ --- +from models.Detection.Model_routing_1004.run_routed_inference import RoutedInference +from models.Recognition.ocr import OCRModel + +load_dotenv() + +# ----------------------------------------------------------- +# ๋กœ๊น… ์„ค์ • +# ----------------------------------------------------------- +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +# ----------------------------------------------------------- +# ๋ฉ”์ธ ํŒŒ์ดํ”„๋ผ์ธ ํด๋ž˜์Šค +# ----------------------------------------------------------- +class LLMDBPipeline: + """๋ฌธ์ œ์ง‘ ์ด๋ฏธ์ง€ โ†’ ์ด๋ฏธ์ง€ ์ €์žฅ""" + + def __init__(self, model_dir: str, groq_api_key: Optional[str] = None): + self.router = RoutedInference(model_dir) + self.ocr = OCRModel() + + # JSON ํŒŒ์ผ ์ดˆ๊ธฐํ™” + self._init_json_file() + + logger.info("LLMDBPipeline ์ดˆ๊ธฐํ™” ์™„๋ฃŒ") + + # ------------------------------------------------------- + # JSON ์ €์žฅ + # ------------------------------------------------------- + def _init_json_file(self): + """JSON ํŒŒ์ผ ์ดˆ๊ธฐํ™” (๋นˆ ๋ฐฐ์—ด๋กœ ์ƒ์„ฑ)""" + try: + with open(self.output_json_path, 'w', encoding='utf-8') as f: + json.dump([], f, ensure_ascii=False, indent=2) + logger.info(f"JSON ํŒŒ์ผ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ: {self.output_json_path}") + except Exception as e: + logger.error(f"JSON ํŒŒ์ผ ์ดˆ๊ธฐํ™” ์‹คํŒจ: {e}") + + def save_to_json(self, question: Dict): + """์งˆ๋ฌธ์„ JSON ํŒŒ์ผ์— ์ถ”๊ฐ€""" + try: + # ๊ธฐ์กด JSON ํŒŒ์ผ ์ฝ๊ธฐ + with open(self.output_json_path, 'r', encoding='utf-8') as f: + questions_data = json.load(f) + + # ์ƒˆ๋กœ์šด ์งˆ๋ฌธ ์ถ”๊ฐ€ + questions_data.append(question) + + # ํŒŒ์ผ์— ์ €์žฅ + with open(self.output_json_path, 'w', encoding='utf-8') as f: + json.dump(questions_data, f, ensure_ascii=False, indent=2) + + logger.info(f"JSON ์ €์žฅ ์™„๋ฃŒ: ํŽ˜์ด์ง€ {question['page_number']} - ๋ฌธ์ œ {question['problem_number']}") + except Exception as e: + logger.error(f"JSON ์ €์žฅ ์‹คํŒจ: {e}") + + # ------------------------------------------------------- + # OCR ์œ ํ‹ธ + # ------------------------------------------------------- + def extract_text_from_image(self, image_path: str) -> str: + """์ด๋ฏธ์ง€์—์„œ ํ…์ŠคํŠธ๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค (ํ•œ๊ตญ์–ด/์˜์–ด ๋ชจ๋‘ ์ง€์›).""" + try: + # OCRModel์˜ extract_text ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ + text = self.ocr.extract_text(image_path) + return text.strip() + except Exception as e: + logger.error(f"OCR ์ถ”์ถœ ์‹คํŒจ ({image_path}): {e}") + return "" + + # ------------------------------------------------------- + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ + # ------------------------------------------------------- + def crop_page_number(self, image_path: str, detections: List[Dict], output_dir: Path) -> Tuple[Optional[str], Optional[str]]: + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return None, None + + page_num_dets = [d for d in detections if d['class_name'] == 'page_number'] + if not page_num_dets: + logger.warning(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ: {image_path}") + return None, None + + best_det = max(page_num_dets, key=lambda x: x['confidence']) + x1, y1, x2, y2 = map(int, best_det['bbox']) + h, w = image.shape[:2] + x1, y1, x2, y2 = max(0, x1), max(0, y1), min(w, x2), min(h, y2) + cropped = image[y1:y2, x1:x2] + + save_dir = output_dir / "page_numbers" + save_dir.mkdir(parents=True, exist_ok=True) + save_path = save_dir / f"{Path(image_path).stem}_page_number.jpg" + cv2.imwrite(str(save_path), cropped) + + logger.info(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€ ์ €์žฅ: {save_path}") + return str(save_path), None # OCR์€ ๋‚˜์ค‘์— ์ˆ˜ํ–‰ + + # ------------------------------------------------------- + # ์ด๋ฏธ์ง€ crop ๋ฐ ์ €์žฅ (์ด ๋‹จ๊ณ„์—์„œ๋Š” OCR ๋ฏธ์ˆ˜ํ–‰) + # ------------------------------------------------------- + def crop_and_save_images(self, image_path: str, section_idx: int, + output_dir: Path, section_bbox: List[float], all_detections: List[Dict]) -> List[Dict]: + """์ด๋ฏธ์ง€๋ฅผ cropํ•˜๊ณ  ์ €์žฅ๋งŒ ์ˆ˜ํ–‰ (OCR ๋ฏธ์ˆ˜ํ–‰)""" + image = cv2.imread(image_path) + if image is None: + return [] + + sx1, sy1, sx2, sy2 = section_bbox + section_output = output_dir / f"section_{section_idx:02d}" + section_output.mkdir(parents=True, exist_ok=True) + + detections = [d for d in all_detections if sx1 <= (d['bbox'][0]+d['bbox'][2])/2 <= sx2 + and sy1 <= (d['bbox'][1]+d['bbox'][3])/2 <= sy2] + + problems = [d for d in detections if d['class_name'] == 'problem_number'] + results = [] + + for idx, prob_det in enumerate(problems): + # ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€ ์ €์žฅ + x1, y1, x2, y2 = map(int, prob_det['bbox']) + cropped = image[y1:y2, x1:x2] + prob_num_path = section_output / f"prob_{idx:02d}_number.jpg" + cv2.imwrite(str(prob_num_path), cropped) + + result = { + "page_number": None, # OCR ๋‹จ๊ณ„์—์„œ ์ฑ„์›€ + "problem_number": None, # OCR ํ›„ ์ฑ„์›€ + "korean_content": None, + "english_content": None, + "answer_option": None, + "crop_paths": {"problem_number": str(prob_num_path)} + } + + # --- ์˜์–ด ์ง€๋ฌธ ์ด๋ฏธ์ง€ ์ €์žฅ --- + eng_dets = [d for d in detections if d['class_name'] == 'english_content'] + if eng_dets: + ed = eng_dets[0] + x1, y1, x2, y2 = map(int, ed['bbox']) + cropped = image[y1:y2, x1:x2] + eng_path = section_output / f"prob_{idx:02d}_english_content.jpg" + cv2.imwrite(str(eng_path), cropped) + result["crop_paths"]["english_content"] = str(eng_path) + + # --- ํ•œ๊ตญ์–ด ์ง€๋ฌธ ์ด๋ฏธ์ง€ ์ €์žฅ --- + kor_dets = [d for d in detections if d['class_name'] == 'korean_content'] + if kor_dets: + kd = kor_dets[0] + x1, y1, x2, y2 = map(int, kd['bbox']) + cropped = image[y1:y2, x1:x2] + kor_path = section_output / f"prob_{idx:02d}_korean_content.jpg" + cv2.imwrite(str(kor_path), cropped) + result["crop_paths"]["korean_content"] = str(kor_path) + + # --- ์„ ํƒ์ง€ ์ด๋ฏธ์ง€ ์ €์žฅ --- + answer_dets = [d for d in detections if d['class_name'] in ['answer_option', 'answer_1', 'answer_2']] + answer_dets = sorted(answer_dets, key=lambda x: x['class_name']) + for a_idx, a_det in enumerate(answer_dets): + x1, y1, x2, y2 = map(int, a_det['bbox']) + cropped = image[y1:y2, x1:x2] + a_path = section_output / f"prob_{idx:02d}_{a_det['class_name']}.jpg" + cv2.imwrite(str(a_path), cropped) + result["crop_paths"][a_det['class_name']] = str(a_path) + + results.append(result) + logger.info(f"๋ฌธ์ œ {idx:02d} ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ") + + return results + + # ------------------------------------------------------- + # OCR ์ธ์‹ (์ €์žฅ๋œ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ์ˆ˜ํ–‰) + # ------------------------------------------------------- + def perform_ocr_on_saved_images(self, question: Dict): + """์ €์žฅ๋œ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด OCR ์ˆ˜ํ–‰""" + crop_paths = question.get("crop_paths", {}) + + # ๋ฌธ์ œ ๋ฒˆํ˜ธ OCR + if "problem_number" in crop_paths: + prob_num = self.ocr.extract_number(crop_paths["problem_number"]) + question["problem_number"] = prob_num + logger.info(f"๋ฌธ์ œ ๋ฒˆํ˜ธ OCR ์™„๋ฃŒ: {prob_num}") + + # ์˜์–ด ์ง€๋ฌธ OCR + if "english_content" in crop_paths: + eng_text = self.extract_text_from_image(crop_paths["english_content"]) + question["english_content"] = eng_text + logger.info(f"์˜์–ด ์ง€๋ฌธ OCR ์™„๋ฃŒ") + + # ํ•œ๊ตญ์–ด ์ง€๋ฌธ OCR + if "korean_content" in crop_paths: + kor_text = self.extract_text_from_image(crop_paths["korean_content"]) + question["korean_content"] = kor_text + logger.info(f"ํ•œ๊ตญ์–ด ์ง€๋ฌธ OCR ์™„๋ฃŒ") + + # ์„ ํƒ์ง€ OCR + answer_list = [] + for key in sorted(crop_paths.keys()): + if key in ['answer_option', 'answer_1', 'answer_2']: + ans_text = self.extract_text_from_image(crop_paths[key]) + answer_list.append(ans_text) + + if answer_list: + question["answer_option"] = json.dumps(answer_list, ensure_ascii=False) + logger.info(f"์„ ํƒ์ง€ OCR ์™„๋ฃŒ ({len(answer_list)}๊ฐœ)") + + return question + + # ------------------------------------------------------- + # ํŽ˜์ด์ง€ ๋‹จ์œ„ ์ฒ˜๋ฆฌ - 1๋‹จ๊ณ„: ์ด๋ฏธ์ง€ Crop + # ------------------------------------------------------- + def crop_page(self, image_path: str, output_dir: Path): + """์ด๋ฏธ์ง€๋ฅผ cropํ•˜์—ฌ output ํด๋”์— ์ €์žฅ""" + try: + result = self.router.route_infer_single_image(image_path) + detections = result.get("detections", []) + + page_output = output_dir / Path(image_path).stem + page_output.mkdir(parents=True, exist_ok=True) + + page_num_path, _ = self.crop_page_number(image_path, detections, page_output) + if not page_num_path: + logger.error(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€ ์ €์žฅ ์‹คํŒจ: {image_path}") + return + + section_dets = sorted( + [d for d in detections if d["class_name"] == "section"], + key=lambda x: x["bbox"][1] + ) + + total_questions = 0 + for s_idx, s_det in enumerate(section_dets): + questions = self.crop_and_save_images(image_path, s_idx, page_output, s_det["bbox"], detections) + total_questions += len(questions) + + logger.info(f"ํŽ˜์ด์ง€ {Path(image_path).stem}: {total_questions}๊ฐœ ๋ฌธ์ œ ์ด๋ฏธ์ง€ ์ €์žฅ ์™„๋ฃŒ") + except Exception as e: + logger.error(f"ํŽ˜์ด์ง€ Crop ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ({image_path}): {e}") + + def process_multiple_pages(self, images_dir: str, output_dir: str): + """์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰""" + # Step 1: ๋ชจ๋“  ์ด๋ฏธ์ง€ Crop + logger.info("=== Step 1: ๋ชจ๋“  ์ด๋ฏธ์ง€ Crop ์‹œ์ž‘ ===") + images = sorted(Path(images_dir).glob("*.jpg")) + sorted(Path(images_dir).glob("*.png")) + + for img in images: + logger.info(f"Crop ์ฒ˜๋ฆฌ ์ค‘: {img.name}") + self.crop_page(str(img), Path(output_dir)) + + logger.info(f"=== Step 1 ์™„๋ฃŒ: Crop ์ €์žฅ ===") + +# ----------------------------------------------------------- +# ์‹คํ–‰ ์˜ˆ์‹œ +# ----------------------------------------------------------- +if __name__ == "__main__": + import os + + model_dir = "./models/Detection/Model_routing_1004" + images_dir = "./DB/images/database1z" + output_dir = "./DB/output/database1" + + pipeline = LLMDBPipeline(model_dir) + pipeline.process_multiple_pages(images_dir, output_dir) + + logger.info("์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์™„๋ฃŒ โœ…") \ No newline at end of file diff --git a/ai-service/DB/files/database1_fixed.json b/ai-service/DB/files/database1_fixed.json new file mode 100644 index 0000000..dcf16cd --- /dev/null +++ b/ai-service/DB/files/database1_fixed.json @@ -0,0 +1,715 @@ +[ + { + "page_number": "88", + "problem_number": "04", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๊ทธ๋ฆผ์—์„œ ๋Œ€ํ™”์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Sam, look what I found!\nM: Wow! Mom, isn't this a picture from when we lived in Greenville? I remember this playground.\nW: Yes, you and your sister Mary had so much fun playing there every day.\nM: Right. Here she is on the swing. She had the only swing all to herself.\nW: And here you are on top of the slides, waving at the camera. You look so happy.\nM: I loved those slides, especially this tunnel slide in the middle.\nW: Do you recognize the two boys on the seesaw?\nM: Wait a minute! Aren't they the brothers who lived next door? The one on the left wearing glasses must be Joe.\nW: You're right. And the one in the baseball cap is Jimmy.\nM: And this girl on the spring rider is their little sister,\nSally, right?\nW: Yes. She was always active and loved playing rough.\nM: I remember she used to ride this rocking horse on a spring, pretending to be a cowboy.\nW: Haha. I wonder what they're up to now. It's been so long since we've seen them.", + "answer_option": null + }, + { + "page_number": "88", + "problem_number": "01", + "korean_content": "๋‹ค์Œ์„ ๋“ฃ๊ณ , ๋‚จ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "Hello everyone, and welcome to Greendale Library's humanities program. We're thrilled to see so many of you here. As you know, we're honored to host a distinguished guest for today's lecture, Professor Joan Reed, Vice President of Southfield University. Professor Reed is an expert on the Fourth Industrial Revolution and the best-selling author of Journey into the Metaverse. Her highly anticipated new book, Al Odyssey, is coming out next month. She'll share her insights on how the humanities can help us navigate through the challenges and opportunities of an Al-driven world. Please join me in warmly welcoming Professor Reed.", + "answer_option": "(1)๊ฐ•์˜๋ฅผ ์ง„ํ–‰ํ•  ๊ฐ•์‚ฌ๋ฅผ ์†Œ๊ฐœํ•˜๋ ค๊ณ  (2)์ธ๋ฌธํ•™ ํ”„๋กœ๊ทธ๋žจ ์ฐธ๊ฐ€๋ฅผ ๊ถŒ์œ ํ•˜๋ ค๊ณ  (3)๋„์„œ๊ด€ ํ–‰์‚ฌ ์ผ์ • ๋ณ€๊ฒฝ์„ ๊ณต์ง€ํ•˜๋ ค๊ณ  (4)์ธ๊ณต ์ง€๋Šฅ ๊ด€๋ จ ์‹ ๊ฐ„ ๋„์„œ๋ฅผ ์ถ”์ฒœํ•˜๋ ค๊ณ  (5)ํ–‰์‚ฌ ์ฐธ์„์ž๋“ค์—๊ฒŒ ๊ฐ์‚ฌํ•จ์„ ํ‘œํ˜„ํ•˜๋ ค๊ณ " + }, + { + "page_number": "88", + "problem_number": "02", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž์˜ ์˜๊ฒฌ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "M: Hey, Jane! Didn't you hear me? I've been calling your name from over there!\nW: Oh, Dean! Sorry. I didn't notice with these earphones on.\nM: What are you listening to? Music?\nW: No, I'm listening to Anne of Green Gables. I love this novel.\nM: I love it too. Do you think an audiobook is a good way to experience the story?\nW: Definitely. Have you ever tried audiobooks? They're really awesome.\nM: I haven't. But doesn't it take a lot more time to listen to the book than to read it?\nW: Yeah. It's a time-saver for me though.\nM: How so?\nW: I can listen to audiobooks while commuting, doing chores, or even exercising. It's perfect for multitasking.\nM: I see what you mean. It's hard to find time to sit and read these days.\nW: Why don't you try audiobooks? I'm sure you'll find them very convenient.", + "answer_option": "(1)์ด์–ดํฐ์„ ์˜ค๋žซ๋™์•ˆ ์ฐฉ์šฉํ•˜๋ฉด ์ฒญ๋ ฅ์ด ์†์ƒ๋  ์ˆ˜ ์žˆ๋‹ค. (2)์˜ค๋””์˜ค ๋ถ์€ ๋…์ž๊ฐ€ ์ž‘ํ’ˆ์— ๋น ๋ฅด๊ฒŒ ๋ชฐ์ž…ํ•˜๋„๋ก ๋•๋Š”๋‹ค. (3)์˜ค๋””์˜ค ๋ถ์€ ๋‹ค๋ฅธ ์ผ์„ ํ•˜๋ฉด์„œ ๋“ค์„ ์ˆ˜ ์žˆ์–ด ํŽธ๋ฆฌํ•˜๋‹ค. (4)์—ฌ๋Ÿฌ ์ผ์„ ๋™์‹œ์— ํ•˜๋Š” ๊ฒƒ์€ ์‹ค์ œ๋กœ ํšจ์œจ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค. (5)ํ‹ˆ์ด ๋‚  ๋•Œ๋งˆ๋‹ค ์ฑ…์„ ์ฝ๋Š” ์Šต๊ด€์„ ๊ธฐ๋ฅด๋Š” ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค." + }, + { + "page_number": "88", + "problem_number": "05", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž๊ฐ€ ํ•  ์ผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "[Cell phone rings.]\nW: Hello, Jason. Where are you?\nM: Hi, Anne. I'm on my way to the office. I went to the bank to run some errands.\nW: I see. You know the workshop starts in an hour. And we still need to set some things up.\nM: I know. But don't worry. Everything is basically already taken care of.\nW: That's good. So have you copied the handout for the workshop?\nM: Yes. They're in the cabinet to the right of my desk.\nW: Okay. Have you heard from Professor Kim about when she's coming? She's the instructor of the workshop.\nM: She should be there by one-thirty. I have her phone number. I'll call her now to check.\nW: Thanks. Then I'll open the windows in the conference room to let some fresh air in.\nM: Good idea. While you're at it, could you check the projector too?\nW: No problem. Anyway, try to get here as soon as you can.\nM: I'll be there in ten minutes.", + "answer_option": "(1) ์€ํ–‰์— ๊ฐ€๊ธฐ (2) ๊ฐ•์‚ฌ์—๊ฒŒ ์ „ํ™” ๊ฑธ๊ธฐ (3) ํšŒ์˜์‹ค ์ฐฝ๋ฌธ์„ ์—ด์–ด ํ™˜๊ธฐ์‹œํ‚ค๊ธฐ (4) ํšŒ์˜์‹ค ํ”„๋กœ์ ํ„ฐ ํ™•์ธํ•˜๊ธฐ (5) ์œ„ํฌ์ˆ ์œ ์ธ๋ฌผ ๋ณต์‚ฌํ•˜๊ธฐ" + }, + { + "page_number": "88", + "problem_number": "03", + "korean_content": "๋‹ค์Œ์„ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Good morning, listeners! If you've stayed up all night, you know you're not at 100 percent the next day. You might feel sleepy, dizzy, or slow. But when you get a good night's sleep, you're ready to take on the day. Taking care of your mental health is just as important. Ignoring your emotions and not addressing your issues can make you feel terrible. Thankfully, mindfulness meditation can help you manage your feelings. Try starting your day with a five-minute breathing exercise every morning. Breathe. Relax. Think about all you hope to accomplish today and how you'll go about it. And smile. Morning meditation is an excellent way to maintain your mental health.", + "answer_option": "(1)์ž์‹ ์˜ ๊ฐ์ •์„ ์ ์ ˆํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๋Š” ๋ฒ•์„ ์ตํ˜€์•ผ ํ•œ๋‹ค. (2)์•„์นจ ๋ช…์ƒ์€ ์ •์‹  ๊ฑด๊ฐ•์„ ์œ ์ง€ํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค. (3)ํ‹ˆํ‹ˆ์ด ์ŠคํŠธ๋ ˆ์นญ์œผ๋กœ ํ”ผ๋กœ๋ฅผ ํ’€์–ด ์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. (4)๋ฐ์€ ๋ฏธ์†Œ๋ฅผ ์ง“๋‹ค ๋ณด๋ฉด ์ €์ ˆ๋กœ ๋งˆ์Œ์ด ๋ฐ์•„์ง„๋‹ค. (5)์ˆ˜๋ฉด ๋ถ€์กฑ์€ ์‹ฌ๋ฆฌ ์ƒํƒœ์— ๋ถ€์ •์  ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค." + }, + { + "page_number": "89", + "problem_number": "06", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ์ง€๋ถˆํ•  ๊ธˆ์•ก์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hi, I'd like to settle the bill, please.\nM: Okay. I hope you and your family enjoyed the dinner tonight.\nW: Oh, it was terrific! So delicious. Thank you.\nM: I'm delighted to hear that. Let me go over your order again. You had the Margherita pizza, the spaghetti carbonara, and the lobster risotto. Is that correct?\nW: Yes, that's right.\nM: Great. The Margherita pizza is $20, the spaghetti carbonara is $15, and the lobster risotto is $25. So, that comes to a total of $60.\nW: And could I get one piece of tiramisu to go? I'd like to try it later when I'm not so full.\nM: Sure. Our tiramisu is really good.\nW: I've heard. It's $10, right?\nM: Yes. Would you like to pay by card or cash?\nW: I'll pay by card, please. Oh, and I have this coupon.\nM: Alright. That'll give you 10 percent off the total price.\nW: That's great. Thanks.", + "answer_option": "(1)$54 (2)$60 (3)$63 (4)$70 (5)$72" + }, + { + "page_number": "89", + "problem_number": "07", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž๊ฐ€ ํ•ด์™ธ ์—ฐ์ˆ˜ ํ”„๋กœ๊ทธ๋žจ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hello, Thomas. How are you?\nM: Hi, Susie. I've never been better. How about you?\nW: I'm doing well. I heard your team successfully completed your challenging project and will now attend a two-week training program in South America. Great job!\nM: Thanks! My team is excited since the company is covering all the expenses.\nW: That's wonderful! Since you're fluent in Spanish, you can help translate for others.\nM: Well, actually, I'm not going.\nW: What? Why not? Isn't this your first chance for oversea training?\nM: Yes, but I'm hoping there'll be another chance later.\nW: I don't understand. Why are you passing up this opportunity?\nM: My wife is due to give birth soon.\nw: Oh, congratulations! Now I get it. It's best to stay close to her right now.\nM: Exactly. My wife and I are thrilled to have our first child.", + "answer_option": "(1)ํ•ด์™ธ ์—ฐ์ˆ˜๋ฅผ ๋‹ค๋…€์˜จ ์ ์ด ์žˆ์–ด์„œ (2)์•„๋‚ด๊ฐ€ ๊ณง ์ถœ์‚ฐํ•  ์˜ˆ์ •์ด์–ด์„œ (3)์ŠคํŽ˜์ธ์–ด๊ฐ€ ์œ ์ฐฝํ•˜์ง€ ๋ชปํ•ด์„œ (4)์ƒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งก๊ฒŒ ๋˜์–ด์„œ (5)์—ฐ์ˆ˜ ๋น„์šฉ์ด ๋ถ€๋‹ด๋˜์–ด์„œ" + }, + { + "page_number": "89", + "problem_number": "08", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , Riverside ๋งˆ๋ผํ†ค ๋Œ€ํšŒ์— ๊ด€ํ•ด ์–ธ๊ธ‰๋˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Ben, have you seen the poster for the Riverside Marathon?\nIt sounds fun!\nM: Yeah, it's on October 25th, right? I'm planning to sign up.\nW: Really? That's awesome! Can I join you? I've wanted to run a marathon for ages.\nM: Of course, Rachel! It'd be great to do it together.\nW: Do you know the marathon course?\nM: It starts at City Hall, goes through Braxton Park, along the river, and finishes at Riverside Stadium.\nW: That sounds tough but enjoyable! By the way, the entry fee is $80 per person. Don't you think it's a bit high?\nM: I know what you mean. It's a bit pricey, but you get a T-shirt and a finisher's medal as souvenirs as well as snacks. Plus, the experience is priceless!\nW: That's true. I've never run a full marathon before, so I'm really looking forward to it.\nM: Me too. It's going to be a great experience!", + "answer_option": "(1)๋Œ€ํšŒ ์ผ์ž (2)์ถœ๋ฐœ ์žฅ์†Œ (3)์ฐธ๊ฐ€ ์‹ ์ฒญ ๋ฐฉ๋ฒ• (4)์ฐธ๊ฐ€๋น„ (5)๊ธฐ๋…ํ’ˆ" + }, + { + "page_number": "89", + "problem_number": "09", + "korean_content": "Young Scientist Program์— ๊ด€ํ•œ ๋‹ค์Œ ๋‚ด์šฉ์„ ๋“ฃ๊ณ , ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "M: Hello, students! I'm your science teacher Alan Cho. I have exciting news! Since 1991, Lewistown University has been running the Young Scientist Summer Program every summer. It's an eight-week internship that pays you $1,000. As an intern, you'll work alongside real scientists from Lewistown University on their research projects. Plus, you'll take two courses to improve your science communication skills and learn how to write research reports. Any senior high school student interested in biomedical science can apply. Interns are selected through a document screening and interview process in the spring. The application deadline this year is April 10, and the program begins in July. Don't miss this fantastic opportunity to work on lab projects and receive personalized mentorship!", + "answer_option": "(1)1991๋…„๋ถ€ํ„ฐ ๋งค๋…„ ์—ฌ๋ฆ„๋งˆ๋‹ค ์ง„ํ–‰๋˜์–ด ์™”๋‹ค. (2)์ฐธ๊ฐ€์ž๋Š” ๊ฐ๊ฐ ์ž์‹ ์ด ๊ณ„ํšํ•œ ์—ฐ๊ตฌ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค. (3)์ฐธ๊ฐ€์ž๋Š” ๊ณผํ•™ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ๊ธฐ์ˆ  ํ–ฅ์ƒ์„ ๋•๋Š” ๊ฐ•์ขŒ๋ฅผ ๋“ฃ๋Š”๋‹ค. (4)์ฐธ๊ฐ€์ž ์„ ๋ฐœ์€ ์„œ๋ฅ˜ ์‹ฌ์‚ฌ์™€ ๋ฉด์ ‘์œผ๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค. (5)์ฐธ๊ฐ€ ์ง€์› ๋งˆ๊ฐ์ผ์€ 4์›” 10์ผ์ด๋‹ค." + }, + { + "page_number": "89", + "problem_number": "10", + "korean_content": "๋‹ค์Œ ํ‘œ๋ฅผ ๋ณด๋ฉด์„œ ๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‘ ์‚ฌ๋žŒ์ด ์ฃผ๋ฌธํ•  ์ฑ…์ƒ ์˜์ž๋ฅผ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Honey, can you help me pick out a desk chair for Tommy?\nM: Sure. It's time we got him a new one since his current chair is really old.\nW: Right. Look at this one. Doesn't it look nice?\nM: Well, I don't want to spend more than $100 on a chair.\nHe's only ten.\nW: I agree. We don't need to spend that much. But we definitely should get him a chair with adjustable height, since he's growing.\nM: Absolutely! Should we get one with armrests?\nW: I don't think so. Chairs without armrests don't take up as much space. And as you know, his room is really small.\nM: Good point. It's down to these two options.\nW: I prefer this one. It'll keep Tommy cool when he sits for a long time.\nM: True. Also, mesh is easier to clean than fabric.\nW: Perfect. Let's order it.", + "answer_option": "(1)Model:A, Price:$105, Adjustable Height: O, Armrests: O, Backrest Material: Mesh (2)Model:B, Price:$90, Adjustable Height: O, Armrests: O, Backrest Material: Plastic (3)Model:C, Price:$75, Adjustable Height: O, Armrests: X, Backrest Material: Soft Fabric (4)Model:D, Price:$55, Adjustable Height: O, Armrests: X, Backrest Material: Mesh (5)Model:E, Price:$35, Adjustable Height: X, Armrests: X, Backrest Material: Plastic" + }, + { + "page_number": "90", + "problem_number": "14", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž์˜ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Man:", + "script": "W: Hello. Welcome to Happy Family Restaurant. Are you here to dine in or to pick up?\nM: Hi. Actually, I just have a question. I was here yesterday and had lunch at that table over there.\nW: I see. Was there something wrong with the service?\nM: No. But did you happen to find a wallet on the table? I lost it, and this is the last place I remember having it.\nW: Oh, I'm sorry to hear that. Let me check with the staff who were here yesterday.\nM: Thanks. I appreciate it.\nW: Of course. Please wait a moment. [Pause] Good news!\nThey found a wallet yesterday.\nM: Oh, that's a relief!\nW: I just need to confirm it's yours. Can you tell me the color of your wallet?\nM: It's blue. I really hope it's my wallet.", + "answer_option": "(1)That's too bad This one is purple. (2)No, I don't have my wallet with me. (3)It's blue. I really hope it's my wallet. (4)Actually, I'm not a fan of that color. (5)Well, I expect better service next time." + }, + { + "page_number": "90", + "problem_number": "11", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "[Telephone rings.]\nM: Thank you for calling Luxe Hair Studio. How can I help you today?\nW: Hi, Steve, it's Emily. I have an appointment tomorrow at 11:00 a.m., but something came up, and I was hoping to reschedule. After 3:00 p.m. would work best for me.\nM: Hi, Emily! Let me check the schedule. Just a moment.\n[Pause] Thanks for waiting. I'm afraid tomorrow afternoon is fully booked.\nW: I see. Then when would be the next available time slot?", + "answer_option": "(1)That's perfect for me. See you tomorrow then. (2)Okay. I'II take the morning off and catch up on rest. (3)Don't worry. Shall I recommend a new stylist for you? (4)Sorry, I completely forgot about the appointment today. (5)I see. Then when would be the next available time slot?" + }, + { + "page_number": "90", + "problem_number": "12", + "korean_content": "๋Œ€ํšŒ๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Honey, are you ready? We need to head out now.\nM: I know, but I can't find my phone. Have you seen it?\nW: No. Let me call it. It'll be easier to find if it's ringing.\nM: Thanks. We can head out as soon as I find it.", + "answer_option": "(1)Thanks. We can head out as soon as I find it. (2)No problem Let's just go there another time. (3)Not really. I don't need to answer this call. (4)Of course. I always keep it on silent mode. (5)Sure. Give me your number right now." + }, + { + "page_number": "90", + "problem_number": "15", + "korean_content": "๋‹ค์Œ ์ƒํ™ฉ ์„ค๋ช…์„ ๋“ฃ๊ณ , Mr. Peterson์ด Claire์—๊ฒŒ ํ•  ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Mr Peterson:", + "script": "W: Claire is a high school student. She has been catching a lot of colds recently. Mr. Peterson, her homeroom teacher, is worried and calls her to his office to find out if something is wrong. During their conversation, Claire says that she sleeps with her windows wide open. She feels that it gets too stuffy in her room when they're closed. However, Mr. Peterson read in an article that leaving the windows open all night can drop one's body temperature, leading to poor sleep quality and weaker immune system. So, he thinks that's the reason Claire often gets sick and he wants to advise her to close the windows before she goes to bed. In this situation, what would Mr. Peterson most likely say to Claire?\nMr. Peterson: Be sure to keep your windows closed while you sleep for your health.", + "answer_option": "(1)I think you should go to bed earlier to feel better in the morning. (2)You'd better turn on the heater in your room before going to bed. (3)Consider talking to your doctor about why you keep catching colds. (4)Be sure to keep your windows closed while you sleep for your health. (5)You should get your windows fixed so that you can lock them to stay safe." + }, + { + "page_number": "90", + "problem_number": "13", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Woman:", + "script": "M: Hi, Olivia. Did you hear that James Bennett, the best-selling author, is coming to our school tomorrow?\nW: Really? I love his books! Why's he coming?\nM: He's giving a lecture at the auditorium.\nW: I have to go to it. Do you want to go together?\nM: Sure! I was planning to go too.\nW: Awesome! What's the lecture about?\nM: It's about his latest book, which came out last week.\nW: Oh, I didn't realize it's already come out! Do you know if he'll be signing books?\nM: Yes, there's a book-signing event after the lecture.\nW: Do we need to bring a copy, or will they be selling the book there?\nM: I heard that they'll be selling it at the event.\nW: Great. I'll buy a copy at the event and ask him to sign it.", + "answer_option": "(1)Great. I'll buy a copy at the event and ask him to sign it. (2)Dont worry. I can get your book signed for you. (3)Unfortunately, I failed to sign up for the event. (4)No thank you. I already have a copy of his book. (5)Absolutely.\\nI loved the copy that you gave me last time." + }, + { + "page_number": "91", + "problem_number": "18", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Dear Ms. Thompson, I trust this note finds you in good spirits. For the past 20 years, my husband and I have enjoyed our weekends at Meadowbrook Public Library, where the joy of reading together has become a treasured part of our lives. As my husband approaches retirement, we've decided to return to our roots in Cedar Falls. While packing for this new chapter, we've discovered an extensive collection of books we've accumulated over the years. We would be delighted if these beloved volumes could find a new home through your library's upcoming free book giveaway event. It would be a fitting way to share the joy we've experienced at Meadowbrook with others in the community. Please let us know the best way to coordinate this donation. We're deeply grateful for the wonderful experiences we've had at your library. Warmest regards, Susan and Robert Miller", + "script": null, + "answer_option": "(1)๋„์„œ๊ด€ ์ฃผ๋ง ์šด์˜ ์‹œ๊ฐ„ ์—ฐ์žฅ์„ ๊ฑด์˜ํ•˜๋ ค๊ณ  (2)๋„์„œ๊ด€ ๋ณด์œ  ์žฅ์„œ ๊ด€๋ฆฌ ๋ฐฉ๋ฒ• ๊ฐœ์„ ์„ ์ œ์•ˆํ•˜๋ ค๊ณ  (3)๋„์„œ๊ด€ ์ •๊ธฐ ์ด์šฉ์ž ๋ชจ์ž„ ๊ฐ€์ž… ๋ฐฉ๋ฒ•์„ ์•ˆ๋‚ดํ•˜๋ ค๊ณ  (4)๋„์„œ๊ด€ ์ฃผ๋ง ์€ํ‡ด์ž ๊ต์œก ํ”„๋กœ๊ทธ๋žจ ์ฐธ๊ฐ€๋ฅผ ์‹ ์ฒญํ•˜๋ ค๊ณ  (5)๋„์„œ๊ด€ ๋ฌด๋ฃŒ ๋„์„œ ๋‚˜๋ˆ” ํ–‰์‚ฌ ๋„์„œ ๊ธฐ์ฆ ๋ฐฉ๋ฒ•์„ ๋ฌธ์˜ํ•˜๋ ค๊ณ " + }, + { + "page_number": "91", + "problem_number": "16", + "korean_content": "๋‚จ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": null, + "script": "M: Good morning, everyone. In our last class, we learned that 3D printing, also known as additive manufacturing. creates objects layer by layer from digital designs. Today, we'll explore its diverse applications across various fields. First, in medicine, 3D printing enables the creation of custom artificial bones and implants. For example, doctors can make hip joints that perfectly fit individual patients. Second, in manufacturing, companies use 3D printing to quickly and affordably produce samples, which helps them design products faster. Third, the aerospace industry uses 3D printing to manufacture lightweight, durable components, significantly reducing production times and costs. Lastly, in fashion, designers use 3D printing to make unique clothes and accessories, experimenting with new shapes and materials that are difficult to make by hand. 3D printing is a powerful tool transforming multiple industries. As technology advances, we'll discover even more amazing uses for it. Now, let's watch a video about this.", + "answer_option": "(1)introduction to 3D digital design (2)industries devoted to manufacturing (3)cutting-edge materials used in 3D printing (4)techniques for prototyping in architecture (5)uses of 3D printing across different sectors" + }, + { + "page_number": "91", + "problem_number": "17", + "korean_content": "์–ธ๊ธ‰๋œ ๋ถ„์•ผ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์€?", + "english_content": null, + "script": "M: Good morning, everyone. In our last class, we learned that 3D printing, also known as additive manufacturing. creates objects layer by layer from digital designs. Today, we'll explore its diverse applications across various fields. First, in medicine, 3D printing enables the creation of custom artificial bones and implants. For example, doctors can make hip joints that perfectly fit individual patients. Second, in manufacturing, companies use 3D printing to quickly and affordably produce samples, which helps them design products faster. Third, the aerospace industry uses 3D printing to manufacture lightweight, durable components, significantly reducing production times and costs. Lastly, in fashion, designers use 3D printing to make unique clothes and accessories, experimenting with new shapes and materials that are difficult to make by hand. 3D printing is a powerful tool transforming multiple industries. As technology advances, we'll discover even more amazing uses for it. Now, let's watch a video about this.", + "answer_option": "(1)medicine (2)manufacturing (3)education (4)aerospace (5)fashion" + }, + { + "page_number": "92", + "problem_number": "19", + "korean_content": "๋‹ค์Œ ๊ธ€์— ๋“œ๋Ÿฌ๋‚œ Faith์˜ ์‹ฌ๊ฒฝ ๋ณ€ํ™”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Once she strapped on the safety gear, Faith climbed up and stood at the edge of the highline. Oh man, if I don't do this right I could kill myself. She was gripped by a nearly overwhelming fear. Her body shook as she tried to walk across the narrow line โ€” and fell. Now she was dangling below the line. It took enormous strength to climb the rope to get back up. Trying a few more times, she fell again and again, each time climbing back up to try once more to walk across the line. The voice of fear kept crushing her confidence. She told herself, I'm not cut out for this. Gradually, though, Faith's fear transformed into resolution. After multiple falls wearing the harness, she knew she was safe. Still, attached to her leash and hanging below each line, she knew she was going to keep trying. She told herself that it was important to fall in order to reinforce the fact that she was safe.", + "script": null, + "answer_option": "(1)terrified -> determined (2)thrilled -> indifferent (3)bored -> expectant (4)angry -> embarrassed (5)confident -> frightened" + }, + { + "page_number": "92", + "problem_number": "20", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ํ•„์ž๊ฐ€ ์ฃผ์žฅํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "When you start where your students are, you don't think in terms of 'should.' If you want to motivate students to learn, first find out what currency they are spending (or what currency they value), and pay them in that currency. From there, you can teach them how to find the reward in other things. For many of our students, intrinsic motivation has to be developed. It comes only after they have experienced the pleasure of doing well and know the rewards of success. At the beginning, many of our students haven't experienced consistent academic success and are not convinced that it will bring any pleasure. In fact, academic success has been a source of pain for them because it has been heretofore an unachievable goal. This is why it is so important to start with what motivates them and then, as they experience more success, help them transfer or become motivated by that success.", + "script": null, + "answer_option": "(1)ํ•™์ƒ์ด ๊ฒฝ์ œ์  ์„ฑ๊ณต์˜ฌ ๊ฒฝํ—˜ํ•˜๋„๋ก ์‹ค์ƒํ™œ๊ณผ ์—ฐ๊ณ„๋œ ๊ฒฝ์ œ ๊ต์œก์˜ฌ ๊ฐ•ํ™”ํ•ด์•ผ ํ•œ๋‹ค. (2)ํ•™์ƒ์ด ์›ํ•˜๋Š” ๋ณด์ƒ์˜ฌ ์ฃผ๊ณ  ์„ฑ๊ณต ๊ฒฝํ—˜์˜ฌ ์Œ“๋„๋ก ๋„์™€ ํ•™์Šต ๋™๊ธฐํ‹€ ๋†’์—ฌ์•ผ ํ•œ๋‹ค. (3)์„ฑ์ ์ด ์ €์กฐํ•œ ํ•™์ƒ์—๊ฒŒ๋Š” ๊ฐœ๋ณ„ํ™”๋œ ํ•™์Šต ํ”„๋กœ๊ทธ๋žจ์„ ์ถฉ๋ถ„ํ•˜๊ฒŒ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค. (4)ํ•™์ƒ ์Šค์Šค๋กœ ํƒ์ƒ‰ํ•˜์—ฌ ์ž์‹ ์—๊ฒŒ ๋งž๋Š” ์ง„๋กœ๋ฅผ ์„ ํƒํ•˜๋„๋ก ๋™๊ธฐ๋ฅผ ๋ถ€์—ฌํ•ด์•ผ ํ•œ๋‹ค. (5)ํ•™์Šต์— ๋Œ€ํ•œ ํฅ๋ฏธ๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ๋„๋ก ๋‹ค์–‘ํ•œ ์ƒˆ๋กœ์šด ๊ต์ˆ˜๋ฒ•์„ ์‹œ๋„ํ•ด์•ผ ํ•œ๋‹ค." + }, + { + "page_number": "93", + "problem_number": "21", + "korean_content": "๋ฐ‘์ค„ ์นœ burning fossil fuels in our cars๊ฐ€ ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "If truth is what we must seek, then we have both opportunities and responsibilities. We have opportunities to discover facts, which by virtue of being true are likely to be useful, certainly more useful than falsehoods. And we have responsibilities not to pollute the infosphere with falsehood and hot air. This requires a form of cognitive and linguistic literacy: an awareness of how language works on the mind and in social interaction. And it requires intellectual discipline. When we unthinkingly boost the signal of some misinformation, even just by 'liking' a post we haven't fact-checked, the effect is like \n\n ๋ฐ‘์ค„:. \n\n As individuals, when we produce emissions, we feel that our singular contribution to the problem does not make a difference in the larger context. But of course it would make a difference if only we acted collectively. In the same way, says legal scholar Ilya Somin, 'Widespread public ignorance is a type of pollution that infects the political system.'", + "script": null, + "answer_option": "(1)accumulating seemingly harmless contributions to information pollution (2)enhancing the public good at the expense of individual interests (3)minimizing the impact of the spread of false information on society (4)diminishing the importance of linguistic literacy in the digital age (5)boosting collective efforts to construct a reliable informative environment" + }, + { + "page_number": "93", + "problem_number": "22", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Ambitious business development goals impose high pressure on all employees to demonstrate personal achievements and improvement. Companies often create a climate in which goals must be achieved at all costs. Managers will not tolerate subordinates bringing them bad news, demanding to see only successful results. In some organizations, a state of total fear of the management develops: it becomes almost impossible to admit any professional mistake without risking sanctions or punishment, including dismissal. Some employees cannot function well under this pressure and, to preserve the impression of success, they falsify their achievements and embellish reality. Hearing nothing but good news from their cowed employees, executives are under the illusion that everything is going well. When a crisis finally comes, it turns out that the real situation was being concealed to fit in with the impossible standards promoted in an organization and the demand to achieve success at any price.", + "script": null, + "answer_option": "(1)๊ณผ๋„ํ•œ ๋ชฉํ‘œ ๋‹ฌ์„ฑ ์••๋ฐ•์€ ์กฐ์ง์— ์œ„๊ธฐ๋ฅผ ์ดˆ๋ž˜ํ•  ๋ฌธ์ œ๋งˆ์ € ์€ํํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. (2)์กฐ์ง์œผ๋กœ๋ถ€ํ„ฐ์˜ ์••๋ฐ•์ด ๊ฐ•ํ• ์ˆ˜๋ก ์กฐ์ง์˜ ๊ตฌ์„ฑ์›์€ ์œ ๋Šฅํ•˜๊ฒŒ ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. (3)์กฐ์ง์˜ ๊ด€๋ฆฌ์ž๋Š” ์™ธ๋ถ€์˜ ์ƒํ™ฉ ๋ณ€ํ™”์— ๋Œ€ํ•ด ๋ฉด๋ฐ€ํ•˜๊ฒŒ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค. (4)์ƒ๊ธ‰์ž์™€ ํ•˜๊ธ‰์ž ์‚ฌ์ด์˜ ํ™œ๋ฐœํ•œ ์˜์‚ฌ์†Œํ†ต์€ ์กฐ์ง ๋‚ด ๊ฐˆ๋“ฑ ์™„ํ™”์˜ ์ฒซ ๋‹จ์ถ”์ด๋‹ค. (5)์ง์›์˜ ์žฆ์€ ์‹ค์ˆ˜์— ๋Œ€ํ•ด ๊ด€์šฉ์ ์ธ ์กฐ์ง ๋ฌธํ™”๋Š” ์กฐ์ง์˜ ๋ชฉํ‘œ ๋‹ฌ์„ฑ์„ ์ €ํ•ดํ•œ๋‹ค." + }, + { + "page_number": "94", + "problem_number": "24", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Because archaeologists study material culture, it is easy to over-emphasize the importance of physical objects versus social aspects of culture. Culture and worldview, however, are far removed from a list of material-culture traits. Such traits can be symptomatic of different kinds of society, but they can never be definitive: only social phenomena can define social formations. Many archaeologists are wary of studying social phenomena because they are not directly observable in the archaeological record. It is nevertheless possible to study social aspects of culture in the same way as natural scientists study unobservables, that is, through their material effects. Indeed, this is what archaeologists really do. We do not excavate technology, subsistence, or adaption, for example. These concepts are no less abstract than worldview, and all are derived from theory. Even though we cannot observe prehistoric worldview directly, it was no less real: it guided technology, subsistence, and adaptive behavior and in many cases caused it.", + "script": null, + "answer_option": "(1)Archaeological Targets: Beyond Material to Social Aspects of Culture (2)The Contributions of Multidisciplinary Approaches to Archaeology (3)Beyond Artifacts: How Society Constructs Cultural Heritage (4)Technological Innovations Transforming Archaeological Excavations (5)Archaeology: Exploring the Origins of Civilization Through Material Culture" + }, + { + "page_number": "94", + "problem_number": "23", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "AMBITION, DISTRACTION, UGLIFICATION, and DERISION. These are the playful names Charles Lutwidge Dodgson, a mathematics professor better known to us as Lewis Carroll, gave to the four arithmetical operations. Obviously, Carroll did not hold too many illusions about his pupils' calculation abilities. And perhaps he was right. While children easily acquire number syntax, learning to calculate can be a challenge. Children, and even adults, often err in the most elementary of calculations. Who can say that they never get 7x9 or 8x7 wrong? How many of us can mentally compute 113-37 or 10-24 in less than two seconds? Calculation errors are so widespread that far from stigmatizing ignorance, they attract sympathy when they are admitted publicly ('I've always been hopeless at math!'). Many of us can almost identify with Alice's difficulty as she attempts to calculate while traveling through Wonderland: 'Let me see: four times five is twelve, and four times six is thirteen, and four times seven is โ€” oh dear! I shall never get to twenty at that rate!'", + "script": null, + "answer_option": "(1)challenges writers face in developing ideas for novels (2)general social tolerance for commnon arithmetical errors (3)effective methods for overcoming arithmetical challenges (4)critical attitudes towards arithmnetical mistakes in education (5)benefits of strong calculation skills in elementary education" + }, + { + "page_number": "95", + "problem_number": "26", + "korean_content": "Korney Chukovsky์— ๊ด€ํ•œ ๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "Korney Chukovsky was born in St. Petersburg to a young peasant woman and her Jewish husband. Korney Chukovsky began his career as a journalist in Odessa, where he and his mother moved while he was still in school. He served as a foreign correspondent in London from 1903 to 1905, having taught himself English. Upon his return to Russia, he immersed himself in the literary scene, translating Walt Whitman and other Anglophone poets, as well as writing lively and penetrating essays on the leading Russian writers of the day, including the poet Aleksandr Blok, who was a personal friend. Between 1907 and 1913, the young Chukovsky flourished as a writer and intellectual. After the Russian Revolution, Chukovsky remained in the Soviet Union and concentrated on translation and children's poetry, for which he is now best remembered. In 1962 he received an honorary doctorate from Oxford University.", + "script": null, + "answer_option": "(1)Odessa์—์„œ ๊ธฐ์ž๋กœ์„œ์˜ ๊ฒฝ๋ ฅ์„ ์‹œ์ž‘ํ–ˆ๋‹ค. (2)๋Ÿฐ๋˜์—์„œ ์™ธ์‹  ํŠนํŒŒ์›์œผ๋กœ ๊ทผ๋ฌดํ–ˆ๋‹ค. (3)์‹œ์ธ Aleksandr Blok์— ๋Œ€ํ•œ ๊ธ€์„ ์ผ๋‹ค. (4)๋Ÿฌ์‹œ์•„ ํ˜๋ช… ์ดํ›„ ์†Œ๋น„์—ํŠธ ์—ฐ๋ฐฉ์—์„œ ํƒˆ์ถœํ–ˆ๋‹ค. (5)์˜ฅ์Šคํผ๋“œ ๋Œ€ํ•™๊ต์—์„œ ๋ช…์˜ˆ๋ฐ•์‚ฌ ํ•™์œ„ํ‹€ ๋ฐ›์•˜๋‹ค." + }, + { + "page_number": "95", + "problem_number": "25", + "korean_content": "๋‹ค์Œ ๋„ํ‘œ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "The graph above shows the average number of domestic and international trips taken by various generations in the past two years. (1) Overall, domestic trips were more frequent than international trips, with the largest gap between the two being among Baby Boomers. (2) Millennials were the most active travelers, taking an average of 2.7 domestic trips and 2.3 international trips. (3) Among the four generations, Baby Boomers took the fewest trips overall, averaging 3.4 trips, including 2.3 domestic trips and 1.1 international trips. (4) Gen Z travelers averaged 2.3 domestic trips and 2.1 international trips, showing the smallest gap between the average numbers of domestic and international trips among all the age groups surveyed. (5) Gen X took fewer domestic trips than all the other generations, but their combined average of domestic and international trips still exceeded 4.", + "script": null, + "graph": " " + }, + { + "page_number": "96", + "problem_number": "27", + "korean_content": "Going Green Rewards์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "Going Green Rewards\n\nThis weekend (August 9-10), every purchase at Magic Square Mall brings you closer to eco-friendly living โ€”don't miss our 'green rewards' event!\n- Spend $30 and exchange your receipts for a beautiful potted plant.\n- Spend $60 and exchange your receipts for a free Green Workshop pass.\n- Spend $120 and exchange your receipts for a stylish folding lunch box, perfect for eco-friendly meals.\n- Bring 10 plastic bottle caps and get a discount coupon.\n\n: At the Event Hall\n\nAugust 9(Sat):\n- 1 p.m.: Plant Pot Recycling Workshop\n- 3 p.m.: Fabric Bag Workshop\n\nAugust 10(Sun):\n- 1 p.m.: Carpet Upcycling Workshop\n- 3 p.m.: Reversible Hat Workshop\n\n- Present your workshop pass at the Event Hall entrance to participate.\n- The workshop is first-come, first-served. Limited slots available.", + "script": null, + "answer_option": "(1)์ด๋ฒˆ ์ฃผ๋ง ๋™์•ˆ Magic Mall์—์„œ ์ง„ํ–‰ํ•œ๋‹ค. (2)30๋‹ฌ๋Ÿฌ ๊ตฌ๋งค ์˜์ˆ˜์ฆ์„ ์‹๋ฌผ ํ™”๋ถ„์œผ๋กœ ๊ตํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. (3)ํ”Œ๋ผ์Šคํ‹ฑ ๋ณ‘๋šœ๊ป‘ 10๊ฐœ๋กœ ํ• ์ธ ์ฟ ํฐ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. (4)8์›” 9์ผ ์˜คํ›„ 3์‹œ์— ๋ชจ์ž ๋งŒ๋“ค๊ธฐ ์›Œํฌ์ˆ์ด ์žˆ๋‹ค. (5)์œ„ํฌ์ˆ์€ ์„ ์ฐฉ์ˆœ์œผ๋กœ ๋งˆ๊ฐ๋œ๋‹ค.", + "graph": " " + }, + { + "page_number": "96", + "problem_number": "28", + "korean_content": "Coastal Marine Mammal Center Field Trip์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์€?", + "english_content": "Coastal Marine Mammal Center\nField Trip\n\nJoin us for the Coastal Marine Mammal Center's most popular field trip! Students will learn how marine mammals are rescued and nursed back to recovery to give them a second chance at life.\n\nProgram: Marine Mammal Rescue, Recovery, and Release Tour (2 hours)\n\nFeatures: Experience a multimedia presentation on the challenges faced by marine mammals, and watch live demonstrations of rescue procedures.\n\nImportant Information:\n- Open to students aged 15 to 18\n- Group Size: Limit of 25 individuals per venue\n- Field Trip Photography Notice: Please be aware that photographs will be taken for use on the Coastal Marine Mammal Center's website. If you prefer not to be photographed, please inform the Field Trip Coordinator in advance.\n\nHow to Register:\n- Email the application to marine@center.org or contact our Field Trip Coordinator at 375-259-0134.\n- Ensure that you complete the registration at least one week before the field trip.", + "script": null, + "answer_option": "(1)ํ•œ ์‹œ๊ฐ„ ๋™์•ˆ ์ง„ํ–‰๋˜๋Š” ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค. (2)14์„ธ ํ•™์ƒ๋ถ€ํ„ฐ ์ฐธ์—ฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. (3)๋ชจ๋“  ์ฐธ๊ฐ€์ž๋Š” ์‚ฌ์ง„ ์ดฌ์˜์— ํ˜‘์กฐํ•ด์•ผ ํ•œ๋‹ค. (4)์ด๋ฉ”์ผ๋กœ๋งŒ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค. (5)์ ์–ด๋„ ํ˜„์žฅ ํ•™์Šต ์ผ์ฃผ์ผ ์ „์— ๋“ฑ๋ก์˜ฌ ์™„๋ฃŒํ•ด์•ผ ํ•œ๋‹ค.", + "graph": " " + }, + { + "page_number": "97", + "problem_number": "29", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ์–ด๋ฒ•์ƒ ํ‹€๋ฆฐ ๊ฒƒ์€?", + "english_content": "There are several fields of expertise found in the intersection of graphic design and science that (1) about visualizing complex information. The main purpose of this field is to make information accessible. There is a direct line from diagramming to information visualization and design. Diagrams are as old as advanced human culture. One could say we draw diagrams with our hands when gesturing. However, diagrams developed (2) ever more complex issues. Florence Nightingale was an early user of diagrams to communicate statistics. Her diagrams are an excellent example of (3) quantitative data is made accessible with visualization to trigger action and change. In our times, it developed into a universe of advanced diagrams described by, for example, Tufte. With the rise of the computer information, visualization (4) in several streams, one based on graphic design and the other driven by scientific visualization. Rich quantitative information that before was impossible to interpret was now visualized in a way that made (5) possible to identify patterns and phenomena in the data. Information visualization is developing its aesthetics and as a craft and, one might say, an art form.", + "script": null + }, + { + "page_number": "97", + "problem_number": "30", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘, ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "Ethics is about our thinking process. The experience of learning about ethics can be frustrating for students who expect to walk out of class armed with clear-cut answers for how to deal with different types of problems. But in fact, such (1) answers are rare in ethics. Instead, ethics is (2) with asking the right questions. The focus is on the quality of the deliberative process and not on the outcome. This can be (3) because so much of Western culture is goal oriented. We care deeply about good performance, about results, about the bottom line โ€” often with only passing interest in how we achieve those goals or what we do to attain 'success.' But expecting ethics to (4) the necessary 'correct' answers usually just leads to moralizing - making broad, often unsubstantiated claims about a course of action that some will accept as reflecting their moral beliefs and others won't. Most ethical dilemmas don't present any fully acceptable solutions and instead offer several options that are unsatisfactory in some way. The trick is to figure out which one is most (5) as you see it and which embodies key values.", + "script": null + }, + { + "page_number": "98", + "problem_number": "32", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "The default mode network (DMN) is one neural network. It is located in both the prefrontal and parietal lobes in the brain. This network of interconnected brain regions is active when you are not focused on the outside world but rather focused internally. It is who you are when untouched by stimuli. This is the place where memories, a collection of events and knowledge about yourself, are housed. It's known to be the home of mind wandering, dreams, and daydreaming. It helps you optimize what you need to remember, and what you need to forget. It aids in envisioning your future. It's a catalyst for wondering, and it's also the place where you think about things that don't have an explicit goal. When you're making art, how you choose to express yourself comes in part from this network. The DMN is a filter for what you think is beautiful or not beautiful, memorable or not, meaningful or not, and it's what helps to make the arts and aesthetics [๋นˆ์นธ]", + "script": null, + "answer_option": "(1)a core aspect of our memory (2)an integral part of our cultural identity (3)a very personal experience for each of us (4)an effective tool for concentration training (5)an opportunity to explore the world around us" + }, + { + "page_number": "98", + "problem_number": "31", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "If you go to the store to buy a gallon of milk, you probably think of milk as the product, and in many ways, it is. But if the producer of that milk thought as you did, they would expect you to show up at a spigot with a jug you could fill with milk. But, in fact, that gallon of milk, the bottle it comes in, the labeling on the bottle, the placement of the bottle on the shelf, the expiration date, the additives or lack thereof, the preservatives or lack thereof, and even the care of the cows from which the milk comes are all part of the product. Consumers may say they want (or need) milk but providing a spigot that delivers milk does not actually satisfy most consumers, because what they really want is milk that is convenient to get from store to home. All the other pieces of the product such as labeling, expiration, and even ingredients also speak to the details of what consumers of the milk truly want. In this example, we refer to milk as the core product, but not the [๋นˆ์นธ] product.", + "script": null, + "answer_option": "(1)entire (2)raw (3)reliable (4)unique (5)exclusive" + }, + { + "page_number": "99", + "problem_number": "34", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Contrary to predictions of a U-shaped curve between exercise dose and mortality, there is little solid evidence that [๋นˆ์นธ]. A number of studies have found that elite athletes, especially those who do endurance sports, live longer and require less medical care than nonathletes. In case you are worried that athletes might have better genes than the rest of us, thus protecting them from the rigors of extreme exercise, a study that followed nearly 22,000 ordinary nonathletes for fifteen years found that the highest dose exercisers did not have higher or lower rates of death including by heart disease than those who exercised moderately. An even larger analysis of more than 600,000 individuals found that extremists who exercised more than ten times the standard recommended dose of 150 minutes per week did not have significantly higher rates of death than those who exercised between five and ten times the standard dose.", + "script": null, + "answer_option": "(1)extreme levels of exercise are either harmful or additionally healthy (2)not doing much exercise is just as healthy as exercising regularly (3)ordinary nonathletes benefit equally from higher doses of exercise (4)moderate doses of exercise have clear and proven health benefits (5)the effects of extreme exercise depend on genetic advantages" + }, + { + "page_number": "99", + "problem_number": "33", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Though there can be great advantages attached to radical designing, there are also often new kinds of risks that arise. One such example is the introduction of the jet engine. Not very long after the jet engine had been introduced to the world of civil aviation, two such aeroplanes โ€” with the rather unfortunate name Havilland Comet โ€” crashed. The problem did not so much reside in the engines themselves as in the fact that jet-powered planes flew at much higher altitudes than previous aircraft had done. This meant that cabins had to be pressurised to make flying comfortable for the passengers. As a result, some points of the fuselage were subjected to greater stresses than before. That, in turn, led to metal fatigue and ultimately to disaster. What this proves is that existing frameworks designed to safeguard certain moral values โ€” in this case safety โ€” [๋นˆ์นธ]. When choosing between normal and radical designs there are also, therefore, moral considerations alongside the technical considerations.", + "script": null, + "answer_option": "(1)can serve as a principle agreed upon by all parties involved (2)cannot be automatically transferred to radical designs (3)can adapt flexibly to groundbreaking design changes (4)can benefit from the integration with radical designs (5)cannot be part of the discourse on future design development" + }, + { + "page_number": "100", + "problem_number": "36", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[Every culture provides its members with a series of lessons.] \n\n (A)By instructing its members, culture guides behavior and communication, showing members how to act, think, talk, and listen. In effect, culture is ubiquitous in every aspect of our lives. Its influence passes from our family, friends, schooling, traditional and social media, and rites and rituals. (B)It is in the food we eat, the music we listen to, the art we appreciate, the games we play, and the friends we make. It is our entire social interaction with the world that shapes the cultural being we are, and which in turn, we also will pass on. (C)Among the lessons learned are how to say 'hello' and 'goodbye,' when to speak or remain silent, how to act when angry or upset, where to focus the eyes when functioning as a source or message encoder and receiver or message decoder, how much to gesture, how close to stand to another, and how to display emotions such as happiness or rage.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "100", + "problem_number": "35", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "A mighty immune cell trying to support a cell that is unhealthy and threatened from its mitochondrial dysfunction is made completely ineffective. The immune cell cannot halt the damaging factors and the lack of resources resulting from the unnatural environment of our modern industrial world. (1)An immune cell can't stop you from drinking a soda, filter your water, turn off the stress-inducing notifications on your phone, prevent you from eating hormone-disrupting pesticides and microplastics, or get you to go to sleep earlier. (2)So the immune cell will use the tools at its disposal: it will recruit more immune cells, send out more inflammatory signals, and just keep fighting until things resolve. (3)Other immune system problems happen when your immune system does not work correctly. (4)But the problems don't resolve, because the damaging environmental inputs never resolve. (5)This is the root of chronic inflammation.", + "script": null + }, + { + "page_number": "101", + "problem_number": "37", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[Biodiversity protection poses a challenge to corporate social responsibility because damage to ecosystems is poorly understood, often lacks visibility, and generally has indirect linkages to business activity. Further, a high degree of stakeholder engagement and local responsiveness is required to address biodiversity protection.] \n\n (A)As a result, the burden of proof is generally placed on the scientific community so that environmental degradation such as biodiversity loss often goes unrecognized as a responsibility of firms. In the absence of legislation or other enforceable means to influence firm behaviour, there may be little accountability for environmental damage that accrues while sufficient evidence is gathered. (B)Biodiversity loss that occurs through the global spread of invasive species provides such an example. Companies are likely to be sceptical of their indirect impact on the environment and to demand sufficient scientific evidence before acknowledging responsibility. (C)Biodiversity loss can, of course, be visible and result from direct effects of business on the environment such as the loss of marine life from an oil spill. Corporate responsibility is evident in such a case. Responsibility is more difficult to identify when the environmental impact of business activity has low visibility and is diffused on a global scale.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "101", + "problem_number": "38", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ:[These are reasons why owning a lion would be difficult but not reasons why it would be impossible, and children must learn to distinguish the two.] \n\n When children explain why improbable events could not occur in real life, their justifications are similar to those provided for impossible events. They claim a person couldn't own a lion for a pet because it might bite you or because you could own a cat instead. (1)These justifications imply that children are not searching for principled, lawlike reasons why the event cannot occur. (2)If they did, they would realize that no such reasons exist. (3)Instead, they attempt to imagine how the event might occur, given what they know about lions and pets, and report on the mental roadblocks that pop into mind: lions are too big, they live far away, they eat other animals, they need a lot of space, they make a lot of noise, and so forth. (4)Indeed, as children begin to distinguish improbable events from impossible ones, they also begin to provide better justifications for their judgments. (5)Searching for a reason why an event is impossible may yield the realization that it's possible after all.", + "script": null + }, + { + "page_number": "102", + "problem_number": "39", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ:[Shy pedestrians (those less likely to look up anyway) and pedestrians in front of whom the investigator looked up (who felt tricked) were less likely to participate.] \n\n Suppose an investigator conducted a randomized experiment to answer the causal question 'Does one's looking up to the sky make other pedestrians look up too?' She found a strong association between her looking up and other pedestrians' looking up. (1)Does this association reflect a causal effect? (2)Well, by definition of a randomized experiment, confounding bias is not expected in this study. (3)However, there was another potential problem: The analysis included only those pedestrians that, after having been part of the experiment, gave consent for their data to be used. (4)Thus participating individuals in front of whom the investigator looked up (a reason to decline participation) are less likely to be shy (an additional reason to decline participation) and therefore more likely to look up. (5)That is, the process of selection of individuals into the analysis guarantees that one's looking up is associated with other pedestrians' looking up, regardless of whether one's looking up actually makes others look up.", + "script": null + }, + { + "page_number": "102", + "problem_number": "40", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์„ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋นˆ์นธ (A), (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Bias โ€” the inclination of prejudice towards or against a person, group, object, or position โ€”is an inherent part of society and of how human beings operate. As subjective individuals, we are unable to grasp anything we encounter in a purely objective manner, but always do so through the filter of our personal knowledge and experience. This filter in turn constitutes a reflection of our upbringing, education, cultural exposure, personality, and numerous other traits. In this broad sense, bias is not necessarily bad. Yet, under certain conditions, bias can be unfair or lead to discrimination. Al systems are developed by human beings, and fed data collected and shaped by human beings. It is hence no surprise that their decisions also reflect the individual and societal biases of their creators and users for better or worse. It is thus crucial to address this risk, even if unjust bias in machines is not always easily perceptible โ€” in particular if it slips in through proxies rather than through legally protected criteria such as gender, age, or ethnicity. \n\n => ์š”์•ฝ: Bias isn't always ๋นˆ์นธ (A) when it comes to understanding the world, but Al systems ๋นˆ์นธ (B) the biases of their human developers, requiring our careful attention to prevent unfair or discriminatory results.", + "script": null, + "answer_option": "(1)(A): harmful, (B): mirror (2)(A): harmful, (B): mask (3)(A): risky, (B): distort (4)(A): specific, (B): ignore (5)(A): specific, (B): correct" + }, + { + "page_number": "103", + "problem_number": "41", + "korean_content": "์œ—๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Many crucial functions of the self involve volition: making choices and decisions, taking responsibility, initiating and inhibiting behavior and making plans of action and carrying out those plans. The self (a) control over itself and over the external world. To be sure, not all human behavior involves planful or deliberate control by the self, and, in fact, recent work has shown that a great deal of human behavior is (b) by automatic or nonconscious processes. But undoubtedly some portion involves deliberate, conscious, controlled responses by the self, and that portion may be (c) important to the long-term health, happiness, and success of the individual. Even if it were shown that 95% of behavior consisted of lawful, predictable responses to situational stimuli by (d) processes, psychology could not afford to ignore the remaining 5%. As an analogy, cars are probably driven straight ahead at least 95% of the time, but ignoring the other 5% (such as by building cars without steering wheels) would seriously compromise the car's ability to reach most destinations. By the same token, the relatively few active, controlling choices by the self greatly (e) the self's chances of achieving its goals. And if those few 'steering' choices by the self are important, then so is whatever internal structure of the self is responsible for it.", + "script": null, + "answer_option": "(1)Clear Destinations: What Drives You Forward (2)Life-changing Choices That Shape Your Future (3)How Automatic Responses Contribute to Success (4)The Significance of Control of the Self in Human Behavior (5)Steering Without Purpose: Finding Direction in Uncertainty" + }, + { + "page_number": "103", + "problem_number": "42", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)~(e) ์ค‘์—์„œ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "Many crucial functions of the self involve volition: making choices and decisions, taking responsibility, initiating and inhibiting behavior and making plans of action and carrying out those plans. The self (a) control over itself and over the external world. To be sure, not all human behavior involves planful or deliberate control by the self, and, in fact, recent work has shown that a great deal of human behavior is (b) by automatic or nonconscious processes. But undoubtedly some portion involves deliberate, conscious, controlled responses by the self, and that portion may be (c) important to the long-term health, happiness, and success of the individual. Even if it were shown that 95% of behavior consisted of lawful, predictable responses to situational stimuli by (d) processes, psychology could not afford to ignore the remaining 5%. As an analogy, cars are probably driven straight ahead at least 95% of the time, but ignoring the other 5% (such as by building cars without steering wheels) would seriously compromise the car's ability to reach most destinations. By the same token, the relatively few active, controlling choices by the self greatly (e) the self's chances of achieving its goals. And if those few 'steering' choices by the self are important, then so is whatever internal structure of the self is responsible for it.", + "script": null, + "answer_option": "(1)(a) (2)(b) (3)(c) (4)(d) (5)(e)" + }, + { + "page_number": "104", + "problem_number": "43", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ (A)์— ์ด์–ด์งˆ ๋‚ด์šฉ์„ ์ˆœ์„œ์— ๋งž๊ฒŒ ๋ฐฐ์—ดํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "(A)Once upon a time, in a small village, there lived two neighbors. One was a kind young man named Tom. The other was a grumpy old man named Mr. Grumbles. In Mr. Grumbles' garden, there was an apple tree with a beautiful golden apple. (a) would spend most of his time peering out his window, watching the village with suspicious eyes, being worried someone might take his golden apple. (B)The next day, the judge told Mr. Grumbles, 'Before receiving the sentence, you will have to go out and gather all the pieces of paper that you threw out yesterday.' (b) replied, 'I can't do that! The wind must have scattered them and I won't know where to find them.' The judge then replied, 'The same way, simple comments may destroy the honor of a man to such an extent that one is not able to fix it.' Mr.Grumbles' face fell as he realized his mistake and sincerely apologized to Tom. (C)Tom tried to explain that he didn't steal the apple, but no one believed him. After a while, (c) was finally released as there was no proof of his guilt. Angry at what had happened, Tom sued Mr. Grumbles for wrongly accusing him. In the village court, Mr. Grumbles told the judge, 'They were just comments, they didn't harm anyone!' The judge told (d), 'Write all the things you said about Tom on a piece of paper. Cut them up and on the way home, throw the pieces of paper out. Tomorrow, come back to hear the sentence.' (D)One sunny morning, Mr. Grumbles noticed that his precious golden apple was missing from his tree. Without thinking, (e) started telling everyone who would listen that Tom must have stolen it. 'That young fellow next door is a thief!' he declared, his voice loud and angry. Word spread quickly through the village, like leaves caught in a strong wind. Soon, the sheriff came and arrested poor Tom, who was confused and upset.", + "script": null, + "answer_option": "(1)(B)-(D)-(C) (2)(C)-(B)-(D) (3)(C) (D)-(B) (4)(D)-(B)-(C) (5)(D)-(C)-(B)" + }, + { + "page_number": "104", + "problem_number": "44", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)~(e) ์ค‘์—์„œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€์ƒ์ด ๋‚˜๋จธ์ง€ ๋„ท๊ณผ ๋‹ค๋ฅธ ๊ฒƒ์€?", + "english_content": "(A)Once upon a time, in a small village, there lived two neighbors. One was a kind young man named Tom. The other was a grumpy old man named Mr. Grumbles. In Mr. Grumbles' garden, there was an apple tree with a beautiful golden apple. (a) would spend most of his time peering out his window, watching the village with suspicious eyes, being worried someone might take his golden apple. (B)The next day, the judge told Mr. Grumbles, 'Before receiving the sentence, you will have to go out and gather all the pieces of paper that you threw out yesterday.' (b) replied, 'I can't do that! The wind must have scattered them and I won't know where to find them.' The judge then replied, 'The same way, simple comments may destroy the honor of a man to such an extent that one is not able to fix it.' Mr.Grumbles' face fell as he realized his mistake and sincerely apologized to Tom. (C)Tom tried to explain that he didn't steal the apple, but no one believed him. After a while, (c) was finally released as there was no proof of his guilt. Angry at what had happened, Tom sued Mr. Grumbles for wrongly accusing him. In the village court, Mr. Grumbles told the judge, 'They were just comments, they didn't harm anyone!' The judge told (d), 'Write all the things you said about Tom on a piece of paper. Cut them up and on the way home, throw the pieces of paper out. Tomorrow, come back to hear the sentence.' (D)One sunny morning, Mr. Grumbles noticed that his precious golden apple was missing from his tree. Without thinking, (e) started telling everyone who would listen that Tom must have stolen it. 'That young fellow next door is a thief!' he declared, his voice loud and angry. Word spread quickly through the village, like leaves caught in a strong wind. Soon, the sheriff came and arrested poor Tom, who was confused and upset.", + "script": null, + "answer_option": "(1)(a) (2)(b) (3)(c) (4)(d) (5)(e)" + }, + { + "page_number": "104", + "problem_number": "45", + "korean_content": "์œ—๊ธ€์— ๊ด€ํ•œ ๋‚ด์šฉ์œผ๋กœ ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "(A)Once upon a time, in a small village, there lived two neighbors. One was a kind young man named Tom. The other was a grumpy old man named Mr. Grumbles. In Mr. Grumbles' garden, there was an apple tree with a beautiful golden apple. (a) would spend most of his time peering out his window, watching the village with suspicious eyes, being worried someone might take his golden apple. (B)The next day, the judge told Mr. Grumbles, 'Before receiving the sentence, you will have to go out and gather all the pieces of paper that you threw out yesterday.' (b) replied, 'I can't do that! The wind must have scattered them and I won't know where to find them.' The judge then replied, 'The same way, simple comments may destroy the honor of a man to such an extent that one is not able to fix it.' Mr.Grumbles' face fell as he realized his mistake and sincerely apologized to Tom. (C)Tom tried to explain that he didn't steal the apple, but no one believed him. After a while, (c) was finally released as there was no proof of his guilt. Angry at what had happened, Tom sued Mr. Grumbles for wrongly accusing him. In the village court, Mr. Grumbles told the judge, 'They were just comments, they didn't harm anyone!' The judge told (d), 'Write all the things you said about Tom on a piece of paper. Cut them up and on the way home, throw the pieces of paper out. Tomorrow, come back to hear the sentence.' (D)One sunny morning, Mr. Grumbles noticed that his precious golden apple was missing from his tree. Without thinking, (e) started telling everyone who would listen that Tom must have stolen it. 'That young fellow next door is a thief!' he declared, his voice loud and angry. Word spread quickly through the village, like leaves caught in a strong wind. Soon, the sheriff came and arrested poor Tom, who was confused and upset.", + "script": null, + "answer_option": "(1)Mr.Grumbles์˜ ์‚ฌ๊ณผ๋‚˜๋ฌด์—๋Š” ์•„๋ฆ„๋‹ค์šด ํ™ฉ๊ธˆ๋น› ์‚ฌ๊ณผ๊ฐ€ ์žˆ์žˆ๋‹ค. (2)ํŒ์‚ฌ๋Š” Tom์—๊ฒŒ ์–ด์ œ ๋ฒ„๋ฆฐ ์ข…์ด ์กฐ๊ฐ์„ ๋ชจ๋‘ ์ฃผ์›Œ ์˜ค๋ผ๊ณ  ํ–ˆ๋‹ค. (3)ํ™”๊ฐ€ ๋‚œ Tom์€ Mr.Grumbles๋ฅผ ๊ณ ์†Œํ–ˆ๋‹ค. (4)Mr. Grumbles๋Š” ์ž์‹ ์˜ ํ™ฉ๊ธˆ๋น› ์‚ฌ๊ณผ๊ฐ€ ์—†์–ด์ง„ ๊ฒƒ์˜ฌ ์•Œ์•„ ์ฐจ๋ ธ๋‹ค. (5)๋ณด์•ˆ๊ด€์ด ์™€์„œ Tom์„ ์ฒดํฌํ–ˆ๋‹ค." + }, + { + "page_number": "105", + "problem_number": "04", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๊ทธ๋ฆผ์—์„œ ๋Œ€ํ™”์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Mr. Thompson, what are you looking at on your phone: You can't stop smiling! M: I'm looking at a picture I took of the blackboard in my classroom. My students decorated it for me to celebrate Teachers' Day. W: How nice! Can I see it? M: Of course. Here it is. W: I see the students wrote'Happy Teachers' Day' at the top. That's cool. M: Right. And they put two balloons in the top left corner of the board as decorations. W: They also wrote 'Mr. T' in a heart below the balloons. That's you, right? M: Yes. That's what my students call me. Do you see the drawing of the cake in the middle? It has two candles on it because this is my second year teaching them. W: Wow. They're great at drawing. The drawing looks exactly like you. M: I agree. Do you see the stick with a hand at the end? I always use it in class to point at things on the board. W: Haha. That's why your students drew it. They did an excellent job." + }, + { + "page_number": "105", + "problem_number": "01", + "korean_content": "๋‹ค์Œ์„ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hello, students. This is your vice principal, Mrs. Williams.\nAs you know, our new study hall opened up last week.\nThis space is designed to provide a quiet and comfortable environment for all students to focus on their studies.\nHowever, there have already been complaints about students eating there. This disturbs other students who are studying and makes the space dirty. I would like to remind you that food is not permitted in the study hall.\nPlease respect this rule to ensure the space remains in excellent condition for everyone. Thank you for your understanding and cooperation. Enjoy the new study space, and good luck with your studies.", + "answer_option": "(1)์ƒˆ๋กœ ๊ฐœ๊ด€ํ•œ ์ž์Šต์‹ค์˜ ์ด์šฉ์ž๋ฅผ ๋ชจ์ง‘ํ•˜๋ ค๊ณ  (2)์ž์Šต์‹ค ๋‚ด ์Œ์‹ ๋ฐ˜์ž…์ด ๋ถˆ๊ฐ€ํ•จ์„ ์•ˆ๋‚ดํ•˜๋ ค๊ณ  (3)์ƒˆ ์ž์Šต์‹ค์˜ ๊ฐœ๊ด€์‹ ํ–‰์‚ฌ ์ฐธ์—ฌ๋ฅ  ๋…๋ คํ•˜๋ ค๊ณ  (4)์ˆ˜์—… ์‹œ๊ฐ„์— ์ •์ˆ™ํ•œ ํ™˜๊ฒฝ์„ ์œ ์ง€ํ•˜๋„๋ก ์š”์ฒญํ•˜๋ ค๊ณ  (5)๊ณต๋ถ€์— ์ง‘์ค‘ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ์žฅ์†Œ๋ฅผ ์†Œ๊ฐœํ•˜๋ ค๊ณ " + }, + { + "page_number": "105", + "problem_number": "02", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ์˜๊ฒฌ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Dad, do you have a minute?\nM: Sure. What's up?\nW: Well, I've set big goals for myself, but I can't seem to make any progress on them.\nM: I see. What have you done to achieve them?\nW: Actually, my friends and I share our goals with each other and talk about what we should do to achieve them.\nBut that doesn't seem to help much.\nM: Maybe you're focusing too much on the end result.\nHow about focusing more on your progress instead?\nW: What do you mean?\nM: I mean, share your progress and talk about what you've done to keep yourself motivated.\nW: But isn't that just celebrating small victories? How would that help?\nM: When others know what you're doing, they can give you feedback and help you stay motivated. It helps you stay on track.\nW: That makes sense. I'll give it a try. Thanks for the advice, Dad.", + "answer_option": "(1)์ž‘์€ ์„ฑ์ทจ์— ๋งŒ์กฑํ•˜์ง€ ๋ง๊ณ  ํฐ ๋ชฉํ‘œ๋งŒ ์„ธ์›Œ์•ผ ํ•œ๋‹ค (2)๋ฌด์–ธ๊ฐ€๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์ธกํ•ด ๋ณด์•„์•ผ ํ•œ๋‹ค. (3)๋‹ค๋ฅธ ์‚ฌ๋žŒ๊ณผ ์ง„ํ–‰ ์ƒํ™ฉ์„ ๊ณต์œ ํ•˜๋ฉด ๋™๊ธฐ ๋ถ€์—ฌ์— ๋„์›€์ด ๋œ๋‹ค. (4)์ข‹์€ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋ ค๋ฉด ์‹คํ–‰ ๊ณผ์ •์— ๋Œ€ํ•œ ๊ตฌ์ƒ์ด ๋ช…ํ™•ํ•ด์•ผ ํ•œ๋‹ค. (5)๋ชฉํ‘œ๋ฅผ ์„ค์ •ํ•  ๋•Œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์˜ ์˜๊ฒฌ์˜ฌ ๋“ค์–ด ๋ณด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค." + }, + { + "page_number": "105", + "problem_number": "05", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ํ•  ์ผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hey, Mike, I'm so excited to make a cake for Mom and Dad's anniversary.\nM: Me too. They're going to love it. Let's make sure we follow the recipe step by step.\nW: Definitely! First, we need to preheat the oven to 350 degrees.\nM: Let me do that now. Okay, the oven's preheating.\nWhat's next?\nW: Now, we need to mix the flour, sugar, and baking powder. You already measured everything out, right?\nM: Yes, I did. It's all right here.\nW: Awesome! Let's start mixing everything. Now, it says we need to add the eggs and milk. And the eggs should be at room temperature.\nM: Oh, they're still in the fridge. I didn't take them out.\nW: No worries, Mike. I'll put them in some warm water to quickly bring them to room temperature. We'll be ready in no time!\nM: Great idea. I should text Mom to check when they're coming home, just to be sure we have enough time.", + "answer_option": "(1)์—„๋งˆ์—๊ฒŒ ๋„์ฐฉ ์‹œ๊ฐ„ ์•Œ๋ ค ์ฃผ๊ธฐ (2)๋”ฐ๋œปํ•œ ๋ฌผ์— ๋‹ฌ๊ฑ€ ๋‹ด๊ฐ€ ๋†“๊ธฐ (3)์ผ€์ดํฌ ์กฐ๋ฆฌ๋ฒ• ์ฐพ์•„๋ณด๊ธฐ (4)์˜ค๋ธ ์˜ˆ์—ดํ•˜๊ธฐ (5)์žฌ๋ฃŒ ๊ณ„๋Ÿ‰ํ•˜๊ธฐ" + }, + { + "page_number": "105", + "problem_number": "03", + "korean_content": "๋‹ค์Œ์„ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hello everyone, today I want to talk about something we often try to escape from: boredom. In our fast-paced lives, boredom is seen as something to avoid, yet it holds immense potential. When we allow ourselves to be bored, we create space for reflection, creativity, and self-discovery. It's during these moments that our minds can wander freely, making unexpected connections and finding innovative solutions. Embracing boredom isn't about doing nothing; it's about allowing ourselves moments of quiet to recharge and explore our inner world. So, the next time you feel bored, embrace it as an opportunity rather than an inconvenience. You might just uncover new hobbies, insights, and a deeper connection with yourself.", + "answer_option": "(1)๋น ๋ฅธ ์†๋„์˜ ์‚ถ์€ ์ž‘์ง€๋งŒ ์†Œ์ค‘ํ•œ ์ˆœ๊ฐ„๋“ค์˜ฌ ๋†“์น˜๊ฒŒ ํ•œ๋‹ค. (2)์ง€๋ฃจํ•œ ์ˆœ๊ฐ„๋“ค์„ ํ”ผํ•˜๋ ค๋ฉด ์ƒˆ๋กœ์šด ์ทจ๋ฏธ์— ๋„์ „ํ•ด์•ผ ํ•œ๋‹ค. (3)์ง€๋ฃจํ•จ์„ ์ž์‹ ์—๊ฒŒ ์œ ์˜ํ•œ ์‹œ๊ฐ„์„ ๊ฐ€์งˆ ๊ธฐํšŒ๋กœ ์‚ผ์•„์•ผ ํ•œ๋‹ค. (4)์ž์œ ๋กœ์šด ์‚ฌ๊ณ ๋ฅผ ์žฅ๋ คํ•˜๋ฉด ํ˜์‹ ์ ์ธ ํ•ด๊ฒฐ์ฑ…์ด ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค. (5)์ƒ๋Œ€๋ฐฉ์„ ์ดํ•ดํ•˜๋ ค๋ฉด ์šฐ์„  ์ž์‹ ์˜ ๋‚ด๋ฉด์„ ๋“ค์—ฌ๋‹ค๋ณด์•„์•ผ ํ•œ๋‹ค." + }, + { + "page_number": "106", + "problem_number": "09", + "korean_content": "Forest Healing Camp์— ๊ด€ํ•œ ๋‹ค์Œ ๋‚ด์šฉ์„ ๋“ฃ๊ณ , ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hello, listeners! Kate Mitchel here from Smoky Mountains National Park. If you need a break from your fast-paced city life, join our Forest Healing Camp! Each day begins at 6 a.m. with guided forest bathing and outdoor yoga, surrounded by towering trees. Then, you'll join expert-led meditation programs and practice breathing exercises in nature. This is followed by a peaceful trail walk, where you can observe a variety of fascinating plants and wildlife. Also, our cozy, eco-friendly cabins provide modern comforts for a convenient stay. To support our commitment to sustainability, we offer electric shuttle buses running every 15 minutes from key locations to the camp. For the best experience, we encourage you to leave your personal vehicles at home. Visit our website to reserve your spot and embrace nature's beauty!", + "answer_option": "(1)๋งค์ผ ์•„์นจ 6์‹œ๋ถ€ํ„ฐ ํ•˜๋ฃจ๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค. (2)์ „๋ฌธ๊ฐ€๊ฐ€ ์ง€๋„ํ•˜๋Š” ๋ช…์ƒ ํ”„๋กœ๊ทธ๋žจ์ด ์žˆ๋‹ค. (3)์ˆฒ๊ธธ์„ ๋”ฐ๋ผ ๊ฑธ์œผ๋ฉฐ ์•ผ์ƒ ๋™๋ฌผ์„ ๊ด€์ฐฐํ•œ๋‹ค. (4)ํ˜„๋Œ€์ ์ธ ํŽธ์˜ ์‹œ์„ค์„ ๊ฐ–์ถ˜ ์นœํ™˜๊ฒฝ ์ˆ™์†Œ๊ฐ€ ์žˆ๋‹ค. (5)์ฃผ์š” ๊ฑฐ์ ์—์„œ ์ „๊ธฐ ์…”ํ‹€๋ฒ„์Šค๋ฅผ 30๋ถ„๋งˆ๋‹ค ์šดํ–‰ํ•œ๋‹ค." + }, + { + "page_number": "106", + "problem_number": "06", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž๊ฐ€ ์ง€๋ถˆํ•  ๊ธˆ์•ก์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: Hello! Welcome to the art gallery gift shop. How can I help you today?\nM: I'd like to buy this set of cups. It's $30, right?\nW: Yes, that's correct. Would you like anything else?\nM: Yes, I also need two keychains. They're for my granddaughters.\nW: Okay. They're $7 each. So, with the cups and the two keychains, your total comes to $44.\nM: You have some type of promotion going on, don't you?\nW: Yes, we do. If you spend over $50, you get a free art magnet worth $10.\nM: Great. I'll take two more keychains then.\nW: So now you have the set of cups and four keychains.\nAnd here's your free art magnet.\nM: Thanks. Actually, I collect magnets, so this is perfect.\nW: Wonderful! So did you enjoy the exhibition?\nM: Yes. It was fantastic! I'll go ahead and pay. Here's my card.\nW: Thank you. Please insert your card here.", + "answer_option": "(1)$30 (2)$44 (3)$54 (4)$58 (5)$68" + }, + { + "page_number": "106", + "problem_number": "07", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ์˜์ž๋ฅผ ๋ฐ˜ํ’ˆํ•˜๋ ค๋Š” ์ด์œ ๋ฅผ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "M: Hey, Jen, why are you packing up that new chair? 1 thought you liked it.\nW: Oh, hey, Brad! I'm returning it.\nM: Returning it? Why? Is there something wrong with it?\nW: No, it's not broken or anything.\nM: Then, why? You seemed pretty excited about it when you bought it. Did you find a better design?\nW: No, it's not that either. It's just ... complicated, okay?\nM: What do you mean? It's the color you wanted. It matches your room perfectly.\nW: 1 know. And it's really comfortable too. The reviews were absolutely right.\nM: Then, why are you returning it?\nW: Well, I realized I spent more money than I should have, and now I can't afford the concert tickets I want. So, I need to return the chair to get my money back.\nM: Ah, I see. That makes sense. But as your cousin, I have to say, you should try to plan your spending better if you want to avoid situations like this.\nW: I'll definitely do that. I hate having to return things because of poor planning.", + "answer_option": "(1)๋ฐฐ์†ก ๋„์ค‘ ํŒŒ์†๋˜์–ด์„œ (2)๋” ์ข‹์€ ๋””์ž์ธ์„ ๋ฐœ๊ฒฌํ•ด์„œ (3)์ƒ‰์ƒ์ด ๋ฐฉ๊ณผ ์–ด์šธ๋ฆฌ์ง€ ์•Š์•„์„œ (4)ํŽธ์•ˆํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ตฌ๋งคํ‰์ด ๋งŽ์•„์„œ (5)์ฝ˜์„œํŠธ ์ž…์žฅ๊ถŒ ๊ตฌ๋งค ๋น„์šฉ์„ ๋งˆ๋ จํ•ด์•ผ ํ•ด์„œ" + }, + { + "page_number": "106", + "problem_number": "10", + "korean_content": "๋‹ค์Œ ํ‘œ๋ฅผ ๋ณด๋ฉด์„œ ๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ์ฃผ๋ฌธํ•  ๋ฐ˜๋ ค๊ฒฌ ๋ชฉ๊ฑธ์ด๋ฅผ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Honey, could you help me choose a dog collar online?\nI want to find one that looks good but is also practical for Max.\nM: Sure! Let's start with the price. What's our budget?\nW: I don't want to spend more than 20 dollars.\nM: Sounds good. So, let's move on to the size.\nW: I think Max would be comfortable with a collar over 19 inches. He's grown quite a bit.\nM: True. What about a quick-release button?\nW: We definitely need that. It's much safer.\nM: Safety first! That narrows it down to these two options.\nWhich one do you prefer?\nw: I don't think white is a good choice. It'll get dirty too easily.\nM: Good point. Let's go with the other color. I think it'll look better on Max too.\nW: I agree. I'll order this one.", + "answer_option": "(1)Model:A, Price:$13, Size(inches):11-18, Quick Release Button:X, Color:Red (2)Model:B, Price:$15, Size(inches):13-20, Quick Release Button:X, Color:Blue (3)Model:C, Price:$17, Size(inches):15-22, Quick Release Button:O, Color:White (4)Model:D, Price:$19, Size(inches):17-24, Quick Release Button:O, Color:Gold (5)Model:E, Price:$21, Size(inches):19-26, Quick Release Button:O, Color:Black" + }, + { + "page_number": "106", + "problem_number": "08", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ice hockey game์— ๊ด€ํ•ด ์–ธ๊ธ‰๋˜์ง€ ์•Š์€ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hey, Mark. This is my first time watching an ice hockey game, so I'm not familiar with the rules.\nM: No worries, Mindy. You're in for an exciting experience.\nAnd I'll give you an overview. There are two teams, and six players on each team play at the same time, including a goalie.\nW: Oh, so the goalie protects the net?\nM: Yes, exactly. And the goal of each team is to get the puck, the little black rubber thing, in the net.\nw: Got it. I heard ice hockey is really fast-paced.\nM: It absolutely is. It's known for its speed and physical play. Players skate fast and even bodycheck each other.\nW: That sounds intense! How long is a game?\nM: A game has three periods, each 20 minutes long, with breaks in between. If the score is tied after that, they play overtime.\nW: What happens in overtime?\nM: The game goes to sudden-death in overtime. The first team to score wins the game.\nW: Wow, it sounds thrilling! Thanks for the explanation!\nM: Anytime! Enjoy the game!", + "answer_option": "(1)ํŒ€๋‹น ๊ฒฝ๊ธฐ ์ธ์› (2)ํฝ์˜ ์žฌ์งˆ (3)๋ณดํ˜ธ ์žฅ๋น„ (4)๊ฒฝ๊ธฐ ์‹œ๊ฐ„ (5)์—ฐ์žฅ์ „ ๊ฒฝ๊ธฐ ๋ฐฉ์‹" + }, + { + "page_number": "107", + "problem_number": "14", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Man:", + "script": "W: Hi, Chris! Have you been busy knitting today?\nM: Hi, Emily! Yeah, I've been working on a new sweater design.\nW: I can't wait to see it. Your work is so amazing. By the way, have you ever heard of Evan Whitaker?\nM: Yeah. He started a jam business at a young age and became really successful, right?\nW: That's right! Thinking about his story, I thought maybe you could start a business with your knitting skills.\nM: A business? How would I even start a knitting business?\nW: Well, like Evan, you could create products with your skills and sell them. For example, your sweaters or scarves.\nM: That sounds interesting, but I'm not sure how to get started.\nW: You could start small. For instance, you could use online marketplaces or social media to sell your items.\nM: That sounds like a lot of work.\nW: I can help you with that. I know a bit about social media marketing.\nM: If you could help me, that'd be amazing. But it sounds like a big risk.\nW: Everyone feels that way at first. The important thing is just to start. Your skills are so good that I'm sure it'll go well.\nM: Thank you. I think I'll give it a shot and see where it leads.", + "answer_option": "(1)Thank you. I think I'll give it a shot and see where it leads. (2)That's not true. Social media marketing is a promising field. (3)I'm sorry, but you'll have to wait until the item is back in stock. (4)That's too bad. The jam stain on your sweater isn't coming out. (5)I guess so. The era of handcrafted clothes is coming to an end." + }, + { + "page_number": "107", + "problem_number": "11", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "M: Hey, I heard you've been walking along the coast every Saturday morning and doing some plogging. That sounds really cool!\nW: Yeah, it's amazing! It feels great to get some exercise and help clean up the beach at the same time.\nM: Sounds fun. Do you think I could join you this Saturday?\nW: Perfect! We usually meet at 7 a.m. by the lighthouse.", + "answer_option": "(1)Amazing! I just saw your social media updates. (2)Perfect! We usually meet at 7 a.m. by the lighthouse. (3)I know. Keeping a schedule is tough, even on Saturdays. (4)Right. Plogging is new to me too, so let's learn together. (5)No worries. I'll drop you off at the beach right now." + }, + { + "page_number": "107", + "problem_number": "12", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Wow, it's so lovely being out here in the park for a picnic this early. But, Sam, you're not eating as much as I thought you would.\nM: Actually, I had a late-night snack last night, so I'm not really hungry.\nW: You should try cutting back on those late-night snacks.\nSnacking late at night isn't good for your health.\nM: That's true, but habits are hard to break.", + "answer_option": "(1)That's true, but habits are hard to break. (2)Let's hurry. Finish the picnic before dark. (3)No. You should get your stomach checked. (4)Don't give up. You'll cook better next time. (5)Of course. Follow my plan and get in shape." + }, + { + "page_number": "107", + "problem_number": "13", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Woman:", + "script": "[Cell phone rings.]\nM: Hello?\nW: Hey, Jacob! How's it going? Any plans for the weekend?\nM: Oh, hi, Angela! Nothing special planned. Just thinking of taking some street photos.\nW: Perfect timing. I'm working on a fun project with some friends, and I thought you might be interested.\nM: Really? What's it about?\nW: We're creating a map of local historical sites that can be explored by bike.\nM: A bike route to visit the historical landmarks? That sounds awesome.\nW: Thanks! Since you're into photography, it'd be great if you could take pictures of the sites. We want to include photos and descriptions for each location on the map.\nM: I'd love to! It's a perfect way to combine my love for street photography with something meaningful.\nW: Fantastic! Your photos will add a lot of value to our project.\nM: Thanks for thinking of me. What should I do first?\nW: Nothing specific yet. We can figure out the details when\nwe meet.", + "answer_option": "(1)Nothing specific yet. We can figure out the details when we meet. (2)How about Saturday morning? We can kick off our exploration then. (3)Oh my goodness! You should've emailed me the list of historical sites. (4)Fortunately, we won't be required to include any photos in the project. (5)Thanks for inviting me. I'm excited to started on this great project." + }, + { + "page_number": "107", + "problem_number": "15", + "korean_content": "๋‹ค์Œ ์ƒํ™ฉ ์„ค๋ช…์„ ๋“ฃ๊ณ , Maggie๊ฐ€ Bobby์—๊ฒŒ ํ•  ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Maggie:", + "script": "M: Bobby is Maggie's son. Late at night, Bobby suddenly remembers that he needs to buy some first aid supplies for a club activity the next day. He panics and asks Maggie if she knows a pharmacy that's still open at that hour. She says she isn't sure and asks him why he waited until so late to get the first aid supplies. Feeling embarrassed, Bobby admits that he spent the entire afternoon doing trivial things, and completely forgot about the club activity. Concerned about Bobby's poor time management, Maggie wants to advise Bobby to better manage his time and avoid leaving tasks until the last moment. In this situation, what would Maggie most likely say to Bobby?\nMaggie: You need to plan your time better not to rush at the\nlast minute.", + "answer_option": "(1)I think you should go to the closest hospital right away. (2)Make a habit of writing down the goals you want to achieve. (3)You need to plan your time better not to rush at the last minute. (4)Fortunately, the pharmacy across the street is open until midnight. (5)I think we have the first aid supplies you're looking for here at home." + }, + { + "page_number": "108", + "problem_number": "18", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Dear Valued Subscribers\nWe hope this letter finds you well. We are writing to inform you of an upcoming change with Travel Compass Magazine, where we pride ourselves on providing fresh and accurate information about various travel destinations. Our dedication to reliable and up-to-date content sets us apart in the travel magazine industry.\nHowever, due to rising production and distribution costs, we need to increase our subscription fees. We want to assure you that this decision was not made lightly.\nThis adjustment will help us continue delivering the insightful travel tips, in-depth features, and exclusive content you enjoy.\nThe new monthly subscription fee will take effect this September. If you have any questions or concerns, please contact our customer service team. Thank you for your understanding.\nSincerely, Travel Compass Magazine", + "script": null, + "answer_option": "(1)์žก์ง€์— ์‹ค์„ ์—ฌํ–‰๋‹ด ๊ธฐ๊ณ ๋ฅผ ์š”์ฒญํ•˜๋ ค๊ณ  (2)์ •๊ธฐ ๊ตฌ๋…์ž์—๊ฒŒ ์ฃผ๋Š” ์‚ฌ์€ํ’ˆ์„ ์†Œ๊ฐœํ•˜๋ ค๊ณ  (3)์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ์—ฌํ–‰์ง€ ์†Œ๊ฐœ ์ฝ”๋„ˆ๋ฅผ ํ™๋ณดํ•˜๋ ค๊ณ  (4)์žก์ง€์— ์†Œ๊ฐœ๋˜์—ˆ๋˜ ๊ด€๊ด‘์ง€ ์ •๋ณด๋ฅผ ์ •์ •ํ•˜๋ ค๊ณ  (5)์žก์ง€์˜ ๊ตฌ๋…๋ฃŒ๊ฐ€ ์ธ์ƒ๋  ์˜ˆ์ •์ž„์„ ์•ˆ๋‚ดํ•˜๋ ค๊ณ " + }, + { + "page_number": "108", + "problem_number": "16", + "korean_content": "์—ฌ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€", + "english_content": null, + "script": "W: Hello, students. Last week, we explored the impac of insects on agriculture in both positive and negative ways. Today, we'll discuss how insects rely on their sense of smell to find important resources. Many butterfly species rely on their sense of smell to find the right plants to lay their eggs on. These plants then provide food for the caterpillars that hatch from the eggs. Flies have an extremely sharp sense of smell, allowing them to quickly locate food sources from far away. This makes them highly effective at finding food in almost any environment. Bees use their ability to smell to identify flowers with nectar, which they collec for food. It also helps them recognize different types of flowers. Cockroaches depend on their sense of smell to find food and shelter. They can detect smells from a distance, allowing them to locate these resources. Now, Iet's watch a close-up video showing how these insects use their remarkable sense of smell.", + "answer_option": "(1)the role of insects in plant reproduction (2)the impact of insects on plant diversity (3)how the climate affects insect behavior (4)how insects use their smell for essentials (5)how human activity affects insect habitats" + }, + { + "page_number": "108", + "problem_number": "17", + "korean_content": "์–ธ๊ธ‰๋œ ๊ณค์ถฉ์ด ์•„๋‹Œ ๊ฒƒ์€?", + "english_content": null, + "script": "W: Hello, students. Last week, we explored the impac of insects on agriculture in both positive and negative ways. Today, we'll discuss how insects rely on their sense of smell to find important resources. Many butterfly species rely on their sense of smell to find the right plants to lay their eggs on. These plants then provide food for the caterpillars that hatch from the eggs. Flies have an extremely sharp sense of smell, allowing them to quickly locate food sources from far away. This makes them highly effective at finding food in almost any environment. Bees use their ability to smell to identify flowers with nectar, which they collect for food. It also helps them recognize different types of flowers. Cockroaches depend on their sense of smell to find food and shelter. They can detect smells from a distance, allowing them to locate these resources. Now. let's watch a close-up video showing how these insects use their remarkable sense of smell.", + "answer_option": "(1)butterflies (2)flies (3)bees (4)fleas (5)cockroaches" + }, + { + "page_number": "109", + "problem_number": "19", + "korean_content": "๋‹ค์Œ ๊ธ€์— ๋“œ๋Ÿฌ๋‚œ Lila์˜ ์‹ฌ๊ฒฝ ๋ณ€ํ™”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€", + "english_content": "The soft morning sun shone into Lila's room, waking her up. Today was finally the day she had been eagerly anticipating for weeks. Her childhood friend Alex, who had moved away years ago, was finally visiting. She could hardly contain her enthusiasm as she cleaned up the house and prepared a nice meal for the reunion. She couldn't wait to catch up on all the years they had been apart and find out what had happened in their lives. At last, the appointed hour arrived. But, the door bell was silent and there was no sign of Alex. Her calls went unanswered. Then, a message from Alex arrived: an unexpected work emergency had kept him away, and he apologized sincerely. Lila knew Alex wouldn't have missed their reunion without a good reason. She tried to calm herself by thinking she could set up another appointment with Alex, but despite her best efforts, she couldn't shake the feeling of being let down that filled her.", + "script": null, + "answer_option": "(1)excited -> disappointed (2)worried -> indifferent (3)delighted -> relieved (4)frustrated -> hopeful (5)frightened -> calm" + }, + { + "page_number": "109", + "problem_number": "20", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ํ•„์ž๊ฐ€ ์ฃผ์žฅํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Our group behaviour may be defined by our different personalities, but much of the human instinct is towards uniformity. Most of us are basically driven by the desire to fit in, and win acceptance from our peers. Although we fulfil different roles in social situations, this is largely done unconsciously, and we don't understand and harness these dynamics in a helpful way. What's more, our urge to belong risks being counterproductive, when it is actually our differences that define us and underpin effective communication and cooperation. Rather than denying or masking our true personality, we should embrace and harness it. If you're a listener, then make the most of being someone with high levels of empathy; or if you're one of the world's kinases, then your ability to make people laugh is probably your superpower. We would work better as humans โ€” in both social and professional contexts โ€”if we allowed ourselves to be ourselves, and were more accepting of other people doing the same.", + "script": null, + "answer_option": "(1)์‚ฌํšŒ์  ๊ฒฐ์†๋ ฅ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ง‘๋‹จ์˜ ๊ทœ์น™์„ ์ค€์ˆ˜ํ•ด์•ผํ•œ๋‹ค. (2)ํšจ๊ณผ์ ์ธ ์˜์‚ฌ์†Œํ†ต์„ ์ด๋ฃจ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹น์‚ฌ์ž ๊ฐ„ ๊ณตํ†ต์ ์„ ์ฐพ์•„์•ผ ํ•œ๋‹ค. (3)์ž์‹ ์˜ ์ง„์‹คํ•œ ๋ชจ์Šต์„ ์ˆจ๊ธฐ๊ธฐ๋ณด๋‹ค ๊ฐ์ž์˜ ๊ฐœ์„ฑ์„ ์ธ์ •ํ•˜๊ณ  ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค. (4)๊ฐœ์ธ์ด ์‚ฌํšŒ์—์„œ ๊ธฐ๋Œ€๋˜๋Š” ์—ญํ• ์„ ์ž˜ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ์˜์‹์ ์œผ๋กœ ๋…ธ๋ ฅํ•ด์•ผ ํ•œ๋‹ค. (5) ํ˜„๋Œ€ ์‚ฌํšŒ์—์„œ ๊ฒฝ์Ÿ๋ ฅ์„ ๊ฐ–์ถ”๋ ค๋ฉด ์ˆจ๊ฒจ์ง„ ๊ฐ์ •์„ ์ฝ๋Š” ๊ณต๊ฐ ๋Šฅ๋ ฅ์ด ํ•„์š”ํ•˜๋‹ค." + }, + { + "page_number": "110", + "problem_number": "22", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Some people say that science just is, that it is merely a collection of facts and measurements that exist outside of the realm of emotion and caring. But I disagree. Of the millions (perhaps infinity) of possible facts about the world we memorize, document, and pass on to others, we select those that we think are important, and this is an emotional judgment. We are motivated to care about some and not others, and emotion and motivation are two sides of the same neurochemical coin. It is true that the mere fact that 2 + 2=4, or that hydrogen is the lightest element we know of, is without emotional content. But the fact that we know these things, have gone to the trouble to learn them, reflects interests, priorities, motivation โ€” in short, reflects emotion. Scientists are motivated by intense curiosity and a desire to interpret and represent reality in terms of higher truths โ€” to take collections of observations and formulate them into a coherent whole that we call a theory.", + "script": null, + "answer_option": "(1)๊ณผํ•™์€ ๊ฐ๊ด€์  ์‚ฌ์‹ค์„ ๋„˜์–ด ๊ฐ์ •์ด ๋ฐ˜์˜๋œ ๊ฒฐ๊ณผ๋ฌผ์ด๋‹ค. (2)๊ฐœ์ธ์˜ ๊ฐ์ •๊ณผ ์„ ํ˜ธ๋„๊ฐ€ ์‹คํ—˜์— ๊ฐœ์ž…๋˜๋ฉด ๊ฒฐ๊ณผ๊ฐ€ ์™œ๊ณก๋  ์ˆ˜ ์žˆ๋‹ค. (3)๋ฐœ๊ฒฌ์ด ์ด๋ก ์œผ๋กœ ์ธ์ •๋ฐ›์œผ๋Ÿฌ๋ฉด ์ถฉ๋ถ„ํ•œ ํ•™๋ฌธ์  ๋ฐฐ๊ฒฝ๊ณผ ์ฆ๊ฑฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. (4)์‚ฌ๋žŒ๋“ค์€ ํฅ๋ฏธ๋กญ์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์„ ๋ฐฐ์šฐ๋Š” ๋ฐ ๋” ๊ธด ์‹œ๊ฐ„์„ ์“ด๋‹ค. (5)๊ณผํ•™์˜ ๊ฐ€์น˜๋Š” ์‚ฌ์‹ค์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ง€์‹์„ ์ œ๊ณตํ•˜๋Š” ๋ฐ ์žˆ๋‹ค." + }, + { + "page_number": "110", + "problem_number": "21", + "korean_content": "๋ฐ‘์ค„ ์นœ books do not take time, they give time์ด ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "The books one most remembers deliver their quarry so wonderfully that those (fictional) lives actually exist in people's minds alongside the 'real' people one knows. Oedipus, Hamlet, Jane Eyre, Gatsby โ€” among many others โ€” occupy a good bit of human real estate, and some have claimed that we may know them better, more fully, than we know the 'actual' people we know. Further: one actually sees the arc of those fictional lives: Oedipus's transition from proud King back to cast-out infant and closing as blind exile; Jane Eyre's arc from unloved and abused child to wealthy, married woman. This, we say, is the work of plot. But consider the true magic here: how all these transformations (which can take weeks, months, years, even a lifetime to happen, which therefore escape our vision, our knowing) are compressed, contained, or delivered in the scope of a few hundred pages, requiring mere hours to access, to process. We enter the bookstore, see all the books arrayed there, and think: so many books, so little time; but the truth goes other way: \n\n ๋ฐ‘์ค„: .", + "script": null, + "answer_option": "(1)Reading and understanding a book in depth requires hours of immersion. (2)No matter how realistic fictional characters are, they can never replace real people. (3)Fiction takes less time to write than non-fiction since it requires less fact-checking. (4)Books often fail to convey the full lives of characters due to the confines of the pages. (5)Books provide concentrated life experiences, offering insights beyond the bounds of time." + }, + { + "page_number": "111", + "problem_number": "23", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "True, human decision-making is full of biases and inconsistencies, but our inconsistencies are relatively predictable. We know how to account for them. And there are limits to how nonsensical an intelligent, balanced person's 'wrong' decision will be, due to the vague, currently uncomputable concept we call 'common sense' This is not necessarily the case with AI. When AI is 'wrong', it can be spectacularly wrong, with more unpredictable outcomes. Simple algorithms should be extremely predictable, but can make bizarre decisions in 'unusual' circumstances. A trivial example: in 2011, two very basic pricing algorithms โ€” one programmed to sell a book a shade cheaper than its nearest competitor, the other to sell a book at a considerably higher price than its competitors โ€”kept automatically pushing each other's prices up, to the point where a textbook was being sold on amazon for $23 million. Less trivially, unusual circumstances (concerns over European debt crisis leading to unusual algorithmic stock sales), and a cascade of unexpected interactions between high-frequency trading algorithms played a key role in wiping a trillion dollars off the US stock market during the 2010 Flash Crash.", + "script": null, + "answer_option": "(1)benefits of using algorithms in the decision-making process (2)strategies for companies to control the price in the market (3)ways to make human decision-making more trustworthy (4)importance of ethical safeguards in machine learning algorithms (5)limits of Al decision-making due to its unpredictability and error" + }, + { + "page_number": "111", + "problem_number": "24", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Due to higher scope and greater degree of division of labor and cooperation, the efficiency of human society has been improved unprecedentedly. It has incomparable competitive advantages with other species, and has evolved into a species without competitors. With the progress of science and technology, human beings have lost their competitors and almost controlled the natural system. Human beings have created a comfortable and stable environment like a palace for themselves. However, in such a more stable environment, social division of labor, which is the motive force of inertia, will lead to a single and simple behavior habit in the functional unit of society. The individual may gradually lose its independent personality as a complete biological body and โ€”just like an organ of the body โ€” cannot live independently without the collective group. This will be a great challenge to our ideals, perceptions and values as an independent and free person. Human beings have achieved infinite success in the process of population expansion, competition with other species, and struggle with nature, but we have lost our individual selves as a result.", + "script": null, + "answer_option": "(1)Cooperation: What Makes Humans Unique Among Animals (2)Division of Labor: Progress and the Loss of Individuality (3)Preserving Individual Identity Amidst Collective Growth (4)Rethinking Labor: Its Role in Shaping Society (5)What Are the Steps to Independent Living?" + }, + { + "page_number": "112", + "problem_number": "26", + "korean_content": "Jean Macnamara์— ๊ด€ํ•œ ๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "Jean Macnamara (1899-1968), an Australian medical scientist, was born into a family that prized hard work and education. She studied medicine at the University of Melbourne, graduating in 1922, and the following year, she was appointed resident medical officer at the Royal Children's Hospital, where she specialized in polio care. In 1931, in collaboration with future Nobel Prize winner Macfarlane Burnet, she discovered that there was more than one type of the polio virus and their finding was a crucial step toward the eventual development of the polio vaccine by Jonas Salk in 1955. Macnamara also developed new methods of treatments and rehabilitation for disabled patients. Her remarkable ability to inspire confidence in her patients, mostly children, filled her clinics with families prepared to wait hours for her attention. She married a fellow physician, Joseph Connor, in 1934 and had two daughters. Macnamara passed away in 1968 due to heart disease, and her funeral was attended by many of her former patients.", + "script": null, + "answer_option": "(1)Melbourne ๋Œ€ํ•™๊ต ์กธ์—… ํ›„ ์™•๋ฆฝ ์•„๋™ ๋ณ‘์›์—์„œ ์ผํ–ˆ๋‹ค. (2)Macfarlane Burnet๊ณผ ํ•จ๊ป˜ ์†Œ์•„๋งˆ๋น„ ๋ฐฑ์‹  ๊ฐœ๋ฐœ์— ์„ฑ๊ณตํ–ˆ๋‹ค. (3)์žฅ์• ๊ฐ€ ์žˆ๋Š” ํ™˜์ž๋ฅผ ์œ„ํ•œ ์ƒˆ๋กœ์šด ์น˜๋ฃŒ๋ฒ•์„ ๊ฐœ๋ฐœํ–ˆ๋‹ค. (4)๋Œ€๊ฐœ ์–ด๋ฆฐ์ด์ธ ํ™˜์ž๋“ค์—๊ฒŒ ์ž์‹ ๊ฐ์„ ๋ถˆ์–ด๋„ฃ์–ด ์ฃผ์—ˆ๋‹ค. (5)๋™๋ฃŒ ์˜์‚ฌ์™€ ๊ฒฐํ˜ผํ•˜์—ฌ ๋”ธ ๋‘˜์„ ๋‘์—ˆ๋‹ค." + }, + { + "page_number": "112", + "problem_number": "25", + "korean_content": "๋‹ค์Œ ๋„ํ‘œ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "The graph above shows the preferred in-room amenities for the perfect hotel stay among travelers by country in 2024. (1)Except for the U.K., travelers from the other four countries shared the following top four preferences: air conditioning, power outlets near the bed, a nice view, and bathroom toiletries including shampoo and conditioner. (2) Among travelers from the U.S.A., Spain, and the U.K., air conditioning and power outlets near the bed ranked first and second, respectively, in their favorite amenities. (3)On the other hand, German travelers placed a higher value on power outlets near the bed and a nice view than on air conditioning, with TV/streaming services also making it to their top five. (4)For French travelers, a nice view was their highest priority, followed by power outlets near the bed and bathroom toiletries, with room service ranking fifth. (5)Notably, the U.K. travelers prioritized having a tea kettle in the room as the third most essential amenity, ranking it higher than a nice view and bathroom toiletries.", + "script": null, + "graph": " " + }, + { + "page_number": "113", + "problem_number": "28", + "korean_content": "Sun Valley Botanical Garden Gift Membership์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์€?", + "english_content": "Sun Valley Botanical Garden\nGift Membership\n\nGift a membership to Sun Valley Botanical Garden and share year-round access to ever-changing exhibits, exclusive events, and the beauty of nature.\n\nMembership Levels:\n- Senior Citizen $75\nFor one adult aged 62 or over\n- Individual $85\nFor one adult\n- Family/ Household $129\nFor two adults and up to four children aged 18 or younger\n\nMembership Benefits:\n- Free entry to Sun Valley Botanical Garden\n- 10-20% year-round discounts in the Sun Valley Botanical Garden gift shop plus additional savings during members-only sales or events\n- Discount on most classes and workshops\n- Weekly e-newsletters and digital bulletins\n- Invitations to members-only appreciation events and programs\n\nNotes:\n- Memberships are non-refundable. Membership extensions, exchanges, and downgrades are not available.\n- Gift membership can be purchased via our website or by calling Member Services at 01-438-741.", + "script": null, + "answer_option": "(1)62์„ธ ์ด์ƒ ์„ฑ์ธ ํšŒ์›๊ถŒ์€ 1์ธ๋‹น 85๋‹ฌ๋Ÿฌ์ด๋‹ค. (2)๊ฐ€์กฑ ํšŒ์›๊ถŒ์€ ์„ฑ์ธ ๋‘ ๋ช…๊ณผ 18์„ธ ์ดํ•˜ ์ž๋…€ ์ตœ๋Œ€ ๋‘ ๋ช…๊นŒ์ง€ ํฌํ•จ๋œ๋‹ค. (3)ํšŒ์›์€ ๋Œ€๋ถ€๋ถ„์˜ ์ˆ˜์—…๊ณผ ์›Œํฌ์ˆ์„ ๋ฌด๋ฃŒ๋กœ ๋“ค์„ ์ˆ˜ ์žˆ๋‹ค. (4)ํšŒ์›๊ถŒ์€ ์—ฐ์žฅ ๋ฐ ๊ตํ™˜์ด ๋˜์ง€ ์•Š๋Š”๋‹ค. (5)์„ ๋ฌผ์šฉ ํšŒ์›๊ถŒ์€ ์›น์‚ฌ์ดํŠธ์—์„œ๋งŒ ๊ตฌ๋งคํ•  ์ˆ˜ ์žˆ๋‹ค.", + "graph": " " + }, + { + "page_number": "113", + "problem_number": "27", + "korean_content": "BCU Online Screenwriting Course์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "BCU Online Screenwriting Course\n\nDevelop your writing skills for film and television through this dynamic online course at the BCU School of the Arts! This course is open to anyone aged 16-18.\n\nSchedule and Fee:\n- Course Dates: July 21-August 15 (4 weeks)\n- Application Deadline: May 31\n- Fee: $500\n\nHow to Apply:\n- Visit our website (click here) and follow the directions on the application.\n- Applicants should submit the following:\n - Online application form and a personal statement (500-1,500 words)\n - A portfolio or writing samples\n\nNotes:\n- The class will be delivered through weekly pre-recorded online lectures, which you can view at your own pace.\n- You must upload your assigned projects to the course's online platform on a daily basis.\n- Live online meetings with faculty and classmates are scheduled throughout the 4-week session.", + "script": null, + "answer_option": "(1)16์„ธ์—์„œ 18์„ธ๊นŒ์ง€ ๋ˆ„๊ตฌ๋‚˜ ์‹ ์ฒญํ•  ์ˆ˜ ์žˆ๋‹ค. (2)7์›” 21์ผ๋ถ€ํ„ฐ 8์›” 15์ผ๊นŒ์ง€ 4์ฃผ๊ฐ„ ์ง„ํ–‰๋œ๋‹ค. (3)์‹ ์ฒญ์ž๋Š” ํฌํŠธํด๋ฆฌ์˜ค๋‚˜ ์ž‘๋ฌธ ๊ฒฌ๋ณธ์„ ์ œ์ถœํ•ด์•ผ ํ•œ๋‹ค. (4)๋งค์ฃผ ์˜จ๋ผ์ธ ์‹ค์‹œ๊ฐ„ ๊ฐ•์˜๋ฅผ ํ†ตํ•ด ์ˆ˜์—…์ด ์ด๋ฃจ์–ด์ง„๋‹ค. (5)๋ถ€์—ฌ๋œ ๊ณผ์ œ๋ฅผ ์˜จ๋ผ์ธ ํ”Œ๋žซํผ์— ๋งค์ผ ์—…๋กœ๋“œํ•ด์•ผ ํ•œ๋‹ค.", + "graph": " " + }, + { + "page_number": "114", + "problem_number": "30", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘, ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "The brain has been described by social psychologists Susan Fiske and Shelly Taylor as a 'cognitive miser,' responding in energy-efficient ways to the vast amount of information received. As a result, humans often take mental (1), thinking as quickly and simply as possible. These processes have evolutionary origins, and lightning-quick decisions were useful in escaping predators in the ancestral environment of the savanna, (2) survival. Fast, frugal, automatic responses continue to help (3) cognitive energy, and no one would want to spend time carefully deliberating all the decisions required in a single day. But the 'System 1' mechanismโ€”a term coined by social psychologist Daniel Kahneman for the more primitive part of the brain that reacts quickly, making swift intuitive decisions, drawing on experience and emotionโ€” is greatly (4) for the complexities of modern living, especially in understanding science or making socio-scientific decisions. Quick judgments drive individuals to choices that may feel intuitively and emotionally right but are (5) quite wrong, and they can lead to stereotypes and prejudicial thinking.", + "script": null + }, + { + "page_number": "114", + "problem_number": "29", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ์–ด๋ฒ•์ƒ ํ‹€๋ฆฐ ๊ฒƒ์€?", + "english_content": "According to the traditional mainstream view, science is a collection of (1) truths. For Aristotle, the premises of scientific syllogisms are necessary truths. The medieval conception of science was static: scientia is the possession and contemplation of knowledge, and (2) method is needed to organize the already established truths for the purpose of teaching. However, after the Scientific Revolution in the early seventeenth century, Francis Bacon and Renรฉ Descartes (3) the dynamic view that the aim of science is to find new truths by inquiry. After this shift in the aims of science, it became relevant (4) the conceptual problem about scientific progress: what is meant by progress in science? Both the empiricist Bacon and the rationalist Descartes adhered to the requirement (5) scientific knowledge is completely certain to be true โ€” at least after the employment of right inductive or deductive methods โ€” and hence they answered the conceptual problem by asserting that scientific progress is the accumulation of knowledge.", + "script": null + }, + { + "page_number": "115", + "problem_number": "32", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "As a species, we fool ourselves when we imagine that we would prefer a certain world that we could fully control. In truth, we crave [๋นˆ์นธ], fulfilled by our world of accidental convergence. The physicist Alan Lightman notes, 'We love the structure of Western classical music, as well as the free-wheeling runs or spontaneous rhythms of jazz. We are drawn to the symmetry of a snowflake, but we also delight in the shapeless form of a high-riding cloud.... We might respect those who manage to live sensibly and lead upright lives. But we also esteem the mavericks who break the mould, and we celebrate the wild, the unrestricted and the unpredictable in ourselves.' Life would be boring and monotonous if everything were structured and ordered, but pure disorder would destroy us. Nietzsche wrote that this tension comes from the human impulses for both the Apollonian and Dionysian. Both were sons of Zeus, but Apollo represented order, logic, and reason, while Dionysus is said to be an irrational agent of chaos who loves to party and dance. To fully live, we need both.", + "script": null, + "answer_option": "(1)absolute freedom rooted in free will (2)a healthy balance between order and disorder (3)order achieved through deliberate preparation (4)a blend of psychological tension and emotional depth (5)luck and the unexpected, life-changing fortune it can bring" + }, + { + "page_number": "115", + "problem_number": "31", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Many of us have seen the phenomenon of adults in online social groups who shut down or even 'unfriend' those who bring up controversial topics, probably because they do not want to experience strong negative emotions in their social experiences. The same can happen if you are researching a science topic online. These strong emotions can lead to what psychologists call 'foreclosure,' shutting down the critical thinking process prematurely before one has the information needed to make an evidence-based decision. For example, many individuals are avoiding specific foods based more on fads than on true medical risk factors. A small percentage of people cannot tolerate gluten, yet gluten-free products are broadly popular. Some individuals may be missing out on easy ways to get key nutrients by avoiding foods that are fine for them. Recognizing how negative emotions and attitudes may be leading to [๋นˆ์นธ] of scientific information without full evaluation is a first step. Be open to new ideas, and be sure to evaluate them critically.", + "script": null, + "answer_option": "(1)Variation (2)rejection (3)correction (4)appreciation (5)categorization" + }, + { + "page_number": "116", + "problem_number": "33", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "What is time? Here is a concept we all think we understand, and one that physics requires. Yet both ordinary folk and physicists would be hard-pressed to tell us what exactly time is. Notice that to define time in terms of hours, minutes, and seconds is to mistake the units of time for what they measure. It would be like defining space in terms of meters or yards. Space is measured with equal accuracy in meters or yards. But suppose we ask which is the correct way of measuring space? The answer of course is that there is no uniquely correct set of units for measuring space; yards and meters do equally well. By the same token, neither can be said to 'define' or constitute space. The same goes for time. Seconds, centuries, millennia are just different amounts of the same 'thing.' And it's that thing, time, which comes in different amounts that we want a definition of. We could say that time is duration, but then duration is just the passage of time. Our definition would [๋นˆ์นธ]", + "script": null, + "answer_option": "(1)presuppose the very notion we set out to define (2)deal with its existence as well as its uniqueness (3)start with distinguishing science from nonscience (4)evolve flexibly according to ongoing technical development (5)require us to determine the most accurate measurement" + }, + { + "page_number": "116", + "problem_number": "34", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "It's worth noting that [๋นˆ์นธ] With great solemnity like Tolstoy's, you rarely get lightheartedness humor (although he does enjoy mocking the weaknesses of some of his minor characters). A chatty author โ€” one who is enthusiastic about lots of details and commentary โ€” can't also be a strong, silent Hemingway type. The very qualities that we identify as the reasons we like an author's voice may be the identical reasons why other readers dislike the voice. One reader finds the work brilliant, another show-offy. One reader's philosophically deep is another's ponderous. One reader's funny is another reader's trivial. Even a writer's rich imagery, her flights of poetry, may cause some readers to warn, 'I don't care how dawn breaks on yonder sky. Get on with it!' In evaluating fiction, we don't want to ask whether it's what we want for dinner, but whether the food is properly prepared and presented - not whether we approve of the voice, but whether the writer has achieved the desired effect well and consistently.", + "script": null, + "answer_option": "(1)a writer can't manifest all qualities to all people at all times (2)writers who deliver universal lessons are often highly respected (3)messages cannot be conveyed effectively if they are delivered through jokes (4)it is a quality of talented writers to change their tone according to the genre (5)writers always keep their readers' reactions in mind as they craft their work" + }, + { + "page_number": "117", + "problem_number": "35", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "It is surely a goal of scientific explanation to find or 'derive' the governing equation for the phenomenon being investigated. Applied mathematicians would call this 'constructing a model.' In most practical cases, this aspect of mathematical physics is often a matter of educated guesswork. It is here that the physicist's experience and intuition play their most prominent roles. (1)However, it is extremely unlikely that the equation one finds is the 'real' equation that governs the behavior of the system. (2)Typically, things are much too complicated for us to expect this to be the case. (3)Equations derived from scientists' intuition often prove to be more accurate and reliable than those carefully developed based on experience and established theories. (4)Thus, the equation one finds (if, indeed, one finds one at all) is more likely than not an approximation to the 'true' or 'real' equation. (5)In fact, I'm not really convinced that it makes sense to speak of the 'true' governing equation.", + "script": null + }, + { + "page_number": "117", + "problem_number": "36", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[The earliest document that might be considered a student record was an annual 'child census.'] \n\n (A)The need for individual records changed, however, once states passed compulsory school laws that required all children of a certain age to attend. Now schools were increasingly expected to maintain common sets of records that allowed information to be transferred from school to school in order to keep track of students and verify that families were complying with school laws. (B)These censuses were often required by states as they developed their early public school systems and were used for the purpose of assessing taxes, and, later, determining the denominator for school attendance rates. These were records of children who should be students, but they weren't student records โ€” they didn't record individual attendance or achievement. (C)In addition to being good for record-keeping, the practice was intended to thwart an excuse common among youth stopped by truant officers: they weren't absent, they were simply crossing town to the school where they were enrolled. A quick check of a school's records could determine the truth of the claim - and whether the student's family would be issued a warning or worse.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "118", + "problem_number": "37", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[Social media has become an important means of large-scale information sharing and communication in all occupations, including marketing, journalism, public relations, and more. This change in consumption behaviors is due to some novel features such as mobility, being free, and interactiveness.] \n\n (A)Therefore, it becomes increasingly important for policy makers to regulate and discourage the creation of fake news, for online business to detect and prevent fake news, and for citizens to protect themselves from fake news. (B)When the Pakistani defense minister mistakenly believed a fake news story, he almost started a war with a neighboring country. These examples clearly demonstrate that fake news stories are problematic not only for the credibility of online journalism, but also due to their adverse real-world consequences, resulting in violence or influencing election results. (C)However, the low cost, easy access, and rapid distribution of information of social media draw a large audience and enable the wide spread of fake news, i.e., news with intentionally false information. For instance, in 2016, millions of people read and 'liked' fake news stories proclaiming that Pope Francis had supported a specific candidate for U.S. president.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "118", + "problem_number": "38", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ:[Despite imperfect geographical information and knowledge and limited abilities to think geographically weโ€”as individuals and societies โ€” have to cope with everyday or long-term challenges.] \n\n The successful functioning of people and societies requires a successful perception and cognition of the circumstances in the physical and social environment in which we live. (1)To be successful in everyday life, though, as individuals, we need not know everything. (2)As Tuan, the father of humanistic geography, put it, the geographical 'knowledge we have as individuals and as members of a particular society remains very limited, selective, and biased.' (3)To do so, we need both geographical knowledge and the abilities to act effectively in new situations. (4)This knowledge is accumulated and strengthened through formal and informal education as well as through personal or collectively shared experiences. (5)This justifies the importance of learning just-in-case about previously unknown geographies, like through geography lessons in schools, reading literature or following the media news.", + "script": null + }, + { + "page_number": "119", + "problem_number": "39", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ:[The scientists who have studied these abilities believe that animals possess a mental module, traditionally called the 'accumulator,' that can hold a register of various quantities.] \n\n One of the brain's specialized mental organs is a primitive number processor that prefigures, Without quite matching it, the arithmetic that is taught in our schools. (1)Improbable as it may seem, numerous animal species that we consider stupid or vicious, such as rats and pigeons, are actually quite gifted at calculation. (2)They can represent quantities mentally and transform them according to some of the rules of arithmetic. (3)Rats exploit this mental accumulator to distinguish series of two, three, or four sounds, or to compute approximate additions of two quantities. (4)The accumulator mechanism opens up a new dimension of sensory perception through which the cardinal of a set of objects can be perceived just as easily as their color, shape, or position. (5)This 'number sense' provides animals and humans alike with a direct intuition of what numbers mean.", + "script": null + }, + { + "page_number": "119", + "problem_number": "40", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์„ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋นˆ์นธ (A), (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "You've probably noticed that as a TV or radio program yields to a commercial, the speech rate often increases. The reason for this can be purely practical, to squeeze in as much information as possible into a pricey 30-second commercial slot. Sometimes, when the taped commercial runs slightly over the allotted time, it's compressed to fit in, so it runs faster than actual life. Researchers began to notice that time-compressed commercials could actually be more effective than the same commercial run at normal speed. When they took a closer look they found that surprisingly, people use less brainpower, not more, in listening to time-compressed ads. Since thinking takes more time than reacting, it may be that people just gave up on it when the speech ran faster than cognition. In that case, we'd expect to see signs that people were thinking superficially when they heard time-compressed ads. Sure enough, ads that sounded extremely fast led to people relying less on the strength of its arguments, and more on a general impression of how credible the announcer seemed. \n\n => ์š”์•ฝ: Time-compressed commercials that pack a lot of information in a short period are likely to be ๋นˆ์นธ (A) in influencing audiences and potential consumers because they tend to ๋นˆ์นธ (B) deep thinking, which takes longer than reacting.", + "script": null, + "answer_option": "(1)(A):inefficient - (B):manipulate (2)(A):inefficient - (B):evaluate (3)(A):appealing - (B):categorize (4)(A):successful - (B):abandon (5)(A):successful - (B):consider" + }, + { + "page_number": "120", + "problem_number": "41", + "korean_content": "์œ—๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Creativity, like ethics, beauty, decision-making, or the ability to think or reason, is not located anywhere in the brain. To create means having the ability to get excited and think, learn, remember, imagine, and all these are brain functions whose processing is (a) in areas, neural systems, and specific networks functioning within codes of time, not space. Creativity is an important ingredient in any artistic activity. It is the capacity to do new things, therefore, that (b) the artist to capture on canvas, wood, rock, or holograms feelings, abstracts, and ideals. It has been speculated that the artistic creativity may emerge from that clash between the abstractions created by the brain, with its emotional component, unique and personal, and the (C) sensory objects of the world from which precisely those same abstractions have been constructed. Think of this as something like an unconscious dissatisfaction caused by a mismatch between mental objects and real sensory objects, between ideas of the objects created by the brain and the real objects themselves, something like a divorce between the 'tree' the artist sees, which is 'real,' and the 'tree' that the artist constructs unconsciously on the screen of his mind. From that (d), an emotional reaction arises, leading to that dissatisfaction (frustration). It could be precisely this frustration that acts as the starter of the creative process. The creative act would then stand as the need of the artist to find a personal (e) through his work of art, with this work no longer reflecting the 'objective reality' but his 'mental reality.'", + "script": null, + "answer_option": "(1)How Do Artistic Brains Differ from Creative Brains? (2)Optical Illusions: Why Do We Get Distorted Images? (3)Pressure to Be Creative Leads to Emotional Instability (4)Artistic Creativity from the Between Mental Images and Reality (5)Problems from Inconsistency Between Sensory Perception and Reality" + }, + { + "page_number": "120", + "problem_number": "42", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)~(e) ์ค‘์—์„œ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "Creativity, like ethics, beauty, decision-making, or the ability to think or reason, is not located anywhere in the brain. To create means having the ability to get excited and think, learn, remember, imagine, and all these are brain functions whose processing is (a) in areas, neural systems, and specific networks functioning within codes of time, not space. Creativity is an important ingredient in any artistic activity. It is the capacity to do new things, therefore, that (b) the artist to capture on canvas, wood, rock, or holograms feelings, abstracts, and ideals. It has been speculated that the artistic creativity may emerge from that clash between the abstractions created by the brain, with its emotional component, unique and personal, and the (C) sensory objects of the world from which precisely those same abstractions have been constructed. Think of this as something like an unconscious dissatisfaction caused by a mismatch between mental objects and real sensory objects, between ideas of the objects created by the brain and the real objects themselves, something like a divorce between the 'tree' the artist sees, which is 'real,' and the 'tree' that the artist constructs unconsciously on the screen of his mind. From that (d), an emotional reaction arises, leading to that dissatisfaction (frustration). It could be precisely this frustration that acts as the starter of the creative process. The creative act would then stand as the need of the artist to find a personal (e) through his work of art, with this work no longer reflecting the 'objective reality' but his 'mental reality.'", + "script": null, + "answer_option": "(1)(a) (2)(b) (3)(c) (4)(d) (5)(e)" + }, + { + "page_number": "121", + "problem_number": "43", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ (A)์— ์ด์–ด์งˆ ๋‚ด์šฉ์„ ์ˆœ์„œ์— ๋งž๊ฒŒ ๋ฐฐ์—ดํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "(A)Puz wakes me up with her movements. I try to pat her, but my hand in empty air truly wakes me up. Puz is my eleven-year-old golden retriever, retired search-and-rescue dog, and I was her partner in finding missing persons. When she retired, I adopted her. We take a nap together, but today, something gets her up. I follow her to the front yard and see a young woman running toward us. Now I understand what woke (a) up. (B)'His name is Odie,' the young woman tells us about her dog as we jog back to her house. She says while she was in the kitchen, someone else in the house was going in and out through the front door. 'Maybe the door screen didn't close tightly and that's how the dog got out,' she adds. When we arrive at (b) house, she gestures for us to enter. Moving quickly, Puz and I search the house. Puz sniffs around to track Odie down. (c) stops and looks at me as if to say, 'No sign of the little dog here.' (C)Puz leads us to a back door, signaling me to go out. 'There is no way he could have gone out this way,' the young woman says. I ask her to stay inside not to distract Puz. My golden retriever stretches toward some tall bushes, and from beneath them, a small black dog slides toward (d), whimpering and dragging his legs. I pick up Odie and carry him back inside. The young woman bursts into tears, shouting his name. She thanks us a million times. Puz seems satisfied and looks at me as if to say, 'Can we go back to our nap now?' (D)The woman's expression is panicked. 'My dog,' she says. 'My dog is gone.' She struggles to catch her breath. 'A lady next to my house.. says you...your dog...says she can...' She looks at me and Puz blankly, like she doesn't know what to ask for. 'My dog...he is old and his heart is bad,' she says. 'We'll help,' I say. As I put the leash on Puz, (e) seems ready for the task ahead. But I wonder. Puz was trained to find people, not animals. Can she find a missing pet? I worry that she might not.", + "script": null, + "answer_option": "(1)(B)-(D)-(C) (2)(C)-(B) (D) (3)(C)-(D)-(B) (4)(D)-(B)-(C) (5)(D)-(C)-(B)" + }, + { + "page_number": "121", + "problem_number": "44", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)~(e) ์ค‘์—์„œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€์ƒ์ด ๋‚˜๋จธ์ง€ ๋„ท๊ณผ ๋‹ค๋ฅธ ๊ฒƒ์€?", + "english_content": "(A)Puz wakes me up with her movements. I try to pat her, but my hand in empty air truly wakes me up. Puz is my eleven-year-old golden retriever, retired search-and-rescue dog, and I was her partner in finding missing persons. When she retired, I adopted her. We take a nap together, but today, something gets her up. I follow her to the front yard and see a young woman running toward us. Now I understand what woke (a) up. (B)'His name is Odie,' the young woman tells us about her dog as we jog back to her house. She says while she was in the kitchen, someone else in the house was going in and out through the front door. 'Maybe the door screen didn't close tightly and that's how the dog got out,' she adds. When we arrive at (b) house, she gestures for us to enter. Moving quickly, Puz and I search the house. Puz sniffs around to track Odie down. (c) stops and looks at me as if to say, 'No sign of the little dog here.' (C)Puz leads us to a back door, signaling me to go out. 'There is no way he could have gone out this way,' the young woman says. I ask her to stay inside not to distract Puz. My golden retriever stretches toward some tall bushes, and from beneath them, a small black dog slides toward (d), whimpering and dragging his legs. I pick up Odie and carry him back inside. The young woman bursts into tears, shouting his name. She thanks us a million times. Puz seems satisfied and looks at me as if to say, 'Can we go back to our nap now?' (D)The woman's expression is panicked. 'My dog,' she says. 'My dog is gone.' She struggles to catch her breath. 'A lady next to my house.. says you...your dog...says she can...' She looks at me and Puz blankly, like she doesn't know what to ask for. 'My dog...he is old and his heart is bad,' she says. 'We'll help,' I say. As I put the leash on Puz, (e) seems ready for the task ahead. But I wonder. Puz was trained to find people, not animals. Can she find a missing pet? I worry that she might not.", + "script": null, + "answer_option": "(1)(a) (2)(b) (3)(c) (4)(d) (5)(e)" + }, + { + "page_number": "121", + "problem_number": "45", + "korean_content": "์œ—๊ธ€์— ๊ด€ํ•œ ๋‚ด์šฉ์œผ๋กœ ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "(A)Puz wakes me up with her movements. I try to pat her, but my hand in empty air truly wakes me up. Puz is my eleven-year-old golden retriever, retired search-and-rescue dog, and I was her partner in finding missing persons. When she retired, I adopted her. We take a nap together, but today, something gets her up. I follow her to the front yard and see a young woman running toward us. Now I understand what woke (a) up. (B)'His name is Odie,' the young woman tells us about her dog as we jog back to her house. She says while she was in the kitchen, someone else in the house was going in and out through the front door. 'Maybe the door screen didn't close tightly and that's how the dog got out,' she adds. When we arrive at (b) house, she gestures for us to enter. Moving quickly, Puz and I search the house. Puz sniffs around to track Odie down. (c) stops and looks at me as if to say, 'No sign of the little dog here.' (C)Puz leads us to a back door, signaling me to go out. 'There is no way he could have gone out this way,' the young woman says. I ask her to stay inside not to distract Puz. My golden retriever stretches toward some tall bushes, and from beneath them, a small black dog slides toward (d), whimpering and dragging his legs. I pick up Odie and carry him back inside. The young woman bursts into tears, shouting his name. She thanks us a million times. Puz seems satisfied and looks at me as if to say, 'Can we go back to our nap now?' (D)The woman's expression is panicked. 'My dog,' she says. 'My dog is gone.' She struggles to catch her breath. 'A lady next to my house.. says you...your dog...says she can...' She looks at me and Puz blankly, like she doesn't know what to ask for. 'My dog...he is old and his heart is bad,' she says. 'We'll help,' I say. As I put the leash on Puz, (e) seems ready for the task ahead. But I wonder. Puz was trained to find people, not animals. Can she find a missing pet? I worry that she might not.", + "script": null, + "answer_option": "(1)Puz๋Š” ๋‚ฎ์ž ์—์„œ ๊นจ์–ด ์•ž๋งˆ๋‹น์œผ๋กœ ๋‚˜๊ฐ„๋‹ค. (2)์ Š์€ ์—ฌ์„ฑ์€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์•ž๋ฌธ์œผ๋กœ ๋“œ๋‚˜๋“ค์—ˆ๋‹ค๊ณ  ๋งํ•œ๋‹ค. (3)'I'๋Š” ์ Š์€ ์—ฌ์„ฑ์—๊ฒŒ ์ง‘ ์•ˆ์— ๋จธ๋ฌผ๋Ÿฌ ๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ•œ๋‹ค. (4)๋ค๋ถˆ ์†์—์„œ ์ž‘๊ณ  ๊ฒ€์€ ๊ฐœ๊ฐ€ ๋‹ค๋ฆฌ๋ฅผ ๋Œ๋ฉฐ ๋‚˜ํƒ€๋‚œ๋‹ค. (5)'I'๋Š” Puz๊ฐ€ ์‹ค์ข…๊ฒฌ์˜ฌ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•œ๋‹ค." + } +] \ No newline at end of file diff --git a/ai-service/DB/files/database2_fixed.json b/ai-service/DB/files/database2_fixed.json new file mode 100644 index 0000000..1035228 --- /dev/null +++ b/ai-service/DB/files/database2_fixed.json @@ -0,0 +1,714 @@ +[ + { + "page_number": "122", + "problem_number": "04", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ๊ทธ๋ฆผ์—์„œ ๋Œ€ํ™”์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "M: Honey we need to leave for the bus terminal soon.\\nW:Im almost ready. I'm so excited for our baby's first trip!\nM: Me too. But Im worried he might get hungry on the bus. It' d be great if we could feed him while waiting for the bus.\nW: Don't worry. There's a nursing room at the terminal, and it looks nice! I found some pictures on a blog. See?\nM: There are two microwaves on the upper left. Nice! Then we can heat the baby food there.\nW: Yes. And there's a sink under the window, So we can wash up too.\nM: Aww! I just noticed the teddy bear sitting on the chair in the right corner That's so sweet!\nW:It's really cute. They've thought of everything. The couch next to the lamp looks like a perfect spot to rest.\nM: Ooh! And look at the baby bed in the middle of the room with the striped pad! Families can let their babies nap there.\nW:\\nEverything looks perfect. Let's get ready and head out." + }, + { + "page_number": "122", + "problem_number": "01", + "korean_content": "๋‹ค์Œ์„ ๋“ฃ๊ณ  ๋‚จ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Good afternoon. This is Michael Roberts, Director of the National Gallery of Art. Thank you for visiting and supporting our gallery. We' re excited to inform you about updates to our annual memberships for this year: Annual memberships still include free admission to our permanent exhibitions, but we are now also offering a 30% discount for access to our special exhibitions. Additionally, members can now register early for workshops and educational programs, as well as receive invitations to members-only events and lectures. Membership fees remain unchanged from last year at $50. For more information, please visit the main information desk in the lobby. Thank you for your attention.", + "answer_option": "(1) ๊ด€๋žŒ ์‹œ ์ฃผ์˜ ์‚ฌํ•ญ์„ ์„ค๋ช…ํ•˜๋ ค๊ณ \\n(2) ๋ฏธ์ˆ ๊ด€ ์ž์›๋ด‰์‚ฌ์ž๋ฅผ ๋ชจ์ง‘ํ•˜๋ ค๊ณ \\n(3) ์—ฐ๊ฐ„ ํšŒ์› ์ „์šฉ ํŠน๊ฐ•์˜ฌ ํ™๋ณดํ•˜๋ ค๊ณ \\n(4) ํŠน๋ณ„ ๋ฌด๋ฃŒ ์ „์‹œํšŒ ๊ฐœ์ตœ ์†Œ์‹์˜ฌ ์ „ํ•˜๋ ค๊ณ \\n(5) ์—ฐ๊ฐ„ ํšŒ์›์ œ์˜ ๊ฐฑ์‹ ๋œ ํ˜œํƒ์„ ์•ˆ๋‚ดํ•˜๋ ค๊ณ " + }, + { + "page_number": "122", + "problem_number": "02", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ์—ฌ์ž์˜ ์˜๊ฒฌ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Honey, our son spent his entire allowance on another computer game.\nW: Really? Didn't he just one recently?\nM: Yeah. He spent his money again without thinking. I don't think we should give him an allowance anymore.\nW: That seems a little too harsh, don' t you think?\nM: He's 14 years old. He should know how to save and spend money\nW: Well, I don't think cutting off his allowance is the solution.\nM: But if we don't do that, he'II buying unnecessary things.\nW: Maybe you're right. But he can learn self-regulation by managing his own spending.\nM: And you think that's more important?\nW: Yes. I think this process will help him build self-control.\nM: Okay Let' s continue giving him an allowance, but teach him how to use a spending diary.\nW: That's a plan. Let's talk to him when he gets back from school.", + "answer_option": "(1) ์ž๋…€์˜ ์šฉ๋ˆ์€ ์ •ํ•ด์ง„ ๋‚ ์—๋งŒ ์ฃผ์–ด์•ผ ํ•œ๋‹ค.\\n(2) ์ž๋…€๊ฐ€ ์–ด๋ฆด ๋•Œ๋ถ€ํ„ฐ ๊ธˆ์œต ๊ต์œก์„ ํ•ด์•ผ ํ•œ๋‹ค.\\n(3) ์ž๋…€๊ฐ€ ์šฉ๋ˆ์„ ์“ฐ๋ฉด์„œ ์ž๊ธฐ ํ†ต์ œ๋ ฅ์„ ๊ธธ๋Ÿฌ์•ผ ํ•œ๋‹ค.\\n(4) ์ž๋…€์—๊ฒŒ ๊ถŒ์žฅ ์—ฐ๋ น์— ๋งž๋Š” ์žฅ๋‚œ๊ฐ์„ ์ฃผ์–ด์•ผ ํ•œ๋‹ค.\\n(5) ์ž๋…€์˜ ์šฉ๋ˆ ์ง€์ถœ ๋‚ด์šฉ์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค." + }, + { + "page_number": "122", + "problem_number": "05", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ์—ฌ์ž๊ฐ€ ํ•  ์ผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Ms. Grace, when is Isabel Simpson's guest lecture again?\nW: This Friday. I can't believe a best-selling author is going to be guest speaking! What an opportunity for the school!\nM: I know! Shall we go over the plans one more time to make sure we don't forget anything?\nW: Sure. You put the banners up, right?\nM:Yes, they're all installed in the library.\nW: Thank you Oh, and did you order copies of the author's newest book?\nM: Yes, I ordered 10 copies as prizes. I also created some quizzes about her.\nW: Perfect. And I sent a newsletter with information about the event last week\nM:l hope a lot of students come. Have you contacted Simpson again since the schedule was finalized?\nW: Oh, I forgot to email her, but IIl do it this afternoon.\nM: Sounds good. Please make sure to include directions to the school. I'Il do a final check of the library's broadcast facilities.\nW: Yep! Thank you, Mr Kevin.", + "answer_option": "(1) ํ˜„์ˆ˜๋ง‰ ์„ค์น˜ํ•˜๊ธฐ\\n(2) ์ƒํ’ˆ์šฉ ์ฑ… ์ฃผ๋ฌธํ•˜๊ธฐ\\n(3) ์ž‘๊ฐ€์—๊ฒŒ ์ด๋ฉ”์ผ ๋ณด๋‚ด๊ธฐ\\n(4) ๋„์„œ๊ด€ ๋ฐฉ์†ก ์‹œ์„ค ์ ๊ฒ€ํ•˜๊ธฐ\\n(5) ์˜จ๋ผ์ธ ๊ฐ€์ • ํ†ต์‹ ๋ฌธ ๋ฐœ์†กํ•˜๊ธฐ" + }, + { + "page_number": "122", + "problem_number": "03", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ๋‘ ์‚ฌ๋žŒ์˜ ๊ด€๊ณ„๋ฅผ ๊ฐ€์žฅ ์ž˜ ๋‚˜ํƒ€๋‚ด ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hello, you must be Jack Im Jennifer.\nM: Hi, Jennifer. It's a pleasure to finally meet you.\nW:Likewise! I'm looking forward to directing this shoot with you. Is the model food ready?\nM: Yes, here are the steaks with the fake butter and sauce, as well as the decorations that the restaurant requested.\nW: Wow, these all look incredibly realistic! How long will it take to finish setting up the table for filming?\nM:I need another 30 minutes to place and perfect everything here. Is anything missing?\nW: No, but please ensure the steaks look moist and tender need to look perfect on screen.\nM: Certainly. We'II brush them with syrup to make them look delicious.\nW:Our staff will go over the details of the table setting with you.\nM: Understood, I'II let you know when I'm finished.\nW: Perfect. We'II start as soon as the table is ready. Thank you.", + "answer_option": "(1) ํŒŒํ‹ฐ ํ”Œ๋ž˜๋„ˆ - ๋ ˆ์Šคํ† ๋ž‘ ๋งค๋‹ˆ์ €\\n(2) ์ดฌ์˜ ๊ฐ๋… - ํ‘ธ๋“œ ์Šคํƒ€์ผ๋ฆฌ์ŠคํŠธ\\n(3) ์‹์ž์žฌ ๊ณต๊ธ‰์—…์ฒด ์ง์› - ์˜์–‘์‚ฌ\\n(4) ๋ฐฉ์†ก ์ž‘๊ฐ€ - ์Œ์‹ ํ‰๋ก ๊ฐ€\\n(5) ์Œ์‹ ๋ธ”๋กœ๊ฑฐ - ์Œ์‹์  ์ง์›" + }, + { + "page_number": "123", + "problem_number": "06", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ๋‚จ์ž๊ฐ€ ์ง€๋ถˆํ•  ๊ธˆ์•ก์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: Welcome to Fresh Bakery. How may I help\nM: Hello; I'd like to get the strawberry cake from the top shelf, please.\nW:Certainly, that'II be $50. Would you like anything else?\nM: How much are the birthday party accessories?\nW: The birthday hats and the glasses are $2 each.\nM: Alright IIl take one hat and three pairs of glasses.\nW:Got it. Would you like to add any candles? You can pick any of our candles for $1 each.\nM: Oh, yes. I'd like two candles with the number 5, please. Also, can I use my coupon for 10% off?\nW:Im Sorry, sir; but that coupon has expired.\nM: Oh I see.\nW: Alright, So that's one strawberry cake, one hat, three pairs of glasses, and two candles?\nM: Yes, exactly. Here's my credit card.", + "answer_option": "(1) $54\\n(2) $58\\n(3) $60\\n(4) $63\\n(5) $68" + }, + { + "page_number": "123", + "problem_number": "09", + "korean_content": "Higher Education Experience Day์— ๊ด€ํ•œ ๋‹ค์Œ ๋‚ด์šฉ์˜ฌ ๋“ฃ๊ณ  ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: Hello Harris High School! This is Ms. Park. and I have a special message for all the seniors. As you should all know by now, the Higher Education Experience Day is next Thursday. This is a great opportunity for you to learn about your options for university. There are a total of 8 universities participating this year; and students will choose oneuniversity to visit and join 3 to 4 different programs offered there. Remember online applications for the program open at 6.00 PM tomorrow. Make sure you register early to secure your spot since there is a limit of 30 students per university. Spaces are on a first-come, first-served basis. Buses will be coming on Thursday morning to take you to the university of your choice. If you have any questions, please contact one of the teachers leading the trip.", + "answer_option": "(1) ๋‹ค์Œ ์ฃผ ๋ชฉ์š”์ผ์— ์‹ค์‹œํ•œ๋‹ค.\\n(2) 8๊ฐœ ๋Œ€ํ•™ ์ค‘ ๋ฐฉ๋ฌธํ•  ๊ณณ์„ ์„ ํƒํ•˜๊ฒŒ ๋œ๋‹ค.\\n(3) ๋‚ด์ผ ์˜คํ›„ 6์‹œ๋ถ€ํ„ฐ ์˜จ๋ผ์ธ์œผ๋กœ ์‹ ์ฒญํ•  ์ˆ˜ ์žˆ๋‹ค.\\n(4) ๋Œ€ํ•™๋‹น 40๋ช…์œผ๋กœ ์ธ์› ์ œํ•œ์ด ์žˆ๋‹ค.\\n(5) ๋ฒ„์Šค ๊ตํ†ตํŽธ์ด ์ œ๊ณต๋œ๋‹ค." + }, + { + "page_number": "123", + "problem_number": "07", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž๊ฐ€ ์šฐ์ฒด๊ตญ์— ๊ฐ€๋ ค๋Š” ์ด์œ ๋ฅผ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: Thank you for the ride, Alex. It made getting here a lot easier.\\nM: You're welcome. Go check in and get some rest. We have an early meeting tomorrow morning.\\nW:I'II wait for you in the lobby while you park your car.\\nM: No, go ahead inside I'm going to stop by the office before I check in.\\nW: The post office? If you need to send mail, our hotel can handle that.\\nM: Actually I don't need any postal services.\\nW: Then what's the stop for?\\nM: My car needs to be charged and the hotel's parking lot doesn' t have any clectric car spaces left.\\nW: Oh! I can go with you if you want\\nM: That s okay. It might take a while, and I also need to stop at a convenience store later\\nW: Alright. Have a good night, then.\\nM: Thanks. See you tomorrow.", + "answer_option": "(1) ์ „๊ธฐ์ฐจ๋ฅผ ์ถฉ์ „ํ•ด์•ผ ํ•ด์„œ\\n(2)์šฐํŽธ๋ฌผ์„ ๋ณด๋‚ด์•ผ ํ•ด์„œ\\n(3) ์ฃผ์ฐจ ๊ณต๊ฐ„์ด ๋ถ€์กฑํ•ด์„œ\\n(4) ๋ณดํ—˜์— ๊ฐ€์ž…ํ•ด์•ผ ํ•ด์„œ\\n(5) ํ˜„๊ธˆ์„ ์ฐพ์•„์•ผ ํ•ด์„œ" + }, + { + "page_number": "123", + "problem_number": "10", + "korean_content": "๋‹ค์Œ ํ‘œ๋ฅผ ๋ณด๋ฉด์„œ ๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‘ ์‚ฌ๋žŒ์ด ์ฃผ๋ฌธํ•  ๊ฐ€์Šต๊ธฐ๋ฅผ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Honey, we really need a humidifier. Jenny keeps coughing. So I think the air is too dry.\\nW:I was thinking the same. A few ago, I saved a list of five models from a website. Here they are.\\nM: Great, let's see. We need one that holds more than 2 liters.\\nW:Okay. Which type do you think is better?\\nM: Well what' s the difference?\\nW: Ultrasonic ones have a cool mist. They're quiet and energy-efficient Vaporizer ones boil the water into a hot mist. They can be a bit noisy but warm up the room.\\nM: Let's skip the vaporizer ones. I'm afraid Jenny might accidentally burn herself.\\nW: Good point. I was thinking a night light function would be useful\\nM: I agree. Jenny is afraid of the dark sometimes. A soft, dim light would be helpful.\\nW: And what's our budget?\\nM: Let's spend less than $50.\\nW: Okay Then this one is our choice Let's put in an order.", + "answer_option": "(1) Model: A, Capacity(liter): 1.8, Type: vaporizer, Night Light: x, Price: $45\\n(2) Model: B, Capacity(liter): 2.5, Type: ultrasonic, Night Light: x, Price: $40\\n(3) Model: C, Capacity(liter): 2.5, Type: ultrasonic, Night Light: o, Price: $45\\n(4) Model: D, Capacity(liter): 3, Type: vaporizer, Night Light: o, Price: $58\\n(5) Model: E, Capacity(liter): 3.5, Type: ultrasonic, Night Light: o, Price: $52\\n" + }, + { + "page_number": "123", + "problem_number": "08", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  Youth Paper Airplane Competition์— ๊ด€ํ•ด ์–ธ๊ธ‰๋˜์ง€ ์•Š์€ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "[Cell phone rings.]\\nM: Hi.\\nW:Hi. James it's Sarah. Did you sign up for the Youth Airplane Competition?\\nM: Oh the one at the National Sports Center?\\nW: Yes, same place as last year. Remember we saw the poster together?\\nM: Yeah, I really want to participate this year. When is the application deadline?\\nW: The deadline is midnight tonight. Do you know how to apply?\\nM:l just need to submit my application on the contest website, right?\\nW:Yep. I can send you the website link if you need it\\nM: Please do that. It'd be awesome to win.\\nW: Wouldn't it? You know the winner gets high-end drone!\\nM: That's amazing I'm going to sign up right away.\\nW:I'II text you the link right now. We can talk more later.", + "answer_option": "(1)๊ฐœ์ตœ ์žฅ์†Œ\\n (2)์ง€์› ๋งˆ๊ฐ์ผ\\n (3)์ง€์› ๋ฐฉ๋ฒ•\\n (4)์ฐธ๊ฐ€๋น„\\n (5)์šฐ์Šน ์ƒํ’ˆ" + }, + { + "page_number": "124", + "problem_number": "11", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Honey you look nice! Where are you going?\\nW: Jerry! What are you talking about? We have tickets to the movies tonight.\\nM: Oh, no. I totally forgot. Can I make it in time if I star getting ready now?\\nW:", + "answer_option": "(1) Hold on. I need to get fully dressed up.\\n(2) Alright. You can wait for me to finish my work.\\n(3) Never mind. I already booked the tickets for you.\\n(4) Sounds good. Let's check what movies are playing now\\n(5)It' s okay. We can take\\na cab and still make it there in time." + }, + { + "page_number": "124", + "problem_number": "14", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ์—ฌ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "Man:", + "script": "W: l can't believe how cool it is in this mall, especially comparcd to outside.\\nM: Yeah it 's nice for shopping.\\nW: It's cooler than it needs to be though And look! The doors are open even though the air conditioning is on.\\nM: That's so that people feel comfortable coming in.\\nW: Well, it must take a lot of electricity 10 maintain this temperature.\\nM: I guess, but it's the malls electricity bill, not ours.\\nW: It's not about that. Haven't you seen on the news how bad it is for the environment to use so much electricity?\\nM: I did see one story. It said the increasing demand for electricity is contributing to climate change.\\nW: And the more we use air conditioning, the worse the heat island effect in the in the city gets, causing the temperature to rise.\\nM: So, this isn t just about the temperature in the mall.\\nW: Exactly It' s about global warming. I'II post a suggcstion on the customer bulletin board\\nM: That's a good idea. It's important to see the bigger picture.", + "answer_option": "(1) No problem. I'Il call customer service and get a refund.\\n(2)That' s too bad. We have to do something for the environment.\\n(3) That's a good idea. It's important to see the bigger picture.\\n(4) I'm sorry. I didn't realize our electricity bill would be this high.\\n(5) You're right. Eating too much cold stuff is not good for your health." + }, + { + "page_number": "124", + "problem_number": "12", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ์—ฌ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: Hey, Jim. Are you busy today? Let's have lunch together and talk about the project schcdule;\\nM: Oh Emma! Sounds good. How about going to the sandwich shop at the he corner?\\nW:Uh didn t you know? That place is temporarily closed for renovations.\\nM:", + "answer_option": "(1) I agree. The chicken sandwich there is the best in town.\\n(2) I like that. Can you also ask Terry to join us for lunch today?\\n(3) Don't worry. I brought tomatoes for the sandwiches as you asked\\n(4)Is that so? Then how about trying the new diner down the street?\\n(5) What a relief! I was so worried we wouldn't finish it by lunch.\\nTerry\\nyou" + }, + { + "page_number": "124", + "problem_number": "15", + "korean_content": "๋‹ค์Œ ์ƒํ™ฉ ์„ค๋ช…์˜ฌ ๋“ฃ๊ณ  Chloe๊ฐ€ Evan์—๊ฒŒ ํ•  ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "Chloe:", + "script": "W: Evan and Chloe are friends who enjoy outdoor activities. Recently, Evan has been swelling up and getting rashes after being outdoors. He buys and applies skin medication from the drugstore, which helps to relieve his symptoms, but they just come back every time he is outside. He tries everything: he makes sure to always put on sunscreen before going out, uses spray to protect himself from insect bites, and even switches his lotion to one with gentler and more natural ingredients. Seeing that Evan is still suffering Chloe thinks it would be helpful to find out the underlying cause, and she believes to do so, it is essential for him to get tested for allergies. In this situation what would Chloe most likely say to Evan? Chloe: ", + "answer_option": "(1) Let' s go to the store to buy lotion for sensitive skin.\\n(2) Bug bites can cause allergies, so you should be careful.\\n(3) How about not going outdoors for a while to let your rash heal?\\n(4) Why don't you talk to a doctor first and then buy the right medication?\\n(5) You should get allergy tested to find out what's making you swell up." + }, + { + "page_number": "124", + "problem_number": "13", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "Woman:", + "script": "M: Honey, we need to buy Mia a swimsuit before the summer vacation starts.\\nW: You're right. Let's go to the swimsuit section It's this way\\nM: Oh, this blue swimsuit is nice Mia will love it.\\nW: Not blue. Let's find something else.\\nM: Why? This is her size, and the design is so cute!\\nW:l know, but blue and white are difficult to spot underwater.\\nM: But Mia's favorite color is blue... How about a different shade of blue?\\nW Both light and dark blue are difficult to spot underwater. Let's check online to see which colors are the most visible in water\\nM:[Pause] Hmm. it says bright orange, pink, yellow, and lime green are the safest options for swimsuits.\\nW:Let's look for lime green then. That would be Mia's favorite among the options.\\nM: I understand and agree. Mia will be disappointed, though.\\nW:", + "answer_option": "(1) Absolutely! She can play in the water all day long. \\n(2) What a pity. I think we should get her a new swimsuit.\\n(3) Thank you. She loved the swimsuit you gave her so much.\\n(4) So sweet. It' s touching that you know her favorite color\\n(5) Maybe, but we can't compromise on safety." + }, + { + "page_number": "125", + "problem_number": "18", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Dear Customers,\\nHello! I'm Julian Opie, the owner of Mexican Stove. We've been renovating since last August to accommodate more customers, and the renovations are now nearly complete. Originally, we planned to reopen by October 21st, but we encountered some unexpected electrical issues that will take additional time to resolve. We now need to delay our reopening by two days. We sincerely appreciate your patience while we work to welcome you back. We eagerly look forward to serving you soon at our newly improved restaurant, featuring an attractive interior, expanded seating, and a spacious open kitchen. Thank you for your understanding!", + "script": null, + "answer_option": "(1) ๋ ˆ์Šคํ† ๋ž‘์˜ ์žฌ๊ฐœ์žฅ ์—ฐ๊ธฐ๋ฅผ ๊ณต์ง€ํ•˜๋ ค๊ณ \\n(2) ๋ ˆ์Šคํ† ๋ž‘์˜ ๋ณด์กฐ ์š”๋ฆฌ์‚ฌ๋ฅผ ๋ชจ์ง‘ํ•˜๋ ค๊ณ \\n(3) ๋ ˆ์Šคํ† ๋ž‘์˜ ์žฌ๊ฐœ์žฅ ํ• ์ธ ํ–‰์‚ฌ๋ฅผ ์•ˆ๋‚ดํ•˜๋ ค๊ณ \\n(4) ๋ ˆ์Šคํ† ๋ž‘ ์ด์šฉ๊ฐ์˜ ๋ถˆ๋งŒ์— ๋Œ€ํ•ด ์‚ฌ๊ณผํ•˜๋ ค๊ณ \\n (5) ๋ ˆ์Šคํ† ๋ž‘ ๊ฐœ์„ ์˜ฌ ์œ„ํ•œ ์„ค๋ฌธ์กฐ์‚ฌ๋ฅผ ์š”์ฒญํ•˜๋ ค๊ณ " + }, + { + "page_number": "125", + "problem_number": "16", + "korean_content": "๋‚จ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": null, + "script": "M: Hello everyone. Today, let's talk about newcomers to our neighborhood. Non-native species are plants and animals that have been moved by humans to places where they don't naturally exist. Within this group are invasive species, which cause economic and environmental harm to the new areas where they are found. Do you know of any invasive species in Korea? Nutria were imported from South America for their fur and meat but released into the wild They're destroying crops and small native birds in Korea's wetlands.The spotted lanternfly is native to China and believed to have arrived here on cargo shipments. They suck fluid out of fruit trees, spreading disease and causing many trees to die. Louisiana crawfish, originally brought over as pets from America, are rapidly spreading in streams. They arehuge threat to native animals and spread disease to native shellfish. Lastly, the red-eared slider, a type of turtle, was also brought in from America to serve as as a pet. This turtle outcompeted native turtles for food, pushing native turtles to near extinction.", + "answer_option": "(1) how unfavorable surroundings restrain invasive species\\n(2) ways non-native species adapt to new environments\\n(3) invasive species and their negative impacts \\n(5) economic effects of protecting biodiversity\\n(5) why species have evolved to subdivide" + }, + { + "page_number": "125", + "problem_number": "17", + "korean_content": "์–ธ๊ธ‰๋œ ๋™๋ฌผ์ด ์•„๋‹Œ ๊ฒƒ์€?", + "english_content": null, + "script": "M: Hello everyone. Today, let's talk about newcomers to our neighborhood. Non-native species are plants and animals that have been moved by humans to places where they don't naturally exist. Within this group are invasive species, which cause economic and environmental harm to the new areas where they are found. Do you know of any invasive species in Korea? Nutria were imported from South America for their fur and meat but released into the wild They're destroying crops and small native birds in Korea's wetlands.The spotted lanternfly is native to China and believed to have arrived here on cargo shipments. They suck fluid out of fruit trees, spreading disease and causing many trees to die. Louisiana crawfish, originally brought over as pets from America, are rapidly spreading in streams. They arehuge threat to native animals and spread disease to native shellfish. Lastly, the red-eared slider, a type of turtle, was also brought in from America to serve as as a pet. This turtle outcompeted native turtles for food, pushing native turtles to near extinction.", + "answer_option": "(1) nutria\\n(2) spotted lanternfly\\n(3) Louisiana crawfish\\n(4) American bullfrog\\n(5) red-eared slider" + }, + { + "page_number": "126", + "problem_number": "20", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ํ•„์ž๊ฐ€ ์ฃผ์žฅํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Access is something feature reporters need the most, and it can be one of the most difficult to obtain. Where do you begin to find people affected by home foreclosures or telemarketing scams? Chances are, you might know someone - a friend or family member - who has experience with the story you are reporting. It is essential that you not use someone you have a relationship with as a source. It would be nearly impossible for you to be unbiased. If you were interviewing a friend or family member; you might feel obligated to make that person look good, making it impossible for you to act independently without influence. You also might influence your sources in your questioning, guiding them toward a particular answer because you already know their story or how they will react to certain issues. Additionally, your friends and family members might try to guess at the answers they think you want to hear in hopes of pleasing.", + "script": null, + "answer_option": "(1) ์™œ๊ณก ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ ํŠน์ง‘ ๊ธฐ์ž๋Š” ์ง€์ธ์„ ์ทจ์žฌ์›์œผ๋กœ ์‚ผ์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค.\\n(2) ๋ถ€์ •์ ์ธ ๋‚ด์šฉ์˜ฌ ๋ณด๋„ํ•  ๋•Œ ๊ธฐ์ž๋Š” ๋‹น์‚ฌ์ž์—์ œ ํ•ด๋ช…ํ•  ๊ธฐํšŒ๋ฅผ ์ฃผ์–ด์•ผ ํ•œ๋‹ค.\\n(3) ์ผ๋ฐ˜์ธ์˜ ์‚ฌ๋ก€๋ฅผ ๊ธฐ์‚ฌํ™”ํ•  ๋•Œ ๊ธฐ์ž๋Š” ๋‹น์‚ฌ์ž์˜ ์ต๋ช…์„ฑ์„ ๋ณด์žฅํ•ด์•ผ ํ•œ๋‹ค \\n(4) ๊ฐ๊ด€์ ์ธ ๋‹ต๋ณ€์˜ฌ ์–ป๊ธฐ ์œ„ํ•ด ํŠน์ง‘ ๊ธฐ์ž๋Š” ์ธํ„ฐ๋ทฐ ์งˆ๋ฌธ์„ ์ •์ œํ•ด์•ผ ํ•œ๋‹ค.\\n(5) ๊ธฐ์ž๋Š” ๋ช…ํ™•ํžˆ ํ™•์ธ๋˜์ง€ ์•Š์€ ์‚ฌ์‹ค์„ ๋ณด๋„ํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค." + }, + { + "page_number": "126", + "problem_number": "19", + "korean_content": "๋‹ค์Œ ๊ธ€์— ๋“œ๋Ÿฌ๋‚œ 'I'์˜ ์‹ฌ๊ฒฝ ๋ณ€ํ™”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "A few days after we arrived in the United States from China, my husband started working at a research institute at New York University. I called him to say I was going to take the subway alone to see him. The New York Metro was complicated, and since I couldn't speak English very well, I felt a little anxious, but I decided to take the subway anyway. I boarded the subway in the direction of New York University. When I stepped off the subway I looked around the unfamiliar station. Uneasy thoughts suddenly filled my head I lingered in the subway station for a long time before I finally realized that I had gotten one stop early. Luckily, I hadn't left the station. I reboarded the subway and soon arrived at my destination. When I got off the subway again, I hummed as I happily walked toward the research institute where he worked. I saw my husband walking toward me, waving his hands to my attention, and my tension melted away.", + "script": null, + "answer_option": "(1) excited -> bored\\n(2) worried -> relieved\\n(3) envious -> hesitant\\n(4) indifferent -> angry\\n(5) ashamed -> nervous" + }, + { + "page_number": "127", + "problem_number": "21", + "korean_content": "๋ฐ‘์ค„ ์นœ look at the concept with new eyes๊ฐ€ ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€? [3์ ]", + "english_content": "Domestication can sometimes seem to be taken for granted as a state of affairs the origins of which are now lost in the mists of time, the effects of which will be with us forever. However; this fails to take into account the fact that, in global historical terms, domestication is a relatively recent phenomenon, and in population terms, more than 90 percent of Homo sapiens have lived by hunting and gathering. This calibration helps to undermine some of the definitions of domesticity as the \"natural\" (ironically) relationship between humans and their environment. By making domesticity the hallmark of humanity, we exclude 90 percent of our ancestors from that category By including only the kinds of domesticatory relationships that are embodied by selective breeding and other features of post-industrial agriculture, we exclude 97 percent of the estimated 80 billion people who have lived. At the symposium that gave rise to this collection, the different temporal and spatial scales, priorities and histories of definitions and uses of the term domestication within subdisciplines encouraged each of us to \n\n ๋ฐ‘์ค„: ", + "script": null, + "answer_option": "(1) recognize that humans have domesticated and exploited nature for their benefit\\n(2) question the existing view that domestication is a defining feature of humanity\\n(3) prioritize the features of modern agriculture in redefining humanity\\n(4) acknowledge that domestication is an inherent and unique human trait\\n(5) see humanityโ€™s interaction with nature as a key force in advancing civilization" + }, + { + "page_number": "127", + "problem_number": "22", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "The concept of regulating the total quantity produced, or yield, over a period of years applies to whole forests or forest districts. rather than to particular stands which are the concern of silviculture. In determining the rate at which forests should be exploited, it is designed to counter the free play of short-term market forces, which in many cases would dispose of the assets without replacing them. The general aim of regulating the yield is to sustain it over long periods, often expressed as an aim to do so in perpetuity. The concept was originally based on the realization that the amount of wood a forest can supply is not inexhaustible. If a continuous and permanent supply is to be assured, a forest can only be utilized at a rate corresponding to its natural rate of growth. The concept was extended in the 1990s to cover all the functions of a forest and the maintenance of its soil, biological diversity, and productivity. Its current definition includes elements of time, change, social function and economical and ecological use, economic principles, and ethical obligations.", + "script": null, + "answer_option": "(1)์‚ผ๋ฆผ์˜ ์ด ์ˆ˜ํ™•๋Ÿ‰ ๊ทœ์ œ๋Š” ์ง€์† ๊ฐ€๋Šฅํ•œ ๊ณต๊ธ‰์„ ๋ชฉํ‘œ๋กœ ํ•˜๋Š” ํฌ๊ด„์ ์ธ ๊ฐœ๋…์ด๋‹ค .\\n (2)์‚ผ๋ฆผ์˜ ์ด ์ˆ˜ํ™•๋Ÿ‰์„ ์ธ์œ„์ ์œผ๋กœ ์กฐ์ •ํ•˜๋ฉด ์‚ผ๋ฆผ์˜ ์ž‘์šฉ์„ ์ €ํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.\\n (3)์‚ผ๋ฆผ์ด ์ƒ์‚ฐ๋˜๋Š” ์ด๋Ÿ‰์˜ ๊ฐœ๋…์€ ์‚ผ๋ฆผ์˜ ์ž์—ฐ ์„ฑ์žฅ๋ฌผ๊ณผ ์ƒ๋ฐ˜๋œ ์ž…์žฅ์— ๋†“์ธ๋‹ค.\\n (4)์‚ผ๋ฆผ์˜ ์˜๊ตฌ์ ์ธ ๋ณด์กด์„ ์œ„ํ•ด ์‚ผ๋ฆผ ๊ฐœ๋ฐœ์˜ ์ผ์‹œ์ ์ธ ์ค‘๋‹จ์ด ๊ถŒ๊ณ ๋˜๊ณ  ์žˆ๋‹ค.\\n (5)ํŠน์ • ์‚ผ๋ฆผ์˜ ์žฅ๊ธฐ์ ์ธ ์œก์„ฑ์„ ํ†ตํ•ด ์‚ผ๋ฆผ์˜ ์ด ์ˆ˜ํ•™๋ž‘์„ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค." + }, + { + "page_number": "128", + "problem_number": "23", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "A form of human-centeredness commonly talked about today is loyalty to all members of our own species. Clearly, such loyalty to other humans has become a very important ethical and political factor. Among the greatest achievements of humankind have been successful social movements that sought to abolish slavery and racism and to establish both moral and legal rights for individual humans. In very real sense, these extraordinary achievements had to be consciously chosen to override the matter-of-fact realities of humans not treating each other as important, let alone as equals. The long history of some humans dominating other humans provides evidence that individual humans do not naturally develop a powerful loyalty to all members of their species, but must choose this loyalty. What everyday life realities suggest strongly, then, is that humans consistently develop allegiance only to some humans, such as family members or their local community. This is our biological reality, while the affirmation of the fact that we can, with effort, develop a species-wide loyalty in order to affirm human dignity is a choice and today an important achievement of the human species.", + "script": null, + "answer_option": "(1) conscious human efforts to counter the innate tendency to favor certain people\\n(2) the potential risk of collective unity arising from a species-wide loyalty\\n(3) the involvement of a third party to combat human greed\\n(4) humanity's inherent goodness counteracting human selfishness\\n(5) humanity's notable achievements acquired via mutual competition" + }, + { + "page_number": "128", + "problem_number": "24", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "The American museum movement began in the mid-nineteenth century when private charitable gift giving, testifying to the spirit of individual initiative, played a large part in the country's growth. Perceived as a public benefit, charitable donation was encouraged under subsequent tax legislation and continues to be a primary source of museum income. Most museums are thus quasi-public institutions, incorporated along with hospitals, churches, and various educational and service agencies as nonprofit organizations. In principle, they are thus nominally independent of government supervision, unlike their nationalized European counterparts. In this century, however, most nonprofits have received state financial assistance in the form of grants and subsidies, which enable the government to impose restrictions as a condition of receiving aid. Unable to survive on exclusively private funds, most museums, like other nonprofit organizations, have reluctantly accepted the compromise and lived uneasily with its consequences.", + "script": null, + "answer_option": "(1) Current American Museums' Dilemma: Balancing Financial Support and Independence\\n(2) Improved National Museum Quality Through Government Intervention\\n(3) Contemporary Efforts Promote Public Museum Collections\\n(5) Modern Museums Revitalized Through Private Donations\\n(5) Museums' Ongoing Efforts to Define Their Core Identity" + }, + { + "page_number": "129", + "problem_number": "25", + "korean_content": "๋‹ค์Œ ํ‘œ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "The table above shows orbital launch attempts by country from 2020 to 2023. (1) Both the USA and China increased their orbital launch attempts between 2020 and 2023, while both Russia and Europe decreased their orbital launch attempts between 2022 and 2023. (2) In 2021, the USA attempted 45 orbital launches, three times as many as Europe. (3) In 2022, Russia's orbital launch attempts were more than three times those of Europe and about one-third of China's. (4) Both in 2020 and in 2021, China attempted more orbital launches than the USA, but the trend reversed in 2022, with the USA ranking first. (5) Between 2022 and 2023, โ€œOther countriesโ€ attempted more orbital launches than Europe and ranked fourth in both years.", + "script": null, + "graph": " " + }, + { + "page_number": "129", + "problem_number": "26", + "korean_content": "Frank Lloyd Wright์— ๊ด€ํ•œ ๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "Frank Lloyd Wright was born on June 8, 1867, in Richland Center, Wisconsin. His father was a preacher and a musician and his mother was a teacher from a large Welsh family. Wright enrolled at the University of Wisconsin-Madison to study civil engineering. To pay his tuition, he worked for the dean of the engineering department and assisted the acclaimed architect Joseph Silsbee with the construction of the Unity Chapel. The experience convinced Wright that he wanted to become an architect. Later, Wright established his own architectural firm and designed the Winslow House in River Forest. With its horizontal emphasis and expansive, open interior spaces, the Winslow House is the first example of his revolutionary style, later named โ€œorganic architecture.โ€ Considered the greatest American architect of all time, Wright perfected a distinctly American style of architecture that emphasized simplicity and natural beauty in contrast to the elaborate architecture that had prevailed in Europe. He designed more than 1,000 buildings during his lifetime, nearly one-third of which came during his last decade.", + "script": null, + "answer_option": "(1) ์•„๋ฒ„์ง€๋Š” ๋ชฉ์‚ฌ์ด์ž ์Œ์•…๊ฐ€์˜€๋‹ค.\\n(2) Joseph Silsbee๊ฐ€ Unity Chapel์˜ฌ ๊ฑด์ถ•ํ•˜๋Š” ๋ฐ ๋„์›€์˜ฌ ์ฃผ์—ˆ๋‹ค.\\n(3) Winslow House๋Š” ๊ทธ์˜ ํ˜์‹ ์ ์ธ ์Šคํƒ€์ผ์˜ ์ฒซ ๋ฒˆ์งธ ์‚ฌ๋ก€์ด๋‹ค\\n(4) ๋ณต์žกํ•œ ๊ฑด์ถ•์„ ํŠน์ง•์œผ๋กœ ํ•˜๋Š” ๋ฏธ๊ตญ์ ์ธ ๊ฑด์ถ• ์–‘์‹์„ ์™„์„ฑํ–ˆ๋‹ค.\\n(5) ํ‰์ƒ 1,000๊ฐœ๊ฐ€ ๋„˜๋Š” ๊ฑด๋ฌผ์˜ฌ ์„ค๊ณ„ํ–ˆ๋‹ค." + }, + { + "page_number": "130", + "problem_number": "27", + "korean_content": "DreamDough Walffle Maker์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "DreamDough Waffle Maker\n Enjoy perfect, golden-brown waffles every morning with our easy-to-use waffle maker, DreamDough. Simply preheat, pour in the ingredients, and in minutes, you'll have delicious waffles!\n\nProduct Specifications\nโ€“ Color: Black\nโ€“ Dimensions: 12ร—9ร—6 inches\nโ€“ Product weight: 2 kg\n\nHow to Operate\nStep 1: Preheat \n Plug in the waffle maker. The red and green lights will turn on together, indicating that the machine is preheating. When the green light turns off, preheating is complete.\nStep 2: Pour and Close\nAdd the ingredients, and then close the lid securely. Both lights will turn on again, showing that the machine is cooking. Wait for the process to finish.\nStep 3: Enjoy the Waffles\nWhen the green light turns off, baking is complete, and your delicious waffles are ready to enjoy.\n\nSafety Tips\n- Do not touch the cooking plates when hot; instead, use the handles.\n- Avoid outdoor use.", + "script": null, + "answer_option": "(1) ์ œํ’ˆ์˜ ๋ฌด๊ฒŒ๋Š” 2kg์ด๋‹ค.\\n(2) ์˜ˆ์—ด ์ค‘์ผ ๋•Œ๋Š” ๋นจ๊ฐ„ ๋ถˆ๊ณผ ๋…น์ƒ‰ ๋ถ™์ด ํ•จ๊ป˜ ์ผœ์ง„๋‹ค.\\n(3) ์žฌ๋ฃŒ๋ฅผ ๋„ฃ์€ ํ›„์—๋Š” ๋šœ๊ป‘์˜ฌ ๋‹จ๋‹จํžˆ ๋‹ซ์•„์•ผ ํ•œ๋‹ค.\\n(4) ๊ตฝ๊ธฐ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ๋นจ๊ฐ„ ๋ถ™์ด ๊บผ์ง„๋‹ค. \\n(5) ์•ผ์™ธ์—์„œ์˜ ์‚ฌ์šฉ์€ ํ”ผํ•ด์•ผ ํ•œ๋‹ค.", + "graph": " " + }, + { + "page_number": "130", + "problem_number": "28", + "korean_content": "Hiking Ribou Mountain์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์€?", + "english_content": "Hiking Ribou Mountain\nAre you ready to explore Ribou Mountain? Join us for an unforgettable adventure through stunning valleys, green forests, and breathtaking natural beauty.\n\nDate & Time\nโ€“ Date: August 16, 2025\nโ€“ Time: 9:30 a.m. - 3:00 p.m.\nโ€“ Meeting Point: Base camp at 9:00 a.m. (Hiking starts at 9:30 a.m. sharp.)\n\nActivities\nโ€“ Identifying and documenting local wildlife and plant species\nโ€“ Engaging in quizzes on mountain geography, history, and wildlife during breaks\n\nRegistration\nโ€“ Fee: $10 (includes a beverage)\nโ€“ Deadline: 2:00 p.m. on August 15, 2025\nโ€“ All cancellations made before the deadline are eligible for a full refund.\n\nNotices\nโ€“ We advise you to:\nWear hiking boots to ensure safety and prevent slipping.\nCarry energy-boosting snacks to keep your energy levels up during the hike.", + "script": null, + "answer_option": "(1) ์˜คํ›„ 4์‹œ๊นŒ์ง€ ์ง„ํ–‰๋œ๋‹ค.\\n(2) ํ•˜์ดํ‚น์ด ๋๋‚œ ํ›„ ํ€ด์ฆˆ๊ฐ€ ์ง„ํ–‰๋œ๋‹ค.\\n(3) ์ฐธ๊ฐ€๋น„์—๋Š” ์Œ๋ฃŒ๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค.\\n(3) ๋“ฑ๋ก ๋งˆ๊ฐ ์‹œ๊ฐ„ ์ „ ์ทจ์†Œ ์‹œ ๋ฐ˜์•ก๋งŒ ํ™˜๋ถˆํ•ด ์ค€๋‹ค.\\n(5) ์—๋„ˆ์ง€๋ฅผ ์˜ฌ๋ฆฌ๋Š” ๊ฐ„์‹์„ ํœด๋Œ€ํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.", + "graph": " " + }, + { + "page_number": "131", + "problem_number": "29", + "korean_content": "(A), (B); (C)์˜ ๊ฐ ๋„ค๋ชจ ์•ˆ์—์„œ ์–ด๋ฒ•์— ๋งž๋Š” ํ‘œํ˜„์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Active participation in all parts of public life was the central organizing concept for Athenians, and urban space within Athens was overlaid by a political code that supplanted the earlier cosmological/religious one. The radial street network extending from the center of the omphalos would connect all citizens to the central public space. This development is very different from both the early grid network (A) [finding / found] in cities in the Indus Valley and the random organic growth of urban settlements in Mesopotamia. Radial development was dictated not by the economic concern of easy access to the market but by the political principle (B) [that / which] all homes should be equally distant from the center because all Athenian citizens were equal. Within the center (C) [was / were] placed the citizen assembly hall, the city council hall, and the council chamber, all structures linked to the institution of city politics.", + "script": null, + "answer_option": "(1) (A): finding (B): that (C): was\\n(2) (A): finding (B): which (C): were\\n(3) (A): found (B):that (C): were\\n(4) (A): found (B): that (C): was\\n(5) (A): found (B): which (C): was" + }, + { + "page_number": "131", + "problem_number": "30", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "In The Big Sort, Bill Bishop argues that in recent years people in the United States have increasingly clustered into like-minded groups. He documents how changes in area and regional neighborhood grouping have been reflective of political preferences, leading to (1) communities with divisions that are deeper and more irreconcilable than in previous eras. This geographic, economic, and political clustering is (2) in a similar clustering in our media environments. Fragmentation of the media, including television, spawned niche genres. In turn, these specific segments of mass media (3) audiences that can more easily remain within their own sphere of comfort. Television's evolution, including the development of cable and satellite, has contributed to a (4) notion of the 'commons,' or the common good, and its replacement with social isolation primarily based on interests of the individual. Television has, to a significant degree, moved from promoting the commonalities among us to reinforcing our disagreements by targeting smaller groups and differing interests. This (5) discourages the recognition of common problems or collective action, posing a fundamental threat to a democratic society.", + "script": null + }, + { + "page_number": "132", + "problem_number": "32", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "A delightful episode of the Fredkonomicr podcast in October 2016 explained the drag on the economy from [๋นˆ์นธ]. Stephen Dubner and his guests focused on cities and infrastructure rather than personal habits, but the principle of discounting the future applies equally. Politicians, as Dubner's economist and cities expert Edward Glaeser, pointed out, are motivated to limit spending in the present, while society benefits from today's investments that support communities into the future. Ironically, governments in ancient Rome, investing extensively and wisely in building and maintaining the vital systems upon which communities depend, fell prey less often to temporal discounting than modern cities and states. Without its infrastructure investments, Rome could not have been as populous, nor as lasting. Despite our greater knowledge, technology, and ability to model and predict decay, the speed of change in our modern world seems to exacerbate our hyperfocus on the present.", + "script": null, + "answer_option": "(1) excessive concern over uncontrollable events\\n(2) our unwillingness to invest in preventive maintenance\\n(3) absence of personal responsibility and social awareness\\n(4) prioritization of personal interests over community well-being\\n(5) inefficient public spending that does not drive economic growth" + }, + { + "page_number": "132", + "problem_number": "31", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Infants' early speech production is more sophisticated than it sounds to our naked ears. When infants first start saying words, they seem to fail to make certain distinctions clear. An infant might be heard to pronounce pa and ba at the beginnings of different words exactly the same. However, technical analyses of vocal recordings of infants have revealed that infants actually pronounce the sounds differently, but not differently enough for adults to hear the distinction. This kind of technologically aided finding echoes a theme that has arisen again and again in the study of language development. The roots of complex behaviors may be discovered long before those behaviors are clear and overt, and many infant capacities that seem to bloom overnight have in fact been emerging in more basic forms for months. Developmental scientists recognize this [๋นˆ์นธ] between infantsโ€™ babbling and their early words. Both rest on the same articulatory mechanisms, they share many of the same fundamental speech sounds, and first words often incorporate frequently produced babbling sounds.", + "script": null, + "answer_option": "(1) disorder\\n(2) continuity\\n(3) variability\\n(4) intermission\\n(5) contradiction" + }, + { + "page_number": "133", + "problem_number": "33", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Abraham Luchins studied the problem of [๋นˆ์นธ]. In one puzzle, he asked subjects how to fill a bucket of water using only jars of specific volumes. For example, a puzzle might ask a subject to obtain twenty liters of water, using only a twenty-nine-liter jar and a three-liter jar. The answer is to pour in twenty-nine liters, and then remove three liters, three times. For these puzzles, Luchins presented a sequence of problems that could all be solved by repeating a pattern of adding the second jar, and removing the first jar and two times the third jar. Following multiple repetitions of this pattern, he then gave subjects a puzzle that could be solved with the more complicated pattern they had learned (that is, B-A-2C) or with a simpler solution (A-C). In their initial experiment, none of the subjects noticed the simpler solution. Luchins called this perseveration of a habitual mode of problem-solving Einstellung, or the mindset 'which predisposes an organism to one type of motor or conscious act.", + "script": null, + "answer_option": "(1) how individuals could lose their unique and distinct identities\\n(2) what strategies could improve decision-making under pressure\\n(3) how past successes in problem solving could inhibit future results\\n(4) why pattern identification would ease understanding of complex information\\n(5) when repeated practice would produce the most creative problem-solving" + }, + { + "page_number": "133", + "problem_number": "34", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "A linkage between theory and physical reality helps validate our belief. and increases our confidence, in a theory. However, our levels of belief or confidence may be irrelevant in practice. The disbelief of nineteenth-century race horse breeders in the theory of evolution by natural selection did not the fact that they unknowingly were accelerating the evolution of fast horses by creating a natural environment in which slow horses were not allowed to reproduce - they were selected against. Another example is the movement of the sun relative to the Earth Formally, one does not know, and cannot prove, that the sun will rise every in the future. This has not prevented humankind from using the periodicity of the sun's movement (24 hours) cach day to tell time. Nor has it prevented farmers from planting seeds that will require sunlight once they sprout. These examples emphasize the fact that [๋นˆ์นธ]. The influential expression of this concept is attributed to the statistician George E.P. Box, who in 1978 wrote 'All models are wrong but somne are useful.'", + "script": null, + "answer_option": "(1) theories do not have to be proven correct to be useful\\n(2) technological possibility doesn mean theoretical validity\\n(3) a theory's practicality requires diverse evaluation criteria\\n(5) experiments designed to prove hypothesis are meaningless\\n(5) a single contradictory experiment can falsify accepted theories" + }, + { + "page_number": "134", + "problem_number": "35", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "Informal care through family members and friends is a significant part of the care provision of older individuals with mental illnesses. Ageing often makes living independently and managing activities of daily living, such as bathing, dressing, or eating, more challenging. (1) In many cases, the symptoms of mental illnesses worsen these challenges, further leaving individuals unable to care for themselves without significant assistance. (2) Functional impairment and reduced energy and motivation, for example, can be disabling symptoms of late-life depression. (3) To offset the costs of formal healthcare services, in many cases of severe illness, family members provide care to relatives with mental illness at younger ages. (4) Effective communication and coordination between public health and health care are key to the success of these efforts. (5) Caregiving can lead to burnout and produce caregiver burdens including financial strain, depression, physical illness, and even excess mortality, among other negative consequences.", + "script": null + }, + { + "page_number": "134", + "problem_number": "36", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[One area of materials science where early electron microscopes were able to provide important new insights and understanding was in colloidal systems. Colloid is a term covering a very wide range of materials.] \n\n (A) Particles in wood smoke are on average about 500 nm across. As an additional example, \"smoke\" particles of magnesium oxide formed by burning magnesium metal in air are typically only 100 nm or even less in diameter. This is much smaller than the range of even the best light microscope.\n(B) The magnesium oxide particles appear as perfect cubes in the electron microscope. Magnesium burns a very bright white and is used as a common constituent of fireworks to add white sparks and improve the overall brilliance.\n(C) It is generally applied to describe any two-phase substance where one of the phases consists of tiny particlesโ€”typically in the range of 5 to 1,000 nmโ€”spread through a second substance. Perhaps, an easily visualized example of a colloidal system is smoke particles in air.", + "script": null, + "answer_option": "(1) (A)-(C)-(B)\\n(2) (B)-(A)-(C)\\n(3) (B)-(C)-(A)\\n(4) (C)-(A)-(B)\\n(5) (C)-(B)-(A)" + }, + { + "page_number": "135", + "problem_number": "37", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[The concept of leisure is not new. As long ago as the fourth century BC, Aristotle acknowledged that engagement in musicโ€”by which he referred to an active and embodied experience of melody, drama, poetry, and danceโ€”as leisure was an important element of the life of Athenian citizens.] \n\n(A) Aristotle took an expanded view, considering music to fulfill four functions, including amusement, making the best use of free time, a moral function (ethos), and purgation, cleansing the soul. Music as amusement was seen as a โ€œmedicine for the ills of work.โ€\n(B) He conceived of such artistic experiences as noble uses of leisure time and essential in supporting the private happiness of citizens. In contrast, Plato saw music as a means for inculcating the citizenโ€™s moral character, what he called ethos, and he argued for its necessity in a citizenโ€™s education.\n(C) Music as โ€œemployment of leisureโ€ could contribute to practical wisdom. Solmsen reminds us, however, that although Aristotle encouraged some practicing of music, he made it clear that โ€œa person of liberal education should not aim at the degree of proficiency attained by professional musicians.โ€", + "script": null, + "answer_option": "(1) (A)-(C)-(B)\\n(2) (B)-(A)-(C)\\n(3) (B)-(C)-(A)\\n(4) (C)-(A)-(B)\\n(5) (C)-(B)-(A)\\n'" + }, + { + "page_number": "135", + "problem_number": "38", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: \n\nMost soccer players run up quite quickly to take a penalty, choosing before they do so which side of the to aim at, and kick the ball as hard as possible. (1) The disadvantage of this approach is that if the goalkeeper guesses correctly which direction to dive, they have a reasonable chance of stopping the shot. (2) However, there are a few players in the English Premiership who have developed a rather different penalty-taking technique. (3) They run only slowly up to the penalty spot and then take an almost vertical leap into the air in their final stride before landing and aiming the ball almost accurately away from the goalkeeper's dive. (4) The hard landing produces a strong enhanced pendulum action that helps power the kick, but it does not make their shots more powerful than conventional penalty takers. (5) The technique requires massive skill but can result in success rates of over 90 percent.", + "script": null + }, + { + "page_number": "136", + "problem_number": "39", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: \n\nMany parents are very attentive to signs of depression, but they make the mistake of believing that childhood and adolescent depression appears the same as adult depression. Adults who are particularly sad or depressed tend to have sleep disturbances, become withdrawn, lack energy, seem to have a lower capacity to experience pleasure, and often express hopelessness. (1) This is true of some children and adolescents, but nearly half of adolescents who are depressed are irritable instead of withdrawn. (2) They may have boundless energy and are likely to act out with rage. (3) I have taken care of many depressed teenagers whose parents are loving and attentive but missed their child's depression because it is sometimes difficult for parents to tell a normal teenager from a depressed one. (4) Because parents may have adjusted to this moodiness, they can miss a teen whose rage and irritability are signals of emotional distress or depression. (5) This is a critical reason that parents need to feel comfortable turning to a professional for an evaluation.", + "script": null + }, + { + "page_number": "136", + "problem_number": "40", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์˜ฌ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋นˆ์นธ (A), (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Cultures suggest innumerable social worlds that are constantly contradictory and full of tension. When we are looking across cultures, we should never be at all surprised to find their enormous differences. But this is so also when we look inside specific cultures. Cultures do not speak to consensus and uniformity; by their natures, they cannot. Thus, to speak of cultures harmonious well-ordered consensual wholes is sheer nonsense. Shorthand talk of 'Muslim culture', 'working-class culture', 'women's culture', or 'British culture' is, in truth, to construct a lie. Immediately sociologists can recognize that human social worlds are stuffed full of ambiguities, contradictions, tensions - never worlds of agreed-upon consensus. Social life as lived by all peoples at all times grows out of these tensions. It is extremely important to grasp this because views of cultures which fatten them, homogenize them and turn them into monologic, monolithic and mono-moral overly stable forms are very dangerous to sociological thinking-they foster the stereotypes of much everyday thought. \n\n => ์š”์•ฝ: We should recognize that cultures are inherently ๋นˆ์นธ (A) and that the perspectives that deny or suppress this nature can ๋นˆ์นธ (B) stereotypes and inaccurate sociological unsderstanding in everyday life.", + "script": null, + "answer_option": "(1) (A): conflicting (B): promote \\n(2) (A): comparable (B): reinforce \\n(3) (A): temporary (B): challenge \\n(4) (A): organized (B): produce \\n(5) (A): diverse (B): shatter " + }, + { + "page_number": "137", + "problem_number": "41", + "korean_content": "์œ—๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Through clever experiments, famed neuroscientist Michael Gazzaniga demonstrated how we instinctively create rational explanations to explain our unconscious behaviors. Gazzaniga worked with patients who had their cerebral hemispheres surgically separated as a treatment for severe epileptic seizures. Surgeons disconnect the side of the brain with (a) circuitry from the side that carries out simple commands.\nThrough ingenious manipulation of experimental conditions, Gazzaniga was able to give a simple command to one part of the brain without the response part (b). He found that by giving the command \"get up and walk\" the patient would do so. But when asked why he was up and where he was going, the subject replied creatively, \"I'm thirsty. I thought I'd get a Coke.\" When one hemisphere of the subject's brain was commanded to laugh, he did. When asked why he was laughing, he responded, \"You guys crack me up,\" not \"Because you told me to. After repeated trials, Gazzaniga concluded that many of our explanations about our behaviors are actually (c) by the behavior itself. He believes that all of us do all sorts of things for reasons outside conscious awareness and that one of the main jobs of consciousness is to keep our lives tied together in an understandable and consistent package. We do this by (d) explanatons that best fit our self-image. We instinctively invent reasons to exlpain our behaviors, but remain (e) that these are creations because they fit seamlessly into a self-sustaining self-image.", + "script": null, + "answer_option": "(1) The Influence of Social Interactions on Behavioral Responses\\n(2) Conscious Mind: A Story-creator Justifying Unconscious Actions\\n(3) The Limits of Human Reason: Uncovering Cognitive Biases\\n(4) The Importance of Self-awareness: Understanding Our Motivations\\n(5) Advances in Brain Imaging Techniques and Their Applications" + }, + { + "page_number": "137", + "problem_number": "42", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)-(e) ์ค‘์—์„œ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "Through clever experiments, famed neuroscientist Michael Gazzaniga demonstrated how we instinctively create rational explanations to explain our unconscious behaviors. Gazzaniga worked with patients who had their cerebral hemispheres surgically separated as a treatment for severe epileptic seizures. Surgeons disconnect the side of the brain with (a) circuitry from the side that carries out simple commands.\nThrough ingenious manipulation of experimental conditions, Gazzaniga was able to give a simple command to one part of the brain without the response part (b). He found that by giving the command \"get up and walk\" the patient would do so. But when asked why he was up and where he was going, the subject replied creatively, \"I'm thirsty. I thought I'd get a Coke.\" When one hemisphere of the subject's brain was commanded to laugh, he did. When asked why he was laughing, he responded, \"You guys crack me up,\" not \"Because you told me to. After repeated trials, Gazzaniga concluded that many of our explanations about our behaviors are actually (c) by the behavior itself. He believes that all of us do all sorts of things for reasons outside conscious awareness and that one of the main jobs of consciousness is to keep our lives tied together in an understandable and consistent package. We do this by (d) explanatons that best fit our self-image. We instinctively invent reasons to exlpain our behaviors, but remain (e) that these are creations because they fit seamlessly into a self-sustaining self-image.", + "script": null, + "answer_option": "(1) (a)\\n(2) (b)\\n(3) (c)\\n(4) (d)\\n(5) (e)" + }, + { + "page_number": "138", + "problem_number": "43", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ (A)์— ์ด์–ด์งˆ ๋‚ด์šฉ์„ ์ˆœ์„œ์— ๋งž๊ฒŒ ๋ฐฐ์—ดํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "(A)The most popular and celebrated spectacle at Harbin Polarland is the Beluga whale display, in which the world-famous Mila and Nicola perform with their female trainers. In July 2009, 26-year-old Yang Yun entered a competition to become one of these trainers and was among the seven finalists. She couldn't wait to demonstrate (a) skills and prove she would be the best competitor to work with the two Belugas.\n(B) After being checked over by doctors, Yang Yun was given a clean bill of health, but she knew she was fortunate to have survived the whole experience without any injury. She firmly believed she owed her life to Mila. As the pool was monitored with cameras, the whole rescue was captured on film to document an astonishing example of an animal coming to the aid of (b) The following year, Mila, then nine years old, was honored with the Shining World Hero award for her\n\"swift, life-saving act\" and a cash gift of US $500 for a few extra comforts. (C) She had no idea what had happened, but Mila, the Beluga whale, must have sensed Yang Yun's desperation. (c) had grasped hold of one of the young woman's legs and dragged her to safety even before event organizers realized poor Yang Yun was in distress. They weren't shocked; Mila had worked closely with humans for many years and had developed an understanding and sensitivity towards her trainers. Because Beluga whales have small teeth that are not sharp, Yang Yun's leg was completely unharmed. (D) When it was her turn to free-dive into the Arctic pool without any breathing equipment, Yang Yun quickly plunged (d) into the icy depths but was horrified that she couldn't feel her legs. She had dived too deep, where the water pressure and the freezing temperatures had effectively paralyzed them. She could not swim to the surface and began to sink further down. She felt sure she would die there very soon. But, suddenly, she felt what she called \"an incredible force\" pushing (e) to the surface.", + "script": null, + "answer_option": "'(1) (B)-(D)-(C)\\n(2) (C)-(B)-(D)\\n(3) (C)-(D)-(B)\\n(4) (D)-(B) -(C)\\n(5) (D)-(C)-(B)" + }, + { + "page_number": "138", + "problem_number": "44", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)~(e) ์ค‘์—์„œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€์ƒ์ด ๋‚˜๋จธ์ง€ ๋„ท๊ณผ ๋‹ค๋ฅธ ๊ฒƒ์€?", + "english_content": "(A)The most popular and celebrated spectacle at Harbin Polarland is the Beluga whale display, in which the world-famous Mila and Nicola perform with their female trainers. In July 2009, 26-year-old Yang Yun entered a competition to become one of these trainers and was among the seven finalists. She couldn't wait to demonstrate (a) skills and prove she would be the best competitor to work with the two Belugas.\n(B) After being checked over by doctors, Yang Yun was given a clean bill of health, but she knew she was fortunate to have survived the whole experience without any injury. She firmly believed she owed her life to Mila. As the pool was monitored with cameras, the whole rescue was captured on film to document an astonishing example of an animal coming to the aid of (b) The following year, Mila, then nine years old, was honored with the Shining World Hero award for her\n\"swift, life-saving act\" and a cash gift of US $500 for a few extra comforts. (C) She had no idea what had happened, but Mila, the Beluga whale, must have sensed Yang Yun's desperation. (c) had grasped hold of one of the young woman's legs and dragged her to safety even before event organizers realized poor Yang Yun was in distress. They weren't shocked; Mila had worked closely with humans for many years and had developed an understanding and sensitivity towards her trainers. Because Beluga whales have small teeth that are not sharp, Yang Yun's leg was completely unharmed. (D) When it was her turn to free-dive into the Arctic pool without any breathing equipment, Yang Yun quickly plunged (d) into the icy depths but was horrified that she couldn't feel her legs. She had dived too deep, where the water pressure and the freezing temperatures had effectively paralyzed them. She could not swim to the surface and began to sink further down. She felt sure she would die there very soon. But, suddenly, she felt what she called \"an incredible force\" pushing (e) to the surface.", + "script": null, + "answer_option": "(1) (a)\\n(2) (b)\\n(3) (c)\\n(4) (d)\\n(5) (e)" + }, + { + "page_number": "138", + "problem_number": "45", + "korean_content": "์œ—๊ธ€์— ๊ด€ํ•œ ๋‚ด์šฉ์œผ๋กœ ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "(A)The most popular and celebrated spectacle at Harbin Polarland is the Beluga whale display, in which the world-famous Mila and Nicola perform with their female trainers. In July 2009, 26-year-old Yang Yun entered a competition to become one of these trainers and was among the seven finalists. She couldn't wait to demonstrate (a) skills and prove she would be the best competitor to work with the two Belugas.\n(B) After being checked over by doctors, Yang Yun was given a clean bill of health, but she knew she was fortunate to have survived the whole experience without any injury. She firmly believed she owed her life to Mila. As the pool was monitored with cameras, the whole rescue was captured on film to document an astonishing example of an animal coming to the aid of (b) The following year, Mila, then nine years old, was honored with the Shining World Hero award for her\n\"swift, life-saving act\" and a cash gift of US $500 for a few extra comforts. (C) She had no idea what had happened, but Mila, the Beluga whale, must have sensed Yang Yun's desperation. (c) had grasped hold of one of the young woman's legs and dragged her to safety even before event organizers realized poor Yang Yun was in distress. They weren't shocked; Mila had worked closely with humans for many years and had developed an understanding and sensitivity towards her trainers. Because Beluga whales have small teeth that are not sharp, Yang Yun's leg was completely unharmed. (D) When it was her turn to free-dive into the Arctic pool without any breathing equipment, Yang Yun quickly plunged (d) into the icy depths but was horrified that she couldn't feel her legs. She had dived too deep, where the water pressure and the freezing temperatures had effectively paralyzed them. She could not swim to the surface and began to sink further down. She felt sure she would die there very soon. But, suddenly, she felt what she called \"an incredible force\" pushing (e) to the surface.", + "script": null, + "answer_option": "(1) Yang Yun์€ ์กฐ๋ จ์‚ฌ๋ฅผ ์„ ๋ฐœํ•˜๋Š” ๊ฒฝ์—ฐ ๋Œ€ํšŒ์— ์ฐธ๊ฐ€ํ–ˆ๋‹ค.\\n(2) ์ˆ˜์˜์žฅ์— ์„ค์น˜๋œ ์นด๋ฉ”๋ผ์— ๋ชจ๋“  ๊ตฌ์กฐ ๊ณผ์ •์ด ์ฐํ˜”๋‹ค.\\n(3) Mila๋Š” ์ƒ๋ช…์„ ๊ตฌํ•œ ํ–‰์œ„๋กœ ์ƒ๊ณผ ์ƒ๊ธˆ์„ ๋ฐ›์žˆ๋‹ค.\\n(4) ํ–‰์‚ฌ ์ฃผ์ตœ์ž๋“ค์€ Mila๊ฐ€ ํ•œ ์ผ์— ๋ชน์‹œ ๋†€๋ž๋‹ค.\\n(5) ๋ฌผ์†์— ๋“ค์–ด๊ฐ”์„ ๋•Œ Yang Yun์˜ ๋‹ค๋ฆฌ๊ฐ€ ๋งˆ๋น„๋˜์—ˆ๋‹ค." + }, + { + "page_number": "139", + "problem_number": "04", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ๊ทธ๋ฆผ์—์„œ ๋Œ€ํ™”์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Oh, Elizabeth. What's that flyer about?\nW: Remember when I told you I was opening a bakery? Well, this is an ad for my grand opening next week.\nM: That's fantastic! Let me see. [Pause] In the upper middle, I see a picture of you holding a baguette. It looks great!\nW: Thanks. What do you think about the phrase in the upper right of the picture?\nM: 'TRY IT, LOVE IT'? I like it!\nW: Great to hear! I thought for a long time about what to say.\nM: What's the heart-shaped bread in the circle? It looks delicious.\nW: That's Beth's Bread, my bakery's signature bread. Do you have any suggestions for the flyer?\nM: Adding a map would help people find your bakery. There's a contact number on the bottom left, but that might not be enough.\nW: Good idea! Thanks!\nM: Is Sugary Bakery, on the bottom right, the name of the bakery?\nW: That's right! What do you think of that?\nM: I like the bakery name, but how about moving it up a bit? Positioning the name more prominently would help people notice it.\nW: Oh, that's good advice!\nM: I'm looking forward to visiting your bakery!" + }, + { + "page_number": "139", + "problem_number": "01", + "korean_content": "๋‹ค์Œ์„ ๋“ฃ๊ณ  ์—ฌ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: Good evening, AMD residents. This is the building management office with an important announcement. In our surface parking lot, there are spaces marked with yellow lines. These spaces are reserved for ambulances and fire trucks in case of emergencies. According to the law, buildings with a certain number of residents must keep these reserved spaces clear. Unfortunately, it's common to see cars parked in these spots. Parking in these areas is illegal unless there is an emergency, and you will be fined for doing so. We ask all residents to refrain from parking in these spaces so we can always be prepared for any emergency that may occur. Thank you for your cooperation.", + "answer_option": "(1) ํŠน์ • ๊ตฌ์—ญ์— ์ผ๋ฐ˜ ์ฐจ๋Ÿ‰ ์ฃผ์ฐจ ๊ธˆ์ง€๋ฅผ ๋‹น๋ถ€ํ•˜๋ ค๊ณ \\n(2) ์ฃผ์ฐจ์žฅ ๊ณต์‚ฌ ๋™์•ˆ ์ฃผ์ฐจ ์žฅ์†Œ ๋ณ€๊ฒฝ์„ ๊ณต์ง€ํ•˜๋ ค๊ณ \\n(3) ๊ฑด๋ฌผ ๊ทผ์ฒ˜ ์‹ ํ˜ธ์™€ ์ฐจ๋Ÿ‰ ์†๋„ ์ค€์ˆ˜๋ฅผ ์š”์ฒญํ•˜๋ ค๊ณ \\n(4) ๋น„์ƒ ๋ชจ์˜ ํ›ˆ๋ จ ์ผ์ •๊ณผ ๋Œ€ํ”ผ ๊ฒฝ๋กœ๋ฅผ ์•ˆ๋‚ดํ•˜๋ ค๊ณ \\n(5) ๊ฑด๋ฌผ ์•ˆ์—์„œ ์ผ์–ด๋‚œ ์‘๊ธ‰ ์ƒํ™ฉ์— ๊ด€ํ•ด ์„ค๋ช…ํ•˜๋ ค๊ณ " + }, + { + "page_number": "139", + "problem_number": "02", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ๋‚จ์ž์˜ ์˜๊ฒฌ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์˜ฌ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: Ted, I've been thinking about cover ideas for our new book and I've come up with eight.\nM: Oh, great! Let's meet in the conference room to narrow them down.\nW: Okay, I'll let the team know.\nM: Oh, not the whole team; just you, Janice, and me.\nW: Just the three of us? Wouldn't it be better to get everyone's input?\nM: It would take too long to discuss eight options with everyone.\nW: Eight options are quite a lot, right?\nM: Yeah. Too many options will discourage the team from having in-depth discussions.\nW: I see. So how many should we narrow it down to for efficiency?\nM: How about three? We'll base it on cost, the author's preference, and how well it fits the story.\nW: Okay. That sounds manageable for the team to discuss in detail.\nM: Right. It'll make our decision-making process more efficient and persuasive.", + "answer_option": "(1) ๋‹ค์ˆ˜๊ฒฐ๋กœ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ํ•ญ์ƒ ์˜ณ์€ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค\\n(2) ํšจ๊ณผ์ ์ธ ์˜์‚ฌ ๊ฒฐ์ •์„ ์œ„ํ•ด ์„ ํƒ์•ˆ์„ ์ขํ˜€์•ผ ํ•œ๋‹ค.\\n(3) ํš๊ธฐ์ ์ด๊ณ  ์ฐฝ์˜์ ์ธ ์•„์ด๋””์–ด๋Š” ์šฐ์—ฐํ•œ ๊ธฐํšŒ์— ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.\\n(4) ์˜ค๋žœ ์‹œ๊ฐ„์˜ ํ† ๋ก ๊ณผ ๊ณ ๋ฏผ์ด ์žˆ์–ด์•ผ ์ข‹์€ ๊ฒฐ์ •์„ ๋‚ด๋ฆด ์ˆ˜ ์žˆ๋‹ค.\\n(5) ํšŒ์˜์—์„œ ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์ด ์ž์œ ๋กญ๊ฒŒ ์˜๊ฒฌ์„ ์ œ์‹œํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค." + }, + { + "page_number": "139", + "problem_number": "05", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ์—ฌ์ž๊ฐ€ ํ•  ์ผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "[Cell phone rings.]\nM: Honey, did you check out the camping site link I sent? W: Yeah, I saw it. The site looks great!\nM: It was renovated last year, so it's really clean and spacious.\nW: I saw the comments, too. They're all positive.\nM: My friend went there last week and highly recommended it.\nW: Our daughter Judy would love that. By the way, have you checked the weather for this Saturday, the day we're planning to go camping?\nM: No, I haven't. Have you?\nW: Yeah. Unfortunately, it's supposed to rain all day. Plus, it'll be a little too chilly for outdoor activities.\nM: Oh, really? Camping in the cold and rain isn't a good idea. Judy might catch a cold. How about canceling our plans?\nW: Alright. Let's go camping next weekend.\nM: Sounds good. Then, what should we do this weekend?\nW: Judy mentioned that, Lucy's Adventure, the animated movie she's been talking about a lot recently, is coming out this weekend.\nM: Oh, then let's see the movie instead of camping. Can you book tickets?\nW: No problem. She will love it!", + "answer_option": "(1) ์˜ํ™” ์˜ˆ๋งคํ•˜๊ธฐ\\n(2) ์นœ๊ตฌ์—๊ฒŒ ์—ฐ๋ฝํ•˜๊ธฐ\\n(3) ์บ ํ•‘ ์žฅ์†Œ ์˜ˆ์•ฝํ•˜๊ธฐ\\n(4) ์บ ํ•‘ ๋ฌผํ’ˆ ์ค€๋น„ํ•˜๊ธฐ\\n(5) ์บ ํ•‘ ์˜ˆ์•ฝ ์ทจ์†Œํ•˜๊ธฐ" + }, + { + "page_number": "139", + "problem_number": "03", + "korean_content": "๋‹ค์Œ์„ ๋“ฃ๊ณ , ๋‚จ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Hello, students. I'm Howard Stone, and I'm here to talk about building healthy relationships. Throughout your life, you'll have many relationships because humans are social beings. However, maintaining healthy relationships can be challenging. One big reason is the difficulty in saying 'no' to favors. You're occasionally asked to do things you'd rather not do. It's important to say 'no' when necessary. Doing so isn't about being rude; it's about ensuring that your own needs are also considered. When you say 'no' to uncomfortable favors, people will start to respect your position, think twice before making requests, and be more willing to listen to your opinions. This will have a positive impact on your relationships. Give it a try, and you'll notice a meaningful change in your relationships.", + "answer_option": "(1) ์ƒ๋Œ€๋ฐฉ์—๊ฒŒ ๋ถ€ํƒํ•  ๋•Œ๋Š” ์ž์„ธํ•˜๊ณ  ๋ช…ํ™•ํ• ์ˆ˜๋ก ์ข‹๋‹ค.\\n(2) ์ƒํ˜ธ ๊ฐ„์— ๋‹ค์–‘ํ•œ ์ทจ๋ฏธํ‹€ ๊ณต์œ ํ•˜๋ฉด ์œ ๋Œ€๊ฐ์ด ๊ฐ•ํ•ด์ง„๋‹ค.\\n(3) ์ง€์†์ ์ธ ์—ฐ๋ฝ์€ ๊ฑด๊ฐ•ํ•œ ๊ด€๊ณ„๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค.\\n(4) ๋Œ€์ธ ๊ด€๊ณ„๋ฅผ ์ž˜ ํ˜•์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๋จผ์ € ์นœ๋ฐ€๊ฐ์„ ์Œ“๋Š” ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค\\n(5) ํ•„์š”์‹œ ๋ถ€ํƒ์„ ๊ฑฐ์ ˆํ•  ์ค„ ์•„๋Š” ๊ฒƒ์€ ๊ฑด๊ฐ•ํ•œ ๊ด€๊ณ„ ํ˜•์„ฑ์— ์ค‘์š”ํ•˜๋‹ค." + }, + { + "page_number": "140", + "problem_number": "09", + "korean_content": "Run for Hope์— ๊ด€ํ•œ ๋‹ค์Œ ๋‚ด์šฉ์„ ๋“ฃ๊ณ  ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Hello, everyone! Would you like to join a great event that promotes health and supports a good cause? Then, join us for Run for Hope. This event takes place in Central Park at 9 a.m. on October 1st. The goal is to raise funds for children with cancer. The registration fee is $5 per person, and all proceeds will be donated to the Children's Medical Support Organization. You can only register online through our website. Choose from three courses: a half marathon, a 10 km race, and a 5 km race, depending on your physical ability. Due to the expected high attendance, parking for individual cars is not permitted. Please use public transportation and arrive early. We hope you'll join us for this meaningful event. Thank you.", + "answer_option": "(1) ์–ด๋ฆฐ์ด ์•” ํ™˜์ž๋ฅผ ์œ„ํ•œ ๊ธฐ๊ธˆ ๋งˆ๋ จ์ด ๋ชฉ์ ์ด๋‹ค.\\n(2) ๋“ฑ๋ก๋น„๋Š” 1์ธ๋‹น 5๋‹ฌ๋Ÿฌ์ด๋‹ค.\\n(3) ์˜จ๋ผ์ธ์œผ๋กœ๋งŒ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค.\\n(4) ์„ธ ๊ฐœ์˜ ์ฝ”์Šค ์ค‘์—์„œ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค .\\n(5) ๊ฐœ์ธ ์ฐจ๋Ÿ‰์„ ์œ„ํ•œ ์ฃผ์ฐจ ๊ณต๊ฐ„์ด ๋งˆ๋ จ๋˜์–ด ์žˆ๋‹ค." + }, + { + "page_number": "140", + "problem_number": "06", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ๋‚จ์ž๊ฐ€ ์ง€๋ถˆํ•  ๊ธˆ์•ก์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: Welcome to Downtown Souvernirs! Can I help you find something?\nM: Hello. Sure. I'm interested in Sydney T-shirts.\nW: Come right over here. We have various designs with symbols of Sydney. They're all $20 each.\nM: I like this one with the Sydney Opera House.\nW: Well, right now, if you buy one T-shirt, you get one free.\nM: What a great deal! Actually, I'm looking for gifts for my friends. I need four T-shirts.\nW: In that case, if you pay for two T-shirts, you'll get four in total.\nM: Perfect. I'll do that. And can you give me another souvenir suggestion?\nW: How about keychains? They're popular and practical.\nM: Sounds good. What symbols are on the keychains?\nW: We have koalas, the Harbour Bridge, and more. How many would you like?\nM: I'll take eight, with a variety of symbols. How much are they?\nW: They're usually five dollars each, but right now they're for sale for three dollars each.\nM: Perfect timing! I'll take both the T-shirts and the keychains.", + "answer_option": "(1)$34\\n(2)$45\\n(3)$54\\n(4)$60\\n(5)$64" + }, + { + "page_number": "140", + "problem_number": "07", + "korean_content": "๋Œ€ํ™”ํ‹€ ๋“ฃ๊ณ  ์—ฌ์ž๊ฐ€ ๋ฎค์ง€์ปฌ ๊ณต์—ฐ์„ ๋‹ค์Œ ์ฃผ๋ง๋กœ ์˜ˆ์•ฝํ•œ ์ด์œ ๋ฅผ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Scarlett, did you know that the musical A Journey to Freedom is playing right now?\nW: Yeah.\nM: That's the one you've been looking forward to seeing.\nW: Exactly. My favorite performer, Michael Jonson, is starring in it.\nM: You always say he's your favorite.\nW: Have you ever seen him perform? He's so amazing!\nM: You're so into him. I guess you already got a ticket.\nW: Yeah, I booked a ticket for next weekend.\nM: Why not this weekend?\nW: I saw on the ticketing website that Michael has the flu and won't be performing this weekend.\nM: That's too bad.\nW: But he'll be back next week, so I got a ticket for next weekend. If you want to go, I can check for available seats.\nM: Really? That would be great.\nW: No problem.", + "answer_option": "(1) ๋‹ค์Œ ์ฃผ์— ์‹œ๊ฐ„์  ์—ฌ์œ ๊ฐ€ ์žˆ์–ด์„œ\\n(2) ์ข‹์•„ํ•˜๋Š” ๋ฐฐ์šฐ๊ฐ€ ๋‹ค์Œ ์ฃผ์— ์ถœ์—ฐํ•ด์„œ\\n(3) ๋‹ค์Œ ์ฃผ๋ง ๊ณต์—ฐ์— ํŠน๋ณ„ ํ• ์ธ์ด ์ ์šฉ๋ผ์„œ\\n(4) ๋‹ค์Œ ์ฃผ๋ง ๊ณต์—ฐ์— ์ข‹์€ ์ขŒ์„์ด ๋‚จ์•„ ์žˆ์–ด์„œ\\n(5) ์นœ๊ตฌ์™€ ๋‹ค์Œ ์ฃผ๋ง์— ๊ณต์—ฐ์„ ๋ณด๊ธฐ๋กœ ์•ฝ์†ํ•ด์„œ" + }, + { + "page_number": "140", + "problem_number": "10", + "korean_content": "๋‹ค์Œ ํ‘œ๋ฅผ ๋ณด๋ฉด์„œ ๋Œ€ํ™”ํ‹€ ๋“ฃ๊ณ  ๋‚จ์ž๊ฐ€ ์ฃผ๋ฌธํ•  LED ๋ฌด๋“œ ์กฐ๋ช…์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Honey, we need mood lighting for Lily since she's afraid of sleeping in the dark. Which LED mood lighting model is best for her room? There are five options.\n\nW: Well, for the color range, the more colors, the better for her room.\nM: Okay, then let's rule out this model with only two colors. And they all come with a remote and an extra way to control them.\nW: How about this one with a smartphone app option?\nM: I think voice control would be better since Lily doesn't have a smartphone yet.\nW: Oh, that's a good point.\nM: So, it's down to these three models. Do you think a battery-powered source is better?\nW: Batteries run out and need to be replaced. I think USB is better.\nM: Alright, then it comes down to these two.\nW: What's the difference between them?\nM: The angle of the light is different. The narrower the angle, the more focused the light is.\nW: Since it's for her bedroom, I think a wider angle would be better.\nM: I agree. I'll order this one.\nW: She'll love sleeping under the mood lighting.", + "answer_option": "(1) Model: A, Coloar Range: Red, Green, Blue, Control Option: Voice, Power Source: USB, Light Angle: 120 degrees\\n(2) Model: B, Coloar Range: Red, Green, Blue, Control Option: Voice, Power Source: USB, Light Angle: 30 degrees\\n(3) Model: C, Coloar Range: Red, Green, Blue, Control Option: Voice, Power Source: Battery, Light Angle: 30 degrees\\n(4) Model: D, Coloar Range: Red, Green, Blue, Control Option: Smartphone App, Power Source: USB, Light Angle: 120 degrees\\n(5) Model: E, Coloar Range: Red, Green, Control Option: Smartphone App, Power Source: Battery, Light Angle: 30 degrees\\n" + }, + { + "page_number": "140", + "problem_number": "08", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  special lecture์— ๊ด€ํ•ด ์–ธ๊ธ‰๋˜์ง€ ์•Š์€ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Amy, have you heard about the special lecture scheduled after our final exam?\nW: No. What's it about?\nM: A renowned lecturer is visiting our college to give a talk on how to enjoy life.\nW: Sounds interesting. Everyone would want to hear that. Who's the lecturer?\nM: It's William Blake from Ireland.\nW: Oh, I've read some of his books. I don't want to miss his lecture. So, when is it exactly?\nM: November 28th. I think it's a Friday. Are you free that day?\nW: Yes. Can anyone attend the lecture?\nM: Yeah, but you need to sign up in advance because there's limited seating.\nW: How do I sign up?\nM: Go to our school website and click on the post about the lecture. Then, fill in your name and student number, and submit it.\nW: Is it first come, first served?\nM: Yeah. And after the lecture, there will be a photo session and a signing event.\nW: Thanks for the information! I'll sign up right away.", + "answer_option": "(1) ์ฃผ์ œ\\n(2) ๊ฐ•์—ฐ์ž\\n(3) ์‹ ์ฒญ ๋ฐฉ๋ฒ•\\n(4) ๊ฐ•์—ฐ ํ›„ ํ–‰์‚ฌ\\n(5) ์ฐธ๊ฐ€๋น„" + }, + { + "page_number": "141", + "problem_number": "14", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ์—ฌ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "Man:", + "script": "W: Hey, Peter. What are you looking at?\nM: Hi, Kate. Check out this poster! Our school is having an Al art competition.\nW: An AI art competition? What's that?\nM: It means we use AI tools or programs to create artwork instead of traditional methods like using pencils and paints.\nW: Really? I thought you had to be good at drawing to enter an art competition.\nM: Not for this one! You just need creative ideas that fit the theme.\nW: That sounds fun. I've always been interested in art, but I've never thought of entering an art competition because I'm not good at drawing.\nM: Then, this is perfect for you. Also, I know you're great with computer programs.\nW: You're right. What's the theme this year?\nM: The theme is 'Our Dreams Drawn Through AI.'\nW: Oh, I've always wanted to be an astronaut. Maybe I can ask AI to draw me traveling to unknown planets.\nM: Great idea! I'm sure you'll create an amazing piece of art.", + "answer_option": "(1) I'm not sure. I'll go and ask what this year's theme is. \\n (2) That's awesome! I always knew you'd win a prize in the competition. \\n(3) I agree. I wonder why we can't use AI tools in the competition. \\n(4) Right! Sometimes all you need is a pencil to create a beautiful drawing. \\n(5) Great idea! I'm sure you'll create an amazing piece of art." + }, + { + "page_number": "141", + "problem_number": "11", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "M: Honey, Andrew is having trouble understanding his physics class.\nW: I don't understand physics, either. How can we help him?\nM: Yesterday, I stopped by a bookstore and found some books that explain physics concepts through interesting stories. They seemed perfect for Andrew.\nW: That might help! Let's go buy some right away.", + "answer_option": "(1) That might help! Let' s go buy some right away.\\n(2) Don't worry so much. He's doing great in physics.\\n(3) I agree with you. He seemed interested in physics.\\n(4) You're right. Let's do a science experiment with him\\n(5) Which book do you think looks interesting? Choose one." + }, + { + "page_number": "141", + "problem_number": "12", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ  ์—ฌ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: The bus is coming. Ready to get on?\nM: It looks really crowded. It takes 30 minutes to get to the museum, and I'd like to sit comfortably.\nW: We have plenty of time until the museum opens, so we don't need to hurry.\nM: Then, let's wait for the next bus. We might get seats.", + "answer_option": "(1) Yes. It'Il take more time because of the traffic jam. \\n(2) Then, let's wait for the next bus. We might get seats .\\n(3) I'm sorry but I don't really like the exhibits in this museum. \\n(4) If so, let' s take a taxi. The museum is going to close soon.\\n (5) Sure. I've studied a lot about the exhibitions in the museum." + }, + { + "page_number": "141", + "problem_number": "15", + "korean_content": "๋‹ค์Œ ์ƒํ™ฉ ์„ค๋ช…์˜ฌ ๋“ฃ๊ณ  Sarah๊ฐ€ ๊ต์žฅ ์„ ์ƒ๋‹˜์—๊ฒŒ ํ•  ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "Sarah:", + "script": "M: Sarah is the student president of Mayfield High School. Lately, she and her fellow students have been busy preparing for the upcoming school festival. This year, the school decided to hold a talent show for the first time, and many students are excited about it. During a student council meeting, Sarah noticed that many students preferred the festival to begin in the afternoon. An afternoon start would allow students from other schools to visit after their own classes, ensuring a larger audience for the talent show. It would also allow students to have more time to prepare their booths with various activities for visitors to enjoy, such as games and crafts. So, Sarah wants to suggest to the principal that the school schedule the festival to start in the afternoon. In this situation, what would Sarah most likely say to the principal?\nSarah: ", + "answer_option": "(1) Could we encourage students to set up more booths?\\n(2) Would it be possible to start the festival in the afternoon?\\n(3) Will it be all right to visit another school' s festival after the class?\\n(4) Would you consider including a talent show in this year's festival?\\n(5) Can you join our student council meeting and give us some advice?" + }, + { + "page_number": "141", + "problem_number": "13", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "Woman:", + "script": "M: Abigail, you've been really busy these days.\nW: I know. I've been so busy that I haven't had time to work out.\nM: Then why not work out at home?\nW: How can I do that?\nM: Just turn on a fitness video and follow the instructor. My wife and I work out at home every evening for 15 minutes.\nW: That's awesome! Can you send me the link to the video?\nM: No problem. I'll send it to you right away.\nw: Thanks a lot! I'll start working out from home today. M: Just by doing it 15 minutes a day, you'll feel fitter and stronger.\nW: I love the idea of working out from home.\nM: Me too. It's great for busy people like us. W: Do I need any equipment?\nM: Just a mat. If you want, I can send you a link to buy one.\nW: That's okay. I bought one when I was doing yoga last year.", + "answer_option": "(1) Right. I'll have to register at the fitness clube. \\n(2) Nope. That workout is too hard for me to follow. \\n(3) Thanks a million! I'll make good use of your mat. \\n(4) That's okay. I bought one when I was doing yoga last year. \\n(5) Wow. I think I'm actually building muscle after working out." + }, + { + "page_number": "142", + "problem_number": "18", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Dear Mr. Davis\nI am Rachel Winslow, and I am the new project manager at Woodline Construction. I am writing to request an update on the latest Lakefront Build project. As we move forward with the design, my team would like to see the latest drawings before we schedule a financing meeting. Once we have them, we can begin discussing a timeline and budget options. At Woodline, we have successfully completed over 50 builds in the area, and we would love the opportunity to bring your design to life. If you could please send me the latest drawings at your earliest convenience, we can begin discussing the remaining details. Thank you for your time and consideration. I look forward to hearing from you.\nSincerely, en Juods\nRachel Winslow", + "script": null, + "answer_option": "(1) ์„ค๊ณ„ ํšŒ์˜ ์ผ์ •์„ ์—ฐ๊ธฐํ•˜๋ ค๊ณ  \n (2) ๊ฑด์„ค ๋„๋ฉด์˜ ์ˆ˜์ •์„ ๊ถŒ๊ณ ํ•˜๋ ค๊ณ \n(3) ํ”„๋กœ์ ํŠธ์˜ ์ตœ์‹  ๋„๋ฉด์„ ์š”์ฒญํ•˜๋ ค๊ณ \n(4) ์‹œ๊ณต ํšŒ์‚ฌ๋กœ ์„ ์ •๋œ ๊ฒƒ์˜ฌ ํ†ต๋ณดํ•˜๋ ค๊ณ \n(5) ๊ฑด์ถ• ๋””์ž์ธ ๊ณต๋ชจ์ „ ์ถœํ’ˆ์„ ๋…๋ คํ•˜๋ ค๊ณ " + }, + { + "page_number": "142", + "problem_number": "16", + "korean_content": "๋‚จ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": null, + "script": "M: Welcome back, class! We usually think of building materials as standard items like bricks and concrete. But when you travel the world, you may come across some unexpected building materials. In China, sticky rice is a significant building material. When ground into a paste, sticky rice acts like concrete. Sticky rice has been used in both modern construction and ancient structures, such as the Great Wall of China. In India, you can relax in a salt cave spa, made entirely of rock salt. Rock salt has been used as a building material for centuries as it is both safe and fire-resistant. In Norway, companies have started converting newspaper into \"wood.\" This special wood is then rolled into extremely tight logs and cut into boards. In the coldest parts of the world, ice has been traditionally used to create igloos that last through the winter. Surprisingly, it can actually feel warm inside an ice igloo! Now, let's look at some pictures of buildings that use these materials.", + "answer_option": "(1) unusual building materials around the world\\n(2) countries that encourage eco-friendly materials\\n(3) popular construction materials used in the past\\n(4) ways people survive extreme weather across the globe\\n(5) new technologies used in energy-efficient building designs" + }, + { + "page_number": "142", + "problem_number": "17", + "korean_content": "์–ธ๊ธ‰๋œ ์ž์žฌ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์€?", + "english_content": null, + "script": "M: Welcome back, class! We usually think of building materials as standard items like bricks and concrete. But when you travel the world, you may come across some unexpected building materials. In China, sticky rice is a significant building material. When ground into a paste, sticky rice acts like concrete. Sticky rice has been used in both modern construction and ancient structures, such as the Great Wall of China. In India, you can relax in a salt cave spa, made entirely of rock salt. Rock salt has been used as a building material for centuries as it is both safe and fire-resistant. In Norway, companies have started converting newspaper into \"wood.\" This special wood is then rolled into extremely tight logs and cut into boards. In the coldest parts of the world, ice has been traditionally used to create igloos that last through the winter. Surprisingly, it can actually feel warm inside an ice igloo! Now, let's look at some pictures of buildings that use these materials.", + "answer_option": "(1) sticky rice\\n(2) rock salt\\n(3) corn\\n(4) newspaper\\n(5) ice" + }, + { + "page_number": "143", + "problem_number": "19", + "korean_content": "๋‹ค์Œ ๊ธ€์— ๋“œ๋Ÿฌ๋‚œ Nathan์˜ ์‹ฌ๊ฒฝ ๋ณ€ํ™”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "โ€œI should be in Miami in five hours,โ€ Nathan said to himself as he settled back comfortably in his seat, stretching his legs. A broad smile spread across his face, and he watched the outside through the windows. Nathan was enjoying the scenery as the big bus rolled down the highway and cruised through the small towns on that hot summer day. โ€œWhatโ€™s going on?โ€ Nathan said to himself as the bus slowed down and came to a complete stop on a remote part of the highway. The bus door opened, and the strangest man Nathan had ever seen boarded the bus. His long jet-black hair and a two-inch scar on his left cheek drew everyoneโ€™s attention. Without a word, the stranger sat next to Nathan, even though there were plenty of empty seats. Nathanโ€™s heart pounded as the man turned and fixed him with an intense stare, his scarred face mere inches away.", + "script": null, + "answer_option": "(1) bored โ†’ guilty\\n(2) relaxed โ†’ scared\\n(3) touched โ†’ ashamed\\n(4) confused โ†’ disappointed\\n(5) indifferent โ†’ sympathetic" + + }, + { + "page_number": "143", + "problem_number": "20", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ํ•„์ž๊ฐ€ ์ฃผ์žฅํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "A crucial factor in consumer behaviour regarding health claims (and nutritional information in general) is that their effect critically depends on the attention that such information attracts. This is increasingly challenging in information-rich environments and when consumers have limited attentional resources. As attention processes are essential it is crucial to \"guide\" consumers' attention to healthfulness at the moment of choice. This can be achieved by stimulating consumers' health goal accessibility through, other than product- or packaging-related, communication at the point of purchase. Point-of-sale nutrition and health campaigns may activate consumers' health goal accessibility, thus drawing attention more easily to the search for health-related information on packaging. Alternatively, and complementarily, attention can be enhanced if health information \"stands out\" compared to other competing information on packaging. This can be achieved by making health information highly salient (i.e., visible on packaging), and/or by communicating it in terms of visuals rather than text, as these appear to more easily attract attention, especially in information-rich contexts.", + "script": null, + "answer_option": "'(1) ์ œํ’ˆ ๋น„๊ต๊ฐ€ ์‰ฝ๋„๋ก ์‹ํ’ˆ ์˜์–‘ ์ •๋ณด์˜ ๋‹จ์œ„๋ฅผ ๋‹จ์ผํ™”ํ•ด์•ผ ํ•œ๋‹ค\\n(2) ๊ฑด๊ฐ•์‹ํ’ˆ ํ—ˆ์œ„, ๊ณผ๋Œ€ ํ‘œ์‹œ ๋ฐ ๊ด‘๊ณ ์— ๋Œ€ํ•œ ์ฒ˜๋ฒŒ์„ ๊ฐ•ํ™”ํ•ด์•ผํ•œ๋‹ค.\\n(3) ๊ฑด๊ฐ•๊ณผ ๊ด€๋ จ๋œ ์ž˜๋ชป๋œ ์ƒ์‹์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•œ ์บ ํŽ˜์ธ์„ ํ•ด์•ผํ•œ๋‹ค\\n(4) ์ œํ’ˆ ๊ตฌ๋งค ์‹œ์ ์— ์†Œ๋น„์ž๊ฐ€ ๊ฑด๊ฐ• ์ •๋ณด์— ์ฃผ๋ชฉํ•˜๋„๋ก ์œ ๋„ํ•ด์•ผํ•œ๋‹ค.\\n(5) ์†Œ๋น„์ž์˜ ์•Œ ๊ถŒ๋ฆฌ๋ฅผ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด ์ œํ’ˆ ์ œ์กฐ ๊ณผ์ •์„ ๊ณต๊ฐœํ•ด์•ผํ•œ๋‹ค." + }, + { + "page_number": "144", + "problem_number": "22", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "For some, it's tempting to behave in a certain way for an audience, and effectively signal virtues that play well, because they reinforce a certain profile. Influencers have a role to play in our world today in terms of showcasing lifestyles or brands, but often it's an act, and financial motivation dressed up as real life. There's nothing wrong with liking or admiring anyone for the way that they present themselves to the world, but it does risk inviting unrealistic expectations among those who look up to them. We often see this across social media platforms which, let's not forget, are a showreel of people's best moments. Ultimately, we can't know what people in the public eye are really like in private, which is why the best role models are those who we trust embody our core values and/or people we know and love.", + "script": null, + "answer_option": "(1) ์ง„์ •์„ฑ ํ™•์ธ์ด ์–ด๋ ค์šด ์†Œ์„ค ๋ฏธ๋””์–ด ์† ์ธํ”Œ๋ฃจ์–ธ์„œ๋Š” ๋ณธ๋ณด๊ธฐ๋กœ ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.\\n(2) ๋ถ€์ •์ ์ธ ๋‚ด์šฉ์˜ ๊ด‘๊ณ ์ธ ๊ฒฝ์šฐ ์‹ค์กด ์ธ๋ฌผ๋ณด๋‹ค๋Š” ๊ฐ€์ƒ์˜ ์ธ๋ฌผ์ด ๋” ์ ํ•ฉํ•˜๋‹ค.\\n(3) ์†Œ์…œ ๋ฏธ๋””์–ด ์† ์ธํ”Œ๋ฃจ์–ธ์„œ๋“ค์€ ์ž์‹ ์˜ ์–ธํ–‰์— ์ฑ…์ž„์„ ์ง€๋Š” ํƒœ๋„๊ฐ€ ํ•„์š”ํ•˜๋‹ค.\\n(4) ๊ฐ„์ ‘ ๊ด‘๊ณ  ์‹œ ๊ด‘๊ณ  ์—ฌ๋ถ€๋ฅผ ํ‘œ๊ธฐํ•˜์ง€ ์•Š์œผ๋ฉด ์‹œ์ฒญ์ž์˜ ์‹ ๋ขฐ๋ฅผ ์žƒ์„ ์ˆ˜ ์žˆ๋‹ค.\\n(5) ์‹œ์ฒญ์ž์˜ ๋งˆ์Œ์„ ์‚ฌ๋กœ์žก๊ธฐ ์œ„ํ•ด ์˜์ƒ ๊ธฐํš ๋ฐ ํŽธ์ง‘์— ๋งŽ์€ ์‹œ๊ฐ„์˜ ํ• ์• ๊ฐ€ ํ•„์š”ํ•˜๋‹ค." + }, + { + "page_number": "144", + "problem_number": "21", + "korean_content": "๋ฐ‘์ค„ ์นœ ๊ฐ€ ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "One of the most remarkableโ€”yet underratedโ€”feats of human imagination is what's known as willing suspension of disbelief. We spend our lives trying to separate what's real from what is imaginary or illusory. It's a survival technique. Yet when we enter a theatre or a cinema, or even when we turn on a television or a radio, or log on to a website, we \n\n ๋ฐ€์ค„: . \n\n We will ourselves to ignore the curtains, ignore the fact that we're in a dark and crowded room with a sticky floor, ignore the fact that we're looking at shadows coming from a little box, ignore the fact that the people we see are actors pretending to be people they aren'tโ€”saying words written by someone else, and having adventures with special effects that were manufactured in a computer. Instead, we allow ourselves to enter the world of the show, to believe for a little while that we're flying through space, or riding the Hogwarts Express, or witnessing a furious battle, or watching real people falling in love. The distractions of reality become invisible and for the duration of the show, we believe.", + "script": null, + "answer_option": "(1) grasp the main idea of the story\\n(2) assess the content as true or false\\n(3) explore new ideas and perspectives\\n(4) immerse ourselves in fiction as ifit' s real\\n(5) anticipate what will happen nextin the story" + }, + { + "page_number": "145", + "problem_number": "23", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Theories are all about interpreting data and hence the most frequent subject of disputes in science. It can be hard not to develop some degree of emotional attachment to a theory one has proposed. It is always nice to have colleagues debating your ideas, certainly if they subsequently crystallize in what can be considered a real theory. So, when ongoing investigations show that your theory is not the perfect explanation of nature it may be hard to swallow. The opposite also happens. Some scientists have championed their favorite theory with such passion that they were considered preposterous by their peers and barely taken seriously, even though in the end some of them turned out to have been right all along. This once more emphasizes the importance of keeping scientific debates impersonal and focused on the content only. Even if you are fully convinced that you are right and the other side is wrong, one should always remain polite and \"May I suggest an alternative explanation?\" is far more effective in getting a message across than \"Let me explain to you how it really works.\"", + "script": null, + "answer_option": "(1) scientific theorization on the impacts of emotional bonds\\n(2) the impact of methodological biases in data interpretation\\n(3) practical procedures in theory development through debates\\n(4) the importance of keeping emotions out of scientific debates\\n(5) challenges faced when scientific theories are criticized by peers" + }, + { + "page_number": "145", + "problem_number": "24", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Generation is one type of identity categorization that is often overlooked in research about diversity, difference, and communication across cultures. Yet, diverse generations have their own shared system of norms and values for the ways they communicate and interact within the world, thus creating unique cultural systems. Recent research has shown that there are significant differences between the ways that Generation Z conceptualizes good listening and the ways that older generations conceive what \"listening\" means and how it should be enacted. For example, Generation Z is more likely to conceptualize listening as evaluative-involving communicative activities such as being critical, arguing, conceding, and answering-as compared to older generations, and Generation Z and Generation X appear to have the most saliently (and statistically) different conceptualizations of what good listening entails. In other words, how a particular generational cohort expects to listen relationally may differ from another generation's values. This can have real-world implications for instructional spaces when assumptions about whether and how a person is listening are made from specific individual standpoints, social positions, and power structures.", + "script": null, + "answer_option": "(1) Do We Truly Hear or Simply Pretend to Listen?\\n(2) How Good Listening Differs Across Generations\\n(3) What Generation Z Values During Conversations\\n(4) Listening Well: The Art of Intergenerational Dialogue\\n(5) The Invisible Thread: Miscommunication Between Generations" + }, + { + "page_number": "146", + "problem_number": "26", + "korean_content": "Mary Edwards Walker์— ๊ด€ํ•œ ๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "Mary Edwards Walker was born in New York in 1832. She graduated from Syracuse Medical College in 1855 and started a medical practice. She served as a surgeon at a temporary hospital in Washington, D.C. at the outbreak of the American Civil War and later became the first female surgeon in the US Army. She wore men's clothing during her work, claiming it to be easier for the high demands of her work. She crossed enemy lines to treat wounded civilians and was arrested as a spy. She was sent as a prisoner of war to Virginia until released in a prisoner exchange. After the war, she received the Medal of Honor for her efforts during the Civil War. She later became a writer and lecturer supporting the women's suffrage movement until her death in 1919.", + "script": null, + "answer_option": "(1) 1855๋…„์— Syracuse ์˜๊ณผ ๋Œ€ํ•™์„ ์กธ์—…ํ–ˆ๋‹ค.\\n(2) ๋ฏธ๊ตญ ์œก๊ตฐ ์ตœ์ดˆ์˜ ์—ฌ์„ฑ ์™ธ๊ณผ ์˜์‚ฌ๊ฐ€ ๋˜์—ˆ๋‹ค.\\n(3) ์ผํ•  ๋•Œ ํŽธํ•˜๋‹ค๋Š” ์ด์œ ๋กœ ๋‚จ์„ฑ๋ณต์„ ์ž…์—ˆ๋‹ค.\\n(4) ์ „์Ÿ ํฌ๋กœ๋กœ ๋ฒ„์ง€๋‹ˆ์•„๋กœ ๋ณด๋‚ด์กŒ๋‹ค.\\n(5) ์ „์Ÿ ์ค‘์— ๋ช…์˜ˆ ํ›ˆ์žฅ์˜ฌ ๋ฐ›์•˜๋‹ค." + }, + { + "page_number": "146", + "problem_number": "25", + "korean_content": "๋‹ค์Œ ๋„ํ‘œ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "The graph above shows the comparison of gross domestic product (GDP) and national debt in seven euro area countries in 2023. (1) Among the countries represented in the graph, Germany exhibited the highest GDP and the largest gap between GDP and national debt, with GDP significantly exceeding national debt. (2) France had the second highest GDP and the highest national debt, with both figures surpassing 3,000 billion euros. (3) Italy's GDP was approximately half of Germany's, while its national debt exceeded that of Germany. (4) Spain had the fourth highest GDP and national debt, with a relatively small gap of only about 10 billion euros between the two. (5) The remaining countries Ireland, Greece, and Portugal-each reported GDP and national debt figures below 500 billion euros.", + "script": null + }, + { + "page_number": "147", + "problem_number": "27", + "korean_content": "2025 Youth Film & Video Festival์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "2025 Youth Film & Video Festival\nYoung filmmakers, show your talent at the Youth Film & Video Festival! The festival accepts films from youth aged 14 to 25, regardless of their educational background.\n\nGuidelines\n- There is no entry fee.\n- Any music used in submitted films should be original. If not, it must either come from a royalty-free service or be properly licensed.\n- Films can have a maximum running time of 20 minutes.\n- All entries must be\n- submitted either by mailing a DVD or providing a link for a high-resolution download.\n- received by August 1, 2025.\n\nFestival Schedule\nThe selected films will be screened over two nights-Wednesday August 20 and Thursday August 21, 2025 at the Youth Public Library. If you have any questions, feel free to email us at events@youthlibrary.org.", + "script": null, + "answer_option": "(1) ํ•™๋ ฅ ๊ตฌ๋ถ„ ์—†์ด 14์„ธ๋ถ€ํ„ฐ 25์„ธ๊นŒ์ง€์˜ ์ฒญ์†Œ๋…„์„ ๋Œ€์ƒ์œผ๋กœ ํ•œ๋‹ค.\\n(2) ์ฐธ๊ฐ€๋น„๋Š” ๋ฌด๋ฃŒ๋‹ค.\\n(3) ์ถœํ’ˆ์ž‘์˜ ์ƒ์˜ ์‹œ๊ฐ„์€ 20๋ถ„ ์ด๋‚ด์ด์–ด์•ผ ํ•œ๋‹ค.\\n(4) ์ถœํ’ˆ์ž‘์€ DVD์™€ ๋‹ค์šด๋กœ๋“œ ๋งํฌํฌ ๋‘˜ ๋‹ค ์ œ์ถœํ•ด์•ผ ํ•œ๋‹ค.\\n(5) ์„ ์ •๋œ ์˜ํ™”๋Š” ์ดํ‹€์— ๊ฑธ์ณ ์ฒญ์†Œ๋…„ ๊ณต๊ณต ๋„์„œ๊ด€์—์„œ ์ƒ์˜๋œ๋‹ค." + }, + { + "page_number": "147", + "problem_number": "28", + "korean_content": "Online STEAM Adventurer Camp์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์€?", + "english_content": "Online STEAM Adventurer Camp\nAre your children interested in expanding their familiarity with Science, Technology, Engineering, Arts, and Mathematics (STEAM)? Don't miss this opportunity to inspire young minds and foster a love for STEAM!\nParticipants: Elementary students, Grades 1-5 (ages 6-11)\nDates: July 14-August 15, 2025 (5 weeks)\nPrice: $250 per participant\nProgram Schedule: 3:30 p.m.-4:30 p.m.\n\nMON: Grade 1\nTUE: Grade 2\nWED: Grade 3\nTHU: Grade 4\nFRI: Grade 5\n* Each student joins an online session once a week on their designated day, according to their grade.\n\nCamp Highlights\n- Participate in a five-week online summer program guided by full-time university STEAM faculty.\n- Explore different disciplines of STEAM each week.\n- Build a community of learners by sharing weekly STEAM projects with their peers. Learning materials for all 5 weeks will be provided in full at the start of the program.\n* For more information, visit the camp website.", + "script": null, + "answer_option": "(1) 5์„ธ ๋ฏธ๋งŒ์˜ ์•„๋™๋“ค๋„ ์ฐธ์—ฌํ•  ์ˆ˜ ์žˆ๋‹ค.\\n(2) ์ด 4์ฃผ๊ฐ„ ์‹ค์‹œํ•œ๋‹ค.\\n(3) ํ”„๋กœ๊ทธ๋žจ์€ ํ•™๋…„๋ณ„๋กœ ์ฃผ 1 ํšŒ ์ง„ํ–‰๋œ๋‹ค.\\n(4) ๊ณ ๋“ฑํ•™๊ต ๊ต์‚ฌ๊ฐ€ ์ง€๋„ํ•œ๋‹ค.\\n(5) ์ˆ˜์—… ์ž๋ฃŒ๋Š” ๋งค์ฃผ ์ œ๊ณต๋œ๋‹ค." + }, + { + "page_number": "148", + "problem_number": "29", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ์–ด๋ฒ•์ƒ ํ‹€๋ฆฐ ๊ฒƒ์€?", + "english_content": "As their physical growth and brain development proceed, teens develop more powers of reasoning and begin to think in more complicated, multidimensional ways. They develop more sophisticated abilities to understand (1) there are different ways of looking at a situation and imagining other possibilities for action. As a result of these changes, teens gain new perspectives about their own mothers and fathers. They shed the idealized images of their parents they may have previously held and (2) to see them more critically, including their weaknesses and flaws. They are more willing and able (3) and argue with their parents, and there can be increased conflict. Teens' increased abstract reasoning skills also enable them to better understand the complexities of life, including (4) more fearful aspects. With these more sophisticated powers of reasoning, teenagers find it easier to imagine what others are thinking of them, which can mean their sense of the negative side of things can become (5)", + "script": null + }, + { + "page_number": "148", + "problem_number": "30", + "korean_content": "(A), (B), (C)์˜ ๊ฐ ๋„ค๋ชจ ์•ˆ์—์„œ ๋ฌธ๋งฅ์— ๋งž๋Š” ๋‚ฑ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "The power of a good listener is written onto the body. When someone hears us and lets us (A) [know / ignore], it has actual physiological effects that scientists have been able to document. In 2015, for example, a group of Finnish researchers had pairs of people tell stories to each other and measured the emotional arousal of both teller and listener as testified by electrical changes in their skin. The researchers found that when the listener conveyed that they heard and understood the other-through nods, facial expressions, encouraging noises, and even cheers or criesโ€”the storytellers (B) [benefited / suffered] noticeably: when they felt heard by their listeners, they felt calmer such that their emotional arousal decreased, and the more their listeners conveyed that, the stronger the impact. Meanwhile, the more the listeners were allied with the storytellers, the more they themselves experienced (C) [increased / decreased] arousal; when one walks in someone else's shoes, it is apparently like taking on some of their energy. In other words, listening well \"spreads the emotional load.", + "script": null, + "answer_option": "(1) (A) know (B) benefited (C) decreased\\n(2) (A) know (B) suffered (C) increased\\n(3) (A) know (B) benefited (C) increased\\n(4) (A) ignore (B) suffered (C) decreased\\n(5) (A) ignore (B) benefited (C) decreased" + }, + { + "page_number": "149", + "problem_number": "32", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "Science typically progresses not by rejecting previous theories outright but by extending them: new theories do not necessarily contradict older ones; rather, they reconceive the older ones as [๋นˆ์นธ].The new theories extend the older ones to different domains so that more conditions can be explained. For example, Galileo's theory about falling objects (that they all fall at the same speed) works in a vacuum, but Newton's laws work in vacuums and extend to non-vacuums. It became clear in the twentieth century that Newtonian mechanics could not adequately describe objects that are very fast moving (approaching the speed of light) or massive (like black holes). Newtonian physics generated significant errors in these cases, so broader theories were needed that extended to these conditions, which is exactly what Einstein's special relativity did for high speeds and his general relativity did for gravity. But even Einstein's theories did not adequately account for the behaviour of subatomic particles, for which quantum mechanics had to be developed. Scientists are still working to extend general relativity and quantum mechanics (which are incompatible) to a generalized theory that works under all conditions.", + "script": null, + "answer_option": "(1) outdated and discarded\\n(2) limited to certain conditions\\n(3) providing a new perspective\\n(4) conceptually firmly solidified\\n(5) compatible with new conditions" + }, + { + "page_number": "149", + "problem_number": "31", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "In a football game the clock is a [๋นˆ์นธ].The team in the lead will attempt to use as much time as possible, hoping to run out the clock and win the game. It will employ the technique, in a phrase that combines the agrarian with the industrial, of milking the clock. As the end of the game approaches, the team that is trailing finds itself battling against two adversaries: the opposing team, which is trying to prevent it from scoring, and the clock, which is winding down to the point at which the game, and so the team's efforts to win, must end. The final minute of a close game resembles in this sense the climactic scene in James Bond films, in which the hero must fight his way past the villain (or the villain's powerful and dangerous henchmen) to reach and disable the bomb that is set to explode at a designated moment. Bond invariably succeeds in disarming the doomsday machine in the nick of time. In football games, by contrast, one of the teams runs out of time before it can prevent defeat.", + "script": null, + "answer_option": "(1) servant\\n(2) blessing\\n(3) phantom\\n(4) participant\\n(5) decoration" + }, + { + "page_number": "150", + "problem_number": "33", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "There are inevitably multiple trade-offs among design criteria; no single design will be best for all of them. A refrigerator that is more energy efficient may cost more to buy; a truck that pollutes less may have slower acceleration; a computer that is more portable may have a smaller keyboard, increasing the probability of keying errors. The critical point is that many different designs of any given product are possible, all of which achieve the central objective but differ in the degree to which the various design criteria are achieved. Therefore, whoever establishes the priorities attached to the different design criteria has enormous influence on the characteristics of the final product. This is actually true of any functional design situation, whether the designer is an engineer or an architect, whether the product is a toothbrush, an office building, or an urban transportation system. Those who set the priorities attached to the design criteria play a critical role in directing the application of existing technological knowledge. They [๋นˆ์นธ].", + "script": null, + "answer_option": "(1) monopolize knowledge to maintain control\\n(2) conduct evaluations to identify design issues\\n(3) decide the level of automation to implement\\n(4) shape the technology that shapes our society\\n(5) pursue technological advancement for dominance" + }, + { + "page_number": "150", + "problem_number": "34", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "Plato lived at a time when there was a special need for education throughout the ancient Greek city-states. Governments required more administrators and, to fill the void, aristocratic parents hired freelance philosophers to educate their sons for this vocation. Although not members of any particular philosophical school of thought, these teachers were collectively known as Sophists, a term which means \"one who makes people wise.\" They traveled widely throughout the Greek world and contracted out their services from one city-state to another. Many Sophists claimed the ability to teach any subject, but their specialization was rhetorical skills, particularly the kind of arguing and persuasive speaking techniques needed in public debates. The Sophists had a skeptical attitude toward the pursuit of truth and, by and large, maintained that in many areas of inquiry, truth is only a matter of persuasive argumentation. The true position in a debate is the winning position. To this end, they offered an argument strategy called \"antilogic,\" which involved learning to argue both sides of a case as strongly as possible. Using this technique, students could [๋นˆ์นธ].", + "script": null, + "answer_option": "(1) gain a rational ability to discern eternal truths\\n(2) make the weaker argument become the stronger\\n(3) comprehend Plato' s profound concept of true virtue\\n(4) broaden their horizons and achieve personal growth\\n(5) seek the absolute logic underlying knowledge acquisition" + }, + { + "page_number": "151", + "problem_number": "35", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "In the eighteenth and nineteenth century street sellers and oyster bars were as common as takeaways are today in our cities and ports. They were a huge attraction for country folks coming into town. (1) Rural life was not the food paradise we are sometimes led to believe with everyone enjoying ploughman's lunches and the like. (2) For the most part the country folk's diet was poor and lacked vitamins and essential minerals such as zinc needed for good long-term health. (3) Poor farm labourers on their infrequent visits to town went for a filling meal and a protein fix. (4) The poor old native oyster went from being an overabundant food source to a treasured and costly rarity. (5) This was affordable to them in the numerous oyster bars or stalls and they would eat as much as their bellies could stand either fresh ones or pickled in vinegar.", + "script": null + }, + { + "page_number": "151", + "problem_number": "36", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[ince the function of a protein is related to its shape, changing the shape changes the protein's ability to function, usually rendering it useless to the organism.] \n\n(A) On the molecular level, the cable is the protein structure, and the tangles in the cable are secondary bonds between various atoms in the structure. Atoms can be relocated to different bonding spots, changing the overall shape of the molecule, but not actually changing the chemical composition.\n\n(B) With its new shape, however, the molecule isn't always able to perform its original function. It might no longer fit into places that it used to be able to go, or given the new conformation, other molecules might be able to form new bonds with the molecule and prevent it from functioning as it used to.\n\n(C) Think of a protein as a bit like the power cable between a laptop and an outlet: while it has a particular primary structure (the cord and wires inside it), the cord itself invariably gets all tangled up and twisted into some secondary structure.", + "script": null, + "answer_option": "(1) (A)-(C)-(B)\\n(2) (B)-(A)-(C)\\n(3) (B)-(C)-(A)\\n(4) (C)-(A)-(B)\\n(5) (C)-(B)-(A)" + }, + { + "page_number": "152", + "problem_number": "37", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[As automakers around the world shift from gas-powered to electric vehicles and work on future autonomous vehicles, the relative importance of hardware and software to the business has shifted. The capabilities that define great car companies are different in the digital era.] \n\n(A) The hundreds of applications in an electric vehicle cannot be built as separate widgets; they must be part of an integrated operating system. Just as important, the software must be continually updated over the life of the vehicle, just like a smartphoneโ€™s operating system and apps.\n\n(B) These new capabilities start with digital technology. Traditional gas-powered cars were built with software but only for running secondary functions like heating, maps, and entertainment. These simple applications were coded onto separate chips implanted in parts throughout the car.\n\n(C) They were easily outsourced to suppliers and plugged in when the vehicle was assembled. But with the shift to electric vehicles, software is now in the driver's seat. It runs the entire powertrain, brakes, battery, and lights โ€” the most critical systems of any car.", + "script": null, + "answer_option": "(1) (A)-(C)-(B)\\n(2)(B)-(A)-(C)\\n(3) (B)-(C)-(A)\\n(4) (C)-(A)-(B)\\n(5) (C)-(B)-(A)" + }, + { + "page_number": "152", + "problem_number": "38", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: \n\nBehaviorists studying interval timing noticed that individuals often cycled through predictable sequences of actions while waiting to respond at a particular duration. Imagine you are waiting for a bus. (1) Initially, you might sit, then at some point, you stand up, begin pacing, or start looking down the street. (2) Onlookers might interpret these actions as signs of impatience. (3) For example, if you are looking down the street and checking the time on your phone, then those are actions that can let you know that you have been waiting longer. (4) This may seem like a weird way to judge time, but you can probably get some sense of how long people have been waiting in a line based on their actions and expressions. (5) So presumably, those people's brains can also use those same cues too.", + "script": null + }, + { + "page_number": "153", + "problem_number": "39", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: \n\nIt seems reasonable to assume that discussions about the personhood status of digital minds will begin as soon as rights and responsibilities are attributed to them. (1) Digital agents โ€” software programs that take significant decisions on behalf of individuals and corporationsโ€” already exist and are responsible for many events affecting human lives. (2) The most visible of them โ€”automated trading agents, whose behavior is based on complex sets of rules and algorithms โ€” affect the economy enormously and have been blamed for a number of economic crises and other troublesome events. (3) This is simply a consequence of the fact that personhood has not, so far, been granted to any purely digital entity. (4) However, as digital agents and their behavior become more complex, it is natural to shift the responsibilities from the \"owners\" of these agents to the agents themselves. (5) In fact, the concept of ownership of an intelligent agent may one day become a focus of dissension if digital minds are granted full personhood.", + "script": null + }, + { + "page_number": "153", + "problem_number": "40", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์˜ฌ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค ๋ฐ˜์นธ (A). (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "According to Herbert L. Packer, there are two competing models of justice that form the foundations of criminal law and procedure: the crime control model and the due process model. The crime control model believes that justice is based primarily on public safety and on the efficient conviction and strict punishment of criminals. Crime control advocates side with law enforcement agents in assuming that most people charged with a crime are factually guilty. The crime control philosophy of justice is widely associated with a law and order perspective and zero tolerance policies. In contrast, the due process model is based on the rights of the accused and on the presumption of innocence (the idea that a person must be considered innocent of charges until proven guilty in a court of law). Those accused of a crime should be entitled to full legal representation and a fair trial. The justice system must adhere to fair and open procedures to safeguard against abuses of power by justice system officials, which can result in horrific forms of injustice, such as the wrongful conviction of innocent people. \n\n => ์š”์•ฝ: Herbert L. Packer proposed two justice models: the crime control model, which ๋นˆ์นธ (A) public safety and strict punishment of the guilty, and the due process model, which focuses on fair treatment and avoids ๋นˆ์นธ (B) convictions.", + "script": null, + "answer_option": "(1)(A) supports (B) unjust \\n(2)(A) threatens (B) severe \\n(3) (A) addresses (B) definite \\n(4) (A) emphasizes (B) political \\n(5)(A) undermines (B) wrongful" + }, + { + "page_number": "154", + "problem_number": "41", + "korean_content": "์œ—๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "In nature, it is common to find that organisms instinctively take actions that aim to achieve one of four essential objectives for survival: managing resources, particularly sources of energy; protecting themselves from environmental forces; forming and maintaining relationships with others; and defending themselves against threats from other entities. Furthermore, many living organisms have similar functional components or organs, such as those for sensing, movement, and adhesion, that contribute to these (a) objectives. This similarity among organisms allows for the comparison of different organisms, regardless of their habitat or specific methods of achieving these objectives. As most physiological and behavioral adaptations observed in living organisms are related to one or more of the four basic objectives, it is possible to compare (b) across different entities that are otherwise dissimilar. As an example, we can compare the water conservation strategies of the saguaro cactus (Carnegiea gigantea) and the dromedary camel, despite the two organisms not being closely (c) . This comparison may (d) common principles. In fact, the more dissimilar the entities being compared, the more likely it is that common principles will be identified, if they indeed exist. These common principles can then be confidently applied to human systems due to their (e) . For example, one potential application that could be influenced by the water-conserving strategies of the dromedary and the saguaro is the development of water-efficient systems in vehicle manufacturing, irrigation, or sustainable architecture.", + "script": null, + "answer_option": "(1) Shared Survival Principles Across Species\\n(2) Impact of Environmental Changes on Human Systems\\n(3) Do Animals Exhibit Similar Survival Objectives?\\n(4) Behavioral Adaptations: Understanding Complex Animal Migrations\\n(5) Unlocking Nature' s Secrets: The Principles of Water Management Why" + }, + { + "page_number": "154", + "problem_number": "42", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)-(e) ์ค‘์—์„œ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "In nature, it is common to find that organisms instinctively take actions that aim to achieve one of four essential objectives for survival: managing resources, particularly sources of energy; protecting themselves from environmental forces; forming and maintaining relationships with others; and defending themselves against threats from other entities. Furthermore, many living organisms have similar functional components or organs, such as those for sensing, movement, and adhesion, that contribute to these (a) objectives. This similarity among organisms allows for the comparison of different organisms, regardless of their habitat or specific methods of achieving these objectives. As most physiological and behavioral adaptations observed in living organisms are related to one or more of the four basic objectives, it is possible to compare (b) across different entities that are otherwise dissimilar. As an example, we can compare the water conservation strategies of the saguaro cactus (Carnegiea gigantea) and the dromedary camel, despite the two organisms not being closely (c) . This comparison may (d) common principles. In fact, the more dissimilar the entities being compared, the more likely it is that common principles will be identified, if they indeed exist. These common principles can then be confidently applied to human systems due to their (e) . For example, one potential application that could be influenced by the water-conserving strategies of the dromedary and the saguaro is the development of water-efficient systems in vehicle manufacturing, irrigation, or sustainable architecture.", + "script": null, + "answer_option": "(1) (a)\\n(2) (b)\\n(3) (c)\\n(4) (d)\\n(5) (e)" + }, + { + "page_number": "155", + "problem_number": "43", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ (A)์— ์ด์–ด์งˆ ๋‚ด์šฉ์˜ฌ ์ˆœ์„œ์— ๋งž๊ฒŒ ๋ฐฐ์—ดํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "(A) On a warm summer afternoon, Mia and Daniel decided to visit the local park, where they often went to relax and talk. Mia, an emerging artist, had been feeling uninspired lately, while Daniel, an aspiring writer, struggled with a lack of motivation. They hoped that spending time outdoors might refresh their creativity. As they strolled through the park, they noticed an elderly man sitting on a bench and feeding the pigeons.\n\n(B) Mr. Thompson then shared a story from (a) youth. \"When I was your age, I had a mentor who taught me that art isn't about perfection, but about expressing what's in your heart. One day, I sculpted a statue, but it wasn't perfect. I wanted to get rid of it, but my mentor stopped me. (b) said, 'This piece is beautiful because it reflects your journey, your effort, and your passion.' That moment changed my perspective. I learned to embrace my imperfections and let my heart guide my hands.\"\n\n(C) They recognized him as Mr. Thompson, a well-known sculptor in the neighborhood famous for (c) beautiful statues scattered around the park. Curious and seeking inspiration, Mia and Daniel approached him. \"Good afternoon, Mr. Thompson,\" Mia greeted. \"Your sculptures are amazing. How do (d) stay so inspired?\" Mr. Thompson smiled warmly and gestured for them to sit beside him. \"Thank you. Inspiration comes from life's simple moments and the passion within us,\" he replied.\n\n(D) Mia and Daniel listened intently, moved by Mr. Thompson's words. They realized they had been too focused on achieving perfection, rather than enjoying their creative processes. (e) story taught them that true art and creativity come from within, embracing both flaws and strengths. As they left the park, Mia and Daniel felt a renewed sense of purpose. They understood that their unique journeys and personal expressions were what made their art special. The encounter with Mr. Thompson sparked their creative spirits, and they couldn't wait to get started on their new pieces.", + "script": null, + "answer_option": "(1) (B)-(D)-(C)\\n(2)(C)-(B)-(D)\\n(3) (C)-(D)-(B)\\n(4) (D)-(B)-(C)\\n(5) (D)-(C)-(B)" + }, + { + "page_number": "155", + "problem_number": "44", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)~(e) ์ค‘์—์„œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€์ƒ์ด ๋‚˜๋จธ์ง€ ๋„ท๊ณผ ๋‹ค๋ฅธ ๊ฒƒ์€?", + "english_content": "(A) On a warm summer afternoon, Mia and Daniel decided to visit the local park, where they often went to relax and talk. Mia, an emerging artist, had been feeling uninspired lately, while Daniel, an aspiring writer, struggled with a lack of motivation. They hoped that spending time outdoors might refresh their creativity. As they strolled through the park, they noticed an elderly man sitting on a bench and feeding the pigeons.\n\n(B) Mr. Thompson then shared a story from (a) youth. \"When I was your age, I had a mentor who taught me that art isn't about perfection, but about expressing what's in your heart. One day, I sculpted a statue, but it wasn't perfect. I wanted to get rid of it, but my mentor stopped me. (b) said, 'This piece is beautiful because it reflects your journey, your effort, and your passion.' That moment changed my perspective. I learned to embrace my imperfections and let my heart guide my hands.\"\n\n(C) They recognized him as Mr. Thompson, a well-known sculptor in the neighborhood famous for (c) beautiful statues scattered around the park. Curious and seeking inspiration, Mia and Daniel approached him. \"Good afternoon, Mr. Thompson,\" Mia greeted. \"Your sculptures are amazing. How do (d) stay so inspired?\" Mr. Thompson smiled warmly and gestured for them to sit beside him. \"Thank you. Inspiration comes from life's simple moments and the passion within us,\" he replied.\n\n(D) Mia and Daniel listened intently, moved by Mr. Thompson's words. They realized they had been too focused on achieving perfection, rather than enjoying their creative processes. (e) story taught them that true art and creativity come from within, embracing both flaws and strengths. As they left the park, Mia and Daniel felt a renewed sense of purpose. They understood that their unique journeys and personal expressions were what made their art special. The encounter with Mr. Thompson sparked their creative spirits, and they couldn't wait to get started on their new pieces.", + "script": null, + "answer_option": "(1) (a)\\n(2) (b)\\n(3) (c)\\n(4) (d)\\n(5) (e)" + }, + { + "page_number": "155", + "problem_number": "45", + "korean_content": "์œ—๊ธ€์— ๊ด€ํ•œ ๋‚ด์šฉ์œผ๋กœ ์ ์ ˆํ•˜์ง€ ์•ˆ์€ ๊ฒƒ์€?", + "english_content": "(A) On a warm summer afternoon, Mia and Daniel decided to visit the local park, where they often went to relax and talk. Mia, an emerging artist, had been feeling uninspired lately, while Daniel, an aspiring writer, struggled with a lack of motivation. They hoped that spending time outdoors might refresh their creativity. As they strolled through the park, they noticed an elderly man sitting on a bench and feeding the pigeons.\n\n(B) Mr. Thompson then shared a story from (a) youth. \"When I was your age, I had a mentor who taught me that art isn't about perfection, but about expressing what's in your heart. One day, I sculpted a statue, but it wasn't perfect. I wanted to get rid of it, but my mentor stopped me. (b) said, 'This piece is beautiful because it reflects your journey, your effort, and your passion.' That moment changed my perspective. I learned to embrace my imperfections and let my heart guide my hands.\"\n\n(C) They recognized him as Mr. Thompson, a well-known sculptor in the neighborhood famous for (c) beautiful statues scattered around the park. Curious and seeking inspiration, Mia and Daniel approached him. \"Good afternoon, Mr. Thompson,\" Mia greeted. \"Your sculptures are amazing. How do (d) stay so inspired?\" Mr. Thompson smiled warmly and gestured for them to sit beside him. \"Thank you. Inspiration comes from life's simple moments and the passion within us,\" he replied.\n\n(D) Mia and Daniel listened intently, moved by Mr. Thompson's words. They realized they had been too focused on achieving perfection, rather than enjoying their creative processes. (e) story taught them that true art and creativity come from within, embracing both flaws and strengths. As they left the park, Mia and Daniel felt a renewed sense of purpose. They understood that their unique journeys and personal expressions were what made their art special. The encounter with Mr. Thompson sparked their creative spirits, and they couldn't wait to get started on their new pieces.", + "script": null, + "answer_option": "(1) Mia์™€ Daniel์€ ํ•œ ๋…ธ์ธ์ด ๋ฒค์น˜์— ์•‰์•„ ์žˆ๋Š” ๊ฒƒ์˜ฌ ๋ณด์•˜๋‹ค\\n(2) Mr. Thompson์˜ ๋ฉ˜ํ† ๋Š” ๊ทธ์—๊ฒŒ ์‹คํŒจํ•œ ์กฐ๊ฐ์ƒ์„ ๋ฒ„๋ฆฌ๋ผ๊ณ  ํ–ˆ๋‹ค.\\n(3) ๊ณต์›์—๋Š” Mr. Thompson์ด ์ œ์ž‘ํ•œ ์กฐ๊ฐ ์ž‘ํ’ˆ๋“ค์ด ์žˆ์—ˆ๋‹ค\\n(4) Mr. Thompson์€ Mia์™€ Daniel์—๊ฒŒ ์˜†์— ์•‰์œผ๋ผ๊ณ  ํ–ˆ๋‹ค\\n(5) Mia์™€ Daniel์€ ๊ณต์›์„ ๋– ๋‚˜๋ฉด์„œ ์ƒˆ๋กœ์šด ๋ชฉ์ ์˜์‹์„ ๋А๊ผˆ๋‹ค" + } +] \ No newline at end of file diff --git a/ai-service/DB/files/database3_fixed.json b/ai-service/DB/files/database3_fixed.json new file mode 100644 index 0000000..1ca871f --- /dev/null +++ b/ai-service/DB/files/database3_fixed.json @@ -0,0 +1,439 @@ +[ + { + "page_number": "156", + "problem_number": "04", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๊ทธ๋ฆผ์—์„œ ๋Œ€ํ™”์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hi, Royce. How was your weekend?\nM: It was great. I went camping with my dog, Max. Do you want to see a picture of us?\nW: I'd love to. [Pause) Oh, there's Max! He's inside the tent.\nM: Yeah, he seemed to really like it.\nW: And you look comfortable sitting in front of the tent.\nWhat's in your cup? Coffee?\nM: Yep. You know how much I like coffee!\nW: I like the round table in front of you. It looks perfect for camping-\nM: I like it, too. It was really useful for putting my cup on.\nW: Is this stripe-patterned blanket for Max?\nM: You mean the one next to the table? Yeah, that was for Max. I put it there so he could sleep outside the tent.\nW: It looks cozy. And I love these two big trees next to the tent.\nM: Me too. It was such a great spot for camping!", + "answer_option": "" + }, + { + "page_number": "156", + "problem_number": "01", + "korean_content": "๋‹ค์Œ์„ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Good morning, students! This is the vice principal speaking. As you all know, a mini concert is scheduled in the school garden this afternoon. We have performances from the student band, as well as a special stage featuring professional musicians. However, since the weather forecast predicts very hot and sunny conditions this afternoon, with temperatures expected to exceed 35 degrees Celsius, we're concerned it might be too hot for everyone to enjoy the show outdoors. To ensure everyone's comfort, we have decided to move the event to the school gym. Hope to see you all there!", + "answer_option": "(1)์ฝ˜์„œํŠธ ์žฅ์†Œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์Œ์„ ๊ณต์ง€ํ•˜๋ ค๊ณ  (2)ํ•™๊ต ์ฒด์œก๊ด€ ์ด์šฉ ์ˆ˜์น™์„ ์•ˆ๋‚ดํ•˜๋ ค๊ณ  (3)์ฝ˜์„œํŠธ์— ์ฐธ์—ฌํ•  ๋ฐด๋“œํ‹€ ๋ชจ์ง‘ํ•˜๋ ค๊ณ  (4)๋”์šด ๋‚ ์”จ์— ๋Œ€๋น„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•˜๋ ค๊ณ  (5)ํญ์—ผ์œผ๋กœ ์ธํ•ด ํ–‰์‚ฌ๊ฐ€ ์ทจ์†Œ๋˜์—ˆ์Œ์„ ์•Œ๋ฆฌ๋ ค๊ณ " + }, + { + "page_number": "156", + "problem_number": "02", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ์˜๊ฒฌ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค", + "english_content": null, + "script": "W: Tom, did you know we should drink at least 8 glasses of water a day?\nM: Hmm... Who told you that?\nW: A friend of mine. She told me that it would keep me healthy and fit.\nM: That makes sense, but I don't think 8 glasses is necessary for everyone.\nW: What do you mean?\nM: Everyone needs water, but I think the right amount depends on the person.\nW: So, you're saying some people need more and some people need less?\nM: Exactly. It can be too little for athletes or too much for kids.\nW: Oh, that makes sense.\nM: Just drink what's right for you. Don't focus too much on the 8 glasses a day.\nW: You're right. I should drink the amount of water that's right for me.", + "answer_option": "(1)ํ•˜๋ฃจ์— ๋งˆ์‹ค ๋ฌผ์˜ ์ ์ •๋Ÿ‰์€ ์‚ฌ๋žŒ๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค. (2)๊ฒฉ๋ ฌํ•œ ์šด๋™์„ ํ•  ๋•Œ๋Š” ์ˆ˜๋ถ„์„ ์ž์ฃผ ์„ญ์ทจํ•ด์•ผ ํ•œ๋‹ค. (3)๋ชจ๋“  ์‚ฌ๋žŒ์€ ํ•˜๋ฃจ์— ์ ์–ด๋„ 8์ž”์˜ ๋ฌผ์„ ๋งˆ์…”์•ผ ํ•œ๋‹ค . (4)์•„์ด๋“ค์€ ์‹ ์ง„๋Œ€์‚ฌ๊ฐ€ ํ™œ๋ฐœํ•˜์—ฌ ๋ฌผ์„ ๋งŽ์ด ๋งˆ์„œ์•ผ ํ•œ๋‹ค. (5)์•„์นจ์— ์ผ์–ด๋‚˜์„œ ๋ฌผ ํ•œ ์ž”์„ ๋งˆ์‹œ๋Š” ๊ฒƒ์€ ๊ฑด๊ฐ•์— ๋„์›€์ด ๋œ๋‹ค." + }, + { + "page_number": "156", + "problem_number": "05", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ํ•  ์ผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Honey, what did you get at the market?\nM: I bought some apples. I'm going to use them to make homemade pickles.\nW: Pickles from apples? I thought pickles were only made from cucumbers.\nM: They usually are, but you can make pickles with fruit, too.\nW: I didn't know that. Do you know how to make them?\nM: Yes, I found a good recipe online.\nW: Do you have all the ingredients?\nM: Of course. I just need vinegar, salt, and sugar. We already have those at home.\nW: Great. Are you going to put the pickles in these jars?\nM: Yes, but I still need to clean the jars with hot water.\nW: I can do that for you.\nM: Thanks! I'll start cutting the apples in the meantime.", + "answer_option": "(1)์‚ฌ๊ณผ ์ž๋ฅด๊ธฐ (2)์‹œ์žฅ์—์„œ ์‚ฌ๊ณผ ์‚ฌ๊ธฐ (3)๋œจ๊ฑฐ์šด ๋ฌผ๋กœ ๋ณ‘ ์”ป๊ธฐ (4)์„คํƒ•๊ณผ ์†Œ๊ธˆ ์ฃผ๋ฌธํ•˜๊ธฐ (5)ํ”ผํด ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• ์ฐพ์•„๋ณด๊ธฐ" + }, + { + "page_number": "156", + "problem_number": "03", + "korean_content": "๋‹ค์Œ์„ ๋“ฃ๊ณ , ๋‚จ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "M: Good morning, listeners. Welcome back to Tom's Radio Lounge. Take a look at your calendar โ€” what kind of reminders do you see? Probably some important meetings, like a session with your boss or a dentist appointment. But calendars aren't just for major events. It might seem unusual to add small things like 'take vitamins before bed' or 'water the plants' to your calendar, but doing so can make a big difference in how you manage life. We rarely miss a dentist appointment, yet we often forget to take our vitamins or water the plants. By noting these small tasks, we can stay on top of all the details in our lives, both for work and personal care. Why not start adding those small reminders to your calendar today?", + "answer_option": "(1)๊ทœ์น™์ ์ธ ์ƒํ™œ์„ ์œ„ํ•ด ์ผ์ •์„ ์ž์„ธํžˆ ์„ธ์›Œ์•ผ ํ•œ๋‹ค. (2)๋งค์ผ ํ•ด์•ผ ํ•  ์ผ์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ •ํ•ด ์ง‘์ค‘ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค. (3)์ž‘์€ ์ผ๋„ ๋‹ฌ๋ ฅ์— ์ถ”๊ฐ€ํ•˜๋ฉด ๊ฐœ์ธ ์ƒํ™œ์„ ๋” ์ž˜ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. (4)๋งค์ผ ์•„์นจ ๋‹ฌ๋ ฅ์„ ํ™•์ธํ•˜๋ฉด ํ•ด์•ผ ํ•  ์ผ์„ ๋†“์น˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. (5)์ค‘์š”ํ•œ ์ผ์€ ์žŠ์ง€ ์•Š๋„๋ก ๋ˆˆ์— ๋„๋Š” ๊ณณ์— ํ‘œ์‹œํ•ด ๋‘๋Š” ๊ฒƒ์ด ์ข‹๋‹ค." + }, + { + "page_number": "157", + "problem_number": "06", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž๊ฐ€ ์ง€๋ถˆํ•  ๊ธˆ์•ก์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Honey, what are you looking at?\nM: I'm booking a boarding service for our dog, Happy,while we're on vacation.\nW: Oh, you mean a pet hotel? That's a great idea! What are their rates?\nM: It's $20 a day for small dogs 10 kg or under, and $30 a day for bigger dogs.\nW: Happy is 7 kg, so she fits into the small dog category.\nM: Exactly. Since our vacation is for a week, we'll need to book for seven days.\nW: Right. Oh, look! We can add special programs while she's there.\nM: Let's see. (Pause) This one looks nice. They'll take Happy out for an hour-long walk. It's $20 per session.\nW: I think three sessions would be good for Happy.\nM: Yeah, let's include that.\nW: Oh, and they offer a 10% discount on the total price for first-time customers like us.\nM: Wonderful. Let's use that coupon. I'll make the payment.", + "answer_option": "(1)$140 (2)$180 (3)$190 (4)$200 (5)$230" + }, + { + "page_number": "157", + "problem_number": "09", + "korean_content": "2025 Step Count Challenge์— ๊ด€ํ•œ ๋‹ค์Œ ๋‚ด์šฉ์„ ๋“ฃ๊ณ , ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hello, everyone! I'm thrilled to invite you to join the 2025 Step Count Challenge! This is a great opportunity for us all to get moving and stay healthy. The challenge starts on July Ist and runs throughout the entire month. To register, simply download the Step Count Challenge app and sign up directly in the app. You can track your steps using any step-counting devices you have โ€” whether it's a smartphone, smartwatch, or step counter. Every day you hit 6,000 steps, you'll earn a stamp in the app. You can exchange 5 stamps for 500 points, which you can use as actual cash! Plus, there are special prizes for the top three participants with the highest step counts. Our app also features a daily leaderboard so you can see your rank compared to other participants, and it includes information on great spots for walking. You can find more details in the Step Count Challenge app. Let's get walking!", + "answer_option": "(1)7์›” 1์ผ๋ถ€ํ„ฐ ํ•œ ๋‹ฌ ๋™์•ˆ ์ง„ํ–‰๋œ๋‹ค. (2)๊ฑธ์Œ ์ˆ˜๋ฅผ ๊ธฐ๋กํ•˜๋Š” ์žฅ์น˜๋Š” ๋ฌด์—‡์ด๋“  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. (3)ํ•˜๋ฃจ 6,000๋ณด๋ฅผ ๊ฑธ์œผ๋ฉด ์Šคํ…œํ”„ ํ•˜๋‚˜๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. (4)๊ฑธ์Œ ์ˆ˜๊ฐ€ ๊ฐ€์žฅ ๋งŽ์€ ์ฐธ๊ฐ€์ž ํ•œ ๋ช…๋งŒ ํŠน๋ณ„ ์ƒํ’ˆ์„ ๋ฐ›๋Š”๋‹ค. (5)๊ฑท๊ธฐ ์ข‹์€ ์žฅ์†Œ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์•ฑ์—์„œ ์ œ๊ณตํ•œ๋‹ค." + }, + { + "page_number": "157", + "problem_number": "07", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ์ž๋…€์˜ ์œ ์น˜์› ์žฅ๊ธฐ ์ž๋ž‘์— ์ฐธ์„ํ•˜์ง€ ๋ชปํ•˜๋Š” ์ด์œ ๋ฅผ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "M: Honey, did you read this newsletter from Logan's kindergarten?\nW: No, what's it about?\nM: It says that they're having a talent show at the end of the month, and parents can come and watch.\nW: That's so cool! I'd love to see our little Logan perform.\nCan both parents come?\nM: Yes. It's on Friday, August 29th at 10 a.m. Should we go together?\nW: Oh no. I can't make it if it's on the 29th.\nM: Why not? Is it because of the health check-up you mentioned the other day?\nW: No. I can reschedule that.\nM: Then is it because you have a meeting with a client that day?\nW: No, that's not it either. But it is because of work. I have to give a presentation on our company's new product on that day.\nM: 1 see. Don't worry. I'll go to the talent show and cheer extra hard for both of us.", + "answer_option": "(1)๋ชธ์ด ์ข‹์ง€ ์•Š์•„์„œ (2)๊ณ ๊ฐ๊ณผ์˜ ์•ฝ์†์ด ์žˆ์–ด์„œ (3)๊ฑด๊ฐ• ๊ฒ€์ง„์„ ๋ฐ›์œผ๋Ÿฌ ๊ฐ€์•ผ ํ•ด์„œ (4)์‹ ์ œํ’ˆ์— ๋Œ€ํ•œ ๋ฐœํ‘œ๋ฅผ ํ•ด์•ผ ํ•ด์„œ (5)๋ถ€๋ชจ ์ค‘ ํ•œ ๋ช…๋งŒ ์ฐธ์„ํ•  ์ˆ˜ ์žˆ์–ด์„œ" + }, + { + "page_number": "157", + "problem_number": "10", + "korean_content": "๋‹ค์Œ ํ‘œ๋ฅผ ๋ณด๋ฉด์„œ ๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‘ ์‚ฌ๋žŒ์ด ๊ตฌ๋งคํ•  ์ •์ˆ˜๊ธฐ๋ฅผ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "M: Sophia, how about buying a countertop water purifier instead of always getting plastic bottled water?\nW: That sounds good. It'll save us money in the long run, and reducing plastic waste is good for the environment.\nM: I found a site that sells them. Here are the models they have.\nW: We'll put it next to the toaster oven, right? Then, it needs to be less than 30 centimeters wide.\nM: That's right. What do you think about getting one that dispenses both hot and cold water?\nW: Hmm... I don't think we use hot water enough to make it worth it. And that uses a lot of electricity. So let's choose one without that function.\nM: Okay. And how about a UV function?\nW: What's that for?\nM: It cleans the water outlet with UV light, which prevents bacteria and germs from growing.\nW: We definitely need that. It's important to keep it clean.\nM: Then it comes down to cost.\nW: The cheaper, the better. Looks like this one is our best option.", + "answer_option": "(1)Model: A, Width(cm): 31, Hot/Cold Water: O, UV Function: X, Price: $275 (2)Model: B, Width(cm): 28, Hot/Cold Water: X, UV Function: O, Price: $250 (3)Model: C, Width(cm): 28, Hot/Cold Water: O, UV Function: X, Price: $265 (4)Model: D, Width(cm): 26, Hot/Cold Water: X, UV Function: O, Price: $240 (5)Model: E, Width(cm): 22, Hot/Cold Water: X, UV Function: X, Price: $220" + }, + { + "page_number": "157", + "problem_number": "08", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž๊ฐ€ ์˜ˆ์•ฝํ•œ ํšŒ์˜์‹ค์— ๊ด€ํ•ด ์–ธ๊ธ‰๋˜์ง€ ์•Š์€ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "[Telephone rings.]\nM: Hello, this is the marketing department. David Carter speaking.\nW: Hello, Mr. Carter. This is Kate from Brightstone Technologies. I'm calling to share the details of our meeting.\nM: Oh, I've been waiting for your call. Can you tell me where it's being held?\nW: It's at the Phoenix Conference Center.\nM: Phoenix Conference Center? Is that near Central Station?\nW: Yes. Just take exit 3 at Central Station, and you'll see it right at the corner. Have you been there before?\nM: Only once. I heard it's quite popular because they have advanced video conferencing equipment in every room.\nW: You're right. I was actually lucky to get a reservation for 3 to 5 p.m. โ€” maybe someone canceled.\nM: That's great. And the rooms there are quite spacious.\nW: Right. The room I booked can accommodate up to 10 people. Please share the location details with your team.\nM: No problem. Thanks for the information. See you then.", + "answer_option": "(1)์œ„์น˜ (2)ํ™”์ƒ ํšŒ์˜ ์žฅ๋น„ (3)์˜ˆ์•ฝ ์‹œ๊ฐ„ (4)๋Œ€๊ด€๋ฃŒ (5)์ž…์‹ค ๊ฐ€๋Šฅ ์ธ์›" + }, + { + "page_number": "158", + "problem_number": "11", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "M: Amanda, you've been leaving work really late these days. I'm worried you're pushing yourself too hard with all the prep for next week's meeting.\nW: Yeah, you're right. I've been pretty exhausted. I'm thinking of leaving early today, especially since it's supposed to rain a lot around 5.\nM: That sounds like a good idea. If we leave around the same time, I can give you a ride to the station.\nW: Thanks, but I have other plans. Maybe another time.", + "answer_option": "(1)Thanks, but I have other plans. Maybe another time. (2)That's very kind of you, but I'm already near the office. (3)That's unfortunate. It would be quite inconvenient for you. (4)I'm really sorry, but it looks like I'll have to stay late today. (5)Perfect! You should get some much-needed rest after work." + }, + { + "page_number": "158", + "problem_number": "14", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Man:", + "script": "M: Good morning! How was your night at our campsite?\nW: It was wonderful, thank you. The heater you provided kept us very warm, and we had a great sleep.\nM: I'm glad to hear that. You can return the heater to our main office when you check out.\nW: Sure. Is the checkout time 11 a.m.?\nM: Yes, it is. After we check your site, we'll return your deposit.\nW: Understood. By the way, is it possible to leave our car parked here after we check out?\nM: That's not a problem. Do you have any specific plans?\nW: We came here to hike the Blue Mountains, but the rain stopped us. We're planning to hike today before heading home.\nM: That sounds like a great plan! It usually takes about three hours to reach the top.\nW: Really? Then we'll probably be back around 5 p.m. and then grab dinner at a nearby restaurant.\nM: If you'd like, you're welcome to use our shower facilities for free after your hike.\nW: That's very kind of you! We'll be really sweaty after the hike.\nM: I'll open the showers for you when you're back.", + "answer_option": "(1)A towel fee will be taken from your deposit. (2)The shower areas are currently under repair. (3)Due to heavy rain, hiking isn't possible today. (4)You need to grab some food before your hike. (5)I'll open the showers for you when you're back." + }, + { + "page_number": "158", + "problem_number": "12", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ์—ฌ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ๋‚จ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": null, + "script": "W: Hello, are there any tables available for lunch? There are three of us.\nM: I'm sorry, but we're currently full. If you'd like to wait, you can put your name and phone number on the waiting list.\nW: All right. I'll do that now.\nM: Sounds good! I'll contact you when your table is ready.", + "answer_option": "(1)Come in! I'll guide you to your table shortly. (2)Sounds good! I'll contact you when your table is ready. (3)We're fully booked inside. But there is a table free outside. (4)I'll check to see if you have a reservation. What's your name? (5)Unfortunately, we're closing soon to take a break before dinner." + }, + { + "page_number": "158", + "problem_number": "15", + "korean_content": "๋‹ค์Œ ์ƒํ™ฉ ์„ค๋ช…์„ ๋“ฃ๊ณ , Rachel์ด Rodgers ์„ ์ƒ๋‹˜์—๊ฒŒ ํ•  ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Rachel:", + "script": "W: Rachel is a teacher at Pan High School. During a staff meeting, Mr. Rodgers, the vice principal, asks for suggestions for new school programs. Rachel recalls how interested her students are in making videos. They often create short clips to express themselves and make humorous contents. They even use the videos for class assignments or to promote school clubs. However, many of them lack basic editing skills like cutting videos and adding subtitles. It's difficult for them to learn these skills on their own. And the current after-school programs mostly focus only on school subjects such as English, math, and science. Therefore, Rachel wants to ask Mr. Rodgers if the school could offer an after-school program on video editing. In this situation, what would Rachel most likely say to Mr. Rodgers?\nRachel: How about starting an after-school program on video-editing for students?", + "answer_option": "(1)We need to educate students about social media privacy. (2)Can we buy a new camera to film students' school life? (3)I recommend that we open up advanced level classes more. (4)We should add subtitles to videos to help students learn English. (5)How about starting an after-school program on video-editing for students?" + }, + { + "page_number": "158", + "problem_number": "13", + "korean_content": "๋Œ€ํ™”๋ฅผ ๋“ฃ๊ณ , ๋‚จ์ž์˜ ๋งˆ์ง€๋ง‰ ๋ง์— ๋Œ€ํ•œ ์—ฌ์ž์˜ ์‘๋‹ต์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Woman:", + "script": "W: Mr. Davis, do you have a minute?\nM: Sure, Mia. What's up?\nW: Actually, I wanted to talk to you about the new seating arrangement.\nM: What about it?\nW: I'm seated at the back. Is there any way I could move to the front?M: Is there a particular reason you want to sit at the front?\nM: Is there a particular reason you want to sit at the front?\nW: Well... I tend to pay attention more when I'm in the front row.\nM: I'm glad to hear you're interested in the class. But it's not practical to accommodate everyone's preferences, which is why the seats are assigned randomly.\nW: I understand. But students usually dislike the front row.\nWouldn't it be possible to make an exception?\nM: Not really. If you get to choose your seat, it would only be fair for all of the other students to have the same option.\nW: You're right. I'll just do my best to focus from the back.", + "answer_option": "(1)I'm sorry. I won't rearrange the seats anymore. (2)Thank you. I can concentrate better at the back. (3)No problem. It was my choice to get a seat at the front. (4)You're right. I'll just do my best to focus from the back. (5)Of course. I made sure to consider everybody's preferences." + }, + { + "page_number": "159", + "problem_number": "18", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ชฉ์ ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Dear Hansfield Education College\nMy name is Amelia Watson, and I am one of the teachers for Hansfield Community Study Class. Our program provides academic support to underprivileged middle school students who are struggling academically.\nWe help our students overcome their educational challenges and achieve their full potential. However, we are currently facing difficulties due to a shortage of teachers. Therefore, we are reaching out to your respected academic institution for help. We believe your students possess the skills and dedication needed to make a meaningful impact. We would like to request your approval to post the attached Volunteer Teacher Recruitment Notice on your school's web bulletin board. This would greatly help us attract the support we need and provide your students with valuable opportunities to contribute to the community. We look forward to the possibility of collaborating with your institution to support our students.\nSincerely,\nAmelia Watson", + "script": null, + "answer_option": "(1)๋Œ€ํ•™์˜ ์ž…์‹œ ๊ฐ•์‚ฌ ๋ชจ์ง‘์— ์ง€์›ํ•˜๋ ค๊ณ  (2)์ž์›๋ด‰์‚ฌ ํ”„๋กœ๊ทธ๋žจ ์ฐธ์—ฌ ๋‚ ์งœ๋ฅผ ํ™•์ธํ•˜๋ ค๊ณ  (3)์ค‘ํ•™์ƒ์„ ์œ„ํ•œ ํ•™์Šด ๋ฐฉ๋ฒ• ๊ฐ•์—ฐ์„ ์˜๋ขฐํ•˜๋ ค๊ณ  (4)๋Œ€ํ•™ ํƒ๋ฐฉ ํ”„๋กœ๊ทธ๋žจ ์ฐธ์—ฌ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ๋ฌธ์˜ํ•˜๋ ค๊ณ  (5)์ž์›๋ด‰์‚ฌ ๊ต์‚ฌ ๋ชจ์ง‘ ๊ณต๊ณ ์˜ ์›น ๊ฒŒ์‹œ ์Šน์ธ์„ ์š”์ฒญํ•˜๋ ค๊ณ " + }, + { + "page_number": "159", + "problem_number": "16", + "korean_content": "์—ฌ์ž๊ฐ€ ํ•˜๋Š” ๋ง์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": null, + "script": "W: Hello, students. It is a tradition around the world to eat certain foods at the start of the year in the hope of bringing good luck. In various cultures, people consider cooked green vegetables lucky because they resemble money and symbolize economic fortune. In Germany, the preferred vegetable is cabbage. In Italy, lentils are popular because they resemble tiny coins and swell when cooked, symbolizing growing wealth. In the Netherlands, people enjoy Oliebollen, a type of doughnut. Its ring shape symbolizes coming full circle and successfully completing the year. In some countries, eating pork on New Year's Day is considered lucky since pigs are seen as animals that never move backward, always looking ahead for their food. In Hungary, a roasted baby pig with a four-leaf clover in its mouth is considered a symbol of good luck. What foods do you eat to bring in the New Year? Take a few minutes to discuss this with your group members.", + "answer_option": "(1)various foods with religious symbolism (2)superstitions related to food and nutrition (3)popular vegetarian recipes for holiday meals (4)New Year's good luck foods from different cultures (5)tips for planning a budget-friendly New Year's feast" + }, + { + "page_number": "159", + "problem_number": "17", + "korean_content": "์–ธ๊ธ‰๋œ ๋‚˜๋ผ๊ฐ€ ์•„๋‹Œ ๊ฒƒ์€?", + "english_content": null, + "script": "W: Hello, students. It is a tradition around the world to eat certain foods at the start of the year in the hope of bringing good luck. In various cultures, people consider cooked green vegetables lucky because they resemble money and symbolize economic fortune. In Germany, the preferred vegetable is cabbage. In Italy, lentils are popular because they resemble tiny coins and swell when cooked, symbolizing growing wealth. In the Netherlands, people enjoy Oliebollen, a type of doughnut. Its ring shape symbolizes coming full circle and successfully completing the year. In some countries, eating pork on New Year's Day is considered lucky since pigs are seen as animals that never move backward, always looking ahead for their food. In Hungary, a roasted baby pig with a four-leaf clover in its mouth is considered a symbol of good luck. What foods do you eat to bring in the New Year? Take a few minutes to discuss this with your group members.", + "answer_option": "(1)Germany (2)Italy (3)Poland (4)the Netherlands (5)Hungary" + }, + { + "page_number": "160", + "problem_number": "19", + "korean_content": "๋‹ค์Œ ๊ธ€์— ๋“œ๋Ÿฌ๋‚œ Callie์˜ ์‹ฌ๊ฒฝ ๋ณ€ํ™”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Strolling along First Avenue to open her cafe, Callie hummed some carols. The impressive window displays overflowed with red, green, silver, gold, and white. They sparkled with bursts of light, from delicate fairy strands to dazzling snowflake-shaped bulbs. She could feel the festive holiday spirit on her way to work. Her fellow business owners must have eaten a lot of iced sugar cookies to manage all this decorating over the Thanksgiving weekend. Callie suddenly realized her cafe must be the only shop not decked out for the holidays. She intuitively knew something was wrong. She had chosen to spend Thanksgiving with her family and had really enjoyed it, but that put her behind. The First Avenue Business Association required stores to be decorated by the end of November. That gave her three days, which was not plenty of time. Her steps to the cafe quickened. Her mind raced with thoughts of everything she needed to do.", + "script": null, + "answer_option": "(1)urgent -> grateful (2)excited -> confident (3)joyful -> anxious (4)indifferent -> worried (5)determined -> helpless" + }, + { + "page_number": "160", + "problem_number": "20", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ํ•„์ž๊ฐ€ ์ฃผ์žฅํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "In a decent society, all members should have a say about what type of Al is being developed and what services are being offered. The production and implementation of Al must be democratised so that all groups in society are consulted and represented, avoiding exclusion. This element of democracy entails two aspects: everyone is involved and everyone is represented. The latter aspect highlights that when fairness fails, there is a risk of discrimination. The history of Al is full of examples of how technology is being developed by white middle-class men, thereby excluding people of colour and minority communities. Wright, in one of his books, connects democracy and freedom in order to reflect the value of self-determination. In this sense, members of society should be given the possibility to participate meaningfully in decisions that affect their lives. As Al becomes more omnipresent, people should have a say about this. Principles such as fairness, accountability and transparency are key when we want technological development not only to represent the people but also to guarantee control by the people.", + "script": null, + "answer_option": "(1)AI์˜ ๊ฐœ๋ฐœ์€ ๋ชจ๋“  ์ง‘๋‹จ์ด ์ฐธ์—ฌํ•˜๊ณ  ๋ชจ๋“  ์‚ฌ๋žŒ์ด ๋Œ€๋ณ€๋˜๋Š” ๋ฏผ์ฃผ์  ๊ณผ์ •์„ ๊ฑฐ์ฒ˜์•ผ ํ•œ๋‹ค. (2)AI๊ฐ€ ์ฐจ๋ณ„์  ์š”์†Œ๋ฅผ ๊ฐ–์ง€ ์•Š๋„๋ก ๊ฐœ๋ฐœ ๊ณผ์ •์— ๋ฐ์ดํ„ฐ ๋ถ„์„ ์ „๋ฌธ๊ธฐ๋ฅผ ํˆฌ์ž…ํ•ด์•ผ ํ•œ๋‹ค. (3)๋ˆ„๊ตฌ๋‚˜ AI์˜ ๋ฐ์ดํ„ฐ์— ์˜ํ–ฅ์„ ๋ผ์น  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ AI๋ฅผ ์ „์ ์œผ๋กœ ๋ฏฟ์–ด์„œ๋Š” ์•ˆ ๋œ๋‹ค. (4)์ธ๊ฐ„์˜ ์œค๋ฆฌ์  ๊ธฐ์ค€์„ ์ดํ•ดํ•˜๊ณ  ๊ทธ์— ๋”ฐ๋ผ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” AI๋ฅผ ๊ฐœ๋ฐœํ•ด์•ผ ํ•œ๋‹ค. (5)AI์˜ ๊ฐœ๋ฐœ ์ˆ˜์ค€์— ๊ด€ํ•œ ๋…ผ์˜๋Š” ์ „๋ฌธ๊ฐ€์— ์˜ํ•œ ํ•ฉ์˜๊ฐ€ ์„ ํ–‰๋˜์–ด์•ผ ํ•œ๋‹ค." + }, + { + "page_number": "161", + "problem_number": "22", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Beyond a certain point, the use of digital devices correlates with lower learning outcomes. Despite the lack of conclusive evidence on this correlation, it is reasonable to limit time on digital technology, not least to ensure that future generations can still enjoy activities that have been valued by human beings for centuries and which will help them value and continue human heritage and culture into the far future. While the exposure to technology has become a part of current society that education systems cannot ignore, learning activities that do not involve digital technology should remain an important part of children's development and students' formal education. Calibrating the right approach and technology use to the right learners will be key. Teachers should not be expected to be constantly in front of their computer screens analysing data or responding to management or parental requests.", + "script": null, + "answer_option": "(1)์–‘์งˆ์˜ ๊ต์œก ์ฝ˜ํ…์ธ  ๊ฐœ๋ฐœ์ด ๊ต์œก์˜ ๋””์ง€ํ„ธํ™”์— ํ•„์ˆ˜์ ์ด๋‹ค. (2)๋””์ง€ํ„ธ ๊ธฐ๊ธฐ๋‚˜ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ต์œก ํ™œ๋™ ๋˜ํ•œ ์ค‘์š”ํ•˜๋‹ค. (3)๋””์ง€ํ„ธ ๊ธฐ๊ธฐํ‹€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ต์œก ํ™˜๊ฒฝ์˜ ์„ ์ง„ํ™”๊ฐ€ ํ•„์š”ํ•˜๋‹ค. (4)ํ•™์Šต์ž์˜ ๋””์ง€ํ„ธ ๊ธฐ์ˆ  ์ ์‘์„ ๋•๋Š” ๊ต์œก ๊ณผ์ • ๊ฐœ๋ฐœ์ด ์‹œ๊ธ‰ํ•˜๋‹ค. (5)๊ฐœ๋ณ„ ๋งž์ถค ๋œ ํ”ผ๋“œ๋ฐฑ ์ œ๊ณต์ด ๋””์ง€ํ„ธ ๊ธฐ๊ธฐ ํ™œ์šฉ์˜ ํšจ๊ณผ๋ฅผ ๋†’์ธ๋‹ค." + }, + { + "page_number": "161", + "problem_number": "21", + "korean_content": "๋ฐ‘์ค„ ์นœ scratch a prehistoric itch๊ฐ€ ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "The answer to why using social sites is enjoyable and popular has deep behavioral and historical roots. The first is that as primates, humans are inherently social animals. Primate brains appear to have evolved specifically to process social information, to enable primates to function more effectively in groups. Second, one of the main ways humans assess and maintain their positions within social networks is by exchanging information with and about others (i.e., gossip). Through the exchange of gossip, individuals can advertise their status within the group and demonstrate their expertise, trustworthiness, and suitability as an ally. Humans are, in short, built to form networks and to exchange information with others. The third component, media technology, enables literate humans to extend this exchange of information across time and space to include people who are not physically present. The Internet, with its instant, global reach, does this effectively, allowing users to share information with unprecedented ease. But it is not the first technology to have supported such a social-media environment; it is merely the most recent, efficient way that humans have found to ๋ฐ‘์ค„:", + "script": null, + "answer_option": "(1)meet the need to distinguish and express themselves within the group (2)make it easier to get the essentials for survival through social connection (3)fulfill an ancient human need for social connection and information exchange (4)integrate easily with their surroundings to improve their chances of survival (5)satisfy the instinct to dominate the group by signaling their superiority" + }, + { + "page_number": "162", + "problem_number": "23", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "We all play occasionally, and we all know what playing feels like. But when it comes to making theoretical statements about what play is, we fall into silliness. There is little agreement among us, and much ambiguity. Some of the most outstanding scholars of children's play have been concerned by this ambiguity. For example, classical scholar Mihail Spariosu calls play 'amphibolous,' which means it goes in two directions at once and is not clear. Victor Turner, the anthropologist, calls play 'liminal' or 'liminoid,' meaning that it occupies a threshold between reality and unreality, as if, for example, it were on the beach between the land and the sea. Geoffrey Bateson, biologist, suggests that play is a paradox because it both is and is not what it appears to be. Animals at play bite each other playfully, knowing that the playful nip implies a bite, but not what a bite implies. In turn, Richard Schechner, theater scholar, suggests that a playful nip is not only not a bite, it is also not not a bite. That is, it is a positive, the sum of two negatives.", + "script": null, + "answer_option": "(1)the challenge of defining play due to its ambiguity and complexity (2)the psychological effect of play on accepting ambiguity and changes (3)the role of children's play in understanding reality and unreality (4)the various applications of play based on its implications (5)the importance of establishing agreed-upon rules for play" + }, + { + "page_number": "162", + "problem_number": "24", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Nobel Prize-winning economist and philosopher Amartya Sen has examined the nature and importance of freedom and autonomy and the conditions that promote it. In his book Development as Freedom he distinguishes the importance of choice, in and of itself, from the functional role it plays in our lives. He suggests that instead of being obsessed with freedom of choice, we should ask ourselves whether it nourishes us or deprives us, whether it makes us mobile or locks us in, Whether it enhances self-respect or diminishes it, and whether it enables us to participate in our communities or prevents us from doing so. Freedom is essential to self-respect, public participation, mobility, and nourishment, but not all choice enhances freedom. In particular, increased choice among goods and services may contribute little or nothing to the kind of freedom that counts. Indeed, it may impair freedom by taking time and energy we'd be better off devoting to other matters.", + "script": null, + "answer_option": "(1)Do More Choices Contribute to More Freedom? (2)How Can We Promote Self-respect and Autonomy? (3)The Functional Role of Freedom in Public Participation (4)The Right to Choose: The Essence of the Fight for Freedom (5)The Contradictory Nature of Freedom: Deprivation of Choice" + }, + { + "page_number": "163", + "problem_number": "26", + "korean_content": "Mary Kenneth Keller์— ๊ด€ํ•œ ๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "Mary Kenneth Keller was born in Ohio in 1913. At 18, she entered a Roman Catholic religious institute and became a sister. She graduated from DePaul University in 1943 with a bachelor's degree in Mathematical Sciences, which enabled her to teach high school. As a high school math teacher, Keller attended a computer education program at Dartmouth College, where she recognized the potential for computers to promote education. She pursued her Ph.D. at the University of Wisconsin-Madison, and became the first woman in the U.S. to earn a Ph.D. in Computer Science at 51. She founded and directed the computer science department at Clarke University, advocating for women in the field by allowing student parents to bring babies to class and providing nursing facilities. She also helped establish the Association of Small Computer Users in Education, which still promotes uses of technology in education. She died in 1985, leaving a lasting legacy at Clarke University, where the computer lab and a scholarship are named in her honor.", + "script": null, + "answer_option": "(1)18์„ธ์— ๋กœ๋งˆ ๊ฐ€ํ†จ๋ฆญ ์ข…๊ต ์‹œ์„ค์— ๋“ค์–ด๊ฐ€ ์ˆ˜๋…€๊ฐ€ ๋˜์—ˆ๋‹ค. (2)์ˆ˜๋ฆฌ ๊ณผํ•™ ํ•™์œ„๋ฅผ ์ทจ๋“ํ•˜์—ฌ ๊ณ ๋“ฑํ•™๊ต์—์„œ ๊ฐ€๋ฅด์น  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์žˆ๋‹ค. (3)์ปดํ“จํ„ฐ ๊ต์œก ํ”„๋กœ๊ทธ๋žจ์— ์ฐธ์—ฌํ•˜๋ฉด์„œ ์ปดํ“จํ„ฐ๊ฐ€ ๊ต์œก์„ ๋ฐœ์ „์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ์„ ๊นจ๋‹ฌ์žˆ๋‹ค. (4)Clarke University์—์„œ ๋ฏธ๊ตญ ์ตœ์ดˆ์˜ ์—ฌ์„ฑ์œผ๋กœ์„œ ์ปดํ“จํ„ฐ ๊ณผํ•™ ๋ฐ•์‚ฌ ํ•™์œ„๋ฅผ ์ทจ๋“ํ–ˆ๋‹ค. (5)๊ทธ๋…€๋ฅผ ๊ธฐ๋ฆฌ๊ธฐ ์œ„ํ•ด ๋ช…๋ช…๋œ ์ปดํ“จํ„ฐ์‹ค๊ณผ ์žฅํ•™๊ธˆ์ด ์žˆ๋‹ค." + }, + { + "page_number": "163", + "problem_number": "25", + "korean_content": "๋‹ค์Œ ๋„ํ‘œ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "The graph above shows the renewable electricity capacity in gigawatts (GW) by country or region over four time periods; the figures for 2023-2028 are estimates based on data from 2023. (1)All countries or regions show a continuous increase in capacity over time, and the 2023-2028 capacity in each country or region is expected to be more than double that of 2017-2022 except for ASEAN. (2)The EU has the highest capacity across all the time periods, with its capacity increasing by about 50 GW in each period from 2005 to 2022 and by more than 200 GW between 2017-2022 and 2023-2028. (3)The US had a capacity of under 100GW in 2017-2022, but is expected to reach above 300 GW by 2023-2028, about 100 GW less than the EU's projected capacity in the same period. (4)India's 2017-2022 capacity only matched the US's 2011-2016 capacity, but its capacity is projected to far exceed 100 GW for the first time in 2023-2028, which is approximately 200 GW. (5)ASEAN shows the least capacity in each period and is the only region not expected to exceed 100GW by 2028.", + "script": null, + "graph": "" + }, + { + "page_number": "164", + "problem_number": "28", + "korean_content": "Greenville Downtown Beach 2025์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์€?", + "english_content": "Greenville Downtown Beach 2025\n\nGreenville Downtown Beach, which drew more than 600,000 visitors in 2024, is one of Greenville's premier summer festivals. This event offers interactive water play attractions for both tourists and residents, creating a relaxing urban retreat during the hot summer season.\n\nWhen: July 25- August 10, 2025\n\nWhere: Greenville Square\n\nOperating Hours: 10 a.m. -8 p.m.\n\nEntry: Free\n\nWhat's Included:\n- Water park zone with a large 40-meter swimming pool and water slides\n- Resort-style rest zone with sunbeds and parasols\n- Snack zone with food trucks selling a variety of foods from around the world\n\nImportant:\n- Swimwear and a swim cap (baseball caps are acceptable) are required.\n- Aqua shoes are optional.", + "script": null, + "answer_option": "(1)Greenville ์ฃผ๋ฏผ๋งŒ ์นจ์—ฌํ•  ์ˆ˜ ์žˆ๋‹ค. (2)์˜ค์ „ ์‹œ๊ฐ„์—๋Š” ์šด์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค. (3)์œ„ํ„ฐํŒŒํฌ ์กด์—๋Š” ๋‘ ๊ฐœ์˜ ๋Œ€ํ˜• ์ˆ˜์˜์žฅ์ด ์žˆ๋‹ค. (3)ํŒŒ๋ผ์†”์€ ์žˆ์ง€๋งŒ ์„ ๋ฒ ๋“œ๋Š” ์„ค์น˜๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค. (5)์•ผ๊ตฌ ๋ชจ์ž๋ฅผ ์ˆ˜์˜๋ชจ ๋Œ€์‹  ์ฐฉ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.", + "graph": "" + }, + { + "page_number": "164", + "problem_number": "27", + "korean_content": "Window Cleaning์— ๊ด€ํ•œ ๋‹ค์Œ ์•ˆ๋‚ด๋ฌธ์˜ ๋‚ด์šฉ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€?", + "english_content": "Window Cleaning\n\nThe routine exterior window cleaning of ALT Apartments will proceed as follows.\n\nScheduled Cleaning Dates: Monday, October 20th-Friday, October 24th\n\nScope of Work: All exterior windows of apartments will be cleaned.\n\nWorking Hours: 10:00 AM - 5:00 PM\n\nOrder of Cleaning: Starting from Building A to G in alphabetical order\n\nImportant Information:\n- Workers will be using a swing stage along the outside of the building.\n- Keep all windows closed while window cleaning is being done on your building.\n- We recommend blinds and curtains be kept closed for privacy.\n- For some buildings, not all windows may be cleaned on the same day.\n\nNote: These activities are weather dependent, so working days and hours are subject to change.\nIf there is an issue with the quality of cleaning of your apartment window, please contact us at 135-79-1135.", + "script": null, + "answer_option": "(1)10์›” 20์ผ๋ถ€ํ„ฐ 24์ผ๊นŒ์ง€๋กœ ์˜ˆ์ •๋˜์–ด ์žˆ๋‹ค. (2)A๋™๋ถ€ํ„ฐ ์•ŒํŒŒ๋ฒณ ์ˆœ์„œ๋Œ€๋กœ ์ง„ํ–‰๋œ๋‹ค. (3)์‚ฌ์ƒํ™œ ๋ณดํ˜ธ๋ฅผ ์œ„ํ•ด ๋ธ”๋ผ์ธ๋“œ์™€ ์ปคํŠผ์„ ์น  ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค. (4)์•„ํŒŒํŠธ ๋™๋งˆ๋‹ค ๊ทธ ๋™์˜ ์ฐฝ๋ฌธ ์ฒญ์†Œ๋Š” ๊ฐ™์€ ๋‚ ์— ์™„๋ฃŒ๋œ๋‹ค. (5)๋‚ ์”จ๋กœ ์ธํ•ด ์ž‘์—… ์š”์ผ๊ณผ ์‹œ๊ฐ„์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค.", + "graph": "" + }, + { + "page_number": "165", + "problem_number": "29", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘, ์–ด๋ฒ•์ƒ ํ‹€๋ฆฐ ๊ฒƒ์€", + "english_content": "Species that have the power of perception can learn from experience. This increases their ability (1) an effective immediate response and improves the chances of doing things better next time. It also carries the potential to increase distress and anxiety if they learn (2) they cannot cope. Species who demonstrate the property of mental formulation, the ability to create mental pictures (or diagrams) that integrate and interpret complex experiences, sensations, and emotions, are even better equipped to deal with challenges because they do more than recognise the associations between cause and effect; they can understand (3). This gives them the potential to communicate their understanding with others. All species with the power of perception, whether or not they can demonstrate the capacity for mental formulation, (4) the ability to make decisions, based on experience, as to how best to cope with challenge. For all these species, our moral responsibility must extend to provision of a fundamental freedom best (5) as freedom of action to engage in appropriate coping behaviour.", + "script": null + }, + { + "page_number": "165", + "problem_number": "30", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "It's worth it to dive deeper into the idea of optimization in biological evolution. If evolution would eventually produce organisms (1) optimized to their environment, then why do species go extinct? Although there are multiple reasons for extinction of species, one is an (2) to adapt when the environment changes. Say a species of insect has developed a feature that allows it to be the only one to drink the nectar of a certain flower. This strategy is so (3) that the insect consumes nothing else. If that flower dies off because it can't (4) the increasing global temperatures caused by climate change, then that insect species will very likely die off as well. When the environment is stable, being the only one to access a food source is great โ€”you have no competition. But when the environment changes, that optimization becomes a (5).", + "script": null + }, + { + "page_number": "166", + "problem_number": "32", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "At the beginning of the twenty-first century, privacy figures almost obsessively in the media and inhabits an important place in national consciousness. My favorite symptom: I've noticed recently that in upscale hotels the tags that you put on your door to keep the maid from bothering you no longer read 'Do Not Disturb.' Instead, they say 'Privacy Please.' Condensing the force of a negative imperative into a single powerful noun that needs no verb, the new phrase suggests repudiation, rejection of other people, a Greta Garbo stance: I want to be alone. It eliminates the idea of disturbance, some local and limited interference with serenity or pleasure, only to indicate more categorical exclusion of everyone and everything outside the door. The nominally more polite formulation ('Please') in fact conveys greater insistence and a more determined will to be left alone. 'Do Not Disturb' hints a desire for noninterference with some specific activity (sleeping, going through papers) for some limited space of time. 'Privacy Please' imparts a wish for [๋นˆ์นธ]", + "script": null, + "answer_option": "(1)complete silence (2)uninterrupted rest (3)temporary solitude (4)limited disturbance (5)fundamental separation" + }, + { + "page_number": "166", + "problem_number": "31", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Research shows that 72 percent of team members avoid conflict. Too many teams speak critically in separate private conversations. The 'meeting that takes place after the meeting' is a real source of frankness and transparency โ€”but it should happen in the meeting itself. The problem can go as far as the rampant talking behind each other's backs that we were warned about as bad form when we were in the schoolyard, yet is still present in some of the most prestigious corridors of power. Senior leaders who permit back-channel conversation are allowing what our research shows is the most draining behavior of high-performing teams and causes the greatest erosion to shareholder value. Teamship is a shift to a social contract to care enough about each other's success that we withhold nothing from the team that might stand in the way of the best solutions. In our diagnostic, the average team is a 2.4 on a 5-point scale in frankness. Using high-return practices to create psychological safety that allows them to stress-test each other's ideas [๋นˆ์นธ] in service of the mission, teams can reach 4.5 on that 5-point scale for frankness in just six months.", + "script": null, + "answer_option": "(1)ideally (2)openly (3)cautiously (4)optimistically (5)confidentially" + }, + { + "page_number": "167", + "problem_number": "33", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Each individual may have a different reason from any other individual for rereading a given work. You read a C. S. Lewis children's book because of the movie, or because you suddenly noticed it in the bookcase, or because your niece mentioned that she was enjoying the book. You return to Gone with the Wind because some green curtains reminded you of Scarlett O'Hara. The immediate causes, or pretexts, for rereading are infinite โ€” like the possible rewards. Yet those rewards generally [๋นˆ์นธ]. The green curtains will be there every time you return to the novel; the dress Scarlett makes out of them will never change; what your imagination makes of them may shift repeatedly. Those curtains thus illustrate the double promise that rereading holds, of sameness and of difference.", + "script": null, + "answer_option": "(1)derive from the shift in the author's narrative style (2)depend on the unchanged continuity of the storyline (3)cluster around the promise of change or of stability (4)become richer when combined with childhood memories (5)reflect a deep understanding of the historical background" + }, + { + "page_number": "167", + "problem_number": "34", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "Aristotle tells us that 'in matters concerning action and questions of what is beneficial, the agent must consider on each different occasion what\nthe situation demands, just as in medicine and in navigation.' Figuring out what is appropriate in a particular situation rests on moral perception. 'A man of practical wisdom,' argued Aristotle, must 'take cognizance of particulars.' Particular facts are the 'starting points' for our knowledge of 'the goal of action' and, to deliberate and choose well, 'one must have perception of particular facts.' Every day in court, a judge had to sort through a deluge of information about the lives of the defendants and the nature of their misdeeds. To determine motives, to parcel out responsibility, to understand how this crime was different from or similar to others, to determine the future danger to the community โ€” these tasks demanded an ability to pick [๋นˆ์นธ]. These tasks demanded an ability to see the nuance โ€” the gray โ€”of a particular situation, and not simply the black-and-white of the legal and the illegal.", + "script": null, + "answer_option": "(1)actions most likely to be repeated in the future (2)what was significant out of a lot of background noise (3)a path aligned with the general consensus of the public (4)fact patterns marking information hidden from the court (5)whatever cases could serve as references for other cases" + }, + { + "page_number": "168", + "problem_number": "35", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "In the twentieth century, movement moved further from leisure when it moved toward fitness for combat. Of course, the idea wasn't new; soldiers have been battle training for as long as there have been battles (think of Spartan races and Viking workouts). (1)But the push to become fit for battle (hence the term fitness) seems to have reemerged globally when global wars did. (2)Exercises like Pilates have roots in this motivation. (3)During World War I, when German soldier Joseph Pilates was interned at the Isle of Man and needed a way to keep up his battle strength and agility, he found inspiration in the island's cats. (4)They may be known for their naps, but providing daily opportunities for exercise and playtime is essential to the cats' health and mental well-being. (5)After mimicking the cats' stretches and utilizing his hospital bed to intensify them, he succeeded, and taught his eponymous workout to fellow war prisoners to improve their battle 'fitness,' too.", + "script": null + }, + { + "page_number": "168", + "problem_number": "36", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[Newly hatched ducklings must have the ability to make out or tell apart the properties of things they see moving around them. It turns out that ducklings can imprint not just on the first living creature they see moving, but on inanimate things as well.] \n\n (A)If the first moving objects the ducklings see are, for example, a cube and a rectangular prism, they will recognize that the objects have different shapes and will later follow two objects that are different in shape (a pyramid and a cone, for example), but they will ignore two, objects that have the same shape. (B)So, if upon birth the ducklings see two moving red objects, they will later follow two objects of the same color (even if those latter objects are blue, not red), but not two objects of different colors. In this case, the ducklings imprint on the idea of similarity. They also show the ability to discern dissimilarity. (C) Mallard ducklings, for example, can imprint on a pair of moving objects that are similar in shape or color. Specifically, they imprint on the relational concept embodied by the objects.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "169", + "problem_number": "37", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€:[What happens if you don't inoculate yourself against the specific stress you end up facing?] \n\n (A)If, like with the yearly flu vaccine, the doctors and scientists select the wrong influenza viruses and load up the vaccine with a strain that only offers partial immunity to this year's version of the flu, are you out of luck? Destined to get severely sick and possibly die? (B)The adaptive response works better at ensuring safety from a specific virus, but the general response gives you a last line of defense in case of emergency. Within these two responses are a variety of methods to deal with whatever enters our body, even if we've never seen it before. (C)Of course not. You have a backup: your immune system. A healthy and strong immune system can fight many circulating viruses that it has little prior knowledge about or immunity to. Our immune system has both a general response to any foreign invader and an adaptive response of specialized cells tuned toward targeting pathogens.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "169", + "problem_number": "38", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: \n\n Just proposing an amendment to the Constitution requires approval from two-thirds of Congress or a convention proposed by two-thirds of the states, and then ratification requires approval from three-quarters of all states. (1)It's nearly impossible to convince just over half of Congress to keep the government open. (2)And given how hard people fight over parking spots these days, the constitutional convention route seems a bit fraught. (3)In 1982, a sophomore at the University of Texas named Gregory Watson wrote a paper about a long-forgotten amendment originally drafted by James Madison in 1789 that would prevent members of Congress from raising their own salaries without first facing re-election. (4)The amendment never went anywhere, and the paper got a C, but thanks to Greg, it was finally ratified a decade later. (5)Reach for the stars!", + "script": null + }, + { + "page_number": "170", + "problem_number": "39", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„, ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์„ ๊ณ ๋ฅด์‹œ์˜ค.", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: \n\n The sports historian can (as can historians in other areas explore beyond the obvious and add context to the events being described. Let us head south, to the picturesque Adelaide Oval in South Australia, where in 1932 a cricket Test match was played between Australia and England. (1)This was the infamous Bodyline Test match in which, to counter the brilliance of the Australian batsmen, the English bowlers operated a strategy of bowling short-pitched deliveries aimed at the batsmen's bodies. (2)However, it was not just about cricket. (3)The accusation of unsporting behaviour on the part of the English cricket team becomes much more meaningful when it is noted that there was an international economic depression at the time. (4)Many Australians, fearful that imperial preference was being undermined in trade negotiations, thought Britain was not 'playing the game' politically and economically. (5)The Test series became a convenient avenue for unorganized public protest.", + "script": null + }, + { + "page_number": "170", + "problem_number": "40", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์„ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋นˆ์นธ (A), (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Dealing with differences has always been difficult with just two parties, but public figures must deal with constituents, sponsors, and observers. These third parties will hold public figures accountable for their actions. However, many of these constituents et al. did not witness the actual confrontations and negotiations that are central to making policy. When they are present to observe conflict between others, the nature of the conflict changes. The presence of these third parties and any audience increases the likelihood that face issues will dominate, and the social actors will make more dramatic efforts to support their preferred images and attack the images of others. They will become more animated and express more polarized views as communication yields to performance for an audience. Technology diminishes the likelihood that public figures can find a backstage as live coverage and dissemination of their communication has moved from C-SPAN to YouTube. It is difficult to distinguish political drama from governance. Indeed, it has become difficult to distinguish authentic events from staged performances. \n\n => ์š”์•ฝ: The presence of third parties changes the nature of conflicts, prompting public figures to ๋นˆ์นธ (A) their images in order to better appeal to an audience, and technology-driven public disclosure results in ๋นˆ์นธ (B) authenticity.", + "script": null, + "answer_option": "(1)(A): manipulate - (B):valid (2)(A):manipulate - (B):uncertain (3)(A):prioritize - (B):genuine (4)(A):retain - (B):distorted (5)(A):retain - (B):diminished" + }, + { + "page_number": "171", + "problem_number": "41", + "korean_content": "์œ—๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Within the act of creative play, fresh perceptions occur which enable a person to propose a new idea that can be put forward for exploration. As the implications of this idea are unfolded, they are composed or put together with other familiar ideas. Eventually the person supposes that these ideas are (a) ; in other words, he or she makes an assumption or hypothesis and then acts according to the notion that this is the way that things actually are. The movement from propose to compose to suppose (b) everyday actions to be carried out with little or no conscious thought. For example, if you suppose that a road is level, then you are disposed to walk accordingly. After a number of (c) trips, you will be further disposed to take it for granted that the supposition or assumption that the road is level is indeed correct, and you will no longer have to think about this point. However, if some part of the road later turns out to be uneven so that you trip, you will be obliged to (d) your assumption and, through this, a disposition which is no longer appropriate. Taking certain assumptions for granted may be a useful way of freeing the mind to consider other questions, provided it always remains (e) to evidence that the assumption may, at times, be wrong.", + "script": null, + "answer_option": "(1)Human Nature Consistently Questions Established Routines (2)How Can Engaging in Creative Activities Aid Socialization? (3)Habitual Actions Based on Assumptions Are Always Risky (4)The Key Role of Education in Building Scientific Thinking Skills (5)How Assumptions Are Formed and Shape Efficient Automatic Actions" + }, + { + "page_number": "171", + "problem_number": "42", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)~(e) ์ค‘์—์„œ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "Within the act of creative play, fresh perceptions occur which enable a person to propose a new idea that can be put forward for exploration. As the implications of this idea are unfolded, they are composed or put together with other familiar ideas. Eventually the person supposes that these ideas are (a) ; in other words, he or she makes an assumption or hypothesis and then acts according to the notion that this is the way that things actually are. The movement from propose to compose to suppose (b) everyday actions to be carried out with little or no conscious thought. For example, if you suppose that a road is level, then you are disposed to walk accordingly. After a number of (c) trips, you will be further disposed to take it for granted that the supposition or assumption that the road is level is indeed correct, and you will no longer have to think about this point. However, if some part of the road later turns out to be uneven so that you trip, you will be obliged to (d) your assumption and, through this, a disposition which is no longer appropriate. Taking certain assumptions for granted may be a useful way of freeing the mind to consider other questions, provided it always remains (e) to evidence that the assumption may, at times, be wrong.", + "script": null, + "answer_option": "(1)(a) (2)(b) (3)(c) (4)(d) (5)(e)" + }, + { + "page_number": "171", + "problem_number": "43", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ (A)์— ์ด์–ด์งˆ ๋‚ด์šฉ์„ ์ˆœ์„œ์— ๋งž๊ฒŒ ๋ฐฐ์—ดํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "(A)Johan and his son, Eric, were scheduled to perform a violin duet. Johan decided that their normal repertoire was getting monotonous, so he convinced the composer Kevin Smith to write a special violin duet for Johan and Eric. After about two months, Kevin created a masterpiece, Duet for Father and Son. It was dynamic and loaded with tricky rhythms. Johan could usually read a piece of music almost instantly, so he turned to (a) and suggested that they give it a try. (B)About halfway through the first movement, Johan stopped playing. He stood there a few minutes looking at the notes, then he said, 'Wow, this is really hard. Even (b) can't read the notes and rhythms that fast.' Eric responded, 'Well, at least we played it in the same style.' Johan agreed, 'Yes, we were both awful!' And they burst into laughter together. 'Well, let's take an hour or two to practice each part, and then get back together after lunch,' Johan suggested. (C)Eric looked at all the notes and rhythms and said, 'I think (c)need to take a look at this first.' Johan countered with, 'Come on, don't be afraid. We can at least read through this and then fix it later.' Eric typically made a mess of a piece on his first try, but (d) knew his father could always hold it together, so decided to follow his father's lead. Eric suggested, 'Okay, but let's go slow. Our styles need to be identical so the piece sounds nice.' 'Agreed,' said Johan. So Johan and Eric started with the first movement at about 80 percent of the intended speed (D)Later in the afternoon, after lunch, they played through the first movement with a fair approximation of the composer's intent. Johan's part was now almost perfect, but Eric was still fighting (e) way through it. Duet for Father and Son was by far the hardest piece ever written for two violins, and it was designed so that only Johan and Eric could do it justice. Over the next month, they performed the first and third fast movements perfectly and played the second slow movement in style. After another meeting with Kevin, they perfectly realized his intentions for the piece.", + "script": null, + "answer_option": "(1)(B)-(D)-(C) (2)(C)-(B)-(D) (3)(C)-(D)-(B) (4)(D)-(B)-(C) (5)(D)-(C)-(B)" + }, + { + "page_number": "172", + "problem_number": "44", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)~(e) ์ค‘์—์„œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€์ƒ์ด ๋‚˜๋จธ์ง€ ๋„ท๊ณผ ๋‹ค๋ฅธ ๊ฒƒ์€?", + "english_content": "(A)Johan and his son, Eric, were scheduled to perform a violin duet. Johan decided that their normal repertoire was getting monotonous, so he convinced the composer Kevin Smith to write a special violin duet for Johan and Eric. After about two months, Kevin created a masterpiece, Duet for Father and Son. It was dynamic and loaded with tricky rhythms. Johan could usually read a piece of music almost instantly, so he turned to (a) and suggested that they give it a try. (B)About halfway through the first movement, Johan stopped playing. He stood there a few minutes looking at the notes, then he said, 'Wow, this is really hard. Even (b) can't read the notes and rhythms that fast.' Eric responded, 'Well, at least we played it in the same style.' Johan agreed, 'Yes, we were both awful!' And they burst into laughter together. 'Well, let's take an hour or two to practice each part, and then get back together after lunch,' Johan suggested. (C)Eric looked at all the notes and rhythms and said, 'I think (c)need to take a look at this first.' Johan countered with, 'Come on, don't be afraid. We can at least read through this and then fix it later.' Eric typically made a mess of a piece on his first try, but (d) knew his father could always hold it together, so decided to follow his father's lead. Eric suggested, 'Okay, but let's go slow. Our styles need to be identical so the piece sounds nice.' 'Agreed,' said Johan. So Johan and Eric started with the first movement at about 80 percent of the intended speed (D)Later in the afternoon, after lunch, they played through the first movement with a fair approximation of the composer's intent. Johan's part was now almost perfect, but Eric was still fighting (e) way through it. Duet for Father and Son was by far the hardest piece ever written for two violins, and it was designed so that only Johan and Eric could do it justice. Over the next month, they performed the first and third fast movements perfectly and played the second slow movement in style. After another meeting with Kevin, they perfectly realized his intentions for the piece.", + "script": null, + "answer_option": "(1)(a) (2)(b) (3)(c) (4)(d) (5)(3)" + }, + { + "page_number": "172", + "problem_number": "45", + "korean_content": "์œ—๊ธ€์— ๊ด€ํ•œ ๋‚ด์šฉ์œผ๋กœ ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "(A)Johan and his son, Eric, were scheduled to perform a violin duet. Johan decided that their normal repertoire was getting monotonous, so he convinced the composer Kevin Smith to write a special violin duet for Johan and Eric. After about two months, Kevin created a masterpiece, Duet for Father and Son. It was dynamic and loaded with tricky rhythms. Johan could usually read a piece of music almost instantly, so he turned to (a) and suggested that they give it a try. (B)About halfway through the first movement, Johan stopped playing. He stood there a few minutes looking at the notes, then he said, 'Wow, this is really hard. Even (b) can't read the notes and rhythms that fast.' Eric responded, 'Well, at least we played it in the same style.' Johan agreed, 'Yes, we were both awful!' And they burst into laughter together. 'Well, let's take an hour or two to practice each part, and then get back together after lunch,' Johan suggested. (C)Eric looked at all the notes and rhythms and said, 'I think (c)need to take a look at this first.' Johan countered with, 'Come on, don't be afraid. We can at least read through this and then fix it later.' Eric typically made a mess of a piece on his first try, but (d) knew his father could always hold it together, so decided to follow his father's lead. Eric suggested, 'Okay, but let's go slow. Our styles need to be identical so the piece sounds nice.' 'Agreed,' said Johan. So Johan and Eric started with the first movement at about 80 percent of the intended speed (D)Later in the afternoon, after lunch, they played through the first movement with a fair approximation of the composer's intent. Johan's part was now almost perfect, but Eric was still fighting (e) way through it. Duet for Father and Son was by far the hardest piece ever written for two violins, and it was designed so that only Johan and Eric could do it justice. Over the next month, they performed the first and third fast movements perfectly and played the second slow movement in style. After another meeting with Kevin, they perfectly realized his intentions for the piece.", + "script": null, + "answer_option": "(1)Duet for Father and Son์€ ๊นŒ๋‹ค๋กœ์šด ๋ฆฌ๋“ฌ์ด ๊ฐ€๋“ํ–ˆ๋‹ค. (2)ํ•œ๋‘ ์‹œ๊ฐ„ ๊ฐ์ž์˜ ๋ถ€๋ถ„์„ ์—ฐ์Šตํ•œ ํ›„์— ๋‹ค์‹œ ๋ชจ์ด์ž๊ณ  Johan์ด ์ œ์•ˆํ–ˆ๋‹ค. (3)์ฒœ์ฒœํžˆ ์—ฐ์ฃผํ•˜์ž๋Š” Eric์˜ ์ œ์•ˆ์— Johan์€ ๋™์˜ํ•˜์ง€ ์•Š์•˜๋‹ค. (4)์ ์‹ฌ ์‹์‚ฌ ํ›„ ์˜คํ›„์— Johan๊ณผ Eric์€ ์ž‘๊ณก์ž์˜ ์˜๋„์— ๊ทผ์ ‘ํ•˜๊ฒŒ ์ œ1์•…์žฅ์„ ์—ฐ์ฃผํ–ˆ๋‹ค. (5)Duet for Father and Son์€ ๋‘ ๋Œ€์˜ ๋ฐ”์ด์˜ฌ๋ฆฐ์„ ์œ„ํ•ด ์“ฐ์ธ ๊ฐ€์žฅ ์–ด๋ ค์šด ๊ณก์ด์—ˆ๋‹ค." + }, + { + "page_number": "9", + "problem_number": "01", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Conventions are frequently used stylistic techniques or narrative devices typical of (but not necessarily unique to) particular genre traditions. Movies make use of many conventions. Bits of dialogue, musical figures, physical action, and patterns of mise-en-scรจne are all aspects of movies that, repeated from film to film, become established as conventions. In a film musical, for example, narrative progression usually halts for the production numbers as characters break into song and dance accompanied by music that seems suddenly to materialize from nowhere. Where we might find such moments out of place in, say, a gangster film or a horror film, we allow for this artifice in film musicals. According to Bordwell, Staiger, and Thompson, each genre creates its own rules, and the spectator judges any given element in the light of its appropriateness to genre conventions. In other words, conventions function as an implied agreement between makers and consumers to expect certain techniques and devices in certain contexts. Consumers, thus, are crucial to the development of genres over time.", + "script": null, + "answer_option": "(1)์žฅ๋ฅด ์˜ํ™”์˜ ๊ด€์Šต์€ ๊ด€๊ฐ์ด ์˜ํ™”๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์„ ๋•๋Š”๋‹ค. (2)์žฅ๋ฅด ๊ด€์Šต์„ ๊ธฐ๊ณ„์ ์œผ๋กœ ๋‹ต์Šตํ•œ ์˜ํ™”๋Š” ์ง„๋ถ€ํ•˜๊ณ  ์ง€๋ฃจํ•˜๋‹ค. (3)๋ฎค์ง€์ปฌ ์˜ํ™”๋Š” ๋…ํŠนํ•œ ์„œ์‚ฌ ๋ฐฉ์‹๊ณผ ํ˜•์‹์œผ๋กœ ๋Œ€์ค‘์˜ ์ธ๊ธฐ๋ฅผ ์–ป์—ˆ๋‹ค. (4)์˜ํ™”์˜ ์žฅ๋ฅด ๊ด€์Šต์€ ์ œ์ž‘์ž์™€ ๊ด€๊ฐ ์‚ฌ์ด์˜ ๋ฌต์‹œ์  ํ•ฉ์˜์— ๊ทผ๊ฑฐํ•œ๋‹ค. (5)์˜ํ™”์˜ ๊ด€์Šต์€ ์˜ค๋žœ ์„ธ์›” ์†์—์„œ ๋ฐ˜๋ณต๊ณผ ๋ณ€ํ˜•์„ ํ†ตํ•ด ํ˜•์„ฑ๋˜์–ด ์™”๋‹ค." + }, + { + "page_number": "10", + "problem_number": "02", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ํ•„์ž๊ฐ€ ์ฃผ์žฅํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Can you tenderly look at the landscape of your life and lovingly explore its pits and grooves, its highs and lows, without releasing the harsh, hateful, and truly mean voice that lives inside your head? You know that voice all too well. It's the tape that plays over and over that you barely notice but that rules your universe. You are too this, too that, not enough this, not enough that. Can you quiet that voice and find the sweet, loving part of you that has been there for all of your friends, holding the light in the midst of their most devastating failures and worst mistakes? Can you just this once be that for yourself? The process of reinventing yourself and revisioning your life requires not only courage but a deep sense of compassion we don't ordinarily shine on ourselves. It's brave to look at what you've created in every area of your life, and the compassion keeps you from wanting to resist the painful parts. It's the reckoning that launches the dream. And it's a necessary part of the process that can't be shortchanged.", + "script": null, + "answer_option": "(1)ํƒ€์ธ์ด ์ฃผ๋Š” ํ”ผ๋“œ๋ฐฑ์— ๊ท€ ๊ธฐ์šธ์ด๊ณ  ์ž์‹ ์„ ๋Œ๋ณด์•„์•ผ ํ•œ๋‹ค. (2)ํ˜ผ์ž๋งŒ์˜ ์„ฑ์ฐฐ์˜ ์‹œ๊ฐ„์„ ํ†ตํ•ด ์ž์‹ ์— ๋Œ€ํ•ด ๋” ๊นŠ์ด ์ดํ•ดํ•ด์•ผ ํ•œ๋‹ค. (3)์ž์‹ ์— ๋Œ€ํ•œ ๊ฐ๊ด€์  ํ‰๊ฐ€๋ฅผ ๋‚ด๋ฆฌ๋ ค๋ฉด ํƒ€์ธ์˜ ๊ด€์ ์—์„œ ๋ฐ”๋ผ๋ณด์•„์•ผ ํ•œ๋‹ค. (4)์ž์‹ ์— ๋Œ€ํ•œ ๋น„ํŒ์„ ๋ฉˆ์ถ”๊ณ  ์ž๊ธฐ ์—ฐ๋ฏผ์„ ํ†ตํ•ด ์‚ถ์˜ฌ ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. (5)์‚ถ์˜ ์‹คํŒจ์™€ ์‹ค์ˆ˜์— ์ •๋ฉด์œผ๋กœ ๋งž์„œ ์ž๊ธฐ ๋ฐœ์ „์„ ์œ„ํ•œ ์ดˆ์„์œผ๋กœ ์‚ผ์•„์•ผ ํ•œ๋‹ค." + }, + { + "page_number": "11", + "problem_number": "03", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "If success and happiness were more aligned with what you do than who you are being, then it follows that the more work you do and the faster you do it, the more 'success' you will achieve and the faster you will accomplish it. But that simply isn't what happens. Burnout, stress, anxiety, and mental health issues are worse in Western society than previous decades, not better. Despite advances in technology, despite how hard we work, despite the increasing number of hours and overtime we are doing, there is ample research to show that our collective sense of wellbeing is diminishing, not increasing. The world is not a happy place despite all our efforts to the contrary. To follow society's mantra of 'Do more to be more!', then, is no different from following the words of false prophets: you risk submitting yourself to the power of others and enslaving yourself to their whims and desires. Your life is no longer your own.", + "script": null, + "answer_option": "(1)ํ–‰๋ณต์ด ์„ฑ๊ณต์˜ ์ ˆ๋Œ€์ ์ธ ์ฒ™๋„๊ฐ€ ๋  ์ˆ˜๋Š” ์—†๋‹ค. (2)์ผ๊ณผ ์‚ถ์˜ ๊ท ํ˜•์„ ์œ ์ง€ํ•˜์ง€ ๋ชปํ•˜๋ฉด ์ •์‹  ๊ฑด๊ฐ•์„ ํ•ด์นœ๋‹ค. (3)๋” ๋งŽ์ด ์ผํ•˜๋Š” ๊ฒƒ์ด ์„ฑ๊ณต๊ณผ ํ–‰๋ณต์„ ๋ณด์žฅํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค. (4)์„ฑ๊ณตํ•˜๋ ค๋ฉด ์˜ค๋žซ๋™์•ˆ ์ผํ•  ์ˆ˜ ์žˆ๋Š” ์ฒด๋ ฅ์ด ํ•„์ˆ˜์ ์ด๋‹ค. (5)์‚ฌํšŒ์  ๊ธฐ๋Œ€์— ๋ถ€์‘ํ•˜๋ ค๋Š” ๋…ธ๋ ฅ์€ ๋Šฅ๋ฅ  ํ–ฅ์ƒ์„ ๊ฐ€์ ธ์˜จ๋‹ค." + }, + { + "page_number": "12", + "problem_number": "04", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ˆ์„œ ํ•„์ž๊ฐ€ ์ฃผ์žฅํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Just because you have a plan doesn't mean that you can always stick to it. Nevertheless, you still need to have one! You'll be talking with real people who don't necessarily have the same perspective as you. They will have their own agendas, questions that are off-the-wall to you (but fascinating to them), unanticipated confusions, and various personal concerns. They will have their own funds of knowledge. And it's important that you listen for all of these things and respond to them in a genuine way. You don't want your activity to be a performance where the public's contributions are treated like some random humming that ought to be ignored; these contributions are critical to the conversation too, and you will need to let your conversational partners help steer it. So no matter what your plan was when you started, you will need to be flexible and open to different directions once you're actually interacting with people.", + "script": null, + "answer_option": "(1)๊ณ„ํš์„ ์„ธ์šธ ๋•Œ ๋™๊ธฐ ๋ถ€์—ฌ๋ฅผ ์œ„ํ•ด ๋ชฉํ‘œ๋ฅผ ๊ตฌ์ฒดํ™”ํ•ด์•ผ ํ•œ๋‹ค. (2)์ž์‹ ์˜ ๊ฒฌํ•ด๋ฅผ ๋ช…ํ™•ํžˆ ํ‘œํ˜„ํ•˜์—ฌ ์ž์‹ ์ด ์„ธ์šด ๊ณ„ํš์„ ๊ณ ์ˆ˜ํ•ด์•ผ ํ•œ๋‹ค. (3)์‹คํ˜„ ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•˜์—ฌ ๋ˆ„๊ตฌ๋‚˜ ๊ณต๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ณ„ํš์„ ์ œ์•ˆํ•ด์•ผ ํ•œ๋‹ค. (4)์‚ฌ์ „์— ์ „๋ฌธ์ ์ธ ์ง€์‹์„ ์ถฉ๋ถ„ํžˆ ์Šต๋“ํ•˜์—ฌ ๋ฉด๋ฐ€ํ•˜๊ฒŒ ๊ณ„ํš์„ ์ˆ˜๋ฆฝํ•ด์•ผ ํ•œ๋‹ค. (5)์ž์‹ ์˜ ์ƒ๊ฐ๊ณผ ๋‹ค๋ฅธ ๊ด€์ ์„ ์กด์ค‘ํ•˜์—ฌ ๊ณ„ํš์˜ ๋ฐฉํ–ฅ์„ ์œ ์—ฐํ•˜๊ฒŒ ์กฐ์ •ํ•ด์•ผ ํ•œ๋‹ค." + }, + { + "page_number": "13", + "problem_number": "05", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์š”์ง€๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Fiction not only satiates theory of mind but also instructs it. People who read more fiction exhibit enhanced social reasoning, from identifying others' emotions, to adopting their perspective, to empathizing with their situation. Some of the most compelling evidence for this relationship comes from a test called 'Reading the Mind in the Eyes.' Determining what people are thinking just by looking at their eyes can be highly challenging. It's not too difficult to tell whether they are happy or sad, but could you tell if they were suspicious or indecisive? Accusing or irritated? Such differences are detectable, but not everyone is skilled at detecting them. People who read a lot of fiction turn out to be more skilled. They can distinguish romantic signals from gratitude or caution from boredom just from the eyes. Contemplating emotions in fiction appears to improve the detection of these emotions in real life, even though we never see anyone's eyes when reading.", + "script": null, + "answer_option": "(1)๋ˆˆ์€ ์‚ฌ๋žŒ์˜ ๊ฐ์ •์„ ๊ฐ€์žฅ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๋น„์–ธ์–ด์  ์ง€ํ‘œ์ด๋‹ค. (2)์†Œ์„ค ์† ์ธ๋ฌผ์˜ ํ–‰๋™ ๋ฌ˜์‚ฌ๋ฅผ ํ†ตํ•ด ๊ทธ๋“ค์˜ ๊ฐ์ •์„ ์œ ์ถ”ํ•  ์ˆ˜ ์žˆ๋‹ค. (3)๊ณต๊ฐ ๋Šฅ๋ ฅ์„ ํ‚ค์šฐ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์„ ์ง์ ‘ ๊ฒฝํ—˜ํ•ด ๋ด์•ผ ํ•œ๋‹ค. (4)์†Œ์„ค์„ ๋งŽ์ด ์ฝ์œผ๋ฉด ์‹ค์ œ๋กœ ์‚ฌ๋žŒ๋“ค์˜ ๊ฐ์ •์„ ๋” ์ž˜ ํŒŒ์•…ํ•˜๊ฒŒ ๋œ๋‹ค. (5)์‚ฌ๋žŒ๋“ค์˜ ํ‘œ์ •๋งŒ์œผ๋กœ๋Š” ๊ทธ๋“ค์˜ ์‹ค์ œ ๊ฐ์ •์„ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ต๋‹ค." + }, + { + "page_number": "15", + "problem_number": "01", + "korean_content": "๋ฐ‘์ค„ ์นœ We are exercised about exercise.๊ฐ€ ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Our distant ancestors would be puzzled by the way exercise has become commercialized, industrialized, and, above all, medicalized. Although we sometimes exercise for fun, millions of people today pay to exercise to manage their weight, prevent disease, and delay aging and death. Exercise is big business. Walking, jogging, and many other forms of exercise are inherently free, but giant multinational companies persuade us to spend lots of money to work out in special clothes, with special equipment, and in special places like fitness clubs. We also pay money to watch other people exercise, and a handful of us even pay for the privilege of suffering through marathons, ultramarathons, triathlons, and other extreme or potentially dangerous sporting events. For a few thousand dollars, you, too, can run 150 miles across the Sahara Desert. But more than anything else, exercise has become a source of anxiety and confusion because while everyone knows that exercise is good for their health, the majority of us struggle to exercise enough, safely, or enjoyably. ๋ฐ‘์ค„: ", + "script": null, + "answer_option": "(1)Exercise today involves the irony of causing stress in the name of well-being. (2)A lot of research is being done on how to make exercise more enjoyable and safer. (3)Lack of exercise is threatening the physical and mental health of modern individuals. (4)People become increasingly interested in how to age well with a high quality of life. (5)The huge exercise market includes many companies and professionals chasing profits." + }, + { + "page_number": "16", + "problem_number": "02", + "korean_content": "๋ฐ‘์ค„ ์นœ 'I come from an area.'๊ฐ€ ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "People most often speak about the city or the suburban town they live in but rarely about the region. Yet the best way to understand urban growth is to appreciate that it is regional in scale. We might say that we are from Arlington Heights, but we work, shop, attend schools, go to churches, synagogues, or mosques, and pursue recreation in an increasing variety of locations, all within an expanding metropolitan area. Urban texts in the past have addressed this issue, but they do not take it to heart as the central organizing principle of the discussion. In Eric Bogosian's brilliant film Suburbia, actress Parker Posey portrays an L.A. record promoter on tour who grew up in the affluent Southern California suburbs. When asked by a group of small-town teenagers where she is from, she replies, ๋ฐ€์ค„: <'I come from an area.'> We understand that the words city and suburb fail to connect with the more contemporary reality of daily life.", + "script": null, + "answer_option": "(1)I think of my current area as my second hometown because I like it. (2)I consider this area my hometown since my birthplace no longer exists. (3)I can't name a specific place due to many regional influences on my life. (4)I prefer not to mention where I was born because I dislike my birthplace. (5)I am unable to name a birthplace since the boundaries were unclear at my birth." + }, + { + "page_number": "17", + "problem_number": "03", + "korean_content": "๋ฐ‘์ค„ ์นœ catch it์ด ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Throughout your life, you're going to cross paths with a lot of people eager to goad you into conflict or confrontation. There will be times when, despite your best efforts, you may find yourself getting baited into an argument, pulled into a game, or sucked into an agenda. And since we can't always avoid these hot zones, we need to have strategies in place to handle them. How can we manage those specific situations: the daily annoyances and problems that arise at work, school, or with our family and friends? Despite Newton's theory, not every action needs a reaction. Just because someone is demanding your attention doesn't mean you have to give it, especially if that engagement seems emotionally charged. When you decide not to dignify an irrational communication with a response, it's about preserving your personal dignity and mental clarity. Just because someone throws the ball doesn't mean you have to ๋ฐ‘์ค„: ", + "script": null, + "answer_option": "(1)accept an invitation to a social event or gathering willingly (2)understand a complex idea or concept presented by someone (3)interpret someone's opinions and intentions in a distorted way (4)attract someone's attention to a subject that you're interested in (5)get drawn into a conflict or argument that someone has initiated" + }, + { + "page_number": "18", + "problem_number": "04", + "korean_content": "๋ฐ‘์ค„ ์นœ think like a mountain์ด ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "The fierce green fire in the eyes of a dying old wolf reflected something known only to her and the mountain. The hunter, Aldo Leopold, sensed that his own understanding, fewer wolves meant more deer, did not have the wisdom of the wolf and the mountain. In the wolf's eyes, Leopold saw the need to think differently โ€” that human actions and values should acknowledge the interdependence of animals, the environment and humans. Good behaviour, he realised, was that which sustained the integrity, stability and beauty of the land. Leopold was employed to manage the forest, principally for recreational deer hunters, so he set about killing the deer's predators, the wolf and the mountain lion. However, the deer population, no longer held in check by predators (including human hunters), exploded, resulting in severe damage to the forest and the land. As his interests grew to include conservation and ecology, Leopold concluded that the forest feared the deer more than the wolf. As 'only the mountain has lived long enough to listen objectively to the howl of a wolf' we should ๋ฐ‘์ค„: <'think like a mountain'>", + "script": null, + "answer_option": "(1)recognize the intrinsic value of forests and woodlands (2)provide a safe and comfortable environment for wolves (3)control populations of the species threatening biodiversity (4)maintain a tolerant and objective attitude toward each other (5)appreciate the interconnectedness of the elements in an ecosystem" + }, + { + "page_number": "19", + "problem_number": "05", + "korean_content": "๋ฐ‘์ค„ ์นœ it cannot make any software updates without crashing์ด ๋‹ค์Œ ๊ธ€์—์„œ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Dealing with chronic stress that is maladaptive can push us to our limits. When this happens, our brain and body turn on a 'safe mode' of living, or 'low-power mode'. Just like when the battery on your phone is running low, low-power mode saves energy for the most basic functions and lengthens battery life. When you're in this mode of living, your brain reverts to mental heuristics, those shortcuts you're so badly trying to avoid, meaning you repeat old habits you're trying to shake. Decision-making is impaired and your brain will take the route more travelled. Why would you run down a dirt path if you can just drive on the motorway when you're exhausted? When we're living like this, the brain cannot prioritize making habitual and behavioural changes. The hardware that is your brain is working hard to operate and ๋ฐ‘์ค„: ", + "script": null, + "answer_option": "(1)The brain's function breaks down with excessive input. (2)The brain's adaptability is limited to understanding patterns. (3)The brain is unable to handle stress while processing new information. (4)The brain shifts to a low-power mode when making behavioural changes. (5)The brain cannot change our habits under stress as it aims to conserve energy." + } +] \ No newline at end of file diff --git a/ai-service/DB/files/database4_fixed.json b/ai-service/DB/files/database4_fixed.json new file mode 100644 index 0000000..7258c24 --- /dev/null +++ b/ai-service/DB/files/database4_fixed.json @@ -0,0 +1,424 @@ +[ + { + "page_number": "21", + "problem_number": "01", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€", + "english_content": "Social media, mobile Internet, smartphones, QR codes, tablets, mobile apps, virtual fashion and digital shopping windows replace and merge with previous consumption spheres. Consumer activities such as purchasing, comparing and examining goods are increasingly handled through the Internet and mobile digital devices; consumers organize and spread service and product information on social media sites, blogs and forums; and money is spent increasingly on digital items. Furthermore, product searches, decision making and the relationships with physical stores are becoming more intimately dependent on smartphones, tablets and other digital devices. Growing numbers of available recommendation systems and online review platforms have also assumed a prominent role in consumption practices. In their use and co-production of such recommendation systems for books, movies, restaurants, wines, music, electronics, musical instruments and clothes, consumers are relying increasingly on algorithms and artificial intelligence. Taken together, these examples are manifestations of the contemporary ongoing digitalization of consumption that results in the development of new cultures of consumption.", + "script": null, + "answer_option": "(1)widespread use of algorithms in digital and online advertising (2)how digital life has changed the kinds of products people buy (3)the impact of digitalization on contemporary consumer behavior (4)why we buy virtual goods in the digital world with actual currency (5)the effect of digitalization of the market on the decline of offline business" + }, + { + "page_number": "22", + "problem_number": "02", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "When a superior army fails to dominate a weaker enemy, the causes invariably include the unfamiliar terrain and geographical decentralization of the enemy. But that is not the primary characteristic that determines the outcome. The U.S. policy of resettlement on reservation land can be analyzed for each of the tribes to determine how organizational style affects military success. History never simplifies down to singular causes, such as political centralization, but some trends are more evident than others. The more sedentary tribes, who relied on agriculture and were geographically more centralized around fertile locations, were more quickly conquered than the nomadic plains tribes who were widely dispersed. What distinguished the tribes who were more successful against the U.S. military? Political decentralization. Those with strong chieftains were more quickly settled on reservations. The last groups to submit to U.S. military were the most politically decentralized, the Comanche and the Apache.", + "script": null, + "answer_option": "(1)decentralized politics as a key to resisting domination (2)mutual respect essential for effectively implementing a policy (3)multiple historical incidents emerging from a single clear cause (4)the prosperity of tribes accustomed to a settled agricultural lifestyle (5)political decentralization improving the efficiency of local government" + }, + { + "page_number": "23", + "problem_number": "03", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "One of the reasons it is so hard to change careers โ€”or why we change, only to end up in the same boat โ€”is that we can so fully internalize our institutional identities, relying on them to convey our worth and accomplishments to the outside world. Even when we can honestly admit that the external trappings of success โ€” titles, perks, and other markers of status โ€”don't matter much, we can hide from the need for change by telling ourselves how much the company needs us. Like Dan, who postponed vacations and overrode family obligations when the organization needed him, most working adults organize at least some portion of their working lives according to the principle that self-sacrifice is OK when it's for the good of the institution. Since basic assumptions tend to exist in interlocking clusters, what may often appear to be a work-life balance problem, or an inability to free ourselves from unrewarding or overly political working relationships, is in fact our inability to separate our commitment to an organization from being the organization.", + "script": null, + "answer_option": "(1)negative impacts of over-identification with an organization (2)how to enhance employee engagement and organizational loyalty (3)benefits of maintaining a healthy lifestyle and managing boundaries (4)ways to improve job satisfaction through better work-life integration (5)roles of external markers of success in shaping professional identity" + }, + { + "page_number": "24", + "problem_number": "04", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "To make Al systems more human-value aligned, including more respect for privacy, governments are seeking to regulate Al inputs and processes. At the input level, these efforts include strengthening notice and consent regimes and requiring strong data handling safeguards; at the process level, they include rights to explanations and other forms of accountability such as validation studies, bug reports, and so on. But given how useful the outputs of Al systems can be, any desire for control over input or process can quickly lose any sense of priority or urgency for all but the most zealous of privacy advocates. The attraction of Al outputs that are strikingly useful, precise, efficient, accurate, and reliable โ€” contributing to their increasing capture of human time, attention, and trust โ€”often renders attempts to exert control over the inputs or the processes of Al moot. Whether we can introduce human alignment into emergent and evolvable intelligence is a much-debated issue. This has led cautionary experts to argue that, while we are achieving technical progress, Al may move beyond these initial constraints imposed on it to achieve its own best goals.", + "script": null, + "answer_option": "(1)positive aspects of Al in enhancing work productivity (2)the progress of government initiatives in controlling AI (3)misconception about Al's threats to privacy and security (4)biases arising from the integration of human values into Al (5)contexts that undermine efforts to align AI with human values" + }, + { + "page_number": "25", + "problem_number": "05", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ฃผ์ œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Osburn and her colleagues have shown that, contrary to long-held assumptions, Earth's interior is not lifeless. In fact, the majority of the planet's microbes โ€” perhaps more than 90 percent โ€” may live deep underground. These intraterrestrial microbes tend to be quite different from their counterparts on the surface. They are ancient and slow, reproducing infrequently and possibly living for millions of years. They often acquire energy in unusual ways, breathing rock instead of oxygen. And they seem capable of weathering geological disasters that would wipe out most creatures. Like the many tiny organisms in the ocean and atmosphere, the unique microbes within Earth's crust do not simply inhabit their surroundings โ€” they transform them. Subsurface microbes carve vast caverns, concentrate minerals and precious metals, and regulate the global cycling of carbon and nutrients. Microbes may even have helped construct the continents, literally laying the groundwork for all other terrestrial life.", + "script": null, + "answer_option": "(1)survival strategies of microbes under low-nutrient conditions (2)impacts of deep-sea microbes on global mineral and energy resources (3)common misconceptions about microbes thriving in extreme environments (4)metabolic pathways of microbes residing on Earth's crust and their unique features (5)characteristics of subsurface microbes and their role in environmental processes" + }, + { + "page_number": "27", + "problem_number": "01", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "One reason why we are not all sitting in a cold and dark cave right now is that progress makes us happy. Joy often comes from perceiving yourself as moving forward, changing, learning, and evolving. Consider research conducted in London by two neuroscientists, Bastien Blain and Robb Rutledge. They had volunteers report their feelings every few minutes while playing a new game. They found that the volunteers were happiest not when they gained the highest amount of money in the game (although that did make them happy too), but when they learned about the game. Learning contributed more to happiness than money. You habituate to things โ€”a fancy car, a large-screen TV โ€” but you don't habituate to the joy of learning because learning by definition is change. One cannot habituate to change. In Oscar Wilde's Importance of Being Earnest, Ernest Worthing tells his love interest, Gwendolen Fairfax, that she is perfect. She replies, 'Oh! I hope I am not that. It would leave no room for developments, and I intend to develop in many directions.'", + "script": null, + "answer_option": "(1)Why Learning Outweighs Money in Happiness (2)Material Possessions Are the Key to Lasting Joy (3)Finding a Balance in Life: Playing and Learning (4)In Learning. Perfection Is the Enemy of the Good (5)The Comfort Zone: The Ultimate Source of Progress" + }, + { + "page_number": "28", + "problem_number": "02", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Over the course of human history, researchers have discovered that humans' early ancestors were not able to use verbal language. In fact, verbal language likely began with Homo sapiens, although some scholars have noted that bone structures in Neanderthals may have allowed for complex sound to be vocalized. However, primates of all sorts are able to live in community and share the division of labor, including caring for children and sharing food that has been hunted or gathered. How did such interactions occur if verbal language wasn't a part of the lives of our early ancestors? Nonverbal communication like grunts or slight vocalizations was likely the early auditory form of communication, and facial expressions or gestures may have indicated important things like danger or social position or even the presence of spoiled meat. The idea that nonverbal communication came first over the course of our species' evolution is known as phylogenetic primacy, highlighting that our nonhuman ancestors had likely figured out social signaling before humans existed in our current form.", + "script": null, + "answer_option": "(1)Vocal Features as Evolutionary Markers in Ancestral Species (2)Ancestral Social Signals Are a Hidden Window to Ancient Secrets (3)The Mystery of Bone Structures: Uncovering Neanderthal Vocalization (4)Did Social Status Shape Our Ancestors' Nonverbal Communication Patterns? (5)Nonverbal Communication: How Our Ancestors Communicated Before Language" + }, + { + "page_number": "29", + "problem_number": "03", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Why are we so sensitive to negative information and criticism? Well, it seems to have offered a survival advantage for early humans, when the threat of rejection from the tribe could mean death. This left us disproportionately sensitive to threats, even the merely interpersonal threat of looking bad in the eyes of others. Today, many of the interpersonal threats we detect in our day-to-day lives are not truly harmful, but we're hardwired to react, even overreact, to them. We also suffer from what celebrated psychologist Daniel Kahneman called 'loss aversion' โ€” a tendency to overweigh losses (of money, possessions, or even social status) compared to equivalent wins. In one study, participants were given a coffee mug and later offered the chance to sell it. To part with their mug, participants had to be given twice as much in compensation as the amount they were willing to pay to acquire the mug. Irrational, yes. And profoundly human. We don't want to lose; we don't want to fail. The pain of failing, even in simple activities, is more emotionally salient than the pleasure of succeeding.", + "script": null, + "answer_option": "(1)Learning from Wins: A Road to Greater Achievements (2)Long-term Benefits of Being Mindful of Your Reputation (3)How Can We Overcome Our Irrational Fear of Criticism? (4)What Makes Modern People Different from Early Humans (5)Human Nature of Sensitivity to Threats and Fear of Loss" + }, + { + "page_number": "30", + "problem_number": "04", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Discovering what happens in the brain when we are captivated by beautiful objects won't completely solve the question of why the objects are beautiful. To address the why question, we turn to evolutionary psychology. The basic idea of evolutionary psychology is that our mental abilities, like our physical traits, evolved if they enhanced our survival. Our ancestors from a distant past adapted certain behavioral traits to survive tough environments and to choose partners that would give them healthy children. When it comes to beauty in people, certain physical features of faces and bodies advertised a person's health. These features, which were important in choosing a mate tens of thousands of years ago, are what we now regard as beautiful. When it comes to beauty in scenes, some places were more inviting to our hunter-gatherer ancestors wandering around in the distant past. These scenes looked both safe and rich in resources that would help small bands survive a life that was tough, brutish, and a long time ago.", + "script": null, + "answer_option": "(1)Human Perception of Beauty Is All About Survival (2)Cultural Values Define What Is Beautiful and What Is Not (3)Appreciating Beauty: A Gateway to Mental and Physical Well-being (4)The Subjectivity and Ambiguity of Psychology in Evaluating Beauty (5)Being Attractive or Blending In: What Enhances Chances of Survival?" + }, + { + "page_number": "31", + "problem_number": "05", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Obviously, not all habits constitute knowledge because not all habits are acquired with predictive, regulatory, or manipulative intent. In fact, many habits emerge from the casual reinforcement of random associations that are not part of a learning plan. Although agents may not be entirely aware of all the associations between habitual actions and their context of execution, a minimal layer of pragmatic expectations is always attached to habitual behavior. There is no assurance that habits developed unintentionally are advantageous for agents because there is no guarantee that such habits would effectively carry out expert tasks. For example, vices are blind, harmful, and largely compulsive behaviors, often called \"bad habits.\" In sport, we find kinematic and biomechanical inefficiencies, acquired early in development, that become ingrained in such fashion, for example, cyclists who significantly sway their shoulders trying to increase pedalling power rather than minimizing unnecessary upper body movements. Habits do not necessarily support goal-oriented tasks nor are all habits learned for a specific purpose; hence it is correct to state that not all sensorimotor habits convey practical knowledge.", + "script": null, + "answer_option": "(1)How Can Habitual Action Reduce Potential Failures? (2)For Every Routine Behavior There Is an Underlying Cause (3)Habits Formed Beyond Intentionality: A General Lack of Utility (4)Why Purposeful Action Toward Usefulness Creates Good Habits (5)Habits Developed for Handling Tasks with Careful Pre-planning" + }, + { + "page_number": "33", + "problem_number": "01", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ์–ด๋ฒ•์ƒ ํ‹€๋ฆฐ ๊ฒƒ์€?", + "english_content": "One area in which nature exposure is strongly connected to our wellbeing is our stress response. Natural environments decrease stress. Cortisol levels of people living in neighbourhoods with more green space (1) lower than in people in areas with little green space. In fact, as the percentage of green space in neighbourhoods increased, (2) levels of stress decreased. Exposure to nature for thirty minutes over the course of a week reduced blood pressure, and ninety minutes of walking in nature, compared to a walk in an urban environment, (3) activity in brain areas involved with sadness and negative emotions. There is a trickle-down effect of having safe and accessible green space: people are likely to make use of it to move, exercise, and play if it is well maintained and (4) to access. Being able to walk to shops and facilities can reduce social isolation. And (5) safe in your home can help act as a buffer against the stresses and strains of the outside world.", + "script": null + }, + { + "page_number": "34", + "problem_number": "02", + "korean_content": "(A), (B) (C)์˜ ๊ฐ ๋„ค๋ชจ ์•ˆ์—์„œ ์–ด๋ฒ•์— ๋งž๋Š” ํ‘œํ˜„์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "The equal sign (=) in algebraic equations (A)[indicate / indicates] a merely quantitative equivalence between the expressions on either side and therefore tells us nothing about them qualitatively. But similarity is based on formal or qualitative elements inherent to the things being compared and therefore gets at something more specific and fundamental about them. The assumption here is that a circle's being circular, which makes it (B)[similar / similarly] to other circles, matters more than the size of the circle because the circle's qualitative form is what makes it what it is and can be described without reference to magnitude. Indeed, Leibniz viewed the magnitude of geometric figures as somehow less substantial than (C)[its / their] forms. Magnitude is something merely comparative (Leibniz claimed) and can be grasped only by beholding two figures in each other's presence, while the formal, qualitative features are definitionally inherent to each.", + "script": null, + "answer_option": "(1)(A):indicate - (B):similar - (C):its (2)(A):indicate - (B):similarly - (C):their (3)(A):indicates - (B):similar - (C):its (4)(A):indicates - (B):similar - (C):their (5)(A):indicates - (B):similarly - (C):its" + }, + { + "page_number": "35", + "problem_number": "03", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘, ์–ด๋ฒ•์ƒ ํ‹€๋ฆฐ ๊ฒƒ์€?", + "english_content": "As we tell our story to someone else, we hear that familiar story in a perception-changing way. (1) it out of our minds and framing it into words changes the way it feels, sometimes even the way that we understand it. This is emotional work. Sharing difficult news or personal struggles (2) the painful emotions involved to both narrator and listener, making a discussion uncomfortable for both parties in the conversation. The listener may want to comfort or console us, believing that the less we speak of our pain, the less we will suffer. In fact, the opposite is true: the suffering lies within us, waiting (3) to. By offering us their attention, a listener provides the space (4) we can face those issues we alone can wrestle with, within our inner silence; a place to review the components of our distress, understand them better, and find ways to move forward. By listening and allowing the heartache, a compassionate listener helps us to create a container (5) enough to hold it. Often their best contribution is an accepting silence.", + "script": null + }, + { + "page_number": "36", + "problem_number": "04", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ์–ด๋ฒ•์ƒ ํ‹€๋ฆฐ ๊ฒƒ์€?", + "english_content": "Although bacteria were the first inhabitants of the earth, the science dealing with them is a (1) young branch. Invisible to the eye, their discovery was linked to the invention of instruments like the microscope. Although Robert Hooke described the fruiting structure of molds in 1664 using his microscope, the credit for observing and describing the microorganisms in some detail (2) to a Dutchman called Antony van Leeuwenhoek. In 1674, he viewed through his crude microscope a number of materials, such as drops of saliva, water from various sources, blood, and muscle tissues, and (3) a whole range of life forms, like bacteria, red blood cells and muscle cells. So fascinated (4) with these structures that he named them 'dierkens' and wrote a series of letters to the Royal Society of London. His observations along with the diagrams were published by the Royal Society in 1684, (5) these organisms were translated in English as 'wee animalcules.'", + "script": null + }, + { + "page_number": "37", + "problem_number": "05", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ์–ด๋ฒ•์ƒ ํ‹€๋ฆฐ ๊ฒƒ์€?", + "english_content": "Given sufficient exposure and repetition, anyone can learn to improvise in music as successfully as they improvise in life. We are all born with the ability to improvise; the human brain is wired for (1). We deal with many of the challenges in life by improvising in some form or another; it's (2) we cope with the unexpected and is part of being human. It's a natural process โ€” like breathing or walking on uneven ground. Unfortunately, many believe that jazz improvisation is mysterious and only a select few can find their way. This leads to the false belief (3) you either have the ability or you don't. This simply isn't true. Yes, there are teaching methods that make learning jazz (4) as difficult as learning chemistry or physics, but it's not. Regardless of how it might seem, it's just music. Like all music, it takes practice... but that doesn't mean it's difficult. (5) the right way, becoming a jazz musician is a straightforward process.", + "script": null + }, + { + "page_number": "39", + "problem_number": "01", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ๋ฌธ๋ฐฑ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "Sustainable development is one of the goals of post-modern society. The key element to strive for a sustainable society is sustainable well-being. The big challenge is to (1) consumers to move towards more sustainable consumption behaviour. Although consumers generally (2) the desirability of, and even the need for, a more eco-friendly lifestyle, they often do not put their money where their mouth is. A sustainable future is not reached by diminishing 'unsustainability', but by radically changing consumer behaviour. However, it is difficult to change daily routines and consumers' perceptions of sometimes (3) yet environmentally-friendly products. Generally speaking, consumers want attractive, convenient products, thereby often (4) higher consumption levels of energy and materials, and most of the time they find it difficult to change habits. Past behaviour affects future behaviour. For instance, a study of the motivational determinants to adopt electric cars found the strength of habits to be one of the most (5) factors that reduced the willingness to adopt electric mobility.", + "script": null + }, + { + "page_number": "40", + "problem_number": "02", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "How we understand our world is shaped, to a remarkable degree, by people who produce research that tells us how the world works. Yet, social science mostly (1) specific timing. This may be news to you. But most economists, political scientists, and sociologists use quantitative tools that are unable to effectively model exact timing. (2) datasets account for the precise sequence of events. In most quantitative methodologies used by social researchers, such as economists and political scientists, it would be exceedingly (3) to model something like a coup pivoting on a split second, or the notion that sometimes an outcome depends on the precise order of seemingly random events. Instead, (4) measures are used, such as interaction effects โ€” the presence of two variables together, but usually without regard to specific timing. Variables are often just mixed, like a cooking recipe where the order in which the ingredients are added doesn't matter. But most recipes don't work like that, and you'll get unfortunate results if you add flour to a cake after you've baked it, just as you'll get the wrong answers in social research if you pay (5) attention to aspects of timing and sequence.", + "script": null + }, + { + "page_number": "41", + "problem_number": "03", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "The particular allocation of economic resources, like that of other resources, has consequences for productivity and future output. Output is distributed as payments to owners of factors of production and is an important (1) to further production. However, sectors have different inclinations to consume, save, or invest their income. If those that invest their income (2) receive a larger share of output, future production will probably increase. If those sectors that spend all their earnings get more income, aggregate demand is raised and thus investment by others is (3) Some sectors will only hoard income or invest it unproductively. If these sectors are significant in the economy of a developing country, they will (4) economic improvement. If raising gross national product is the statesman's chief concern, he would do well to (5) the allocation of income against such sectors to make the economy more productive. If, however, these sectors are politically important to his regime, no preoccupation with reallocation or GNP growth will be feasible.", + "script": null + }, + { + "page_number": "42", + "problem_number": "04", + "korean_content": "(A, (B), (C)์˜ ๊ฐ ๋„ค๋ชจ ์•ˆ์—์„œ ๋ฌธ๋งฅ์— ๋งž๋Š” ๋‚ฑ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "In his book Caveman Logic, Hank Davis examines the widespread nature of superstitious beliefs and behaviours, and his evolutionary explanation is that interpreting causality on the basis of too little evidence had greater survival prospects than its reverse (i.e., being overly (A)[careless / conservative] in such judgements). Why is this? One answer is simply the value of heuristics: inheriting and being disposed to learn a range of intellectual shortcuts rather than a bias towards the slow analysis of causal relationships seems to have been more adaptively (B)[advantageous / disadvantageous] for our ancestors. Another answer โ€”one that is directly pertinent to superstition โ€” is that feeling in control of situations that we are in fact not in control of is beneficial to us. Several reasons have been suggested for why this is, including the idea that the confidence this inspires, although resulting in some mistakes, also has beneficial side-effects. One of these is being (C)[motivated / disinclined] to put more effort into our endeavours, so that when we can in fact influence outcomes, those outcomes are all the more impressive.", + "script": null, + "answer_option": "(1)(A):careless - (B):advantageous - (C):motivated (2)(A):careless - (B):disadvantageous - (C):disinclined (3)(A):conservative - (B):advantageous - (C):motivated (4)(A):conservative - (B):disadvantageous - (C):motivated (5)(A):conservative - (B):advantageous - (C):disinclined" + }, + { + "page_number": "43", + "problem_number": "05", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋ฐ‘์ค„ ์นœ ๋ถ€๋ถ„ ์ค‘, ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "Perhaps the most important and perhaps the most neglected leadership virtue is hope. One reason why hope is neglected is because of management theories that tell us to look at the (1), to be tough as nails, to be objective, and in other ways to blindly face reality. But facing reality rather than relying on hope means accepting reality as it is. Relying on hope rather than facing reality means working to change reality โ€” hopefully. Leaders can be both hopeful and realistic as long as the possibilities for change remain (2). Being realistic differs from facing reality in important ways. Being realistic means calculating the odds with an eye to optimism, aware of the consequences of fate without being (3) to the inevitability of a situation or circumstance. Why should leaders be hopeful? Because the evidence suggests hope can change events for the (4). It is widely accepted that sick people who are hopeful members of support groups that provide encouragement, prayer, or other forms of targeted social capital get healthier and stay healthier than do sick people who do not have the (5) of this hopeful social capital.", + "script": null + }, + { + "page_number": "45", + "problem_number": "01", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Most collective rituals bond participants to each other and inspire loyalty to the group. Examples are countless, particularly from the ethnographic record but also from historical accounts. People participate in collective rituals in part because they wish to fit in with a group, and even very young children join in with ritualistic behaviors more eagerly when they are fearful of social exclusion. But there are also certain elements of collective ritual that can further strengthen a sense of [๋นˆ์นธ]. One is social synchrony โ€” moving or chanting in time with others creates an illusion of being part of something much larger and stronger. Another is emotional arousal which can help to create personally transformative shared experiences and produce some of the strongest forms of social cohesion known to humankind. Rituals that emphasize common ancestry, such as the funeral rituals of descent groups, can also create a powerful sense of shared essence. And, finally, highly repetitive rituals may help to establish standardized identity markers and unify large populations.", + "script": null, + "answer_option": "(1)pride (2)autonomy (3)belonging (4)inspiration (5)responsibility" + }, + { + "page_number": "46", + "problem_number": "02", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "In a sense, we cannot speak about the infant's needs without considering those of the mother. 'There is no such thing as a baby,' the British pediatrician D. W. Winnicott once said, explaining, 'if you show me a baby, you certainly show me someone else who is caring for the baby ... One sees a 'nursing couple'... The unit is not the individual; the unit is the individual-environment set-up.' Or, in Ashley Montagu's words, 'When a baby is born, a mother is born. There is considerable evidence that at this time, and for months thereafter, her needs for contact exceed those of the infant.' Good thing, too: Were there not built-in physiological and emotional incentives for the ones doing the caregiving, parenthood would be even more of a slog than it already is. Fewer babies would have their survival needs met if fulfilling those needs were not rewarding for parents. With its usual brilliance, our interpersonal-biological makeup dictates that our requirements be [๋นˆ์นธ]", + "script": null, + "answer_option": "(1)mutual (2)distinct (3)realistic (4)adaptive (5)prioritized" + }, + { + "page_number": "47", + "problem_number": "03", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด์นผ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Cultural humility acknowledges one's [๋นˆ์นธ]. The term and concept were developed by doctors Melanie Tervalon and Jann Murray-Garcia in order to address health disparities and institutional inequities in medicine and are now used across industries. Unlike cultural competency, which assumes that learning is finite and masterable, cultural humility recognizes the ongoing nature of this work. While one can never fully understand someone else, they can bring curiosity and a commitment to critical self-reflection and ongoing learning to each interaction. It is about humbly recognizing that there are things one doesn't know and is likely never going to understand about a culture that is not their own, and having this knowledge guide one's thinking, behavior, and actions. This practice encourages us to realize our power, privileges, and prejudices, to be willing to acknowledge we don't have all the answers, and to embrace the complexity and nuance of human dynamics.", + "script": null, + "answer_option": "(1)tendency to resist change (2)failure to reshape traditions (3)bias that cannot be removed (4)inability to know the full story (5)discomfort with unfamiliar cultures" + }, + { + "page_number": "48", + "problem_number": "04", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Our actions influence the way we perceive the world, and the way we perceive the world influences both the way we think about the world and our ability to act within it. When athletes and sportspersons are performing well, they seem to perform effortlessly, but when they are performing badly, their actions seem to be so much harder. A soccer player who has just scored perceives the goal to be bigger than it actually is, making it easier for the player to score again, but a player who repeatedly misses the goal after scoring once perceives it to be smaller and finds it harder to score again. Thus the greater the perceived effort required to achieve any goal, [๋นˆ์นธ]. This general rule applies beyond the playing field: a hill seems steeper when we are tired, or hungry, or when we are carrying a heavy backpack, and a journey to an unfamiliar destination seems so much longer.", + "script": null, + "answer_option": "(1)the closer the goal feels (2)the harder it will be to achieve (3)the greater the outcome will be (4)the less inclined we are to address it (5)the more time we dedicate to the goal" + }, + { + "page_number": "49", + "problem_number": "05", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด์นผ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "What goes unnoticed is that philosophy, rightly understood, has an ancient connection to [๋นˆ์นธ]. For in addition to being a process that examines why some people's ways of thinking about concepts and practices might be more rationally defensible than others (depending on the quality of arguments for and against them), many early thinkers conceived philosophy as 'a deliberative life-practice that brings beauty and happiness to its practitioners'. Indeed, some of history's most renowned philosophers (e.g. Socrates) communicated their teachings and beliefs not through their theoretical writings, but through the critically reflective and purposeful conduct of their admirable lives โ€”through modelling inspiring modes of life (and death) in the pursuit of self-knowledge about and for their own and others' wellbeing. Many contemporary philosophers might scorn the concept of philosophy as the lifelong contemplation and practice of 'artful living'โ€” of virtuous and healthy living for oneself, for the health and happiness of others, and for society as a whole. Yet care for one's self and others was philosophy's primary aim for centuries. It remains an admirable one.", + "script": null, + "answer_option": "(1)a truthful self-awareness (2)issues of health and wellness (3)enlightenment about good and evil (4)the essence of inquiry and knowledge (5)the virtues and morals of being human" + }, + { + "page_number": "51", + "problem_number": "01", + "korean_content": "๋‹ค์Œ ๋นˆ์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Using commerce as an example, we can see [๋นˆ์นธ]: as Piggot explains, 'Prospectors and miners, traders and middlemen, the organization of shipments and caravans, concessions and treaties, the concept of alien peoples and customs in distant lands โ€”all these are involved in the enlargement of social comprehension demanded by the technological step of entering ... a bronze age.' These innovations particularly required that man's ever-present xenophobia be overcome, as it was by new values such as hospitality, protection, and safe passage. For example, Hayek refers to the early Greek custom of the xenos, the guest-friend, who was assured individual admission and protection within an alien territory. He believes that early trade was very much a matter of personal relations between individuals of different communities. As a consequence, the increased opportunities to deal with members of other communities helped break the 'solidarity, common aims and collectivism of the original small groups.'", + "answer_option": "(1)how changes in worldviews and values came about (2)why trade was viewed as distinct from social values (3)how conventional ideas affected business collaboration (4)why commercial development benefited dominant groups (5)which innovations interrupted commerce's social revolution", + "script": null + }, + { + "page_number": "52", + "problem_number": "02", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Suggestions for overcoming bad bedtime habits generally come in the form of establishing rules for better sleep discipline, like avoiding technology before bed. But revenge bedtime procrastinators know the tips and tricks for better sleep and still choose to stay up. As one bedtime procrastinator put it, 'It's a way of revolting against all the obligations that you have. Because, well, my life, and I think the life of most adults, consists of lots and lots of obligations.' These procrastinators are simply reclaiming freedom via one of the only outlets they have. We don't need a reminder to put down our phone before bedtime. We need space to make choices for ourselves. We need to exercise the basic human need to decide our own destiny. If you relate to the bedtime procrastinator, you're not alone. In our survey, 63% of people agreed they sometimes do things that are bad for them just [๋นˆ์นธ]. So, the next time you find yourself scrolling rather than sleeping, realize that part of the reason you're doing so is that you want to feel free to choose.", + "script": null, + "answer_option": "(1)to follow social conventions (2)to please others they're with (3)to feel like they're in control (4)to experience stimulating challenges (5)to be free from the burden of choices" + }, + { + "page_number": "53", + "problem_number": "03", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด์นผ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€", + "english_content": "In praxial terms, sound is deemed to be music according to any personal, social, and cultural functions it serves. Sounds are 'musical' not simply because of their sonic characteristics, but because of the functions people assign them in specific social-cultural situations. Without shared understandings of tonal-rhythmic systems and their socially-related behaviours and uses, music would not be understood as anything more than random sounds. In short, music [๋นˆ์นธ]. The existence and continuance of musical practices depends on human transmission, or various forms of informal and formal education that are also matters of social-musical praxis. Thus, musical values and meanings are not intrinsic, they are not 'fixed-in' sonic forms or captured in notated scores; musical values are socially assigned to sounds according to how sounds are used, experienced, and understood as being 'good for' various purposes in personal and social life. Thus, and far from being strictly individual or 'interior', musical experiences are socially constructed and socially shared phenomena, and musical experiences invariably include many dimensions beyond so-called aesthetic qualities โ€” specific voices, instruments, situations, places, processes, people, and so forth.", + "script": null, + "answer_option": "(1)is made by human beings for other human beings (2)has evolved into a 'context-free art for art' s sake' concept (3)is a matter Of how the brain and auditory nerves respond to sound (4)results from the evolutionary combination of sound-making systems (5)structures environments by manipulating physical spaces with sound" + }, + { + "page_number": "54", + "problem_number": "04", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Many of you will be familiar with the term pathogenesis. We use it quite often in the biomedical sciences to refer to the processes by which a disease develops, including the factors that contribute to its progression. The word comes from the Greek pathos ('suffering', 'disease') and genesis ('origin'). The lesser-known term 'salutogenesis' comes from the Latin salus ('health') and, again, the Greek genesis, and poses the question: how can we move towards greater health? Pathogenesis and salutogenesis are two sides of the same coin. Sadly, much of our modern-day medicine is focused on the pathogenic model: emphasis on all the scary illnesses and diseases that can await us if we don't take good care of ourselves (and sometimes even if we do). It is easier to conceptualise a disease state than a healthy state of an individual. We know that disease is caused by the presence of an insult that can be genetic, environmental, or caused by a decline in normal physiological function, such as during ageing. Health, on the other hand, seems to be more metaphysical โ€” a so-called state of 'wellbeing'. As an absence of disease, [๋นˆ์นธ].", + "script": null, + "answer_option": "(1)fitness allows for greater mobility (2)health becomes somewhat passive (3)physical health is ever more highlighted (4)strength is the body's defense against illness (5)human health no longer depends on medicine" + }, + { + "page_number": "55", + "problem_number": "05", + "korean_content": "๋‹ค์Œ ๋ฐ˜์นธ์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Survivorship bias shows us that we [๋นˆ์นธ] if we fail to consider the wider context. The best known example is from World War II history, when British RAF planes returning from bombing runs in Germany were thought to be the most vulnerable in the areas where they were observed to be hit most often: around the wingtips, rear tail assemblies, and the center of the plane. But that was merely a subset of all the planes sent out; the ones that had failed to return had been fatally hit in the more vital areas of the plane: the engines, cockpit, and fuel tanks. They didn't see those because they never returned. What survived to return was merely hit in less important areas and so to reinforce those areas โ€”as was initially proposed โ€” would have been a tragic error, merely protecting less important parts of the plane while leaving the vital parts exposed. This shows just how easily we can sometimes fool ourselves if we are not more careful in our reasoning.", + "script": null, + "answer_option": "(1)agree with ideas that confirm a previously held belief (2)can focus on invisible data while neglecting visible data (3)are more influenced by the foolish people surrounding us (4)can be fooled by the presence and existence of something (5)are strongly inclined to dismiss strong evidence as ordinary" + }, + { + "page_number": "57", + "problem_number": "01", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "From a competitive perspective, sport enterprises are well advised to invest heavily in their branding strategy. (1)In an increasingly competitive climate built around entertainment and disposable consumerism, sport enterprises must find ways to establish long-term connections with consumers that maintain value beyond a brief transaction. (2)Branding offers the most effective method for cultivating sustainable relationships between brands and their users. (3)In such intense environments where performances can ebb and flow on and off the field, the value inherent in a sport brand is the most resilient and long-lasting form of asset a sport enterprise can possess. (4)Sport enterprises are hiring dedicated psychologists to boost athletes' morale after poor performances, which has been proven effective in enhancing their on-field performance. (5)A strong brand gives its owner a stable foundation of value that can weather poor seasons, new challenges, athletes that come and go, and rough markets.", + "script": null + }, + { + "page_number": "58", + "problem_number": "02", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ˆ์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "Kuhn observed that sometimes anomalies stubbornly resist resolution. Rather than washing away, they pile up, and a few may come to be viewed as especially pressing. As researchers try to fix the problem, counterexamples accumulate. Consequently, the field enters a state of crisis. (1)The typical way out of this quagmire is the development of a fresh start, equipped with a host of novel tools and concepts. (2)As the new framework rapidly establishes itself and makes progress, outdated questions and ideas are set aside and, eventually, they are forgotten. (3)New observations may lead scientists to reassess and reaffirm the value of long-standing theories and hypotheses. (4)When this happens, when an older paradigm is replaced by a newer one, we have what Kuhn calls a scientific revolution. (5)The new paradigm eventually crystallizes into normal science, adopting a consensus-building role, producing fresh anomalies, which eventually trigger a crisis, followed by another revolution, and so on, in a continuous cycle.", + "script": null + }, + { + "page_number": "59", + "problem_number": "03", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ˆ์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "Would not all animals benefit from being smart? (1)For instance, if the common perception that social primates are smarter than social ungulates is true, then we must ask why ungulates did not undergo selection for similar abilities. (2)Considering this issue underscores a fundamental point of evolutionary biology (and one not incorporated into the hypotheses proposed to date), namely that virtually all benefits entail costs of some kind. (3)Among the many costs of cognitive adaptations, perhaps the most prominent one is that the neural tissue underlying the abilities is energetically expensive to grow and maintain. (4)When a neuron is stimulated, it generates an electrical impulse that travels from cell to cell, and nerve impulses to and from the human brain travel as fast as 150-260 miles per hour. (5)Thus, the key to understanding when improved cognition will be selected for is gaining insight into the relative costs and benefits of the ability for the lineage in question.", + "script": null + }, + { + "page_number": "60", + "problem_number": "04", + "korean_content": "๋‹ค์Œ ๊ธ€์—์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "Over time the healthcare industry has grown to favor medical equipment and instruments that are used only once in a hospital, clinic, or patient's home and then discarded. Disposable items were initially developed to advance patient and provider safety. (1)Single-use medical supplies, such as syringes, test kits, and scalpel blades, prevent germs and viruses from spreading from one patient to another and are essential in infection control and reducing hospital bacteria. (2)Disposables โ€” including masks, plastic gloves, and body protection โ€” reduce incidents of infection among healthcare personnel while protecting patients from germs carried by providers on their skin or clothing. (3)Single-use equipment also increases the efficiency of hospital and outpatient physician-patient interactions, which is increasingly important as shortages of healthcare personnel widen. (4)It is critical to choose the right sterilization technique for each medical instrument to ensure that it is completely germ-free and safe to use. (5)By reducing the burden of sterilization and disinfection after each medical intervention, single-use items allow healthcare providers to see more patients and spend more time with them.", + "script": null + }, + { + "page_number": "61", + "problem_number": "05", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ˆ์„œ ์ „์ฒด ํ๋ฆ„๊ณผ ๊ด€๊ณ„ ์—†๋Š” ๋ฌธ์žฅ์€?", + "english_content": "Note that the problem structure of sustainability is not the same as the problem of scarcity, which was central to the sustainability debates in the 1970s. Scarcity is not a good measure for sustainability guidelines because we fail to be interested until the system or resource in question is totally consumed, or nearly so. (1)Scarcity also does not concern itself with how cycles and systems produce the resources, like water, that become scarce. (2)Focusing on scarcity is like mopping up water on the floor without stopping the leak that produces the problem because it is blind to the larger causes. (3)Moreover, unequal access to natural resources in a given society makes them scarce for large segments of the population. (4)In other words, a concern for scarcity simply does not take account of the complexity within which modern societies operate. (5)Still, there is a lot of uncertainty about the concrete boundaries in these systems, and this leaves a lot of contested terrain in the politics of sustainability.", + "script": null + }, + { + "page_number": "63", + "problem_number": "01", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€: [In the United States, individualism is one of our strongest cultural values, and it continues to rise both here and in other countries.] \n\n (A)She found that, over time, individualistic words like me, self, and unique began to appear far more frequently, reflecting our shifting values. The word get quadrupled in use during the course of two hundred years. (B)Another study looked at television shows made for tweens and calculated how often they celebrated specific values. In 1967, personal fame ranked fifteenth out of sixteen of the top values. In 2007, it ranked first out of sixteen. (C)There are clever ways to measure this, like looking at the products that a culture creates. Psychologist Patricia Greenfield conducted a study of more than one and a half million books, starting with those published in 1800 and going all the way up to 2000.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "64", + "problem_number": "02", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€: [While we experience some uncertainty in most interactions, when our level of uncertainty reaches a tipping point, it turns into anxiety. The more uncertain about the other person we feel, the more discomfort we are in.] \n\n (A)Have you heard someone say, 'Ugh! Those first-years (or seniors) are so annoying!' Many try to allay their negative feelings toward members of a perceived out-group by weaving a fictional paradigm that the other person belongs to an inferior culture, and that their own culture is better than the other's culture. (B)Anxiety has a negative impact on a person's willingness to interact with someone from a different culture. And as their anxiety level increases, people become more apt to engage in othering, making others feel they don't belong. (C)Othering could be driven by experiencing more fear of and the desire to avoid 'the other' โ€” anyone who is perceived not to belong to one's group and is therefore relegated to out-group status. It might also be caused by an existing bias favoring in-groups.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "65", + "problem_number": "03", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€: [In 1948, Claude Shannon, an American mathematician and electronics engineer, published a paper called A Mathematical Theory of Communication.] \n\n (A)Eventually, this 'white noise' overwhelms the original message. Shannon's solution was to divide information into the smallest possible chunks, or 'bits' (binary digits). The message is converted into a code made of Os and 1sโ€” every 0 is a low voltage and every 1 is a high voltage. In creating this code, Shannon drew on binary mathematics, the idea that figures can be represented by just Os and 1s, which had been developed by Gottfried Leibniz. (B)This launched the information age by unlocking the mathematics of information and showing how it could be transmitted digitally. At the time, messages could only be transmitted using a continuous, analog signal. The main drawback to this was that waves become weaker the further they travel, and increasing background interference creeps in. (C)Although Shannon was not the first to send information digitally, he fine-tuned the technique. For him, it was not simply about solving technical problems of transmitting information efficiently. By showing that information could be expressed as binary digits, he launched the theory of information.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "66", + "problem_number": "04", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€: [The choice of whether or not to breastfeed exclusively is a completely personal decision for every mother and the role it plays in preventing the development of future allergies is still up for debate, but breastfeeding does appear to be beneficial for the development of the baby's gut microbiome.] \n\n (A)When a mother consumes dairy products, though, this food allergen is passed to her child via her breastmilk. As a result of this phenomenon, breastmilk can trigger cow's milk protein allergies in certain babies. (B)This information is not meant to minimize the benefits of breastfeeding. On the contrary, understanding this possibility can point parents and doctors toward a cow's milk allergy diagnosis if an exclusively breastfed baby is experiencing digestive or skin issues. (C)If mothers decide to breastfeed their children, they should nevertheless be aware of one thing: breastmilk, on its own, does not contain beta-lactoglobulin proteins like those present in cow's milk.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "67", + "problem_number": "05", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ ๋‹ค์Œ์— ์ด์–ด์งˆ ๊ธ€์˜ ์ˆœ์„œ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€", + "english_content": "์ฃผ์–ด์ง„ ๊ธ€: [Cognitive governance means that factual beliefs guide how imagining unfolds. When Kevin imagines lightning hitting a tree, he next imagines the tree bursting into flame.] \n\n (A)If he didn't have these factual beliefs about lightning and trees, his imaginings wouldn't unfold in that fashion. Thus, factual beliefs govern inferential transitions among imaginings (as well as other secondary cognitive attitudes). (B)Otherwise put, the information stored in a person's factual beliefs guides how that person's imaginings unfold; it does the same for other cognitive attitudes. Importantly, imaginings don't do the same for factual beliefs, and this lack of symmetry is a defining contrast. (C)But that imaginative transition - from imagining the lightning strike to imagining the flames โ€” doesn't come from nowhere. Kevin's factual beliefs (that lightning is extremely hot and that trees are wood and hence flammable) guide his imagination from one imagining to the next.", + "script": null, + "answer_option": "(1)(A)-(C)-(B) (2)(B)-(A)-(C) (3)(B)-(C)-(A) (4)(C)-(A)-(B) (5)(C)-(B)-(A)" + }, + { + "page_number": "69", + "problem_number": "01", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„ ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์€?", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: An evolutionary theory supporting the importance of smell implicates retronasal smell in making us human. (1) Richard Wrangham, a professor of Biological Anthropology, argues in Catching Fire: How Cooking Made Us Human that part of what led to an enlarged human brain was the social interaction surrounding the introduction of fire and cooking. (2) Wrangham argues that cooking food not only made food easier to chew and increased its flavor, but also necessitated complex social arrangements for acquiring, storing, protecting, preparing, and consuming food. (3) But even if cooking emerged later, it was still early in human evolution and decisively shaped the future of our species. (4) The neuroscientist Gordon Shepherd has gone on to draw a specific connection between cooked food, sociality, and the sense of smell. (5) Shepherd argues that given the key role retronasal smell plays in creating food flavors, our sense of smell was a significant evolutionary adaptation.", + "script": null + }, + { + "page_number": "70", + "problem_number": "02", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„ ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์€?", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: Documentaries began as a casual experiment in seeing what happened when you pointed a camera at the things around you. They never caught on in cinemas, and were displaced by fiction. (1) For a long time the genre was kept alive by a mixture of corporate and government patronage, with mixed results. (2) Broadcast television saved the form, supplying documentaries with a steady supply of funds and enabling films to reach large audiences. (3) Recently, however, broadcasters have appeared to tire of documentaries. (4) They are shown in cinemas, with fitful results, and they are beginning to carve out a place online. (5) But so much success hasn't resolved the unstable nature of documentary film, far from it; and film-makers still struggle to make good work.", + "script": null + }, + { + "page_number": "71", + "problem_number": "03", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„ ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์€?", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: The difference between groups and teams is about the depth of the interdependency between members. Groups are when people work towards a common goal, interacting with each other to do so. (1) Teams similarly have common goals, but they work intensively with each other to achieve those, with mutual accountability, shared objectives and performance goals and a sense of shared identity. (2) In effective teams, each team member has a defined role and understands the roles of others. (3) Teams are particularly useful in the workplace when there are complex tasks to be completed or when outcomes benefit from diverse inputs. (4) They are also useful when work has interdependent subtasks or when staff would benefit from learning opportunities from each other. (5) However, high-performing teams can work with team members never meeting if they have shared identity and responsibility.", + "script": null + }, + { + "page_number": "72", + "problem_number": "04", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„ ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์€?", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: If a single location epitomizes the region's love of fat, it is the city of Bologna, the birthplace of the notoriously fatty luncheon meat. (1) Locals call it mortadella, and unlike American bologna, this version is dotted with little cubes of white fat. (2) The city of Bologna has its own version of the veal cutlet, which takes the standard breaded and fried cutlet and covers it with ham and melted cheese. (3) In Bologna, it is not unusual to go out for a gran fritto misto, a meal in which every single course, including dessert, is fried - fried lamb, fried chicken, fried mortadella, fried sweetbreads, fried mozzarella cheese balls, fried zucchini, and fried custard. (4) Despite what many non-Italians may believe, it does not contain any garlic or tomatoes or bundles of fresh vegetables and herbs. (5) Its main ingredients are pancetta (cured pork belly), ground beef, beef stock, a small amount of tomato paste, and full-fat milk.", + "script": null + }, + { + "page_number": "73", + "problem_number": "05", + "korean_content": "๊ธ€์˜ ํ๋ฆ„์œผ๋กœ ๋ณด์•„; ์ฃผ์–ด์ง„ ๋ฌธ์žฅ์ด ๋“ค์–ด๊ฐ€๊ธฐ์— ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ณณ์€?", + "english_content": "์ฃผ์–ด์ง„ ๋ฌธ์žฅ: The Sumerians believed that the world was a roughly circular landmass, surrounded on all sides by a huge body of water. (1) They believed that another ocean also lay above their heads, held in place by the solid structure of the sky, which occasionally let some of this water through as rain. (2) Sumerians called their homeland ki-en-gi(-r), which means 'the land of the noble lords'. (3) And that's how the outside world must have looked to them. (4) To their south and west, the desert of Arabia yawned: a rolling sea of sand dunes where no crops could grow, home to nomadic warrior clans. (5) To the north, the rocky Taurus mountains hemmed them in, full of hardy mountain people, while the Zagros mountains of Iran formed the edge of their world to the east.", + "script": null + }, + { + "page_number": "75", + "problem_number": "01", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์˜ฌ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋ฐ˜์นธ (A), (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Empirical studies of auditory imagery have often employed methods in which auditory feedback was deprived. The rationale for this approach lies in the idea that if musicians have access to stable sound representations and auditory imagery, then they may depend less on external acoustic feedback. In a sight-reading study in which different types of feedback were manipulated, pianists did not depend on auditory feedback. Sight-reading performances with the sound of a digital piano switched off did not lead to more errors; thus it was not necessary for them to hear what they actually played. It can be assumed that pianists could vividly imagine and anticipate the sounds during sight-reading. Researcher Finney observed in a related study that manipulations of pitch in auditory feedback interfered with pianists' performance plans and impaired their play. When auditory feedback was completely absent, on the other hand, their imagery skills allowed them to perform without disruptions. The tactile and kinesthetic feedback was evidently more important for pianists to control their performances than the external auditory information. \n\n => Studies show that pianists rely more on feedback from their hands and movements than on ๋นˆ์นธ (A) the actual notes when sight-reading, as they can ๋นˆ์นธ (B) the sounds internally.", + "script": null, + "answer_option": "(1)(A):seeing - (B):control (2)(A):hearing - (B):dismiss (3)(A):seeing - (B):represent (4)(A):hearing - (B):imagine (5)(A):feeling - (B):construct" + }, + { + "page_number": "76", + "problem_number": "02", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์˜ฌ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋ฐ˜์นธ (A), (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "The geographical place where people are born and live, as reported by WHO, helps to establish a relationship between environmental issues and the health of populations. Thus, low- and middle-income countries in the WHO Southeast Asia and Western Pacific regions had the largest environmentally related disease burden in 2012, with a total of 7.3 million deaths, most attributable to indoor and outdoor air pollution. But, at the same time, WHO, with its stakeholders, is working on prevention. They highlight the importance of the health and other sectors needing to work together to reduce the environmental burden of disease, such as reducing traffic congestion and improving public transport networks as important determinants of air pollution. They usually require cooperation with the transport sector and city planners. Because of this, it is important that local governance address environmental health planning. Municipalities are natural leaders of the local environment and health planning. They are often involved in developing the local economy, including transport, tourism and industry, and can play an important role in health planning if they are aware of the potential risks and benefits and are provided with the tools and support they need. \n\n => The WHO emphasizes that one's place of birth and residence is related to ๋นˆ์นธ (A) health risks, and highlights the need for ๋นˆ์นธ (B) efforts across sectors through the planning of local governance to reduce the risks.", + "script": null, + "answer_option": "(1)(A):mental - (B):integrative (2)(A):environmental - (B):physical (3)(A):occupational - (B):strategic (4)(A):environmental - (B):collaborative (5)(A):mental - (B):participatory" + }, + { + "page_number": "77", + "problem_number": "03", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์˜ฌ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋ฐ˜์นธ (A), (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Plato was gravely concerned about the profoundly negative consequences of the great communication revolution of his age: writing. In the Phaedrus, he has Socrates tell the story of a great inventor who has just created the written word, who then presents it as a gift to the Egyptian king. To this, the king replies: 'This discovery of yours will create forgetfulness in the learners' souls, because they will not use their memories; they will trust to the external written characters and not remember of themselves.' By fixating words into text, the truth of the ensouled speech will be reduced to the mere appearance of truth of the characters in the inert page. And, as dead records pile up, living memory will deteriorate. Few people alive today would think that Plato was justified in his criticism of writing. Even ifโ€”as it surely was the case โ€”we lost something irreparably by leaving the mind of the oral tradition behind, the possibilities opened by writing far outstrip any possible downsides it may have. Most of us would surely agree that illiteracy has proven to have much more paralyzing consequences than literacy. \n\n => Plato believed that writing would ๋นˆ์นธ (A) memory and understanding of spoken words, but now the ๋นˆ์นธ (B) of being able to write are considered far greater than any perceived shortcomings.", + "script": null, + "answer_option": "(1)(A):imprint - (B):privileges (2)(A):demage - (B):advantages (3)(A):imprint - (B):potentials (4)(A):demage - (B):responsibilities (5)(A):enhance - (B):implications" + }, + { + "page_number": "78", + "problem_number": "04", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์˜ฌ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋ฐ˜์นธ (A), (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "Many studies of overimitation use puzzle boxes - see-through devices containing a desirable object that can only be obtained by performing certain procedures in sequence, such as unlocking or opening a series of barriers in order to retrieve an object. These boxes can be used to see which sorts of behaviour children copy, and which they don't. Studies of overimitation usually involve a single adult going through a complicated procedure before opening the puzzle box โ€” including weird gestures (such as hand-waving) and obviously unnecessary actions (such as tapping the box with a feather) - before giving the same task to the child. After observing the model performing these sorts of actions, children will typically copy the useless bits as well as the instrumentally sensible ones. Even more bizarrely, it doesn't seem to make any difference if the experimenter explicitly points out that the model will be performing some 'silly' behaviours that have no relevance to opening the box and explicitly advises the children not to bother copying those bits. The children still copy the unnecessary actions regardless. \n\n => Children exhibit overimitation by copying ๋นˆ์นธ (A) actions performed by an adult model when opening puzzle boxes, even when ๋นˆ์นธ (B) told not to try to copy them.", + "script": null, + "answer_option": "(1)(A):random - (B):urgently (2)(A):similar - (B):unclearly (3)(A):irrelevant - (B):directly (4)(A):useful - (B):forcefully (5)(A):tiny - (B):playfully" + }, + { + "page_number": "79", + "problem_number": "05", + "korean_content": "๋‹ค์Œ ๊ธ€์˜ ๋‚ด์šฉ์˜ฌ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์š”์•ฝํ•˜๊ณ ์ž ํ•œ๋‹ค. ๋ฐ˜์นธ (A), (B)์— ๋“ค์–ด๊ฐˆ ๋ง๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "The public's direct experience of the empirical methods of science is widely regarded as responsible for the cultural transformation from the magical and mystical thinking that marked Western medieval thought, to the rationality of modern discourse. Indeed, public accessibility to science may have been the most important contribution of the Renaissance to scientific progress. By the time of Maxwell, Faraday, and Hooke, for example, the public's appetite for science was voracious. Science demonstrations were put on as entertainments in performance halls, and science books sold as quickly as novels. Today, however, we find ourselves in a situation where science is as inaccessible to the public as if it were written in classical Latin. Remarkable new findings are trumpeted in the press, but how they came about, what they may mean beyond a cure or new recreational technology, is rarely part of the story. The result is that the public rightly sees science as a huge fact book, an insurmountable mountain of information recorded in a virtually secret language. \n\n => Science, which was once highly ๋นˆ์นธ (A) to the public, is now seen as a collection of facts in a(n) ๋นˆ์นธ (B) language.", + "script": null, + "answer_option": "(1)(A):engaging - (B):subjective (2)(A):accessible - (B):incomprehensible (3)(A):restricted - (B):explicit (4)(A):credible - (B):unreliable (5)(A):remote - (B):controversial" + }, + { + "page_number": "83", + "problem_number": "01", + "korean_content": "์œ—๊ธ€์˜ ์ œ๋ชฉ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "What time of day do you shower or bathe? When are you most likely to cook your evening meal? Do you have a time of day when you sit down to watch television? Geographers and sociologists have explored why it is that the time of these events (a) for many people. Our lives at home are shaped by social norms, coordination with others and key events โ€” in the language of time geography called 'pacemakers' โ€”that shape when we do common activities. Key pacemakers might be school opening hours, the scheduling of key television programmes, public transport operating hours and so on. While this might seem quite (b), its importance is often overlooked. The fact that we all follow similar domestic routines creates peaks in the demand for energy; providing for this effect is less efficient than if energy demand was the same across the day; therefore, any 'flattening' of such peaks through behaviour change could (c) carbon emissions. Powells and colleagues used geographical theories of time and rhythm to explore which (d) activities are more flexible. They found that practices such as eating an evening meal, which requires coordination with more people and more 'external' forces, are less flexible than activities such as cleaning, which is often done by just one person. They argue that effective interventions to encourage changes in behaviour so that people at home spread their energy use more (e) across the day should therefore be targeted at these solitary practices rather than at more communal activities.", + "script": null, + "answer_option": "(1)How Does Time Shape Our Daily Routines? (2)Daily Life Tasks with the Most Energy Consumption (3)Major External Forces Affecting Our Carbon Footprint (4)Pacemakers: A Common Misunderstanding in Behaviours (5)Causes of Peaks in Energy Demand and How to Manage Them" + }, + { + "page_number": "83", + "problem_number": "02", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)~(e) ์ค‘์—์„œ ๋ฌธ๋งฅ์ƒ ๋‚ฑ๋ง์˜ ์“ฐ์ž„์ด ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "What time of day do you shower or bathe? When are you most likely to cook your evening meal? Do you have a time of day when you sit down to watch television? Geographers and sociologists have explored why it is that the time of these events (a) for many people. Our lives at home are shaped by social norms, coordination with others and key events โ€” in the language of time geography called 'pacemakers' โ€”that shape when we do common activities. Key pacemakers might be school opening hours, the scheduling of key television programmes, public transport operating hours and so on. While this might seem quite (b), its importance is often overlooked. The fact that we all follow similar domestic routines creates peaks in the demand for energy; providing for this effect is less efficient than if energy demand was the same across the day; therefore, any 'flattening' of such peaks through behaviour change could (c) carbon emissions. Powells and colleagues used geographical theories of time and rhythm to explore which (d) activities are more flexible. They found that practices such as eating an evening meal, which requires coordination with more people and more 'external' forces, are less flexible than activities such as cleaning, which is often done by just one person. They argue that effective interventions to encourage changes in behaviour so that people at home spread their energy use more (e) across the day should therefore be targeted at these solitary practices rather than at more communal activities.", + "script": null, + "answer_option": "(1)(a) (2)(b) (3)(c) (4)(d) (5)(e)" + }, + { + "page_number": "85", + "problem_number": "03", + "korean_content": "์ฃผ์–ด์ง„ ๊ธ€ (A)์— ์ด์–ด์งˆ ๋‚ด์šฉ์„ ์ˆœ์„œ์— ๋งž๊ฒŒ ๋ฐฐ์—ดํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ฒƒ์€?", + "english_content": "(A)Michael, a vice president of a mid-sized IT company, was doing quite well and even had an IT consulting business on the side. However, he was no longer feeling as excited or challenged as he once had. As part of a leadership program, his coach, Eddie, asked him to reflect and write a several-page personal vision about the life he dreamed he might have in 10-15 years. Surprisingly, Michael's essay was all about a social advocacy movement in which (a) was involved. He mentioned nothing about his work, his relationships, or himself. \n\n (B)Michael immediately answered that he had helped a group of inner-city teens learn how the computer was a way to a better life, not some nerdy thing. Eddie asked why Michael didn't pursue that further. Michael admitted that if he took a teaching job, he could not afford (b) current lifestyle, which included helping his ex-wife and daughter on a teacher's salary. As a coach, Eddie suggested a compromise. He asked if Michael could spend a half-day a week doing a workshop at a local high school, or a day a month at a community college. \n\n (C)The idea immediately energized Michael. (c) eyes lit up and his energy returned. Within four months, he was teaching special courses at a large, local community college. In subsequent years, he began mentoring programs for 'new-hires' at his company, and then in another company he joined. He was doing his work and pursuing another dimension of his life's dream! This is how coaching with compassion can unlock a person's energy and deep sense of purpose. The coach, Eddie, helped this executive to find (d) true dream and make it happen. \n\n (D)Eddie jokingly said that it was a great vision as long as Michael had a large trust fund. Michael laughed and explained that he had worked his way from a very rough neighborhood, without really knowing what he wanted. Eddie worked with this discontented executive through a dozen reflective exercises, but what (e) kept hearing seemed more like an escape than a dream. Finally, he asked Michael to picture a Friday night, returning home and feeling really good about what he had accomplished. Eddie then asked, 'What happened this week that felt so good?'", + "script": null, + "answer_option": "(1)(B)-(D)-(C) (2)(C)-(B)-(D) (3)(C)-(D)-(B) (4)(D)-(B)-(C) (5)(D)-(C)-(B)" + }, + { + "page_number": "85", + "problem_number": "04", + "korean_content": "๋ฐ‘์ค„ ์นœ (a)-(e) ์ค‘์—์„œ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€์ƒ์ด ๋‚˜๋จธ์ง€ ๋„ท๊ณผ ๋‹ค๋ฅธ ๊ฒƒ์€?", + "english_content": "(A)Michael, a vice president of a mid-sized IT company, was doing quite well and even had an IT consulting business on the side. However, he was no longer feeling as excited or challenged as he once had. As part of a leadership program, his coach, Eddie, asked him to reflect and write a several-page personal vision about the life he dreamed he might have in 10-15 years. Surprisingly, Michael's essay was all about a social advocacy movement in which (a) was involved. He mentioned nothing about his work, his relationships, or himself. \n\n (B)Michael immediately answered that he had helped a group of inner-city teens learn how the computer was a way to a better life, not some nerdy thing. Eddie asked why Michael didn't pursue that further. Michael admitted that if he took a teaching job, he could not afford (b) current lifestyle, which included helping his ex-wife and daughter on a teacher's salary. As a coach, Eddie suggested a compromise. He asked if Michael could spend a half-day a week doing a workshop at a local high school, or a day a month at a community college. \n\n (C)The idea immediately energized Michael. (c) eyes lit up and his energy returned. Within four months, he was teaching special courses at a large, local community college. In subsequent years, he began mentoring programs for 'new-hires' at his company, and then in another company he joined. He was doing his work and pursuing another dimension of his life's dream! This is how coaching with compassion can unlock a person's energy and deep sense of purpose. The coach, Eddie, helped this executive to find (d) true dream and make it happen. \n\n (D)Eddie jokingly said that it was a great vision as long as Michael had a large trust fund. Michael laughed and explained that he had worked his way from a very rough neighborhood, without really knowing what he wanted. Eddie worked with this discontented executive through a dozen reflective exercises, but what (e) kept hearing seemed more like an escape than a dream. Finally, he asked Michael to picture a Friday night, returning home and feeling really good about what he had accomplished. Eddie then asked, 'What happened this week that felt so good?'", + "script": null, + "answer_option": "(1)(a) (2)(b) (3)(c) (4)(d) (5)(e)" + }, + { + "page_number": "85", + "problem_number": "05", + "korean_content": "์œ—๊ธ€์— ๊ด€ํ•œ ๋‚ด์šฉ์œผ๋กœ ์ ์ ˆํ•˜์ง€ ์•Š์€ ๊ฒƒ์€?", + "english_content": "(A)Michael, a vice president of a mid-sized IT company, was doing quite well and even had an IT consulting business on the side. However, he was no longer feeling as excited or challenged as he once had. As part of a leadership program, his coach, Eddie, asked him to reflect and write a several-page personal vision about the life he dreamed he might have in 10-15 years. Surprisingly, Michael's essay was all about a social advocacy movement in which (a) was involved. He mentioned nothing about his work, his relationships, or himself. \n\n (B)Michael immediately answered that he had helped a group of inner-city teens learn how the computer was a way to a better life, not some nerdy thing. Eddie asked why Michael didn't pursue that further. Michael admitted that if he took a teaching job, he could not afford (b) current lifestyle, which included helping his ex-wife and daughter on a teacher's salary. As a coach, Eddie suggested a compromise. He asked if Michael could spend a half-day a week doing a workshop at a local high school, or a day a month at a community college. \n\n (C)The idea immediately energized Michael. (c) eyes lit up and his energy returned. Within four months, he was teaching special courses at a large, local community college. In subsequent years, he began mentoring programs for 'new-hires' at his company, and then in another company he joined. He was doing his work and pursuing another dimension of his life's dream! This is how coaching with compassion can unlock a person's energy and deep sense of purpose. The coach, Eddie, helped this executive to find (d) true dream and make it happen. \n\n (D)Eddie jokingly said that it was a great vision as long as Michael had a large trust fund. Michael laughed and explained that he had worked his way from a very rough neighborhood, without really knowing what he wanted. Eddie worked with this discontented executive through a dozen reflective exercises, but what (e) kept hearing seemed more like an escape than a dream. Finally, he asked Michael to picture a Friday night, returning home and feeling really good about what he had accomplished. Eddie then asked, 'What happened this week that felt so good?'", + "script": null, + "answer_option": "(1)Michael์€ ๋ณธ์—… ์™ธ์—๋„ IT ์ปจ์„คํŒ… ์‚ฌ์—…์„ ์šด์˜ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. (2)Michael์€ ์ž๊ธฐ ์ผ, ์ธ๊ฐ„๊ด€๊ณ„, ๊ทธ๋ฆฌ๊ณ  ์ž์‹ ์— ๊ด€ํ•œ ๊ธ€์„ ์ผ๋‹ค. (3)Eddie๋Š” Michael์—๊ฒŒ ์ง€์—ญ ํ•™๊ต์—์„œ ์œ„ํฌ์ˆ์„ ์ง„ํ–‰ํ•ด ๋ณผ ๊ฒƒ์„ ์ œ์•ˆํ–ˆ๋‹ค. (4)Michael์€ ์˜ฎ๊ฒจ๊ฐ„ ํšŒ์‚ฌ์—์„œ๋„ ์‹ ์ž… ์‚ฌ์›์„ ์œ„ํ•œ ๋ฉ˜ํ† ๋ง ํ”„๋กœ๊ทธ๋žจ์„ ์‹œ์ž‘ํ–ˆ๋‹ค. (5)Eddie๋Š” Michael์—๊ฒŒ ๊ธฐ๋ถ„ ์ข‹๊ฒŒ ๊ท€๊ฐ€ํ–ˆ๋˜ ๊ธˆ์š”์ผ ์ €๋…์„ ์ƒ์ƒํ•ด ๋ณด๋„๋ก ์š”์ฒญํ–ˆ๋‹ค." + } +] \ No newline at end of file diff --git a/ai-service/DB/files/ocr_images.py b/ai-service/DB/files/ocr_images.py new file mode 100644 index 0000000..8f74328 --- /dev/null +++ b/ai-service/DB/files/ocr_images.py @@ -0,0 +1,399 @@ +import os +from dotenv import load_dotenv +import logging +import json +from pathlib import Path +from typing import Dict, List, Optional +import cv2 +import numpy as np +from datetime import datetime + +# EasyOCR +import easyocr + +load_dotenv() + +# ----------------------------------------------------------- +# ๋กœ๊น… ์„ค์ • +# ----------------------------------------------------------- +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +# ----------------------------------------------------------- +# ๋ฉ”์ธ ํŒŒ์ดํ”„๋ผ์ธ ํด๋ž˜์Šค +# ----------------------------------------------------------- +class LLMDBPipelineFromImages: + """์ €์žฅ๋œ ์ด๋ฏธ์ง€ ๊ตฌ์กฐ์—์„œ EasyOCR๋กœ ์ธ์‹ โ†’ JSON ์ €์žฅ""" + + def __init__(self, output_json_path: str = "questions.json"): + """ + Args: + output_json_path: ์ €์žฅํ•  JSON ํŒŒ์ผ ๊ฒฝ๋กœ + """ + # output_json_path๋ฅผ ๋จผ์ € ์„ค์ • + self.output_json_path = output_json_path + + # EasyOCR ์ดˆ๊ธฐํ™” (ํ•œ๊ตญ์–ด + ์˜์–ด) + logger.info("EasyOCR ์ดˆ๊ธฐํ™” ์ค‘...") + self.reader = easyocr.Reader(['ko', 'en'], gpu=True) # GPU ์‚ฌ์šฉ (์—†์œผ๋ฉด ์ž๋™์œผ๋กœ CPU) + + # JSON ํŒŒ์ผ ์ดˆ๊ธฐํ™” + self._init_json_file() + + logger.info("LLMDBPipelineFromImages ์ดˆ๊ธฐํ™” ์™„๋ฃŒ (EasyOCR ์‚ฌ์šฉ)") + + # ------------------------------------------------------- + # JSON ์ €์žฅ + # ------------------------------------------------------- + def _init_json_file(self): + """JSON ํŒŒ์ผ ์ดˆ๊ธฐํ™” (๋นˆ ๋ฐฐ์—ด๋กœ ์ƒ์„ฑ)""" + try: + # ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ + json_path = Path(self.output_json_path) + json_path.parent.mkdir(parents=True, exist_ok=True) + + # ํŒŒ์ผ์ด ์ด๋ฏธ ์žˆ์œผ๋ฉด ๊ฑด๋„ˆ๋›ฐ๊ธฐ + if json_path.exists(): + logger.info(f"๊ธฐ์กด JSON ํŒŒ์ผ ์‚ฌ์šฉ: {self.output_json_path}") + return + + # ์ƒˆ ํŒŒ์ผ ์ƒ์„ฑ + with open(self.output_json_path, 'w', encoding='utf-8') as f: + json.dump([], f, ensure_ascii=False, indent=2) + logger.info(f"JSON ํŒŒ์ผ ์ƒ์„ฑ ์™„๋ฃŒ: {self.output_json_path}") + except Exception as e: + logger.error(f"JSON ํŒŒ์ผ ์ดˆ๊ธฐํ™” ์‹คํŒจ: {e}") + + def save_to_json(self, question: Dict): + """์งˆ๋ฌธ์„ JSON ํŒŒ์ผ์— ์ถ”๊ฐ€""" + try: + # ํŒŒ์ผ์ด ์—†์œผ๋ฉด ๋นˆ ๋ฐฐ์—ด๋กœ ์‹œ์ž‘ + json_path = Path(self.output_json_path) + if json_path.exists(): + with open(self.output_json_path, 'r', encoding='utf-8') as f: + try: + questions_data = json.load(f) + except json.JSONDecodeError: + logger.warning("JSON ํŒŒ์ผ์ด ์†์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.") + questions_data = [] + else: + logger.info("JSON ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.") + questions_data = [] + + # ์ƒˆ๋กœ์šด ์งˆ๋ฌธ ์ถ”๊ฐ€ + questions_data.append(question) + + # ๋””๋ ‰ํ† ๋ฆฌ ํ™•์ธ ๋ฐ ์ƒ์„ฑ + json_path.parent.mkdir(parents=True, exist_ok=True) + + # ํŒŒ์ผ์— ์ €์žฅ + with open(self.output_json_path, 'w', encoding='utf-8') as f: + json.dump(questions_data, f, ensure_ascii=False, indent=2) + + logger.info(f"JSON ์ €์žฅ ์™„๋ฃŒ: ํŽ˜์ด์ง€ {question.get('page_number')} - ๋ฌธ์ œ {question.get('problem_number')}") + except Exception as e: + logger.error(f"JSON ์ €์žฅ ์‹คํŒจ: {e}") + + # ------------------------------------------------------- + # EasyOCR ์œ ํ‹ธ + # ------------------------------------------------------- + def extract_text_with_easyocr(self, image_path: str, lang: str = 'ko') -> str: + """EasyOCR์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฏธ์ง€์—์„œ ํ…์ŠคํŠธ ์ถ”์ถœ + + Args: + image_path: ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ + lang: 'ko' (ํ•œ๊ตญ์–ด) ๋˜๋Š” 'en' (์˜์–ด) - ์ฐธ๊ณ ์šฉ (EasyOCR์€ ๋‘˜ ๋‹ค ์ง€์›) + + Returns: + str: ์ถ”์ถœ๋œ ํ…์ŠคํŠธ + """ + try: + # ์ด๋ฏธ์ง€ ํŒŒ์ผ ์กด์žฌ ํ™•์ธ + if not Path(image_path).exists(): + logger.warning(f"์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค: {image_path}") + return "" + + # EasyOCR readtext ์‹คํ–‰ + # ๊ฒฐ๊ณผ ํ˜•์‹: [([bbox], text, confidence), ...] + result = self.reader.readtext(image_path) + + # ๊ฒฐ๊ณผ์—์„œ ํ…์ŠคํŠธ๋งŒ ์ถ”์ถœ + if result: + texts = [] + for detection in result: + # detection[1]์ด ํ…์ŠคํŠธ, detection[2]๊ฐ€ ์‹ ๋ขฐ๋„ + text = detection[1] + if text: + texts.append(text) + return '\n'.join(texts) + return "" + except Exception as e: + logger.error(f"EasyOCR ์ถ”์ถœ ์‹คํŒจ ({image_path}): {e}") + return "" + + def extract_number_with_easyocr(self, image_path: str) -> str: + """EasyOCR์„ ์‚ฌ์šฉํ•˜์—ฌ ์ˆซ์ž๋งŒ ์ถ”์ถœ + + Args: + image_path: ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ + + Returns: + str: ์ถ”์ถœ๋œ ์ˆซ์ž + """ + try: + text = self.extract_text_with_easyocr(image_path, lang='en') + # ์ˆซ์ž๋งŒ ์ถ”์ถœ + import re + numbers = re.findall(r'\d+', text) + return numbers[0] if numbers else "" + except Exception as e: + logger.error(f"์ˆซ์ž ์ถ”์ถœ ์‹คํŒจ ({image_path}): {e}") + return "" + + # ------------------------------------------------------- + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ + # ------------------------------------------------------- + def get_page_number(self, page_dir: Path) -> Optional[str]: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€์—์„œ ๋ฒˆํ˜ธ ์ถ”์ถœ + + Args: + page_dir: ํŽ˜์ด์ง€ ๋””๋ ‰ํ† ๋ฆฌ (์˜ˆ: output/database_images/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ)-1) + + Returns: + ์ธ์‹๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ + """ + page_numbers_dir = page_dir / "page_numbers" + + # ๋ฐฉ๋ฒ• 1: page_numbers ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ฐพ๊ธฐ + if page_numbers_dir.exists(): + # _page_number.jpg ํŒŒ์ผ ์ฐพ๊ธฐ + page_num_files = list(page_numbers_dir.glob("*_page_number.jpg")) + if page_num_files: + page_num_path = page_num_files[0] + page_number = self.extract_number_with_easyocr(str(page_num_path)) + if page_number: + logger.info(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ (์ด๋ฏธ์ง€): {page_number}") + return page_number + + # ๋ฐฉ๋ฒ• 2: page_numbers ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์—†์œผ๋ฉด ํด๋”๋ช…์—์„œ ์ถ”์ถœ + logger.warning(f"page_numbers ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํด๋”๋ช…์—์„œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ถ”์ถœ ์‹œ๋„: {page_dir.name}") + import re + # ํด๋”๋ช…์—์„œ ์ˆซ์ž ์ฐพ๊ธฐ (์˜ˆ: "ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35" โ†’ "35") + numbers = re.findall(r'\d+', page_dir.name) + if numbers: + # ๋งˆ์ง€๋ง‰ ์ˆซ์ž๋ฅผ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋กœ ์‚ฌ์šฉ + page_number = numbers[-1] + logger.info(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ถ”์ถœ (ํด๋”๋ช…): {page_number}") + return page_number + + logger.error(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {page_dir}") + return None + + # ------------------------------------------------------- + # Section ๋‚ด ๋ฌธ์ œ ์ฒ˜๋ฆฌ + # ------------------------------------------------------- + def process_section(self, section_dir: Path, page_number: str) -> List[Dict]: + """Section ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์˜ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ OCR ์ธ์‹ + + Args: + section_dir: Section ๋””๋ ‰ํ† ๋ฆฌ (์˜ˆ: section00) + page_number: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ + + Returns: + ์ธ์‹๋œ ๋ฌธ์ œ ๋ฆฌ์ŠคํŠธ + """ + results = [] + + # prob_{order}_number.jpg ํŒŒ์ผ๋“ค์„ ์ฐพ์•„์„œ ์ •๋ ฌ + prob_number_files = sorted(section_dir.glob("prob_*_number.jpg")) + + for prob_num_file in prob_number_files: + # prob_{order} ์ถ”์ถœ + prob_order = prob_num_file.stem.split("_")[1] + + logger.info(f" ๋ฌธ์ œ {prob_order} ์ฒ˜๋ฆฌ ์ค‘...") + + result = { + "page_number": page_number, + "problem_number": None, + "korean_content": None, + "english_content": None, + "script": None + } + + # 1. ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ธ์‹ (prob_{order}_number.jpg) + problem_number = self.extract_number_with_easyocr(str(prob_num_file)) + result["problem_number"] = problem_number + logger.info(f" ๋ฌธ์ œ ๋ฒˆํ˜ธ: {problem_number}") + + # 2. ํ•œ๊ตญ์–ด ์ง€๋ฌธ ์ธ์‹ (prob_{order}_korean_content.jpg) + korean_file = section_dir / f"prob_{prob_order}_korean_content.jpg" + if korean_file.exists(): + korean_text = self.extract_text_with_easyocr(str(korean_file), lang='ko') + result["korean_content"] = korean_text + logger.info(f" ํ•œ๊ตญ์–ด ์ง€๋ฌธ: {len(korean_text)}์ž") + else: + logger.info(f" ํ•œ๊ตญ์–ด ์ง€๋ฌธ: ์—†์Œ") + + # 3. ์˜์–ด ์ง€๋ฌธ ์ธ์‹ (prob_{order}_english_content.jpg) + english_file = section_dir / f"prob_{prob_order}_english_content.jpg" + if english_file.exists(): + english_text = self.extract_text_with_easyocr(str(english_file), lang='en') + result["english_content"] = english_text + logger.info(f" ์˜์–ด ์ง€๋ฌธ: {len(english_text)}์ž") + else: + logger.info(f" ์˜์–ด ์ง€๋ฌธ: ์—†์Œ") + + # 4. Script ์ธ์‹ (prob_{order}_script.jpg) + script_file = section_dir / f"prob_{prob_order}_script.jpg" + if script_file.exists(): + # ํ•œ/์˜ ํ˜ผํ•ฉ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ํ•œ๊ตญ์–ด ๋ชจ๋“œ๋กœ ์‹คํ–‰ + script_text = self.extract_text_with_easyocr(str(script_file)) + result["script"] = script_text + logger.info(f" Script: {len(script_text)}์ž") + else: + logger.info(f" Script: ์—†์Œ") + + # 5. Answer option ์ธ์‹ (prob_{order}_answer_option.jpg) - ์„ ํƒ์‚ฌํ•ญ + answer_file = section_dir / f"prob_{prob_order}_answer_option.jpg" + if answer_file.exists(): + # ํ•œ/์˜ ํ˜ผํ•ฉ ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ํ•œ๊ตญ์–ด ๋ชจ๋“œ๋กœ ์‹คํ–‰ + answer_text = self.extract_text_with_easyocr(str(answer_file)) + result["answer_option"] = answer_text + logger.info(f" ์„ ํƒ์ง€: {len(answer_text)}์ž") + + results.append(result) + + return results + + # ------------------------------------------------------- + # ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ + # ------------------------------------------------------- + def process_page(self, page_dir: Path): + """ํ•œ ํŽ˜์ด์ง€ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌ + + Args: + page_dir: ํŽ˜์ด์ง€ ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ (์˜ˆ: output/database_images/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ)-1) + """ + try: + logger.info(f"\n{'='*60}") + logger.info(f"ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ ์‹œ์ž‘: {page_dir.name}") + logger.info(f"{'='*60}") + + # 1. ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ + page_number = self.get_page_number(page_dir) + if not page_number: + logger.error(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {page_dir}") + return + + # 2. ๋ชจ๋“  section ๋””๋ ‰ํ† ๋ฆฌ ์ฐพ๊ธฐ + section_dirs = sorted([d for d in page_dir.iterdir() + if d.is_dir() and d.name.startswith("section")]) + + logger.info(f"Section ๊ฐœ์ˆ˜: {len(section_dirs)}") + + # 3. ๊ฐ section ์ฒ˜๋ฆฌ + total_questions = 0 + for section_dir in section_dirs: + logger.info(f"\n{section_dir.name} ์ฒ˜๋ฆฌ ์ค‘...") + questions = self.process_section(section_dir, page_number) + + # JSON์— ์ €์žฅ + for question in questions: + self.save_to_json(question) + total_questions += 1 + + logger.info(f"\nโœ… ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ ์™„๋ฃŒ: {total_questions}๊ฐœ ๋ฌธ์ œ ์ €์žฅ") + + except Exception as e: + logger.error(f"ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ({page_dir}): {e}", exc_info=True) + + # ------------------------------------------------------- + # ๋‹ค์ค‘ ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ + # ------------------------------------------------------- + def process_all_pages(self, base_dir: str): + """๋ชจ๋“  ํŽ˜์ด์ง€ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌ + + Args: + base_dir: ์ตœ์ƒ์œ„ ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ (์˜ˆ: output/database_images) + """ + logger.info("\n" + "="*60) + logger.info("๋‹ค์ค‘ ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ ์‹œ์ž‘") + logger.info("="*60) + + base_path = Path(base_dir) + if not base_path.exists(): + logger.error(f"๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค: {base_dir}") + return + + # ๋ชจ๋“  ํŽ˜์ด์ง€ ๋””๋ ‰ํ† ๋ฆฌ ์ฐพ๊ธฐ + # database_images/{์ด๋ฏธ์ง€ ํŒŒ์ผ ์ด๋ฆ„}/ ํ˜•ํƒœ์˜ ๋””๋ ‰ํ† ๋ฆฌ๋“ค + page_dirs = [] + for item in sorted(base_path.iterdir()): + if not item.is_dir(): + continue + + # ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด๋ถ€ ํ™•์ธ + has_page_numbers = (item / "page_numbers").exists() + has_sections = any(d.name.startswith("section") for d in item.iterdir() if d.is_dir()) + + if has_page_numbers or has_sections: + page_dirs.append(item) + status = [] + if has_page_numbers: + status.append("page_numbers โœ…") + if has_sections: + section_count = len([d for d in item.iterdir() if d.is_dir() and d.name.startswith("section")]) + status.append(f"sections({section_count}) โœ…") + logger.debug(f"ํŽ˜์ด์ง€ ๋ฐœ๊ฒฌ: {item.name} - {' '.join(status)}") + + logger.info(f"์ด {len(page_dirs)}๊ฐœ ํŽ˜์ด์ง€ ๋ฐœ๊ฒฌ") + + if not page_dirs: + logger.warning(f"ํŽ˜์ด์ง€ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {base_dir}") + logger.info(f"\n์˜ˆ์ƒ ๊ตฌ์กฐ:") + logger.info(f" {base_dir}/") + logger.info(f" โ””โ”€โ”€ {{์ด๋ฏธ์ง€_ํŒŒ์ผ_์ด๋ฆ„}}/") + logger.info(f" โ”œโ”€โ”€ page_numbers/") + logger.info(f" โ”‚ โ””โ”€โ”€ {{์ด๋ฏธ์ง€_ํŒŒ์ผ_์ด๋ฆ„}}_page_number.jpg") + logger.info(f" โ””โ”€โ”€ section00/") + logger.info(f" โ””โ”€โ”€ prob_XX_*.jpg") + return + + # ๊ฐ ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ + total_start_time = datetime.now() + + for idx, page_dir in enumerate(page_dirs, 1): + logger.info(f"\n[{idx}/{len(page_dirs)}] ์ฒ˜๋ฆฌ ์ค‘...") + self.process_page(page_dir) + + total_end_time = datetime.now() + elapsed_time = (total_end_time - total_start_time).total_seconds() + + logger.info("\n" + "="*60) + logger.info("์ „์ฒด ์ฒ˜๋ฆฌ ์™„๋ฃŒ") + logger.info("="*60) + logger.info(f"์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {elapsed_time:.2f}์ดˆ ({elapsed_time/60:.2f}๋ถ„)") + logger.info(f"์ €์žฅ ์œ„์น˜: {self.output_json_path}") + logger.info("="*60) + +# ----------------------------------------------------------- +# ์‹คํ–‰ ์˜ˆ์‹œ +# ----------------------------------------------------------- +if __name__ == "__main__": + import os + + # ๊ฒฝ๋กœ ์„ค์ • + base_dir = "./DB/output/database2" # ํŽ˜์ด์ง€ ๋””๋ ‰ํ† ๋ฆฌ๋“ค์ด ์žˆ๋Š” ์ตœ์ƒ์œ„ ๋””๋ ‰ํ† ๋ฆฌ + output_json_path = "./DB/database2.json" + + # ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ + pipeline = LLMDBPipelineFromImages(output_json_path) + pipeline.process_all_pages(base_dir) + + logger.info("์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ ์™„๋ฃŒ โœ…") + +# ์‹คํ–‰: python -m DB.ocr_images \ No newline at end of file diff --git a/ai-service/README.md b/ai-service/README.md new file mode 100644 index 0000000..858c217 --- /dev/null +++ b/ai-service/README.md @@ -0,0 +1,617 @@ +# ๐ŸŽฏ AI ์ฑ„์  ์„œ๋น„์Šค (Grading Service) + +Kafka ๊ธฐ๋ฐ˜์˜ ์ˆ˜๋Šฅ ์˜์–ด ๋‹ต์•ˆ์ง€ ์ž๋™ ์ฑ„์  ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. + +## ๐Ÿ“‹ ๋ชฉ์ฐจ + +- [๊ฐœ์š”](#๊ฐœ์š”) +- [์‹œ์Šคํ…œ ์š”๊ตฌ์‚ฌํ•ญ](#์‹œ์Šคํ…œ-์š”๊ตฌ์‚ฌํ•ญ) +- [์„ค์น˜](#์„ค์น˜) +- [์„ค์ •](#์„ค์ •) +- [์‹คํ–‰](#์‹คํ–‰) +- [API ๋ช…์„ธ](#api-๋ช…์„ธ) +- [Kafka ๋ฉ”์‹œ์ง€ ํ˜•์‹](#kafka-๋ฉ”์‹œ์ง€-ํ˜•์‹) +- [ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ](#ํ”„๋กœ์ ํŠธ-๊ตฌ์กฐ) +- [ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…](#ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…) + +--- + +## ๊ฐœ์š” + +### ์ฃผ์š” ๊ธฐ๋Šฅ + +- ๐Ÿ“ท ๋‹ต์•ˆ์ง€ ์ด๋ฏธ์ง€์—์„œ ํ•™์ƒ ๋‹ต์•ˆ ์ž๋™ ์ธ์‹ (YOLO + ResNet) +- โœ… ์ •๋‹ต ๋Œ€์กฐ ๋ฐ ์ž๋™ ์ฑ„์  +- ๐Ÿ“ ์˜ค๋‹ต์— ๋Œ€ํ•œ LLM ๊ธฐ๋ฐ˜ ํ•ด์„ค ์ƒ์„ฑ +- ๐Ÿ”„ Kafka๋ฅผ ํ†ตํ•œ ๋น„๋™๊ธฐ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ + +### ์•„ํ‚คํ…์ฒ˜ + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Backend โ”‚ โ”€โ”€ s3-download-url โ”€โ”€โ–ถ โ”‚ AI Server โ”‚ +โ”‚ Server โ”‚ โ—€โ”€โ”€ grading-status โ”€โ”€ โ”‚ (FastAPI) โ”‚ +โ”‚ โ”‚ โ—€โ”€โ”€ student-answer โ”€โ”€ โ”‚ โ”‚ +โ”‚ โ”‚ โ—€โ”€โ”€ answer-explanation โ”‚ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ โ”‚ + โ–ผ โ–ผ + โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” + โ”‚ S3 โ”‚ โ”‚ Kafka โ”‚ + โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +--- + +## ์‹œ์Šคํ…œ ์š”๊ตฌ์‚ฌํ•ญ + +### ํ•˜๋“œ์›จ์–ด +- GPU: NVIDIA GPU (CUDA ์ง€์›, ์ตœ์†Œ 8GB VRAM ๊ถŒ์žฅ) +- RAM: 16GB ์ด์ƒ +- Storage: 20GB ์ด์ƒ + +### ์†Œํ”„ํŠธ์›จ์–ด +- Python 3.10+ +- CUDA 12.x +- Kafka ์„œ๋ฒ„ + +--- + +## ์„ค์น˜ + +### 1. ์ €์žฅ์†Œ ํด๋ก  + +```bash +git clone -b feature/recognition https://github.com/Downy-newlearner/Gradi_25Fall.git +cd Gradi_25Fall +``` + +### 2. ๊ฐ€์ƒํ™˜๊ฒฝ ์ƒ์„ฑ + +```bash +python -m venv venv +source venv/bin/activate # Linux/Mac +# ๋˜๋Š” +venv\Scripts\activate # Windows +``` + +### 3. ํŒจํ‚ค์ง€ ์„ค์น˜ + +```bash +pip install -r requirements.txt +``` + +### ํ•„์ˆ˜ ํŒจํ‚ค์ง€ (requirements.txt) + +```txt +# Web Framework & API +fastapi>=0.100.0 +uvicorn>=0.20.0 +pydantic>=2.0.0 + +# Kafka +aiokafka>=0.8.0 + +# Async HTTP +aiohttp>=3.8.0 + +# OpenAI (LLM) +openai>=1.0.0 + +# Computer Vision & Deep Learning +torch>=2.0.0 +torchvision>=0.15.0 +ultralytics>=8.0.0 +opencv-python>=4.8.0 +pillow>=10.0.0 + +# OCR +easyocr>=1.7.0 + +# Data Processing +numpy>=1.24.0 +pandas>=2.0.0 + +# Utilities +python-dotenv>=1.0.0 +PyYAML>=6.0 +tqdm>=4.65.0 +requests>=2.28.0 +``` + +--- + +## ์„ค์ • + +### ํ™˜๊ฒฝ ๋ณ€์ˆ˜ (.env) + +ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— `.env` ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค: + +```env +# Kafka ์„ค์ • +KAFKA_BOOTSTRAP_SERVERS=3.34.214.133:9092 + +# ๋ชจ๋ธ ๊ฒฝ๋กœ +MODEL_DIR_1104=./models/Detection/legacy/Model_routing_1104 +MODEL_DIR_1004=./models/Detection/legacy/Model_routing_1004 +RESNET_ANSWER_1_PATH=./models/Recognition/models/answer_1_resnet.pth +RESNET_ANSWER_2_PATH=./models/Recognition/models/answer_2_resnet.pth + +# ๋ฐ์ดํ„ฐ ๊ฒฝ๋กœ +ANSWER_KEY_PATH=./DB/answer.txt +CHAPTER_FILE_PATH=./DB/chapter.txt + +# ๊ธฐํƒ€ ์„ค์ • +SECTION_PADDING=50 +ENABLE_LLM_EXPLANATION=true + +# LLM API (Upstage Solar) +UPSTAGE_API_KEY=your_api_key_here +``` + +### ๋ฐ์ดํ„ฐ ํŒŒ์ผ + +#### DB/answer.txt (์ •๋‹ต ํŒŒ์ผ) +``` +102, 40, 3 +102, 41, 4 +102, 42, 2 +103, 43, 1 +103, 44, 5 +``` + +#### DB/chapter.txt (์ฑ•ํ„ฐ ๋งคํ•‘) +``` +001, 9, 13 +002, 15, 19 +003, 21, 25 +``` + +--- + +## ์‹คํ–‰ + +### ์„œ๋ฒ„ ์‹œ์ž‘ + +```bash +python main.py +``` + +### ์‹คํ–‰ ํ™•์ธ + +```bash +# ๊ธฐ๋ณธ ์ƒํƒœ ํ™•์ธ +curl http://localhost:8000/ + +# ์ƒ์„ธ ์ƒํƒœ ํ™•์ธ +curl http://localhost:8000/health +``` + +### ์˜ˆ์ƒ ์ถœ๋ ฅ + +``` +2024-01-01 12:00:00 - INFO - โœ… ์Šค๋ ˆ๋“œ ํ’€ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ (LLM ํ•ด์„ค ์ƒ์„ฑ์šฉ) +2024-01-01 12:00:01 - INFO - โœ… ChapterMapper ์ดˆ๊ธฐํ™” ์™„๋ฃŒ: 3๊ฐœ ์ฑ•ํ„ฐ ๋กœ๋“œ๋จ +2024-01-01 12:00:05 - INFO - โœ… HierarchicalCropPipeline ์ดˆ๊ธฐํ™” ์™„๋ฃŒ +2024-01-01 12:00:05 - INFO - โœ… LLM ํ•ด์„ค ๋ชจ๋“ˆ ๋กœ๋“œ ์™„๋ฃŒ +2024-01-01 12:00:06 - INFO - โœ… Kafka ์—ฐ๊ฒฐ ์™„๋ฃŒ (group_id=grading-service-abc12345) +``` + +--- + +## API ๋ช…์„ธ + +### ํ—ฌ์Šค ์ฒดํฌ + +#### GET / +๊ธฐ๋ณธ ์ƒํƒœ ํ™•์ธ + +**์‘๋‹ต:** +```json +{ + "status": "running", + "service": "grading-service" +} +``` + +#### GET /health +์ƒ์„ธ ์ƒํƒœ ํ™•์ธ + +**์‘๋‹ต:** +```json +{ + "status": "healthy", + "kafka_consumer": true, + "kafka_producer": true, + "pipeline": true, + "chapter_mapper": true, + "chapter_count": 3, + "llm_explanation_enabled": true +} +``` + +--- + +## Kafka ๋ฉ”์‹œ์ง€ ํ˜•์‹ + +### ํ† ํ”ฝ ๊ตฌ์กฐ + +| ํ† ํ”ฝ๋ช… | ๋ฐฉํ–ฅ | ์„ค๋ช… | +|--------|------|------| +| `s3-download-url` | Backend โ†’ AI | ์ฑ„์  ์š”์ฒญ | +| `grading-status` | AI โ†’ Backend | ์ฑ„์  ์ƒํƒœ | +| `student-answer` | AI โ†’ Backend | ๋‹ต์•ˆ ๊ฒฐ๊ณผ | +| `answer-explanation` | AI โ†’ Backend | LLM ํ•ด์„ค | + +--- + +### 1. ์ฑ„์  ์š”์ฒญ (Backend โ†’ AI) + +**ํ† ํ”ฝ:** `s3-download-url` + +```json +{ + "downloadUrl": "https://s3.amazonaws.com/bucket/image.jpg", + "uploadUrl": "https://s3.amazonaws.com/bucket/output/", + "academy_user_id": 123, + "user_id": 456, + "class_id": 789, + "academy_id": 101, + "student_response_id": 1001, + "index": 1, + "total": 5 +} +``` + +| ํ•„๋“œ | ํƒ€์ž… | ์„ค๋ช… | +|------|------|------| +| downloadUrl | string | ๋‹ต์•ˆ์ง€ ์ด๋ฏธ์ง€ S3 ๋‹ค์šด๋กœ๋“œ URL | +| uploadUrl | string | ํฌ๋กญ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ URL | +| academy_user_id | int | ํ•™์› ์‚ฌ์šฉ์ž ID | +| user_id | int | ์‚ฌ์šฉ์ž ID | +| class_id | int | ๋ฐ˜ ID | +| academy_id | int | ํ•™์› ID | +| student_response_id | int | ํ•™์ƒ ์‘๋‹ต ID | +| index | int | ํ˜„์žฌ ์ด๋ฏธ์ง€ ์ธ๋ฑ์Šค | +| total | int | ์ „์ฒด ์ด๋ฏธ์ง€ ์ˆ˜ | + +--- + +### 2. ์ฑ„์  ์ƒํƒœ (AI โ†’ Backend) + +**ํ† ํ”ฝ:** `grading-status` + +#### ์ฑ„์  ์‹œ์ž‘ +```json +{ + "action": "GRADING_STARTED", + "book_id": 0, + "academy_user_id": 123, + "user_id": 456, + "class_id": 789, + "academy_id": 101, + "student_response_id": 1001 +} +``` + +#### ์ฑ„์  ์™„๋ฃŒ +```json +{ + "action": "GRADING_COMPLETED", + "book_id": 0, + "academy_user_id": 123, + "user_id": 456, + "class_id": 789, + "academy_id": 101, + "student_response_id": 1001, + "total_question_count": 5, + "total_score": 3, + "response_start_page": 102, + "response_end_page": 102, + "unrecognized_response_count": 0 +} +``` + +#### ์—๋Ÿฌ ๋ฐœ์ƒ +```json +{ + "action": "ERROR", + "book_id": 0, + "academy_user_id": 123, + "user_id": 456, + "class_id": 789, + "academy_id": 101, + "student_response_id": 1001, + "total_question_count": 0, + "total_score": 0, + "response_start_page": 0, + "response_end_page": 0, + "unrecognized_response_count": 1 +} +``` + +| action ๊ฐ’ | ์„ค๋ช… | +|-----------|------| +| GRADING_STARTED | ์ฑ„์  ์‹œ์ž‘ | +| GRADING_COMPLETED | ์ฑ„์  ์™„๋ฃŒ | +| ERROR | ์—๋Ÿฌ ๋ฐœ์ƒ | + +--- + +### 3. ํ•™์ƒ ๋‹ต์•ˆ ๊ฒฐ๊ณผ (AI โ†’ Backend) + +**ํ† ํ”ฝ:** `student-answer` + +```json +{ + "student_response_id": 1001, + "academy_user_id": 123, + "book_id": 0, + "chapter_id": 1, + "page_number": "102", + "sections": [ + { + "problem_number": "40", + "answer": "3", + "correction": true + }, + { + "problem_number": "41", + "answer": "2", + "correction": false + }, + { + "problem_number": "42", + "answer": "4", + "correction": true + } + ] +} +``` + +| ํ•„๋“œ | ํƒ€์ž… | ์„ค๋ช… | +|------|------|------| +| student_response_id | int | ํ•™์ƒ ์‘๋‹ต ID | +| academy_user_id | int | ํ•™์› ์‚ฌ์šฉ์ž ID | +| book_id | int | ๊ต์žฌ ID | +| chapter_id | int | ์ฑ•ํ„ฐ ID | +| page_number | string | ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ | +| sections | array | ๋ฌธ์ œ๋ณ„ ๋‹ต์•ˆ ๋ชฉ๋ก | +| sections[].problem_number | string | ๋ฌธ์ œ ๋ฒˆํ˜ธ | +| sections[].answer | string | ํ•™์ƒ ๋‹ต์•ˆ | +| sections[].correction | boolean | ์ •๋‹ต ์—ฌ๋ถ€ | + +--- + +### 4. LLM ํ•ด์„ค (AI โ†’ Backend) + +**ํ† ํ”ฝ:** `answer-explanation` + +> โš ๏ธ ์˜ค๋‹ต์ธ ๊ฒฝ์šฐ์—๋งŒ ์ „์†ก๋ฉ๋‹ˆ๋‹ค. + +```json +{ + "student_response_id": 1001, + "academy_user_id": 123, + "book_id": 0, + "chapter_id": 1, + "page": 102, + "question_number": 41, + "sub_question_number": 0, + "user_answer": 2, + "explanation": "๐Ÿ”Ž ๋ฌธ์ œ 41 (p.102)\n\nโœ… ์ •๋‹ต: 4\nโœ๏ธ ์‚ฌ์šฉ์ž์˜ ์„ ํƒ: 2\n\n๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค\n์ด ๋ฌธ์ œ๋Š” ๊ธ€์˜ ํ๋ฆ„์„ ํŒŒ์•…ํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค...\n\n๐Ÿ”น ํ•ด์„ค ์š”์•ฝ\n๊ธ€์˜ ์ฃผ์ œ๋ฅผ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•˜๋ฉด ์ •๋‹ต์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.", + "is_correct": false, + "score": 0 +} +``` + +| ํ•„๋“œ | ํƒ€์ž… | ์„ค๋ช… | +|------|------|------| +| student_response_id | int | ํ•™์ƒ ์‘๋‹ต ID | +| academy_user_id | int | ํ•™์› ์‚ฌ์šฉ์ž ID | +| book_id | int | ๊ต์žฌ ID | +| chapter_id | int | ์ฑ•ํ„ฐ ID | +| page | int | ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ | +| question_number | int | ๋ฌธ์ œ ๋ฒˆํ˜ธ | +| sub_question_number | int | ์†Œ๋ฌธ์ œ ๋ฒˆํ˜ธ (๊ธฐ๋ณธ๊ฐ’: 0) | +| user_answer | int | ํ•™์ƒ์ด ์„ ํƒํ•œ ๋‹ต์•ˆ (1-5) | +| explanation | string | LLM ์ƒ์„ฑ ํ•ด์„ค | +| is_correct | boolean | ์ •๋‹ต ์—ฌ๋ถ€ | +| score | int | ์ ์ˆ˜ (์ •๋‹ต: 1, ์˜ค๋‹ต: 0) | + +--- + +## ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ + +``` +Gradi_25Fall/ +โ”œโ”€โ”€ main.py # ๋ฉ”์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ +โ”œโ”€โ”€ requirements.txt # ํŒจํ‚ค์ง€ ๋ชฉ๋ก +โ”œโ”€โ”€ .env # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ +โ”‚ +โ”œโ”€โ”€ api/ +โ”‚ โ””โ”€โ”€ schemas.py # Pydantic ์Šคํ‚ค๋งˆ +โ”‚ +โ”œโ”€โ”€ services/ +โ”‚ โ”œโ”€โ”€ hierarchical_crop.py # ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ +โ”‚ โ”œโ”€โ”€ chapter_mapper.py # ์ฑ•ํ„ฐ ๋งคํ•‘ +โ”‚ โ””โ”€โ”€ solution_llms.py # LLM ํ•ด์„ค ์ƒ์„ฑ +โ”‚ +โ”œโ”€โ”€ models/ +โ”‚ โ”œโ”€โ”€ Detection/ +โ”‚ โ”‚ โ””โ”€โ”€ legacy/ +โ”‚ โ”‚ โ”œโ”€โ”€ Model_routing_1104/ # YOLO ๋ชจ๋ธ (๋‹ต์•ˆ) +โ”‚ โ”‚ โ””โ”€โ”€ Model_routing_1004/ # YOLO ๋ชจ๋ธ (ํฌ๋กญ) +โ”‚ โ””โ”€โ”€ Recognition/ +โ”‚ โ”œโ”€โ”€ resnetClassifier.py # ResNet ๋ถ„๋ฅ˜๊ธฐ +โ”‚ โ”œโ”€โ”€ ocr.py # OCR ๋ชจ๋ธ +โ”‚ โ””โ”€โ”€ models/ +โ”‚ โ”œโ”€โ”€ answer_1_resnet.pth # ResNet ๊ฐ€์ค‘์น˜ +โ”‚ โ””โ”€โ”€ answer_2_resnet.pth +โ”‚ +โ””โ”€โ”€ DB/ + โ”œโ”€โ”€ answer.txt # ์ •๋‹ต ํŒŒ์ผ + โ”œโ”€โ”€ chapter.txt # ์ฑ•ํ„ฐ ๋งคํ•‘ + โ””โ”€โ”€ files/ # ๋ฌธ์ œ JSON ํŒŒ์ผ +``` + +--- + +## ํ†ต์‹  ํ๋ฆ„ + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ ์ฑ„์  ํ”„๋กœ์„ธ์Šค โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ โ”‚ +โ”‚ 1. [Backend] ์ด๋ฏธ์ง€ S3 ์—…๋กœ๋“œ โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ 2. [Backend] s3-download-url ํ† ํ”ฝ์— ๋ฉ”์‹œ์ง€ ๋ฐœํ–‰ โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ 3. [AI] ๋ฉ”์‹œ์ง€ ์ˆ˜์‹  โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ 4. [AI] grading-status (GRADING_STARTED) ๋ฐœํ–‰ โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ 5. [AI] ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ๋ฐ ์ฑ„์  ์ฒ˜๋ฆฌ โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ 6. [AI] student-answer ํ† ํ”ฝ์— ๋‹ต์•ˆ ๊ฒฐ๊ณผ ๋ฐœํ–‰ โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ 7. [AI] (์˜ค๋‹ต ์‹œ) answer-explanation ํ† ํ”ฝ์— ํ•ด์„ค ๋ฐœํ–‰ โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ 8. [AI] grading-status (GRADING_COMPLETED) ๋ฐœํ–‰ โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ 9. [Backend] ๊ฒฐ๊ณผ ์ˆ˜์‹  ๋ฐ DB ์ €์žฅ โ”‚ +โ”‚ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +--- + +## ๋ฐฑ์—”๋“œ ์—ฐ๋™ ์˜ˆ์‹œ (Java/Spring) + +### Kafka Producer + +```java +@Service +public class GradingRequestService { + + @Autowired + private KafkaTemplate kafkaTemplate; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + public void requestGrading(GradingRequest request) throws JsonProcessingException { + String message = objectMapper.writeValueAsString(request); + kafkaTemplate.send("s3-download-url", message); + } +} +``` + +### Kafka Consumer + +```java +@Service +public class GradingResultConsumer { + + @KafkaListener(topics = "grading-status") + public void handleGradingStatus(String message) { + // ์ฑ„์  ์ƒํƒœ ์ฒ˜๋ฆฌ + } + + @KafkaListener(topics = "student-answer") + public void handleStudentAnswer(String message) { + // ํ•™์ƒ ๋‹ต์•ˆ ์ €์žฅ + } + + @KafkaListener(topics = "answer-explanation") + public void handleExplanation(String message) { + // ํ•ด์„ค ์ €์žฅ + // message์—์„œ user_answer ํ•„๋“œ๋กœ ํ•™์ƒ์ด ์„ ํƒํ•œ ๋‹ต์•ˆ ํ™•์ธ ๊ฐ€๋Šฅ + } +} +``` + +### DTO ํด๋ž˜์Šค ์˜ˆ์‹œ + +```java +// ํ•ด์„ค ๋ฉ”์‹œ์ง€ DTO +@Data +public class AnswerExplanationMessage { + private int studentResponseId; + private int academyUserId; + private int bookId; + private int chapterId; + private int page; + private int questionNumber; + private int subQuestionNumber; + private int userAnswer; // ํ•™์ƒ์ด ์„ ํƒํ•œ ๋‹ต์•ˆ + private String explanation; + private boolean isCorrect; + private int score; +} +``` + +--- + +## ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… + +### 1. Kafka ์—ฐ๊ฒฐ ์‹คํŒจ + +``` +KafkaError: Unable to connect to broker +``` + +**ํ•ด๊ฒฐ:** +```bash +# Kafka ์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ +telnet 3.34.214.133 9092 + +# ๋ฐฉํ™”๋ฒฝ ํ™•์ธ +sudo ufw status +``` + +### 2. ๋ชจ๋ธ ๋กœ๋“œ ์‹คํŒจ + +``` +FileNotFoundError: Model file not found +``` + +**ํ•ด๊ฒฐ:** +- ๋ชจ๋ธ ํŒŒ์ผ ๊ฒฝ๋กœ ํ™•์ธ +- `.env` ํŒŒ์ผ์˜ ๊ฒฝ๋กœ ์„ค์ • ํ™•์ธ + +### 3. GPU ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ + +``` +CUDA out of memory +``` + +**ํ•ด๊ฒฐ:** +```bash +# GPU ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ +nvidia-smi + +# ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ ํ›„ ์žฌ์‹œ์ž‘ +``` + +### 4. LLM API ์˜ค๋ฅ˜ + +``` +OpenAI API Error: Invalid API key +``` + +**ํ•ด๊ฒฐ:** +- `.env` ํŒŒ์ผ์˜ `UPSTAGE_API_KEY` ํ™•์ธ +- API ํ‚ค ์œ ํšจ์„ฑ ํ™•์ธ + +--- + +## ๋ผ์ด์„ ์Šค + +MIT License + +--- + +## ๋ฌธ์˜ + +๋ฌธ์ œ๊ฐ€ ์žˆ์œผ์‹œ๋ฉด ์ด์Šˆ๋ฅผ ๋“ฑ๋กํ•ด์ฃผ์„ธ์š”. \ No newline at end of file diff --git a/ai-service/api/__init__.py b/ai-service/api/__init__.py new file mode 100644 index 0000000..33a8dd1 --- /dev/null +++ b/ai-service/api/__init__.py @@ -0,0 +1 @@ +# API ํŒจํ‚ค์ง€ diff --git a/ai-service/api/__pycache__/__init__.cpython-311.pyc b/ai-service/api/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..146f7b0 Binary files /dev/null and b/ai-service/api/__pycache__/__init__.cpython-311.pyc differ diff --git a/ai-service/api/__pycache__/__init__.cpython-312.pyc b/ai-service/api/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..724c442 Binary files /dev/null and b/ai-service/api/__pycache__/__init__.cpython-312.pyc differ diff --git a/ai-service/api/__pycache__/s3_sts_service.cpython-311.pyc b/ai-service/api/__pycache__/s3_sts_service.cpython-311.pyc new file mode 100644 index 0000000..c4ee631 Binary files /dev/null and b/ai-service/api/__pycache__/s3_sts_service.cpython-311.pyc differ diff --git a/ai-service/api/__pycache__/schemas.cpython-311.pyc b/ai-service/api/__pycache__/schemas.cpython-311.pyc new file mode 100644 index 0000000..c053134 Binary files /dev/null and b/ai-service/api/__pycache__/schemas.cpython-311.pyc differ diff --git a/ai-service/api/__pycache__/schemas.cpython-312.pyc b/ai-service/api/__pycache__/schemas.cpython-312.pyc new file mode 100644 index 0000000..878dfa7 Binary files /dev/null and b/ai-service/api/__pycache__/schemas.cpython-312.pyc differ diff --git a/ai-service/api/schemas.py b/ai-service/api/schemas.py new file mode 100644 index 0000000..b537698 --- /dev/null +++ b/ai-service/api/schemas.py @@ -0,0 +1,132 @@ +# api/schemas.py +""" +Kafka ๋ฉ”์‹œ์ง€ ์Šคํ‚ค๋งˆ ์ •์˜ +""" +from typing import List, Optional +from pydantic import BaseModel + + +class DownloadUrlRequest(BaseModel): + """๋ฐฑ์—”๋“œ์—์„œ ์ „์†กํ•˜๋Š” S3 ๋‹ค์šด๋กœ๋“œ URL ์š”์ฒญ ๋ฉ”์‹œ์ง€""" + total: int + academy_id: int + file_name: str + class_id: int + download_url: str + academy_user_id: int + index: int + student_response_id: int + # ์„ ํƒ์  ํ•„๋“œ (๋ฐฑ์—”๋“œ์—์„œ ๋ณด๋‚ด์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ) + upload_url: Optional[str] = None + user_id: Optional[int] = None + + +class GradingStartMessage(BaseModel): + """์ฑ„์  ์‹œ์ž‘ ๋ฉ”์‹œ์ง€""" + action: str # GRADING_STARTED, ERROR + book_id: int + academy_user_id: int + user_id: int + class_id: int + academy_id: int + student_response_id: int + + +class GradingEndMessage(BaseModel): + """์ฑ„์  ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€""" + action: str # GRADING_ENDED, ERROR + book_id: int + academy_user_id: int + user_id: int + class_id: int + academy_id: int + student_response_id: int + total_question_count: int + total_score: int + response_start_page: int + response_end_page: int + unrecognized_response_count: int + + +class SectionAnswer(BaseModel): + """๊ฐœ๋ณ„ ๋ฌธ์ œ ๋‹ต์•ˆ""" + question_number: int + sub_question_number: int + answer: str + is_correct: bool + + +class StudentAnswerMessage(BaseModel): + """ํ•™์ƒ ๋‹ต์•ˆ ๋ฉ”์‹œ์ง€""" + student_response_id: int + academy_user_id: int + book_id: int + chapter_id: int + page: int + score: int + sections: List[SectionAnswer] + + +class AnswerExplanationMessage(BaseModel): + """ + ๋‹ต์•ˆ ํ•ด์„ค ๋ฉ”์‹œ์ง€ + + ์˜ค๋‹ต ์‹œ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜์–ด answer-explanation ํ† ํ”ฝ์œผ๋กœ ์ „์†ก๋จ + """ + student_response_id: int + academy_user_id: int + user_id: int + book_id: int + chapter_id: int + page: int + question_number: int + sub_question_number: int + explanation: str + + +# ============================================================ +# ํ•ด์„ค API ์Šคํ‚ค๋งˆ +# ============================================================ + +class ExplanationRequest(BaseModel): + """ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ ์Šคํ‚ค๋งˆ (๋ฐฑ์—”๋“œ โ†’ AI ์„œ๋ฒ„)""" + student_response_id: int + academy_user_id: int + user_id: int + page_number: int + question_number: int + answer: Optional[int] = None # ์‚ฌ์šฉ์ž ๋‹ต์•ˆ (์„ ํƒ์ ) + + +class ExplanationResponseItem(BaseModel): + """๊ฐœ๋ณ„ ๋ฌธ์ œ ํ•ด์„ค ์‘๋‹ต""" + book_id: int + chapter_id: int + page: int + question_number: int + sub_question_number: int + explanation: str + + +class ExplanationResponse(BaseModel): + """ํ•ด์„ค ์ƒ์„ฑ ์‘๋‹ต ์Šคํ‚ค๋งˆ (AI ์„œ๋ฒ„ โ†’ ๋ฐฑ์—”๋“œ) - ๋‹จ์ผ ๋ฌธ์ œ""" + success: bool + student_response_id: int + academy_user_id: int + user_id: int + explanation: Optional[ExplanationResponseItem] = None # ๋‹จ์ผ ํ•ด์„ค + kafka_sent: bool = False + error: Optional[str] = None + + +class BatchExplanationRequest(BaseModel): + """๋ฐฐ์น˜ ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ ์Šคํ‚ค๋งˆ""" + requests: List[ExplanationRequest] + + +class BatchExplanationResponse(BaseModel): + """๋ฐฐ์น˜ ํ•ด์„ค ์ƒ์„ฑ ์‘๋‹ต ์Šคํ‚ค๋งˆ""" + total: int + success_count: int + failed_count: int + results: List[ExplanationResponse] \ No newline at end of file diff --git a/ai-service/config/__init__.py b/ai-service/config/__init__.py new file mode 100644 index 0000000..d23b10c --- /dev/null +++ b/ai-service/config/__init__.py @@ -0,0 +1 @@ +# ์„ค์ • ํŒจํ‚ค์ง€ diff --git a/ai-service/config/settings.py b/ai-service/config/settings.py new file mode 100644 index 0000000..83c2a10 --- /dev/null +++ b/ai-service/config/settings.py @@ -0,0 +1,70 @@ +""" +์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ • +Flask์˜ config.py์™€ ๋™์ผํ•œ ์—ญํ•  +""" + +import os +from pydantic import BaseSettings +from typing import List + +class Settings(BaseSettings): + """ + ํ™˜๊ฒฝ ์„ค์ • ํด๋ž˜์Šค + Flask์˜ Config ํด๋ž˜์Šค์™€ ๋™์ผํ•œ ์—ญํ•  + """ + + # ๊ธฐ๋ณธ ์„ค์ • + APP_NAME: str = "Gradi AI Service" + VERSION: str = "1.0.0" + DEBUG: bool = False + + # ์„œ๋ฒ„ ์„ค์ • + HOST: str = "0.0.0.0" + PORT: int = 8000 + + # CORS ์„ค์ • + ALLOWED_ORIGINS: List[str] = [ + "http://localhost:3000", # React ๊ฐœ๋ฐœ ์„œ๋ฒ„ + "http://localhost:8080", # Spring Boot ๊ฐœ๋ฐœ ์„œ๋ฒ„ + "https://gradi.com" # ํ”„๋กœ๋•์…˜ ๋„๋ฉ”์ธ + ] + + # API ํ‚ค ์„ค์ • + GROQ_API_KEY: str = os.getenv("GROQ_API_KEY", "") + OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "") + + # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค์ • + MONGODB_URL: str = os.getenv("MONGODB_URL", "mongodb://localhost:27017") + REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379") + + # ํŒŒ์ผ ์—…๋กœ๋“œ ์„ค์ • + MAX_FILE_SIZE: int = 10 * 1024 * 1024 # 10MB + ALLOWED_EXTENSIONS: List[str] = [".jpg", ".jpeg", ".png", ".webp"] + UPLOAD_FOLDER: str = "uploads" + + # AWS S3 ์„ค์ • + AWS_ACCESS_KEY_ID: str = os.getenv("AWS_ACCESS_KEY_ID", "") + AWS_SECRET_ACCESS_KEY: str = os.getenv("AWS_SECRET_ACCESS_KEY", "") + AWS_REGION: str = os.getenv("AWS_REGION", "ap-northeast-2") + S3_BUCKET_NAME: str = os.getenv("S3_BUCKET_NAME", "gradi-files") + + # ๋กœ๊น… ์„ค์ • + LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") + LOG_FILE: str = "logs/app.log" + + class Config: + env_file = ".env" + env_file_encoding = "utf-8" + +# ์ „์—ญ ์„ค์ • ์ธ์Šคํ„ด์Šค +settings = Settings() + +# Flask ์Šคํƒ€์ผ๋กœ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ +class Config: + """ + Flask ์Šคํƒ€์ผ ์„ค์ • ํด๋ž˜์Šค (ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด) + """ + GROQ_API_KEY = settings.GROQ_API_KEY + MONGODB_URL = settings.MONGODB_URL + DEBUG = settings.DEBUG + MAX_FILE_SIZE = settings.MAX_FILE_SIZE diff --git a/ai-service/main.py b/ai-service/main.py new file mode 100644 index 0000000..14b1326 --- /dev/null +++ b/ai-service/main.py @@ -0,0 +1,1455 @@ +# main.py +""" +Kafka ๊ธฐ๋ฐ˜ ์ฑ„์  ์„œ๋น„์Šค +- s3-download-url ํ† ํ”ฝ์—์„œ ์ด๋ฏธ์ง€ URL ์ˆ˜์‹  +- grading-status ํ† ํ”ฝ์œผ๋กœ ์‹œ์ž‘/์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ์ „์†ก +- student-answer ํ† ํ”ฝ์œผ๋กœ ์ฑ„์  ๊ฒฐ๊ณผ ์ „์†ก +- /api/explanation ์—”๋“œํฌ์ธํŠธ๋กœ ํ•ด์„ค ์š”์ฒญ ์‹œ ์ƒ์„ฑ ํ›„ Kafka ์ „์†ก +- STS ๋ฐฉ์‹์œผ๋กœ S3์— section ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ (์„œ๋ฒ„ ์‹œ์ž‘ ์‹œ ์ž๋™ ๊ฐฑ์‹ ) + +[์ˆ˜์ •์‚ฌํ•ญ] +- CPU-bound ์ž‘์—…(pipeline.process_page)์„ ThreadPoolExecutor๋กœ ๋ถ„๋ฆฌ +- S3 ์—…๋กœ๋“œ ํ•จ์ˆ˜๋ฅผ ๋™๊ธฐ ๋ฒ„์ „์œผ๋กœ ์ˆ˜์ •ํ•˜๊ณ  ๋น„๋™๊ธฐ ๋ž˜ํผ ์ถ”๊ฐ€ +- Consumer ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ์— ํƒ€์ž„์•„์›ƒ ์ถ”๊ฐ€ +- ์ƒ์„ธ ๋กœ๊น… ์ถ”๊ฐ€๋กœ ๋””๋ฒ„๊น… ์šฉ์ด์„ฑ ํ–ฅ์ƒ +- ๋ฐฐ์น˜ ์ƒํƒœ ๊ด€๋ฆฌ ์ถ”๊ฐ€: ๊ฐ™์€ student_response_id์˜ ๋ชจ๋“  ์ด๋ฏธ์ง€ ๊ฒฐ๊ณผ๋ฅผ ์ง‘๊ณ„ +""" + +from __future__ import annotations +import asyncio +import json +import logging +import os +import sys +import tempfile +import uuid +import ssl +import time +from contextlib import asynccontextmanager +from dataclasses import dataclass, field +from pathlib import Path +from typing import List, Optional, Dict, Any +from concurrent.futures import ThreadPoolExecutor + +import uvicorn +from aiokafka import AIOKafkaConsumer, AIOKafkaProducer +from fastapi import FastAPI, HTTPException +from pydantic import BaseModel +import aiohttp +import boto3 +from botocore.client import Config + +from api.schemas import ( + DownloadUrlRequest, + GradingStartMessage, + GradingEndMessage, + StudentAnswerMessage, + SectionAnswer, + AnswerExplanationMessage, + ExplanationRequest, + ExplanationResponse, + ExplanationResponseItem, + BatchExplanationRequest, + BatchExplanationResponse, +) + +# ๋กœ๊น… ์„ค์ • +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +# ============================================================ +# Kafka ์„ค์ • +# ============================================================ + +KAFKA_BOOTSTRAP_SERVERS = os.getenv("KAFKA_BOOTSTRAP_SERVERS", "3.34.214.133:9092") +TOPIC_DOWNLOAD_URL = "s3-download-url" +TOPIC_GRADING_START = "grading-start" +TOPIC_GRADING_END = "grading-end" +TOPIC_STUDENT_ANSWER = "student-answer" +TOPIC_ANSWER_EXPLANATION = "answer-explanation" + +# ============================================================ +# AWS / STS ์„ค์ • +# ============================================================ + +STS_API_URL = os.getenv("STS_API_URL", "https://3.34.214.133/storage/sts/upload?folder=section") +STS_AUTH_TOKEN = os.getenv( + "STS_AUTH_TOKEN", + "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ3b25pd29yeSIsIm5hbWUiOiLsoJXshLHsm5AiLCJ1c2VySWQiOjMsImV4cCI6MTc2MzUzMTU2Nn0.Dxf6JPziYpnzQTy9h8FrzYiJYR0CmSptB0KbL_IQPZs" +) + +STS_CREDENTIALS: Dict[str, Optional[str]] = { + "access_key": None, + "secret_key": None, + "session_token": None, + "expiration": None +} + +AWS_REGION = "ap-northeast-2" +BUCKET_NAME = "gradibucket" + +# ============================================================ +# ๋ชจ๋ธ ๊ฒฝ๋กœ ์„ค์ • +# ============================================================ + +MODEL_DIR_1104 = os.getenv("MODEL_DIR_1104", "./models/Detection/legacy/Model_routing_1104") +MODEL_DIR_1004 = os.getenv("MODEL_DIR_1004", "./models/Detection/legacy/Model_routing_1004") +ANSWER_KEY_PATH = os.getenv("ANSWER_KEY_PATH", "./test/Hierarchical_crop/answers/yolo_answer.txt") +RESNET_ANSWER_1_PATH = os.getenv("RESNET_ANSWER_1_PATH", "./models/Recognition/models/answer_1_resnet.pth") +RESNET_ANSWER_2_PATH = os.getenv("RESNET_ANSWER_2_PATH", "./models/Recognition/models/answer_2_resnet.pth") +SECTION_PADDING = int(os.getenv("SECTION_PADDING", "50")) + +CHAPTER_FILE_PATH = os.getenv("CHAPTER_FILE_PATH", "DB/chapter.txt") + +# ํ•ด์„ค์šฉ ์ •๋‹ต ํŒŒ์ผ ๊ฒฝ๋กœ +ANSWER_FILE_PATH = os.getenv("ANSWER_FILE_PATH", "DB/answer.txt") + +# ============================================================ +# ์ฒ˜๋ฆฌ ํƒ€์ž„์•„์›ƒ ์„ค์ • +# ============================================================ +PROCESSING_TIMEOUT_SECONDS = float(os.getenv("PROCESSING_TIMEOUT_SECONDS", "240")) + +# ๋ฐฐ์น˜ ํƒ€์ž„์•„์›ƒ ์„ค์ • (๋งˆ์ง€๋ง‰ ์ด๋ฏธ์ง€๊ฐ€ ์˜ค์ง€ ์•Š์„ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„) +BATCH_TIMEOUT_SECONDS = float(os.getenv("BATCH_TIMEOUT_SECONDS", "600")) + +# ============================================================ +# ์ „์—ญ ๋ณ€์ˆ˜ +# ============================================================ + +download_consumer: AIOKafkaConsumer | None = None +producer: AIOKafkaProducer | None = None +pipeline = None +chapter_mapper = None +download_consume_task: asyncio.Task | None = None +batch_cleanup_task: asyncio.Task | None = None +thread_executor: ThreadPoolExecutor | None = None + +# ์ •๋‹ต ๋ฐ์ดํ„ฐ ์บ์‹œ (์„œ๋ฒ„ ์‹œ์ž‘ ์‹œ ๋กœ๋“œ) +answer_cache: Dict[tuple, str] = {} + +# ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ์นด์šดํ„ฐ (๋””๋ฒ„๊น…์šฉ) +message_counter = {"received": 0, "processed": 0, "failed": 0} + + +# ============================================================ +# ๋ฐฐ์น˜ ์ƒํƒœ ๊ด€๋ฆฌ +# ============================================================ +@dataclass +class BatchState: + """๊ฐ™์€ student_response_id์˜ ์—ฌ๋Ÿฌ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌ""" + student_response_id: int + academy_user_id: int + user_id: int + class_id: int + academy_id: int + book_id: int + total: int + + # ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์ง‘๊ณ„ + processed_count: int = 0 + total_question_count: int = 0 + total_score: int = 0 + response_start_page: Optional[int] = None + response_end_page: Optional[int] = None + unrecognized_response_count: int = 0 + has_error: bool = False + + # ํƒ€์ž„์Šคํƒฌํ”„ + created_at: float = field(default_factory=time.time) + last_updated: float = field(default_factory=time.time) + + def update_page_range(self, page_int: int): + """ํŽ˜์ด์ง€ ๋ฒ”์œ„ ์—…๋ฐ์ดํŠธ""" + if page_int > 0: + if self.response_start_page is None or page_int < self.response_start_page: + self.response_start_page = page_int + if self.response_end_page is None or page_int > self.response_end_page: + self.response_end_page = page_int + + def is_complete(self) -> bool: + """๋ชจ๋“  ์ด๋ฏธ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ""" + return self.processed_count >= self.total + + def is_expired(self, timeout: float = BATCH_TIMEOUT_SECONDS) -> bool: + """๋ฐฐ์น˜๊ฐ€ ํƒ€์ž„์•„์›ƒ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ""" + return (time.time() - self.created_at) > timeout + + +# ๋ฐฐ์น˜ ์ƒํƒœ ์ €์žฅ์†Œ (student_response_id -> BatchState) +batch_states: Dict[int, BatchState] = {} +batch_states_lock = asyncio.Lock() + + +async def get_or_create_batch_state(request: DownloadUrlRequest, book_id: int = 1) -> tuple[BatchState, bool]: + """ + ๋ฐฐ์น˜ ์ƒํƒœ ์กฐํšŒ ๋˜๋Š” ์ƒ์„ฑ + + Returns: + tuple[BatchState, bool]: (๋ฐฐ์น˜ ์ƒํƒœ, ์ƒˆ๋กœ ์ƒ์„ฑ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€) + """ + async with batch_states_lock: + is_new_batch = False + + if request.student_response_id not in batch_states: + batch_states[request.student_response_id] = BatchState( + student_response_id=request.student_response_id, + academy_user_id=request.academy_user_id, + user_id=request.user_id or 0, + class_id=request.class_id, + academy_id=request.academy_id, + book_id=book_id, + total=request.total + ) + is_new_batch = True + logger.info(f"๐Ÿ“ฆ [๋ฐฐ์น˜์ƒ์„ฑ] student_response_id={request.student_response_id}, total={request.total}") + + return batch_states[request.student_response_id], is_new_batch + + +async def remove_batch_state(student_response_id: int): + """๋ฐฐ์น˜ ์ƒํƒœ ์ œ๊ฑฐ""" + async with batch_states_lock: + if student_response_id in batch_states: + del batch_states[student_response_id] + logger.info(f"๐Ÿ—‘๏ธ [๋ฐฐ์น˜์ œ๊ฑฐ] student_response_id={student_response_id}") + + +async def cleanup_expired_batches(): + """๋งŒ๋ฃŒ๋œ ๋ฐฐ์น˜๋“ค์„ ์ •๋ฆฌํ•˜๊ณ  ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ „์†ก""" + while True: + try: + await asyncio.sleep(60) # 1๋ถ„๋งˆ๋‹ค ์ฒดํฌ + + async with batch_states_lock: + expired_ids = [ + sid for sid, state in batch_states.items() + if state.is_expired() + ] + + for sid in expired_ids: + async with batch_states_lock: + state = batch_states.get(sid) + if state and state.is_expired(): + logger.warning(f"โฐ [๋ฐฐ์น˜๋งŒ๋ฃŒ] student_response_id={sid}, " + f"processed={state.processed_count}/{state.total}") + + # ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ „์†ก + try: + await send_grading_end_from_state(state, is_error=True) + except Exception as e: + logger.error(f"๋งŒ๋ฃŒ๋œ ๋ฐฐ์น˜ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ „์†ก ์‹คํŒจ: {e}") + + del batch_states[sid] + + except asyncio.CancelledError: + break + except Exception as e: + logger.error(f"๋ฐฐ์น˜ ์ •๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {e}") + + +# ============================================================ +# STS ์ž๊ฒฉ์ฆ๋ช… ๊ฐฑ์‹  ํ•จ์ˆ˜ +# ============================================================ + +async def fetch_sts_credentials() -> bool: + global STS_CREDENTIALS + + try: + ssl_context = ssl.create_default_context() + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_NONE + + headers = {} + if STS_AUTH_TOKEN: + headers["Authorization"] = f"Bearer {STS_AUTH_TOKEN}" + + async with aiohttp.ClientSession() as session: + async with session.get( + STS_API_URL, + headers=headers, + ssl=ssl_context, + timeout=aiohttp.ClientTimeout(total=30) + ) as response: + if response.status == 200: + data = await response.json() + + STS_CREDENTIALS["access_key"] = data.get("access_key_id") + STS_CREDENTIALS["secret_key"] = data.get("secret_access_key") + STS_CREDENTIALS["session_token"] = data.get("session_token") + STS_CREDENTIALS["expiration"] = data.get("expiration") + + logger.info(f"โœ… STS ์ž๊ฒฉ์ฆ๋ช… ๊ฐฑ์‹  ์™„๋ฃŒ. ๋งŒ๋ฃŒ ์‹œ๊ฐ„: {STS_CREDENTIALS['expiration']}") + return True + else: + error_text = await response.text() + logger.error(f"STS ์ž๊ฒฉ์ฆ๋ช… ๊ฐฑ์‹  ์‹คํŒจ: HTTP {response.status}, {error_text}") + return False + + except asyncio.TimeoutError: + logger.error("STS ์ž๊ฒฉ์ฆ๋ช… ๊ฐฑ์‹  ์‹คํŒจ: ์š”์ฒญ ํƒ€์ž„์•„์›ƒ") + return False + except Exception as e: + logger.error(f"STS ์ž๊ฒฉ์ฆ๋ช… ๊ฐฑ์‹  ์ค‘ ์˜ค๋ฅ˜: {e}") + return False + + +# ============================================================ +# S3 ํด๋ผ์ด์–ธํŠธ ๋ฐ ์—…๋กœ๋“œ ํ•จ์ˆ˜ +# ============================================================ + +def get_s3_client(): + if not STS_CREDENTIALS["access_key"]: + raise RuntimeError("STS ์ž๊ฒฉ์ฆ๋ช…์ด ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.") + + return boto3.client( + 's3', + aws_access_key_id=STS_CREDENTIALS["access_key"], + aws_secret_access_key=STS_CREDENTIALS["secret_key"], + aws_session_token=STS_CREDENTIALS["session_token"], + region_name=AWS_REGION, + config=Config(signature_version='s3v4') + ) + + +def build_s3_key(academy_user_id: int, student_response_id: int, problem_number: str, filename: str = "section.jpg") -> str: + return f"section/{academy_user_id}/{student_response_id}/{problem_number}/{filename}" + + +def upload_to_s3_sync(file_path: str, s3_key: str) -> bool: + """ + ๋™๊ธฐ S3 ์—…๋กœ๋“œ ํ•จ์ˆ˜ (ThreadPoolExecutor์—์„œ ํ˜ธ์ถœ์šฉ) + """ + try: + s3_client = get_s3_client() + + with open(file_path, 'rb') as f: + s3_client.put_object( + Bucket=BUCKET_NAME, + Key=s3_key, + Body=f.read(), + ContentType='image/jpeg' + ) + + logger.info(f"โœ… S3 ์—…๋กœ๋“œ ์™„๋ฃŒ: {s3_key}") + return True + + except Exception as e: + logger.error(f"S3 ์—…๋กœ๋“œ ์‹คํŒจ: {s3_key}, ์˜ค๋ฅ˜: {e}") + return False + + +async def upload_to_s3(file_path: str, s3_key: str) -> bool: + """ + ๋น„๋™๊ธฐ S3 ์—…๋กœ๋“œ ๋ž˜ํผ ํ•จ์ˆ˜ + """ + loop = asyncio.get_event_loop() + return await loop.run_in_executor( + thread_executor, + upload_to_s3_sync, + file_path, + s3_key + ) + + +# ============================================================ +# ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ +# ============================================================ + +def safe_int(value, default: int = 0) -> int: + """ + ๋ฌธ์ž์—ด์ด๋‚˜ ์ˆซ์ž๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜ + "01" -> 1, "102" -> 102, 1 -> 1 + """ + if value is None: + return default + try: + return int(value) + except (ValueError, TypeError): + return default + + +async def download_image(url: str, dest_path: str) -> bool: + try: + async with aiohttp.ClientSession() as session: + async with session.get(url, timeout=aiohttp.ClientTimeout(total=60)) as response: + if response.status == 200: + content = await response.read() + with open(dest_path, 'wb') as f: + f.write(content) + logger.info(f"์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ: {dest_path}") + return True + else: + logger.error(f"์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ: HTTP {response.status}") + return False + except asyncio.TimeoutError: + logger.error(f"์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ํƒ€์ž„์•„์›ƒ: {url}") + return False + except Exception as e: + logger.error(f"์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜: {e}") + return False + + +def get_chapter_id_for_page(page_number_str: Optional[str]) -> int: + global chapter_mapper + + if chapter_mapper is None: + logger.warning("ChapterMapper๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.") + return 0 + + return chapter_mapper.get_chapter_id_as_int_from_str(page_number_str) + + +# ============================================================ +# ์ •๋‹ต ํŒŒ์ผ ๋กœ๋“œ ๋ฐ ์กฐํšŒ ํ•จ์ˆ˜ +# ============================================================ + +def load_answer_file(answer_file: str = None) -> Dict[tuple, str]: + """ + answer.txt ํŒŒ์ผ์„ ๋กœ๋“œํ•˜์—ฌ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ๋ฐ˜ํ™˜ + ํ‚ค๋Š” (ํŽ˜์ด์ง€๋ฒˆํ˜ธ int, ๋ฌธ์ œ๋ฒˆํ˜ธ int) ํŠœํ”Œ๋กœ ์ €์žฅ + """ + if answer_file is None: + answer_file = ANSWER_FILE_PATH + + mapping = {} + + if not os.path.exists(answer_file): + logger.warning(f"์ •๋‹ต ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ: {answer_file}") + return mapping + + try: + with open(answer_file, encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line: + continue + parts = [x.strip() for x in line.split(",")] + if len(parts) >= 3: + page_int = safe_int(parts[0]) + question_int = safe_int(parts[1]) + answer = parts[2] + mapping[(page_int, question_int)] = answer + + logger.info(f"โœ… ์ •๋‹ต ํŒŒ์ผ ๋กœ๋“œ ์™„๋ฃŒ: {len(mapping)}๊ฐœ ๋ฌธ์ œ") + return mapping + + except Exception as e: + logger.error(f"์ •๋‹ต ํŒŒ์ผ ์ฝ๊ธฐ ์‹คํŒจ: {e}") + return mapping + + +def check_problem_exists(page_number: int, question_number: int) -> bool: + """ + answer.txt์— ํ•ด๋‹น ๋ฌธ์ œ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ (์ •์ˆ˜ ๋น„๊ต) + """ + global answer_cache + + page_int = safe_int(page_number) + question_int = safe_int(question_number) + + exists = (page_int, question_int) in answer_cache + + if exists: + logger.info(f"โœ… ๋ฌธ์ œ ์กด์žฌ ํ™•์ธ: page={page_int}, question={question_int}") + else: + logger.warning(f"โŒ ๋ฌธ์ œ ์—†์Œ: page={page_int}, question={question_int}") + + return exists + + +def get_correct_answer(page_number: int, question_number: int) -> Optional[str]: + """ + answer.txt์—์„œ ์ •๋‹ต ์กฐํšŒ (์ •์ˆ˜ ๋น„๊ต) + """ + global answer_cache + + page_int = safe_int(page_number) + question_int = safe_int(question_number) + + return answer_cache.get((page_int, question_int)) + + +# ============================================================ +# LLM ํ•ด์„ค ์ƒ์„ฑ ํ•จ์ˆ˜ +# ============================================================ + +def generate_explanation_sync(page_number: int, problem_number: int, user_answer: int) -> Optional[str]: + try: + from services.solution_llms import generate_explanation + result = generate_explanation( + page_number=page_number, + problem_number=problem_number, + user_answer=user_answer + ) + return result + except ImportError: + logger.warning("LLM ํ•ด์„ค ๋ชจ๋“ˆ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. services/solution_llms.py๋ฅผ ํ™•์ธํ•˜์„ธ์š”.") + return None + except Exception as e: + logger.error(f"LLM ํ•ด์„ค ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜: {e}") + return None + + +async def generate_explanation_async(page_number: int, problem_number: int, user_answer: int) -> Optional[str]: + loop = asyncio.get_event_loop() + return await loop.run_in_executor( + thread_executor, + generate_explanation_sync, + page_number, + problem_number, + user_answer + ) + + +# ============================================================ +# ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ (๋™๊ธฐ - ThreadPoolExecutor์—์„œ ํ˜ธ์ถœ) +# ============================================================ + +def process_page_sync(image_path: str, output_dir: str) -> Optional[dict]: + """ + ๋™๊ธฐ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ (ThreadPoolExecutor์—์„œ ํ˜ธ์ถœ์šฉ) + """ + global pipeline + + start_time = time.time() + logger.info(f"๐Ÿ”„ [Pipeline] ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์‹œ์ž‘: {image_path}") + + try: + result = pipeline.process_page(image_path, output_dir) + elapsed = time.time() - start_time + + if result is None: + logger.warning(f"โš ๏ธ [Pipeline] ํŽ˜์ด์ง€๊ฐ€ ๋‹ต์ง€์— ์—†์Œ (์†Œ์š”์‹œ๊ฐ„: {elapsed:.2f}์ดˆ)") + else: + section_count = len(result.get('sections', [])) + logger.info(f"โœ… [Pipeline] ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์™„๋ฃŒ: {section_count}๊ฐœ ์„น์…˜ (์†Œ์š”์‹œ๊ฐ„: {elapsed:.2f}์ดˆ)") + + return result + + except Exception as e: + elapsed = time.time() - start_time + logger.error(f"โŒ [Pipeline] ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์˜ค๋ฅ˜ (์†Œ์š”์‹œ๊ฐ„: {elapsed:.2f}์ดˆ): {e}") + raise + + +# ============================================================ +# Kafka ๋ฉ”์‹œ์ง€ ์ „์†ก ํ•จ์ˆ˜ +# ============================================================ + +async def send_grading_start(request: DownloadUrlRequest, book_id: int = 1): + message = GradingStartMessage( + action="GRADING_STARTED", + book_id=book_id, + academy_user_id=request.academy_user_id, + user_id=request.user_id or 0, + class_id=request.class_id, + academy_id=request.academy_id, + student_response_id=request.student_response_id + ) + + logger.info( + f"๐Ÿ“ค ์ฑ„์  ์‹œ์ž‘ ๋ฉ”์‹œ์ง€ ์ „์†ก - student_response_id={message.student_response_id}, " + f"action={message.action}, academy_user_id={message.academy_user_id}, " + f"book_id={message.book_id}, user_id={message.user_id}, " + f"class_id={message.class_id}, academy_id={message.academy_id}" + ) + + await producer.send_and_wait( + TOPIC_GRADING_START, + value=message.model_dump_json().encode('utf-8') + ) + logger.info(f"โœ… ์ฑ„์  ์‹œ์ž‘ ๋ฉ”์‹œ์ง€ ์ „์†ก ์™„๋ฃŒ: student_response_id={request.student_response_id}") + + +async def send_grading_end( + request: DownloadUrlRequest, + book_id: int, + total_question_count: int, + total_score: int, + response_start_page: int, + response_end_page: int, + unrecognized_response_count: int, + is_error: bool = False +): + message = GradingEndMessage( + action="ERROR" if is_error else "GRADING_ENDED", + book_id=book_id, + academy_user_id=request.academy_user_id, + user_id=request.user_id or 0, + class_id=request.class_id, + academy_id=request.academy_id, + student_response_id=request.student_response_id, + total_question_count=total_question_count, + total_score=total_score, + response_start_page=response_start_page, + response_end_page=response_end_page, + unrecognized_response_count=unrecognized_response_count + ) + + logger.info( + f"๐Ÿ“ค ์ฑ„์  ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ์ „์†ก - student_response_id={message.student_response_id}, " + f"action={message.action}, academy_user_id={message.academy_user_id}, " + f"book_id={message.book_id}, user_id={message.user_id}, " + f"class_id={message.class_id}, academy_id={message.academy_id}, " + f"total_question_count={message.total_question_count}, total_score={message.total_score}, " + f"response_start_page={message.response_start_page}, response_end_page={message.response_end_page}, " + f"unrecognized_response_count={message.unrecognized_response_count}" + ) + + await producer.send_and_wait( + TOPIC_GRADING_END, + value=message.model_dump_json().encode('utf-8') + ) + logger.info(f"โœ… ์ฑ„์  ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ์ „์†ก ์™„๋ฃŒ: student_response_id={request.student_response_id}, action={message.action}") + + +async def send_grading_end_from_state(state: BatchState, is_error: bool = False): + """BatchState์—์„œ ์ฑ„์  ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ์ „์†ก""" + message = GradingEndMessage( + action="ERROR" if is_error else "GRADING_ENDED", + book_id=state.book_id, + academy_user_id=state.academy_user_id, + user_id=state.user_id, + class_id=state.class_id, + academy_id=state.academy_id, + student_response_id=state.student_response_id, + total_question_count=state.total_question_count, + total_score=state.total_score, + response_start_page=state.response_start_page or 0, + response_end_page=state.response_end_page or 0, + unrecognized_response_count=state.unrecognized_response_count + ) + + logger.info( + f"๐Ÿ“ค ์ฑ„์  ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ์ „์†ก - student_response_id={message.student_response_id}, " + f"action={message.action}, academy_user_id={message.academy_user_id}, " + f"book_id={message.book_id}, user_id={message.user_id}, " + f"class_id={message.class_id}, academy_id={message.academy_id}, " + f"total_question_count={message.total_question_count}, total_score={message.total_score}, " + f"response_start_page={message.response_start_page}, response_end_page={message.response_end_page}, " + f"unrecognized_response_count={message.unrecognized_response_count}, " + f"processed={state.processed_count}/{state.total}" + ) + + await producer.send_and_wait( + TOPIC_GRADING_END, + value=message.model_dump_json().encode('utf-8') + ) + logger.info(f"โœ… ์ฑ„์  ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ์ „์†ก ์™„๋ฃŒ: student_response_id={state.student_response_id}, action={message.action}") + + +async def send_student_answer( + request: DownloadUrlRequest, + book_id: int, + chapter_id: int, + page_number: str, + sections: List[SectionAnswer], + score: int = 0 +): + page_int = safe_int(page_number) + + message = StudentAnswerMessage( + student_response_id=request.student_response_id, + academy_user_id=request.academy_user_id, + book_id=book_id, + chapter_id=chapter_id, + page=page_int, + score=score, + sections=sections + ) + + logger.info( + f"๐Ÿ“ค ํ•™์ƒ ๋‹ต์•ˆ ๋ฉ”์‹œ์ง€ ์ „์†ก - student_response_id={message.student_response_id}, " + f"academy_user_id={message.academy_user_id}, book_id={message.book_id}, " + f"chapter_id={message.chapter_id}, page={message.page}, score={message.score}, " + f"sections_count={len(message.sections)}" + ) + + await producer.send_and_wait( + TOPIC_STUDENT_ANSWER, + value=message.model_dump_json().encode('utf-8') + ) + logger.info(f"โœ… ํ•™์ƒ ๋‹ต์•ˆ ๋ฉ”์‹œ์ง€ ์ „์†ก ์™„๋ฃŒ: page={page_int}, chapter_id={chapter_id}, sections={len(sections)}, score={score}") + + +async def send_answer_explanation( + student_response_id: int, + academy_user_id: int, + user_id: int, + book_id: int, + chapter_id: int, + page_number: int, + problem_number: int, + sub_question_number: int, + explanation: str +) -> bool: + """ + ๋‹ต์•ˆ ํ•ด์„ค ๋ฉ”์‹œ์ง€ ์ „์†ก (REST API์—์„œ ํ˜ธ์ถœ) + """ + try: + message = AnswerExplanationMessage( + student_response_id=student_response_id, + academy_user_id=academy_user_id, + user_id=user_id, + book_id=book_id, + chapter_id=chapter_id, + page=page_number, + question_number=problem_number, + sub_question_number=sub_question_number, + explanation=explanation + ) + + logger.info( + f"๐Ÿ“ค ๋‹ต์•ˆ ํ•ด์„ค ๋ฉ”์‹œ์ง€ ์ „์†ก - student_response_id={message.student_response_id}, " + f"academy_user_id={message.academy_user_id}, user_id={message.user_id}, " + f"book_id={message.book_id}, chapter_id={message.chapter_id}, " + f"page={message.page}, question_number={message.question_number}" + ) + + await producer.send_and_wait( + TOPIC_ANSWER_EXPLANATION, + value=message.model_dump_json().encode('utf-8') + ) + logger.info(f"โœ… ๋‹ต์•ˆ ํ•ด์„ค ๋ฉ”์‹œ์ง€ ์ „์†ก ์™„๋ฃŒ: page={page_number}, question={problem_number}") + return True + except Exception as e: + logger.error(f"โŒ Kafka ํ•ด์„ค ๋ฉ”์‹œ์ง€ ์ „์†ก ์‹คํŒจ: {e}") + return False + + +# ============================================================ +# ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ (์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ๋งŒ ์ฒ˜๋ฆฌ, ์ €์žฅ ์•ˆํ•จ) +# ============================================================ + +async def process_image_and_upload(request: DownloadUrlRequest) -> dict: + """ + ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ๋ฐ S3 ์—…๋กœ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์ปจํ…์ŠคํŠธ์—์„œ ์ˆ˜ํ–‰ + CPU-bound ์ž‘์—…์€ ThreadPoolExecutor์—์„œ ์‹คํ–‰ + """ + global pipeline + + start_time = time.time() + logger.info(f"๐Ÿ“ฅ [์ฒ˜๋ฆฌ์‹œ์ž‘] student_response_id={request.student_response_id}, index={request.index}/{request.total}") + + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + image_filename = f"image_{request.index}.jpg" + image_path = temp_path / image_filename + + # Step 1: ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ + logger.info(f" [1/3] ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์ค‘... url={request.download_url}") + download_start = time.time() + download_success = await download_image(request.download_url, str(image_path)) + download_elapsed = time.time() - download_start + + if not download_success: + logger.error(f"โŒ ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ (์†Œ์š”์‹œ๊ฐ„: {download_elapsed:.2f}์ดˆ): {request.download_url}") + return {"success": False, "error": "download_failed", "uploaded_keys": []} + + logger.info(f" [1/3] ์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ (์†Œ์š”์‹œ๊ฐ„: {download_elapsed:.2f}์ดˆ)") + + # ์ž„์‹œ ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ (์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉ) + output_dir = temp_path / "output" + output_dir.mkdir(parents=True, exist_ok=True) + + try: + # Step 2: ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ (ThreadPoolExecutor์—์„œ ์‹คํ–‰) + logger.info(f" [2/3] ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ (๋น„๋™๊ธฐ)...") + process_start = time.time() + + loop = asyncio.get_event_loop() + result = await loop.run_in_executor( + thread_executor, + process_page_sync, + str(image_path), + str(output_dir) + ) + + process_elapsed = time.time() - process_start + logger.info(f" [2/3] ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์™„๋ฃŒ (์†Œ์š”์‹œ๊ฐ„: {process_elapsed:.2f}์ดˆ)") + + if result is None: + logger.warning("โš ๏ธ ํŽ˜์ด์ง€๊ฐ€ ๋‹ต์ง€์— ์—†์–ด ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.") + return {"success": False, "error": "page_not_in_answer_key", "uploaded_keys": []} + + # Step 3: S3 ์—…๋กœ๋“œ (๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ) + logger.info(f" [3/3] S3 ์—…๋กœ๋“œ ์ค‘...") + upload_start = time.time() + + uploaded_keys = [] + page_number = result.get('page_number_ocr', 'unknown') + sections = result.get('sections', []) + + upload_tasks = [] + for section in sections: + problem_number = section.get('problem_number_ocr') + if not problem_number: + continue + + # problem_number๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ (ํด๋”๋ช…๊ณผ ์ผ์น˜์‹œํ‚ค๊ธฐ ์œ„ํ•ด) + problem_number_str = str(problem_number) + + section_image_path = output_dir / str(page_number) / problem_number_str / f"{page_number}_{problem_number_str}_section.jpg" + + if not section_image_path.exists(): + logger.warning(f" Section ์ด๋ฏธ์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ: {section_image_path}") + continue + + s3_key = build_s3_key( + academy_user_id=request.academy_user_id, + student_response_id=request.student_response_id, + problem_number=problem_number_str, + filename="section.jpg" + ) + + # ์—…๋กœ๋“œ ํƒœ์Šคํฌ ์ˆ˜์ง‘ + upload_tasks.append((str(section_image_path), s3_key)) + + # ๋ณ‘๋ ฌ๋กœ S3 ์—…๋กœ๋“œ ์‹คํ–‰ + if upload_tasks: + upload_results = await asyncio.gather( + *[upload_to_s3(file_path, s3_key) for file_path, s3_key in upload_tasks], + return_exceptions=True + ) + + for (file_path, s3_key), success in zip(upload_tasks, upload_results): + if success is True: + uploaded_keys.append(s3_key) + elif isinstance(success, Exception): + logger.error(f" S3 ์—…๋กœ๋“œ ์˜ˆ์™ธ: {s3_key}, {success}") + + upload_elapsed = time.time() - upload_start + total_elapsed = time.time() - start_time + + logger.info(f" [3/3] S3 ์—…๋กœ๋“œ ์™„๋ฃŒ: {len(uploaded_keys)}/{len(upload_tasks)}๊ฐœ (์†Œ์š”์‹œ๊ฐ„: {upload_elapsed:.2f}์ดˆ)") + logger.info(f"๐Ÿ“ค [์ฒ˜๋ฆฌ์™„๋ฃŒ] student_response_id={request.student_response_id}, ์ด ์†Œ์š”์‹œ๊ฐ„: {total_elapsed:.2f}์ดˆ") + + return { + "success": True, + "result": result, + "uploaded_keys": uploaded_keys + } + + except Exception as e: + total_elapsed = time.time() - start_time + logger.error(f"โŒ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ (์ด ์†Œ์š”์‹œ๊ฐ„: {total_elapsed:.2f}์ดˆ): {e}") + import traceback + traceback.print_exc() + return {"success": False, "error": str(e), "uploaded_keys": []} + + +async def process_grading_request(request: DownloadUrlRequest): + """ + ์ „์ฒด ์ฑ„์  ์š”์ฒญ ์ฒ˜๋ฆฌ (๋ฐฐ์น˜ ์ƒํƒœ ๊ด€๋ฆฌ ํฌํ•จ) + - ๋ฐฐ์น˜๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋  ๋•Œ GRADING_STARTED ์ „์†ก (์ˆœ์„œ ๋ฌด๊ด€) + - ๊ฐ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์น˜ ์ƒํƒœ์— ์ง‘๊ณ„ + - ๋ชจ๋“  ์ด๋ฏธ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋˜๋ฉด GRADING_ENDED ์ „์†ก (์ˆœ์„œ ๋ฌด๊ด€) + """ + book_id = 1 + + logger.info(f"๐ŸŽฏ [์ฑ„์ ์š”์ฒญ] student_response_id={request.student_response_id}, " + f"index={request.index}/{request.total}") + + # ๋ฐฐ์น˜ ์ƒํƒœ ์กฐํšŒ ๋˜๋Š” ์ƒ์„ฑ (์ƒˆ๋กœ ์ƒ์„ฑ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋„ ๋ฐ˜ํ™˜) + batch_state, is_new_batch = await get_or_create_batch_state(request, book_id) + + # Step 1: ๋ฐฐ์น˜๊ฐ€ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๊ฒฝ์šฐ์—๋งŒ ์ฑ„์  ์‹œ์ž‘ ๋ฉ”์‹œ์ง€ ์ „์†ก (์ˆœ์„œ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ฒซ ๋ฒˆ์งธ๋กœ ๋„์ฐฉํ•œ ์ด๋ฏธ์ง€) + if is_new_batch: + logger.info(f" [Step 1/4] ์ฑ„์  ์‹œ์ž‘ ๋ฉ”์‹œ์ง€ ์ „์†ก ์ค‘... (์ฒซ ๋ฒˆ์งธ๋กœ ๋„์ฐฉํ•œ ์ด๋ฏธ์ง€: index={request.index})") + await send_grading_start(request, book_id) + else: + logger.info(f" [Step 1/4] ์ฑ„์  ์‹œ์ž‘ ๋ฉ”์‹œ์ง€ ์ƒ๋žต (์ด๋ฏธ ์ „์†ก๋จ, ํ˜„์žฌ processed={batch_state.processed_count})") + + image_question_count = 0 + image_score = 0 + image_unrecognized = 0 + + try: + # Step 2: ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ + logger.info(f" [Step 2/4] ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘...") + process_result = await process_image_and_upload(request) + + if process_result["success"]: + result = process_result["result"] + + page_number = result.get('page_number_ocr', 'unknown') + page_int = safe_int(page_number) + + # Step 3: ์ฑ•ํ„ฐ ๋งคํ•‘ ๋ฐ ๋‹ต์•ˆ ์ฒ˜๋ฆฌ + logger.info(f" [Step 3/4] ์ฑ•ํ„ฐ ๋งคํ•‘ ๋ฐ ๋‹ต์•ˆ ์ฒ˜๋ฆฌ ์ค‘...") + + chapter_id = get_chapter_id_for_page(page_number) + if chapter_id > 0: + logger.info(f" ๐Ÿ“– ํŽ˜์ด์ง€ {page_number} โ†’ ์ฑ•ํ„ฐ {chapter_id} ๋งคํ•‘๋จ") + else: + logger.warning(f" โš ๏ธ ํŽ˜์ด์ง€ {page_number}์— ํ•ด๋‹นํ•˜๋Š” ์ฑ•ํ„ฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + + # ๋ฐฐ์น˜ ์ƒํƒœ์— ํŽ˜์ด์ง€ ๋ฒ”์œ„ ์—…๋ฐ์ดํŠธ + batch_state.update_page_range(page_int) + + sections = [] + + for section in result['sections']: + problem_number = section.get('problem_number_ocr') + answer = section.get('answer_number') + correction = section.get('correction') + + image_question_count += 1 + + if problem_number and answer: + is_correct = correction if correction is not None else False + + question_number_int = safe_int(problem_number) + + sections.append(SectionAnswer( + question_number=question_number_int, + sub_question_number=0, + answer=str(answer), + is_correct=is_correct + )) + + if is_correct: + image_score += 1 + else: + image_unrecognized += 1 + + if sections: + await send_student_answer( + request=request, + book_id=book_id, + chapter_id=chapter_id, + page_number=page_number, + sections=sections, + score=image_score + ) + + logger.info(f" ์ฒ˜๋ฆฌ๋œ ๋ฌธ์ œ: {len(sections)}๊ฐœ, ์ •๋‹ต: {image_score}๊ฐœ, ์ธ์‹์‹คํŒจ: {image_unrecognized}๊ฐœ") + + else: + logger.error(f" โŒ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์‹คํŒจ: {process_result.get('error')}") + image_unrecognized += 1 + batch_state.has_error = True + + # ๋ฐฐ์น˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ + batch_state.processed_count += 1 + batch_state.total_question_count += image_question_count + batch_state.total_score += image_score + batch_state.unrecognized_response_count += image_unrecognized + batch_state.last_updated = time.time() + + logger.info(f" ๐Ÿ“Š ๋ฐฐ์น˜ ์ƒํƒœ: processed={batch_state.processed_count}/{batch_state.total}, " + f"total_questions={batch_state.total_question_count}, total_score={batch_state.total_score}, " + f"start_page={batch_state.response_start_page}, end_page={batch_state.response_end_page}") + + # Step 4: ๋ชจ๋“  ์ด๋ฏธ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋˜์—ˆ์„ ๋•Œ๋งŒ ์ฑ„์  ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ์ „์†ก (์ˆœ์„œ ๋ฌด๊ด€) + if batch_state.is_complete(): + logger.info(f" [Step 4/4] ์ฑ„์  ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ์ „์†ก ์ค‘... (๋งˆ์ง€๋ง‰์œผ๋กœ ์ฒ˜๋ฆฌ๋œ ์ด๋ฏธ์ง€: index={request.index})") + await send_grading_end_from_state(batch_state, is_error=batch_state.has_error) + + # ๋ฐฐ์น˜ ์ƒํƒœ ์ œ๊ฑฐ + await remove_batch_state(request.student_response_id) + else: + logger.info(f" [Step 4/4] ์ฑ„์  ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€ ๋Œ€๊ธฐ (์ฒ˜๋ฆฌ ์™„๋ฃŒ: {batch_state.processed_count}/{batch_state.total})") + + logger.info(f"โœ… [์ฑ„์ ์™„๋ฃŒ] student_response_id={request.student_response_id}, index={request.index}/{request.total}") + + except Exception as e: + logger.error(f"โŒ [์ฑ„์ ์˜ค๋ฅ˜] student_response_id={request.student_response_id}: {e}") + import traceback + traceback.print_exc() + + # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ์—๋„ ๋ฐฐ์น˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ + batch_state.processed_count += 1 + batch_state.unrecognized_response_count += 1 + batch_state.has_error = True + batch_state.last_updated = time.time() + + # ๋ชจ๋“  ์ด๋ฏธ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋˜์—ˆ์œผ๋ฉด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ „์†ก + if batch_state.is_complete(): + await send_grading_end_from_state(batch_state, is_error=True) + await remove_batch_state(request.student_response_id) + + +# ============================================================ +# Kafka Consumer +# ============================================================ + +async def consume_download_messages(): + global message_counter + + logger.info("๐Ÿš€ Download Consumer ์‹œ์ž‘๋จ") + + try: + async for msg in download_consumer: + message_counter["received"] += 1 + msg_id = message_counter["received"] + + logger.info(f"๐Ÿ“ฉ [๋ฉ”์‹œ์ง€ #{msg_id}] ์ˆ˜์‹ : topic={msg.topic}, partition={msg.partition}, offset={msg.offset}") + + try: + data = json.loads(msg.value) + logger.debug(f" ๋ฐ›์€ ๋ฐ์ดํ„ฐ: {data}") + + request = DownloadUrlRequest(**data) + + logger.info(f" ์ฒ˜๋ฆฌ ์‹œ์ž‘: student_response_id={request.student_response_id}, " + f"index={request.index}/{request.total}") + + # ํƒ€์ž„์•„์›ƒ ์„ค์ •์œผ๋กœ ๋ฌดํ•œ ๋Œ€๊ธฐ ๋ฐฉ์ง€ + try: + await asyncio.wait_for( + process_grading_request(request), + timeout=PROCESSING_TIMEOUT_SECONDS + ) + message_counter["processed"] += 1 + logger.info(f"โœ… [๋ฉ”์‹œ์ง€ #{msg_id}] ์ฒ˜๋ฆฌ ์™„๋ฃŒ (์ด ์ฒ˜๋ฆฌ: {message_counter['processed']}๊ฑด)") + + except asyncio.TimeoutError: + message_counter["failed"] += 1 + logger.error(f"โฐ [๋ฉ”์‹œ์ง€ #{msg_id}] ์ฒ˜๋ฆฌ ํƒ€์ž„์•„์›ƒ ({PROCESSING_TIMEOUT_SECONDS}์ดˆ ์ดˆ๊ณผ): " + f"student_response_id={request.student_response_id}") + + # ํƒ€์ž„์•„์›ƒ ์‹œ ๋ฐฐ์น˜ ์ƒํƒœ ์—…๋ฐ์ดํŠธ + batch_state, _ = await get_or_create_batch_state(request) + batch_state.processed_count += 1 + batch_state.unrecognized_response_count += 1 + batch_state.has_error = True + + # ๋ชจ๋“  ์ด๋ฏธ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋˜์—ˆ์œผ๋ฉด ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ „์†ก + if batch_state.is_complete(): + try: + await send_grading_end_from_state(batch_state, is_error=True) + await remove_batch_state(request.student_response_id) + except Exception as e: + logger.error(f" ํƒ€์ž„์•„์›ƒ ํ›„ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ „์†ก ์‹คํŒจ: {e}") + + except json.JSONDecodeError as e: + message_counter["failed"] += 1 + logger.error(f"โŒ [๋ฉ”์‹œ์ง€ #{msg_id}] JSON ํŒŒ์‹ฑ ์‹คํŒจ: {e}") + except Exception as e: + message_counter["failed"] += 1 + logger.error(f"โŒ [๋ฉ”์‹œ์ง€ #{msg_id}] ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {e}") + import traceback + traceback.print_exc() + + except asyncio.CancelledError: + logger.info(f"๐Ÿ›‘ Download Consumer ํƒœ์Šคํฌ ์ทจ์†Œ๋จ. " + f"์ด ์ˆ˜์‹ : {message_counter['received']}, " + f"์ฒ˜๋ฆฌ: {message_counter['processed']}, " + f"์‹คํŒจ: {message_counter['failed']}") + except Exception as e: + logger.error(f"๐Ÿ’ฅ Download Consumer ์˜ค๋ฅ˜: {e}") + import traceback + traceback.print_exc() + raise + + +# ============================================================ +# FastAPI ์•ฑ +# ============================================================ + +@asynccontextmanager +async def lifespan(app: FastAPI): + global download_consumer, producer, pipeline, chapter_mapper + global download_consume_task, batch_cleanup_task, thread_executor, answer_cache + + # ThreadPoolExecutor ์ดˆ๊ธฐํ™” (worker ์ˆ˜ ์ฆ๊ฐ€) + thread_executor = ThreadPoolExecutor(max_workers=8) + logger.info("โœ… ์Šค๋ ˆ๋“œ ํ’€ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ (max_workers=8)") + + # ์ •๋‹ต ํŒŒ์ผ ๋กœ๋“œ + answer_cache = load_answer_file(ANSWER_FILE_PATH) + + logger.info("STS ์ž๊ฒฉ์ฆ๋ช… ๊ฐ€์ ธ์˜ค๋Š” ์ค‘...") + sts_success = await fetch_sts_credentials() + if sts_success: + logger.info("โœ… STS ์ž๊ฒฉ์ฆ๋ช… ์ดˆ๊ธฐํ™” ์™„๋ฃŒ") + else: + logger.warning("โš ๏ธ STS ์ž๊ฒฉ์ฆ๋ช… ์ดˆ๊ธฐํ™” ์‹คํŒจ. S3 ์—…๋กœ๋“œ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.") + + if STS_CREDENTIALS["access_key"]: + try: + s3_client = get_s3_client() + s3_client.list_buckets() + logger.info("โœ… S3 ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ ์„ฑ๊ณต") + except Exception as e: + logger.warning(f"โš ๏ธ S3 ์—ฐ๊ฒฐ ํ…Œ์ŠคํŠธ ์‹คํŒจ: {e}") + logger.warning("S3 ์—…๋กœ๋“œ๊ฐ€ ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.") + + logger.info("ChapterMapper ์ดˆ๊ธฐํ™” ์ค‘...") + try: + from services.chapter_mapper import ChapterMapper + chapter_mapper = ChapterMapper(chapter_file_path=CHAPTER_FILE_PATH) + logger.info(f"โœ… ChapterMapper ์ดˆ๊ธฐํ™” ์™„๋ฃŒ: {len(chapter_mapper)}๊ฐœ ์ฑ•ํ„ฐ ๋กœ๋“œ๋จ") + except Exception as e: + logger.warning(f"โš ๏ธ ChapterMapper ์ดˆ๊ธฐํ™” ์‹คํŒจ: {e}") + logger.warning("์ฑ•ํ„ฐ ๋งคํ•‘ ์—†์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค (chapter_id=0)") + + logger.info("HierarchicalCropPipeline ์ดˆ๊ธฐํ™” ์ค‘...") + try: + sys.path.insert(0, os.getcwd()) + from services.hierarchical_crop import HierarchicalCropPipeline + + pipeline = HierarchicalCropPipeline( + model_dir_1104=MODEL_DIR_1104, + model_dir_1004=MODEL_DIR_1004, + section_padding=SECTION_PADDING, + answer_key_path=ANSWER_KEY_PATH if os.path.exists(ANSWER_KEY_PATH) else None, + resnet_answer_1_path=RESNET_ANSWER_1_PATH if os.path.exists(RESNET_ANSWER_1_PATH) else None, + resnet_answer_2_path=RESNET_ANSWER_2_PATH if os.path.exists(RESNET_ANSWER_2_PATH) else None + ) + logger.info("โœ… HierarchicalCropPipeline ์ดˆ๊ธฐํ™” ์™„๋ฃŒ") + except Exception as e: + logger.error(f"โŒ HierarchicalCropPipeline ์ดˆ๊ธฐํ™” ์‹คํŒจ: {e}") + raise + + try: + from services.solution_llms import generate_explanation + logger.info("โœ… LLM ํ•ด์„ค ๋ชจ๋“ˆ ๋กœ๋“œ ์™„๋ฃŒ (REST API๋กœ ํ•ด์„ค ์ œ๊ณต)") + except ImportError: + logger.warning("โš ๏ธ LLM ํ•ด์„ค ๋ชจ๋“ˆ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. /api/explanation ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.") + + download_group_id = f"grading-service-{uuid.uuid4().hex[:8]}" + download_consumer = AIOKafkaConsumer( + TOPIC_DOWNLOAD_URL, + bootstrap_servers=KAFKA_BOOTSTRAP_SERVERS, + group_id=download_group_id, + value_deserializer=lambda v: v.decode("utf-8"), + auto_offset_reset="latest", + enable_auto_commit=True, + session_timeout_ms=60000, + heartbeat_interval_ms=20000, + max_poll_interval_ms=300000, + ) + + producer = AIOKafkaProducer( + bootstrap_servers=KAFKA_BOOTSTRAP_SERVERS, + request_timeout_ms=60000, + retry_backoff_ms=500, + max_request_size=1048576, + ) + + await download_consumer.start() + await producer.start() + logger.info(f"โœ… Kafka ์—ฐ๊ฒฐ ์™„๋ฃŒ") + logger.info(f" - Download Consumer group_id: {download_group_id}") + logger.info(f" - Producer topics: {TOPIC_GRADING_START}, {TOPIC_GRADING_END}, {TOPIC_STUDENT_ANSWER}, {TOPIC_ANSWER_EXPLANATION}") + logger.info(f" - ์ฒ˜๋ฆฌ ํƒ€์ž„์•„์›ƒ: {PROCESSING_TIMEOUT_SECONDS}์ดˆ") + logger.info(f" - ๋ฐฐ์น˜ ํƒ€์ž„์•„์›ƒ: {BATCH_TIMEOUT_SECONDS}์ดˆ") + + download_consume_task = asyncio.create_task(consume_download_messages()) + batch_cleanup_task = asyncio.create_task(cleanup_expired_batches()) + + yield + + download_consume_task.cancel() + batch_cleanup_task.cancel() + + try: + await download_consume_task + except asyncio.CancelledError: + pass + + try: + await batch_cleanup_task + except asyncio.CancelledError: + pass + + await download_consumer.stop() + await producer.stop() + thread_executor.shutdown(wait=True) + logger.info("๐Ÿ›‘ Kafka ์—ฐ๊ฒฐ ์ข…๋ฃŒ") + + +app = FastAPI( + title="์ฑ„์  ์„œ๋น„์Šค", + description="Kafka ๊ธฐ๋ฐ˜ ์ด๋ฏธ์ง€ ์ฑ„์  ์„œ๋น„์Šค (REST API๋กœ ํ•ด์„ค ์ œ๊ณต, STS ๋ฐฉ์‹ S3 ์—…๋กœ๋“œ, ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ)", + lifespan=lifespan +) + + +@app.get("/") +async def root(): + return {"status": "running", "service": "grading-service"} + + +@app.get("/health") +async def health(): + s3_connected = False + if STS_CREDENTIALS["access_key"]: + try: + s3_client = get_s3_client() + s3_client.list_buckets() + s3_connected = True + except Exception: + pass + + return { + "status": "healthy", + "kafka_download_consumer": download_consumer is not None, + "kafka_producer": producer is not None, + "pipeline": pipeline is not None, + "chapter_mapper": chapter_mapper is not None, + "chapter_count": len(chapter_mapper) if chapter_mapper else 0, + "answer_cache_count": len(answer_cache), + "s3_connected": s3_connected, + "sts_expiration": STS_CREDENTIALS.get("expiration"), + "message_stats": message_counter, + "processing_timeout_seconds": PROCESSING_TIMEOUT_SECONDS, + "batch_timeout_seconds": BATCH_TIMEOUT_SECONDS, + "active_batches": len(batch_states) + } + + +@app.get("/stats") +async def get_stats(): + """๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ํ†ต๊ณ„ ์กฐํšŒ""" + return { + "received": message_counter["received"], + "processed": message_counter["processed"], + "failed": message_counter["failed"], + "success_rate": ( + f"{(message_counter['processed'] / message_counter['received'] * 100):.1f}%" + if message_counter["received"] > 0 else "N/A" + ), + "active_batches": len(batch_states) + } + + +@app.get("/batches") +async def get_batches(): + """ํ™œ์„ฑ ๋ฐฐ์น˜ ์ƒํƒœ ์กฐํšŒ""" + async with batch_states_lock: + return { + "count": len(batch_states), + "batches": [ + { + "student_response_id": state.student_response_id, + "processed": state.processed_count, + "total": state.total, + "total_questions": state.total_question_count, + "total_score": state.total_score, + "start_page": state.response_start_page, + "end_page": state.response_end_page, + "has_error": state.has_error, + "age_seconds": time.time() - state.created_at + } + for state in batch_states.values() + ] + } + + +@app.post("/refresh-sts") +async def refresh_sts(): + success = await fetch_sts_credentials() + return { + "success": success, + "expiration": STS_CREDENTIALS.get("expiration") + } + + +@app.post("/reload-answers") +async def reload_answers(): + """์ •๋‹ต ํŒŒ์ผ ๋‹ค์‹œ ๋กœ๋“œ""" + global answer_cache + answer_cache = load_answer_file(ANSWER_FILE_PATH) + return { + "success": True, + "count": len(answer_cache) + } + + +# ============================================================ +# ํ•ด์„ค ์ƒ์„ฑ REST API ์—”๋“œํฌ์ธํŠธ +# ============================================================ + +@app.post("/api/explanation", response_model=ExplanationResponse) +async def generate_explanation_api(request: ExplanationRequest): + """ + ํŠน์ • ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด์„ค ์ƒ์„ฑ ๋ฐ Kafka ์ „์†ก + """ + try: + logger.info( + f"๐Ÿง  ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ ์ˆ˜์‹  - student_response_id={request.student_response_id}, " + f"academy_user_id={request.academy_user_id}, user_id={request.user_id}, " + f"page_number={request.page_number}, question_number={request.question_number}, " + f"answer={request.answer}" + ) + + page_int = safe_int(request.page_number) + question_int = safe_int(request.question_number) + user_answer = safe_int(request.answer) if request.answer is not None else 0 + + if not check_problem_exists(page_int, question_int): + return ExplanationResponse( + success=False, + student_response_id=request.student_response_id, + academy_user_id=request.academy_user_id, + user_id=request.user_id, + error=f"ํŽ˜์ด์ง€ {page_int}, ๋ฌธ์ œ {question_int}์€(๋Š”) answer.txt์— ๋“ฑ๋ก๋˜์ง€ ์•Š์€ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค." + ) + + book_id = 1 + chapter_id = get_chapter_id_for_page(str(page_int)) + sub_question_number = 0 + + explanation_text = await generate_explanation_async( + page_number=page_int, + problem_number=question_int, + user_answer=user_answer + ) + + if not explanation_text: + explanation_text = "ํ•ด์„ค์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + + explanation_item = ExplanationResponseItem( + book_id=book_id, + chapter_id=chapter_id, + page=page_int, + question_number=question_int, + sub_question_number=sub_question_number, + explanation=explanation_text + ) + + kafka_sent = await send_answer_explanation( + student_response_id=request.student_response_id, + academy_user_id=request.academy_user_id, + user_id=request.user_id, + book_id=book_id, + chapter_id=chapter_id, + page_number=page_int, + problem_number=question_int, + sub_question_number=sub_question_number, + explanation=explanation_text + ) + + return ExplanationResponse( + success=True, + student_response_id=request.student_response_id, + academy_user_id=request.academy_user_id, + user_id=request.user_id, + explanation=explanation_item, + kafka_sent=kafka_sent + ) + + except Exception as e: + logger.error(f"ํ•ด์„ค ์ƒ์„ฑ API ์˜ค๋ฅ˜: {e}") + import traceback + traceback.print_exc() + + raise HTTPException( + status_code=500, + detail=f"ํ•ด์„ค ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}" + ) + + +@app.post("/api/explanation/batch", response_model=BatchExplanationResponse) +async def generate_explanation_batch_api(request: BatchExplanationRequest): + """ + ์—ฌ๋Ÿฌ ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด์„ค ์ผ๊ด„ ์ƒ์„ฑ ๋ฐ Kafka ์ „์†ก + """ + logger.info(f"๐Ÿง  ๋ฐฐ์น˜ ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ ์ˆ˜์‹  - total={len(request.requests)}") + + results = [] + success_count = 0 + failed_count = 0 + + for req in request.requests: + try: + response = await generate_explanation_api(req) + results.append(response) + + if response.success: + success_count += 1 + else: + failed_count += 1 + + except Exception as e: + logger.error(f"๋ฐฐ์น˜ ํ•ด์„ค ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜: {e}") + results.append(ExplanationResponse( + success=False, + student_response_id=req.student_response_id, + academy_user_id=req.academy_user_id, + user_id=req.user_id, + error=str(e) + )) + failed_count += 1 + + return BatchExplanationResponse( + total=len(request.requests), + success_count=success_count, + failed_count=failed_count, + results=results + ) + + +@app.post("/api/explanation/generate-only", response_model=ExplanationResponse) +async def generate_explanation_only_api(request: ExplanationRequest): + """ + ํ•ด์„ค๋งŒ ์ƒ์„ฑํ•˜๊ณ  Kafka ์ „์†ก์€ ํ•˜์ง€ ์•Š์Œ + """ + try: + logger.info( + f"๐Ÿง  ํ•ด์„ค ์ƒ์„ฑ(์ „์†ก ์—†์Œ) ์š”์ฒญ ์ˆ˜์‹  - student_response_id={request.student_response_id}, " + f"page_number={request.page_number}, question_number={request.question_number}, " + f"answer={request.answer}" + ) + + page_int = safe_int(request.page_number) + question_int = safe_int(request.question_number) + user_answer = safe_int(request.answer) if request.answer is not None else 0 + + if not check_problem_exists(page_int, question_int): + return ExplanationResponse( + success=False, + student_response_id=request.student_response_id, + academy_user_id=request.academy_user_id, + user_id=request.user_id, + error=f"ํŽ˜์ด์ง€ {page_int}, ๋ฌธ์ œ {question_int}์€(๋Š”) answer.txt์— ๋“ฑ๋ก๋˜์ง€ ์•Š์€ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค." + ) + + book_id = 1 + chapter_id = get_chapter_id_for_page(str(page_int)) + + explanation_text = await generate_explanation_async( + page_number=page_int, + problem_number=question_int, + user_answer=user_answer + ) + + if not explanation_text: + explanation_text = "ํ•ด์„ค์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + + explanation_item = ExplanationResponseItem( + book_id=book_id, + chapter_id=chapter_id, + page=page_int, + question_number=question_int, + sub_question_number=0, + explanation=explanation_text + ) + + return ExplanationResponse( + success=True, + student_response_id=request.student_response_id, + academy_user_id=request.academy_user_id, + user_id=request.user_id, + explanation=explanation_item, + kafka_sent=False + ) + + except Exception as e: + logger.error(f"ํ•ด์„ค ์ƒ์„ฑ API ์˜ค๋ฅ˜: {e}") + raise HTTPException( + status_code=500, + detail=f"ํ•ด์„ค ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}" + ) + + +if __name__ == "__main__": + module_name = Path(__file__).stem + uvicorn.run(f"{module_name}:app", host="0.0.0.0", port=8000, reload=False) \ No newline at end of file diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxF1_curve.png b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxF1_curve.png new file mode 100644 index 0000000..f8fcbb0 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxF1_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxPR_curve.png b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxPR_curve.png new file mode 100644 index 0000000..f02a170 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxPR_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxP_curve.png b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxP_curve.png new file mode 100644 index 0000000..9c4d781 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxP_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxR_curve.png b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxR_curve.png new file mode 100644 index 0000000..d03445c Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/BoxR_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/confusion_matrix.png b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/confusion_matrix.png new file mode 100644 index 0000000..60f86b0 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/confusion_matrix.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/confusion_matrix_normalized.png b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/confusion_matrix_normalized.png new file mode 100644 index 0000000..5cfa788 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/confusion_matrix_normalized.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/labels.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/labels.jpg new file mode 100644 index 0000000..41e83b2 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/results.png b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/results.png new file mode 100644 index 0000000..b964b97 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/results.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/train_batch0.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/train_batch0.jpg new file mode 100644 index 0000000..6c48041 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/train_batch0.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/train_batch1.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/train_batch1.jpg new file mode 100644 index 0000000..3feaddd Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/train_batch1.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/train_batch2.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/train_batch2.jpg new file mode 100644 index 0000000..1ebf79f Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/train_batch2.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch0_labels.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch0_labels.jpg new file mode 100644 index 0000000..f9f0710 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch0_labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch0_pred.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch0_pred.jpg new file mode 100644 index 0000000..97c5117 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch0_pred.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch1_labels.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch1_labels.jpg new file mode 100644 index 0000000..d8dc9c2 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch1_labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch1_pred.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch1_pred.jpg new file mode 100644 index 0000000..3286033 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch1_pred.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch2_labels.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch2_labels.jpg new file mode 100644 index 0000000..02a4c6c Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch2_labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch2_pred.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch2_pred.jpg new file mode 100644 index 0000000..4b7c47a Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8n_imgsz_1280/train/val_batch2_pred.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxF1_curve.png b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxF1_curve.png new file mode 100644 index 0000000..073106a Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxF1_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxPR_curve.png b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxPR_curve.png new file mode 100644 index 0000000..157f8c5 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxPR_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxP_curve.png b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxP_curve.png new file mode 100644 index 0000000..c320d32 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxP_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxR_curve.png b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxR_curve.png new file mode 100644 index 0000000..c94c969 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/BoxR_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/confusion_matrix.png b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/confusion_matrix.png new file mode 100644 index 0000000..acd1247 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/confusion_matrix.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/confusion_matrix_normalized.png b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/confusion_matrix_normalized.png new file mode 100644 index 0000000..c353941 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/confusion_matrix_normalized.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/labels.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/labels.jpg new file mode 100644 index 0000000..9fba26d Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/results.png b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/results.png new file mode 100644 index 0000000..d6384b0 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/results.png differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch0.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch0.jpg new file mode 100644 index 0000000..68df35a Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch0.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch1.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch1.jpg new file mode 100644 index 0000000..2bf07fa Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch1.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch2.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch2.jpg new file mode 100644 index 0000000..dc846d6 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch2.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch7560.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch7560.jpg new file mode 100644 index 0000000..c714ce7 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch7560.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch7561.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch7561.jpg new file mode 100644 index 0000000..558bf50 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch7561.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch7562.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch7562.jpg new file mode 100644 index 0000000..70537de Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/train_batch7562.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch0_labels.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch0_labels.jpg new file mode 100644 index 0000000..2e3b499 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch0_labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch0_pred.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch0_pred.jpg new file mode 100644 index 0000000..f3ba50d Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch0_pred.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch1_labels.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch1_labels.jpg new file mode 100644 index 0000000..3ca3d88 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch1_labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch1_pred.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch1_pred.jpg new file mode 100644 index 0000000..50c66fd Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch1_pred.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch2_labels.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch2_labels.jpg new file mode 100644 index 0000000..f58121c Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch2_labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch2_pred.jpg b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch2_pred.jpg new file mode 100644 index 0000000..5dc5204 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1004/yolov8s_imgsz_2048/train/val_batch2_pred.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxF1_curve.png b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxF1_curve.png new file mode 100644 index 0000000..1b5b484 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxF1_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxPR_curve.png b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxPR_curve.png new file mode 100644 index 0000000..cba0b11 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxPR_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxP_curve.png b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxP_curve.png new file mode 100644 index 0000000..9570457 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxP_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxR_curve.png b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxR_curve.png new file mode 100644 index 0000000..9534197 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/BoxR_curve.png differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/confusion_matrix.png b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/confusion_matrix.png new file mode 100644 index 0000000..91bacab Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/confusion_matrix.png differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/confusion_matrix_normalized.png b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/confusion_matrix_normalized.png new file mode 100644 index 0000000..0d7dc49 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/confusion_matrix_normalized.png differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/labels.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/labels.jpg new file mode 100644 index 0000000..25b7999 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/results.png b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/results.png new file mode 100644 index 0000000..ab4f07d Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/results.png differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/train_batch0.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/train_batch0.jpg new file mode 100644 index 0000000..1ae1a7f Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/train_batch0.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/train_batch1.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/train_batch1.jpg new file mode 100644 index 0000000..19dd535 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/train_batch1.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/train_batch2.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/train_batch2.jpg new file mode 100644 index 0000000..22725e0 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/train_batch2.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch0_labels.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch0_labels.jpg new file mode 100644 index 0000000..d02e11b Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch0_labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch0_pred.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch0_pred.jpg new file mode 100644 index 0000000..fd146d0 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch0_pred.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch1_labels.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch1_labels.jpg new file mode 100644 index 0000000..3ff6010 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch1_labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch1_pred.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch1_pred.jpg new file mode 100644 index 0000000..2349a83 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch1_pred.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch2_labels.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch2_labels.jpg new file mode 100644 index 0000000..82dd729 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch2_labels.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch2_pred.jpg b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch2_pred.jpg new file mode 100644 index 0000000..c093b18 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1104/yolov8s_imgsz_2048_9cls/train/val_batch2_pred.jpg differ diff --git a/ai-service/models/Detection/Model_routing_1111/README.md b/ai-service/models/Detection/Model_routing_1111/README.md new file mode 100644 index 0000000..fb8e7e3 --- /dev/null +++ b/ai-service/models/Detection/Model_routing_1111/README.md @@ -0,0 +1,42 @@ +# ๋ผ์šฐํŒ… ์ถ”๋ก  ๋ฐ ํ‰๊ฐ€ ๊ฒฐ๊ณผ + +## ์‹คํ–‰ ๋ฐฉ๋ฒ• + +> !! main ํ•จ์ˆ˜์— ์žˆ๋Š” ๊ฒฝ๋กœ ์„ค์ •์„ ํ™•์ธ ํ›„ ์‹คํ–‰ํ•˜์„ธ์š” !! + +```bash +python infer_and_evaluate.py +``` + +## ์‹คํ–‰ ์ˆœ์„œ + +1. **ํฐ ๊ฐ์ฒด ํƒ์ง€** (best_big_objects.pt) + + - ํด๋ž˜์Šค: answer_option, english_content, korean_content, section + - ์ด๋ฏธ์ง€ ํฌ๊ธฐ: 1280px + - ์‹ ๋ขฐ๋„ ์ž„๊ณ„๊ฐ’: 0.5 (๋ณ€๊ฒฝ ์ž์œ ) + +2. **์ž‘์€ ๊ฐ์ฒด ํƒ์ง€** (best_small_objects.pt) + + - ํด๋ž˜์Šค: page_number, problem_number, answer_1, answer_2, 1, 2, 3, 4, 5 + - ์ด๋ฏธ์ง€ ํฌ๊ธฐ: 2048px + - ์‹ ๋ขฐ๋„ ์ž„๊ณ„๊ฐ’: 0.5 (๋ณ€๊ฒฝ ์ž์œ ) + +3. **ํ›„์ฒ˜๋ฆฌ** (post-processing.py) + - section bbox ๊ต์ • + - ์›๋ณธ section์€ original_section์œผ๋กœ ๋ณ€๊ฒฝ + +## ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ + +- `results/inference_results/`: ์ถ”๋ก  ๊ฒฐ๊ณผ (JSON + ์‹œ๊ฐํ™” ์ด๋ฏธ์ง€) +- `results/post_processed_results/`: ํ›„์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ (JSON + ์‹œ๊ฐํ™” ์ด๋ฏธ์ง€) +- `results/evaluation/`: ์ถ”๋ก  ๊ฒฐ๊ณผ ํ‰๊ฐ€ +- `results/evaluation_post_processed/`: ํ›„์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ํ‰๊ฐ€ + +## ํ‰๊ฐ€ ์ง€ํ‘œ + +- ์ด ์ด๋ฏธ์ง€ ์ˆ˜ +- ์ด ๊ฒ€์ถœ ์ˆ˜ +- ์ด๋ฏธ์ง€๋‹น ํ‰๊ท  ๊ฒ€์ถœ ์ˆ˜ +- ํ‰๊ท  ์‹ ๋ขฐ๋„ +- ํด๋ž˜์Šค๋ณ„ ๊ฒ€์ถœ ์ˆ˜ diff --git a/ai-service/models/Detection/Model_routing_1111/__pycache__/infer_and_evaluate.cpython-311.pyc b/ai-service/models/Detection/Model_routing_1111/__pycache__/infer_and_evaluate.cpython-311.pyc new file mode 100644 index 0000000..173ab7f Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1111/__pycache__/infer_and_evaluate.cpython-311.pyc differ diff --git a/ai-service/models/Detection/Model_routing_1111/__pycache__/infer_and_evaluate.cpython-313.pyc b/ai-service/models/Detection/Model_routing_1111/__pycache__/infer_and_evaluate.cpython-313.pyc new file mode 100644 index 0000000..310f7dc Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1111/__pycache__/infer_and_evaluate.cpython-313.pyc differ diff --git a/ai-service/models/Detection/Model_routing_1111/infer_and_evaluate.py b/ai-service/models/Detection/Model_routing_1111/infer_and_evaluate.py new file mode 100644 index 0000000..b61852c --- /dev/null +++ b/ai-service/models/Detection/Model_routing_1111/infer_and_evaluate.py @@ -0,0 +1,503 @@ +# infer_and_evaluate.py +""" +๋ผ์šฐํŒ… ์ถ”๋ก  ๋ฐ ํ‰๊ฐ€ ์Šคํฌ๋ฆฝํŠธ +ํฐ ๊ฐ์ฒด ํƒ์ง€ -> ์ž‘์€ ๊ฐ์ฒด ํƒ์ง€ -> ํ›„์ฒ˜๋ฆฌ ์ˆœ์„œ๋กœ ์‹คํ–‰ +""" + +import os +import sys +import json +import cv2 +import numpy as np +from pathlib import Path +from typing import List, Dict, Tuple +from ultralytics import YOLO +from datetime import datetime +import sys + +# post-processing ๋ชจ๋“ˆ import +post_processing_dir = Path(__file__).parent / "post_processing" +sys.path.insert(0, str(post_processing_dir)) +import importlib.util +spec = importlib.util.spec_from_file_location("post_processing", post_processing_dir / "post-processing.py") +post_processing_module = importlib.util.module_from_spec(spec) +spec.loader.exec_module(post_processing_module) +post_processing = post_processing_module.post_processing +visualize_detections = post_processing_module.visualize_detections + +# ํด๋ž˜์Šค ๋ผ์šฐํŒ… ์ •์˜ +SMALL_CLASSES = {"page_number", "problem_number", "answer_1", "answer_2"} +LARGE_CLASSES = {"korean_content", "english_content", "section", "answer_option"} + +# ์ „์ฒด ํด๋ž˜์Šค ๋ชฉ๋ก (data.yaml ๊ธฐ์ค€) +ALL_CLASSES = ['1', '2', '3', '4', '5', 'answer_1', 'answer_2', 'answer_option', + 'english_content', 'korean_content', 'page_number', 'problem_number', 'section'] + +# ํด๋ž˜์Šค๋ณ„ ์ƒ‰์ƒ ์ •์˜ (์ฐธ๊ณ ์šฉ, ์‹ค์ œ ์‹œ๊ฐํ™”๋Š” post-processing.py์˜ visualize_detections ์‚ฌ์šฉ) +CLASS_COLORS = { + # ํฐ ๊ฐ์ฒด ํด๋ž˜์Šค + 'answer_option': (0, 255, 0), # ๋…น์ƒ‰ + 'english_content': (255, 0, 0), # ๋นจ๊ฐ„์ƒ‰ + 'korean_content': (0, 0, 255), # ํŒŒ๋ž€์ƒ‰ + 'section': (255, 255, 0), # ๋…ธ๋ž€์ƒ‰ + 'original_section': (0, 0, 255), # ๋นจ๊ฐ„์ƒ‰ (์›๋ณธ section) + + # ์ž‘์€ ๊ฐ์ฒด ํด๋ž˜์Šค + 'page_number': (255, 0, 255), # ๋งˆ์  ํƒ€ + 'problem_number': (0, 255, 255), # ์‹œ์•ˆ + 'answer_1': (255, 165, 0), # ์˜ค๋ Œ์ง€ + 'answer_2': (128, 0, 128), # ๋ณด๋ผ + + # ์ˆซ์ž ํด๋ž˜์Šค + '1': (255, 200, 0), + '2': (200, 255, 0), + '3': (0, 255, 200), + '4': (0, 200, 255), + '5': (200, 0, 255), +} + +class RoutedInference: + def __init__(self, model_dir: str): + """ + ๋ผ์šฐํŒ… ์ถ”๋ก  ํด๋ž˜์Šค ์ดˆ๊ธฐํ™” + + Args: + model_dir: ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ (best_big_objects.pt, best_small_objects.pt ํฌํ•จ) + """ + self.model_dir = Path(model_dir) + + # ๋ชจ๋ธ ๊ฒฝ๋กœ + self.large_model_path = self.model_dir / "models" / "best_big_objects.pt" + self.small_model_path = self.model_dir / "models" / "best_small_objects.pt" + + # ๋ชจ๋ธ ๋กœ๋“œ + print(f"๐Ÿ“ฆ ํฐ ๊ฐ์ฒด ๋ชจ๋ธ ๋กœ๋”ฉ: {self.large_model_path}") + self.large_model = self._load_model(self.large_model_path) + + print(f"๐Ÿ“ฆ ์ž‘์€ ๊ฐ์ฒด ๋ชจ๋ธ ๋กœ๋”ฉ: {self.small_model_path}") + self.small_model = self._load_model(self.small_model_path) + + # ํด๋ž˜์Šค ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ + self.large_class_names = self._get_class_names(self.large_model) + self.small_class_names = self._get_class_names(self.small_model) + + print(f"โœ… ํฐ ๊ฐ์ฒด ํด๋ž˜์Šค: {self.large_class_names}") + print(f"โœ… ์ž‘์€ ๊ฐ์ฒด ํด๋ž˜์Šค: {self.small_class_names}") + + # ์ถ”๋ก  ํŒŒ๋ผ๋ฏธํ„ฐ + self.large_conf = 0.5 + self.small_conf = 0.4 + self.iou_threshold = 0.5 # ๊ฒน์นจ ์ œ๊ฑฐ๋ฅผ ์œ„ํ•œ IOU ์ž„๊ณ„๊ฐ’ + + def _load_model(self, model_path: Path): + """๋ชจ๋ธ ๋กœ๋“œ""" + if not model_path.exists(): + raise FileNotFoundError(f"๋ชจ๋ธ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {model_path}") + return YOLO(str(model_path)) + + def _get_class_names(self, model): + """๋ชจ๋ธ์—์„œ ํด๋ž˜์Šค ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ""" + if hasattr(model, 'names') and model.names: + # model.names๋Š” ๋”•์…”๋„ˆ๋ฆฌ์ด๋ฏ€๋กœ ๊ฐ’๋“ค์„ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜ + names_dict = model.names + # ํด๋ž˜์Šค ID ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌ + max_id = max(names_dict.keys()) if names_dict else -1 + class_names = [names_dict.get(i, f'class_{i}') for i in range(max_id + 1)] + return class_names + return ALL_CLASSES + + def _calculate_iou(self, bbox1: List[float], bbox2: List[float]) -> float: + """ + ๋‘ bounding box ๊ฐ„์˜ IOU(Intersection over Union) ๊ณ„์‚ฐ + + Args: + bbox1: [x_min, y_min, x_max, y_max] + bbox2: [x_min, y_min, x_max, y_max] + + Returns: + IOU ๊ฐ’ (0.0 ~ 1.0) + """ + x1_min, y1_min, x1_max, y1_max = bbox1 + x2_min, y2_min, x2_max, y2_max = bbox2 + + # ๊ต์ง‘ํ•ฉ ์˜์—ญ ๊ณ„์‚ฐ + inter_x_min = max(x1_min, x2_min) + inter_y_min = max(y1_min, y2_min) + inter_x_max = min(x1_max, x2_max) + inter_y_max = min(y1_max, y2_max) + + # ๊ต์ง‘ํ•ฉ์ด ์—†๋Š” ๊ฒฝ์šฐ + if inter_x_max <= inter_x_min or inter_y_max <= inter_y_min: + return 0.0 + + # ๊ต์ง‘ํ•ฉ ๋ฉด์  + inter_area = (inter_x_max - inter_x_min) * (inter_y_max - inter_y_min) + + # ๊ฐ ๋ฐ•์Šค์˜ ๋ฉด์  + bbox1_area = (x1_max - x1_min) * (y1_max - y1_min) + bbox2_area = (x2_max - x2_min) * (y2_max - y2_min) + + # ํ•ฉ์ง‘ํ•ฉ ๋ฉด์  + union_area = bbox1_area + bbox2_area - inter_area + + # IOU ๊ณ„์‚ฐ + if union_area == 0: + return 0.0 + + return inter_area / union_area + + def _remove_overlapping_detections(self, detections: List[Dict], iou_threshold: float = 0.5) -> List[Dict]: + """ + ๊ฐ™์€ ํด๋ž˜์Šค์˜ ๊ฒน์น˜๋Š” ๊ฒ€์ถœ ์ค‘ ๋” ๋†’์€ ์‹ ๋ขฐ๋„๋ฅผ ๊ฐ€์ง„ ๊ฒƒ๋งŒ ๋‚จ๊น€ + + Args: + detections: ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ + iou_threshold: IOU ์ž„๊ณ„๊ฐ’ (์ด ๊ฐ’ ์ด์ƒ์ด๋ฉด ๊ฒน์นจ์œผ๋กœ ๊ฐ„์ฃผ) + + Returns: + ํ•„ํ„ฐ๋ง๋œ ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ + """ + if not detections: + return detections + + # ํด๋ž˜์Šค๋ณ„๋กœ ๊ทธ๋ฃนํ™” + class_groups = {} + for det in detections: + class_name = det.get('class_name', 'unknown') + if class_name not in class_groups: + class_groups[class_name] = [] + class_groups[class_name].append(det) + + filtered_detections = [] + + # ๊ฐ ํด๋ž˜์Šค๋ณ„๋กœ ์ฒ˜๋ฆฌ + for class_name, class_dets in class_groups.items(): + if len(class_dets) == 1: + # ๊ฒ€์ถœ์ด 1๊ฐœ๋งŒ ์žˆ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ์ถ”๊ฐ€ + filtered_detections.append(class_dets[0]) + continue + + # ์‹ ๋ขฐ๋„ ์ˆœ์œผ๋กœ ์ •๋ ฌ (๋†’์€ ์ˆœ) + sorted_dets = sorted(class_dets, key=lambda x: x.get('confidence', 0.0), reverse=True) + + # NMS ์ ์šฉ + kept = [] + for i, det in enumerate(sorted_dets): + is_overlapping = False + bbox1 = det['bbox'] + + # ์ด๋ฏธ ์„ ํƒ๋œ ๋ฐ•์Šค๋“ค๊ณผ ๊ฒน์น˜๋Š”์ง€ ํ™•์ธ + for kept_det in kept: + bbox2 = kept_det['bbox'] + iou = self._calculate_iou(bbox1, bbox2) + + if iou >= iou_threshold: + # ๊ฒน์น˜๋Š” ๊ฒฝ์šฐ, ๋” ๋†’์€ ์‹ ๋ขฐ๋„๋ฅผ ๊ฐ€์ง„ ๊ฒƒ๋งŒ ์œ ์ง€ + if det['confidence'] > kept_det['confidence']: + # ํ˜„์žฌ ๋ฐ•์Šค๊ฐ€ ๋” ๋†’์€ ์‹ ๋ขฐ๋„๋ฅผ ๊ฐ€์ง€๋ฉด ๊ธฐ์กด ๊ฒƒ์„ ์ œ๊ฑฐํ•˜๊ณ  ํ˜„์žฌ ๊ฒƒ์„ ์ถ”๊ฐ€ + kept.remove(kept_det) + kept.append(det) + is_overlapping = True + break + + # ๊ฒน์น˜์ง€ ์•Š์œผ๋ฉด ์ถ”๊ฐ€ + if not is_overlapping: + kept.append(det) + + filtered_detections.extend(kept) + + return filtered_detections + + def get_all_detections(self, results, class_names: List[str]) -> List[Dict]: + """ + ๋ชจ๋“  ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ + """ + all_detections = [] + + if results.boxes is not None: + for box in results.boxes: + cls_id = int(box.cls[0]) + confidence = float(box.conf[0]) + xyxy = box.xyxy[0].tolist() + + if cls_id < len(class_names): + class_name = class_names[cls_id] + + all_detections.append({ + 'class_name': class_name, + 'class_id': cls_id, + 'confidence': confidence, + 'bbox': xyxy + }) + + return all_detections + + def route_infer_single_image(self, image_path: str) -> Dict: + """ + ๋‹จ์ผ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ๋ผ์šฐํŒ… ์ถ”๋ก  ์ˆ˜ํ–‰ + ์ˆœ์„œ: ํฐ ๊ฐ์ฒด ํƒ์ง€ -> ์ž‘์€ ๊ฐ์ฒด ํƒ์ง€ + """ + # 1. ํฐ ๊ฐ์ฒด ๋ชจ๋ธ ์ถ”๋ก  (๋จผ์ € ์‹คํ–‰) + print(f" ๐Ÿ” ํฐ ๊ฐ์ฒด ํƒ์ง€ ์ค‘...") + large_results = self.large_model( + str(image_path), + imgsz=1280, + conf=self.large_conf, + device='cpu', # CPU ์‚ฌ์šฉ + verbose=False + )[0] + large_detections = self.get_all_detections(large_results, self.large_class_names) + + # 2. ์ž‘์€ ๊ฐ์ฒด ๋ชจ๋ธ ์ถ”๋ก  + print(f" ๐Ÿ” ์ž‘์€ ๊ฐ์ฒด ํƒ์ง€ ์ค‘...") + small_results = self.small_model( + str(image_path), + imgsz=2048, + conf=self.small_conf, + device='cpu', # CPU ์‚ฌ์šฉ + verbose=False + )[0] + small_detections = self.get_all_detections(small_results, self.small_class_names) + + # ๊ฒฐ๊ณผ ๋ณ‘ํ•ฉ (ํฐ ๊ฐ์ฒด ๋จผ์ €) + all_detections = large_detections + small_detections + + # ๊ฐ™์€ ํด๋ž˜์Šค์˜ ๊ฒน์น˜๋Š” ๊ฒ€์ถœ ์ œ๊ฑฐ (๋” ๋†’์€ ์‹ ๋ขฐ๋„๋งŒ ์œ ์ง€) + filtered_detections = self._remove_overlapping_detections(all_detections, self.iou_threshold) + + return { + 'image_path': str(image_path), + 'detections': filtered_detections, + 'large_detections': large_detections, + 'small_detections': small_detections, + 'timestamp': datetime.now().isoformat() + } + + +def process_test_dataset( + model_dir: str, + test_data_root: str, + output_dir: str, + run_post_processing: bool = True +): + """ + ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ์…‹์— ๋Œ€ํ•ด ์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ ์‹คํ–‰ + + Args: + model_dir: ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ + test_data_root: ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ๋ฃจํŠธ ๊ฒฝ๋กœ + output_dir: ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ + run_post_processing: ํ›„์ฒ˜๋ฆฌ ์‹คํ–‰ ์—ฌ๋ถ€ + """ + # ๊ฒฝ๋กœ ์„ค์ • + test_data_path = Path(test_data_root) + output_path = Path(output_dir) + + # ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ (ํ›„์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋งŒ) + if run_post_processing: + (output_path / "post_processed_results").mkdir(parents=True, exist_ok=True) + (output_path / "post_processed_results" / "annotations").mkdir(parents=True, exist_ok=True) + (output_path / "post_processed_results" / "images").mkdir(parents=True, exist_ok=True) + + # ์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ (ํ›„์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ž„์‹œ ์ถ”๋ก  ๊ฒฐ๊ณผ ์ €์žฅ์šฉ) + import tempfile + temp_dir = Path(tempfile.mkdtemp(prefix="inference_temp_")) + + # ๋ผ์šฐํŒ… ์ถ”๋ก  ์ดˆ๊ธฐํ™” + router = RoutedInference(model_dir) + + # ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ + test_images_dir = test_data_path / "test" / "images" + if not test_images_dir.exists(): + print(f"โŒ ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {test_images_dir}") + return + + image_extensions = ['.jpg', '.jpeg', '.png', '.bmp'] + image_files = [] + for ext in image_extensions: + image_files.extend(test_images_dir.glob(f"*{ext}")) + image_files.extend(test_images_dir.glob(f"*{ext.upper()}")) + + image_files = sorted(image_files) + print(f"\n๐Ÿ“Š ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ {len(image_files)}๊ฐœ ๋ฐœ๊ฒฌ\n") + + success_count = 0 + error_count = 0 + + for idx, image_path in enumerate(image_files, 1): + try: + print(f"[{idx}/{len(image_files)}] ์ฒ˜๋ฆฌ ์ค‘: {image_path.name}") + + # 1. ๋ผ์šฐํŒ… ์ถ”๋ก  ์‹คํ–‰ + result = router.route_infer_single_image(str(image_path)) + + # ์ถœ๋ ฅ ์–ต์ œ๋ฅผ ์œ„ํ•ด ์ž„์‹œ๋กœ stdout ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ + import io + import contextlib + f = io.StringIO() + + # 2. ํ›„์ฒ˜๋ฆฌ ์‹คํ–‰ (์˜ต์…˜) + if run_post_processing: + print(f" ๐Ÿ”ง ํ›„์ฒ˜๋ฆฌ ์‹คํ–‰ ์ค‘...") + json_filename = image_path.stem + ".json" + + # ์ž„์‹œ ์ถ”๋ก  ๊ฒฐ๊ณผ ์ €์žฅ (ํ›„์ฒ˜๋ฆฌ ํ•จ์ˆ˜๊ฐ€ JSON ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์š”๊ตฌ) + temp_inference_json_path = temp_dir / json_filename + with open(temp_inference_json_path, "w", encoding="utf-8") as f_temp: + json.dump(result, f_temp, ensure_ascii=False, indent=2) + + # ํ›„์ฒ˜๋ฆฌ ์‹คํ–‰ + post_processed_json_path = output_path / "post_processed_results" / "annotations" / json_filename + with contextlib.redirect_stdout(f): + post_processing( + str(temp_inference_json_path), + str(image_path), + str(post_processed_json_path) + ) + + # ํ›„์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์‹œ๊ฐํ™” + post_processed_viz_path = output_path / "post_processed_results" / "images" / (image_path.stem + ".jpg") + with contextlib.redirect_stdout(f): + visualize_detections(str(image_path), str(post_processed_json_path), str(post_processed_viz_path)) + + # ์ž„์‹œ ํŒŒ์ผ ์‚ญ์ œ + temp_inference_json_path.unlink() + + print(f" โœ… ์™„๋ฃŒ\n") + success_count += 1 + + except Exception as e: + print(f" โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}\n") + import traceback + traceback.print_exc() + error_count += 1 + + # ์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์‚ญ์ œ + import shutil + if temp_dir.exists(): + shutil.rmtree(temp_dir) + + print("=" * 80) + print(f"์ฒ˜๋ฆฌ ์™„๋ฃŒ: ์„ฑ๊ณต {success_count}๊ฐœ, ์‹คํŒจ {error_count}๊ฐœ") + if run_post_processing: + print(f"๊ฒฐ๊ณผ ์ €์žฅ ์œ„์น˜:") + print(f" - ํ›„์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ: {output_path / 'post_processed_results'}") + print("=" * 80) + + # ํ‰๊ฐ€ ์ˆ˜ํ–‰ (ํ›„์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋งŒ) + if success_count > 0 and run_post_processing: + print("\n๐Ÿ“Š ํ‰๊ฐ€ ์ˆ˜ํ–‰ ์ค‘...") + evaluate_results( + test_data_path=test_data_path, + results_dir=output_path / "post_processed_results" / "annotations", + output_dir=output_path / "evaluation_post_processed" + ) + + +def evaluate_results(test_data_path: Path, results_dir: Path, output_dir: Path): + """ + ์ถ”๋ก  ๊ฒฐ๊ณผ๋ฅผ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. + + Args: + test_data_path: ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ๋ฃจํŠธ ๊ฒฝ๋กœ + results_dir: ์ถ”๋ก  ๊ฒฐ๊ณผ JSON ํŒŒ์ผ ๋””๋ ‰ํ† ๋ฆฌ + output_dir: ํ‰๊ฐ€ ๊ฒฐ๊ณผ ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ + """ + from collections import defaultdict + + output_dir.mkdir(parents=True, exist_ok=True) + + # ํด๋ž˜์Šค ์ด๋ฆ„ ๋งคํ•‘ (YOLO ํด๋ž˜์Šค ID -> ์ด๋ฆ„) + class_id_to_name = { + 0: '1', 1: '2', 2: '3', 3: '4', 4: '5', + 5: 'answer_1', 6: 'answer_2', 7: 'answer_option', + 8: 'english_content', 9: 'korean_content', + 10: 'page_number', 11: 'problem_number', 12: 'section' + } + + # ํ†ต๊ณ„ ์ˆ˜์ง‘ + class_counts = defaultdict(int) + total_detections = 0 + total_images = 0 + confidence_sum = 0.0 + + # JSON ํŒŒ์ผ ์ฒ˜๋ฆฌ + json_files = sorted(results_dir.glob("*.json")) + + for json_file in json_files: + try: + with open(json_file, "r", encoding="utf-8") as f: + data = json.load(f) + + detections = data.get('detections', []) + total_images += 1 + + for det in detections: + class_name = det.get('class_name', 'unknown') + confidence = det.get('confidence', 0.0) + + class_counts[class_name] += 1 + total_detections += 1 + confidence_sum += confidence + + except Exception as e: + print(f" โš ๏ธ JSON ํŒŒ์ผ ์ฒ˜๋ฆฌ ์˜ค๋ฅ˜: {json_file.name} - {str(e)}") + + # ๊ฒฐ๊ณผ ์ €์žฅ + results_summary = { + 'total_images': total_images, + 'total_detections': total_detections, + 'average_detections_per_image': total_detections / total_images if total_images > 0 else 0, + 'average_confidence': confidence_sum / total_detections if total_detections > 0 else 0, + 'class_counts': dict(class_counts) + } + + # JSON์œผ๋กœ ์ €์žฅ + summary_path = output_dir / "results_summary.json" + with open(summary_path, "w", encoding="utf-8") as f: + json.dump(results_summary, f, ensure_ascii=False, indent=2) + + # ํ…์ŠคํŠธ ์š”์•ฝ ์ถœ๋ ฅ + print("\n" + "=" * 80) + print("๐Ÿ“Š ํ‰๊ฐ€ ๊ฒฐ๊ณผ ์š”์•ฝ") + print("=" * 80) + print(f"์ด ์ด๋ฏธ์ง€ ์ˆ˜: {total_images}") + print(f"์ด ๊ฒ€์ถœ ์ˆ˜: {total_detections}") + print(f"์ด๋ฏธ์ง€๋‹น ํ‰๊ท  ๊ฒ€์ถœ ์ˆ˜: {results_summary['average_detections_per_image']:.2f}") + print(f"ํ‰๊ท  ์‹ ๋ขฐ๋„: {results_summary['average_confidence']:.3f}") + print("\nํด๋ž˜์Šค๋ณ„ ๊ฒ€์ถœ ์ˆ˜:") + for class_name, count in sorted(class_counts.items()): + print(f" - {class_name}: {count}") + print(f"\n๊ฒฐ๊ณผ ์ €์žฅ: {summary_path}") + print("=" * 80) + + +def main(): + """๋ฉ”์ธ ํ•จ์ˆ˜""" + import argparse + + parser = argparse.ArgumentParser(description="๋ผ์šฐํŒ… ์ถ”๋ก  ๋ฐ ํ‰๊ฐ€") + parser.add_argument("--model_dir", type=str, + default=str(Path(__file__).parent / "models"), + help="๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ") + parser.add_argument("--test_data", type=str, + default=str(Path(__file__).parent.parent.parent / "Data" / "temp_extract_251104"), + help="ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ๋ฃจํŠธ ๊ฒฝ๋กœ") + parser.add_argument("--output_dir", type=str, + default=str(Path(__file__).parent / "results"), + help="์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ") + parser.add_argument("--no_post_processing", action="store_true", + help="ํ›„์ฒ˜๋ฆฌ ๊ฑด๋„ˆ๋›ฐ๊ธฐ") + + args = parser.parse_args() + + process_test_dataset( + model_dir=args.model_dir, + test_data_root=args.test_data, + output_dir=args.output_dir, + run_post_processing=not args.no_post_processing + ) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ai-service/models/Detection/Model_routing_1111/models/best_big_objects.pt b/ai-service/models/Detection/Model_routing_1111/models/best_big_objects.pt new file mode 100644 index 0000000..77a3148 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1111/models/best_big_objects.pt differ diff --git a/ai-service/models/Detection/Model_routing_1111/models/best_small_objects.pt b/ai-service/models/Detection/Model_routing_1111/models/best_small_objects.pt new file mode 100644 index 0000000..032a233 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1111/models/best_small_objects.pt differ diff --git a/ai-service/models/Detection/Model_routing_1111/post_processing/__pycache__/post-processing.cpython-311.pyc b/ai-service/models/Detection/Model_routing_1111/post_processing/__pycache__/post-processing.cpython-311.pyc new file mode 100644 index 0000000..7e44c4c Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1111/post_processing/__pycache__/post-processing.cpython-311.pyc differ diff --git a/ai-service/models/Detection/Model_routing_1111/post_processing/__pycache__/post-processing.cpython-313.pyc b/ai-service/models/Detection/Model_routing_1111/post_processing/__pycache__/post-processing.cpython-313.pyc new file mode 100644 index 0000000..b5f2379 Binary files /dev/null and b/ai-service/models/Detection/Model_routing_1111/post_processing/__pycache__/post-processing.cpython-313.pyc differ diff --git a/ai-service/models/Detection/Model_routing_1111/post_processing/post-processing.py b/ai-service/models/Detection/Model_routing_1111/post_processing/post-processing.py new file mode 100644 index 0000000..155b1c4 --- /dev/null +++ b/ai-service/models/Detection/Model_routing_1111/post_processing/post-processing.py @@ -0,0 +1,388 @@ +# post-processing.py +# ๊ณต๋ฐฑ ์—ฌ๋ถ€ ํŒ๋‹จ ๊ธฐ์ค€ (๋ณตํ•ฉ์ ): +# 1. ํ‰๊ท  ํ”ฝ์…€ ๊ฐ’์ด 240 ์ด์ƒ์ด๋ฉด ๊ณต๋ฐฑ ๊ฐ€๋Šฅ์„ฑ โ†‘ +# 2. ํ‘œ์ค€ํŽธ์ฐจ(standard deviation)๊ฐ€ ๋‚ฎ์œผ๋ฉด(์˜ˆ: 15 ์ดํ•˜), ๋งค์šฐ ๊ท ์ผํ•œ ์ƒ‰์ƒ โ†’ ๊ณต๋ฐฑ ๊ฐ€๋Šฅ์„ฑ โ†‘ +# 3. ์—ฃ์ง€(Edge) ๊ฒ€์ถœ(์˜ˆ: Canny ๋“ฑ) ๊ฒฐ๊ณผ ์—ฃ์ง€ ํ”ฝ์…€ ๋น„์œจ์ด ์ผ์ • ์ดํ•˜(์˜ˆ: 0.5% ๋ฏธ๋งŒ)๋ฉด ํ…์ŠคํŠธ/๋‚ด์šฉ ์—†์Œ โ†’ ๊ณต๋ฐฑ ๊ฐ€๋Šฅ์„ฑ โ†‘ +# 4. ROI๊ฐ€ ์ด๋ฏธ์ง€ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด๊ฐˆ ๋•, ROI๋ฅผ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๋‚ด๋กœ clipํ•˜์—ฌ ์ฒ˜๋ฆฌ (์ตœ๋Œ€ min, ์ตœ์†Œ max๋กœ) +# ์œ„ ๊ธฐ์ค€์„ ์ข…ํ•ฉ์ ์œผ๋กœ ์ ์šฉํ•˜์—ฌ ํ•ด๋‹น ์˜์—ญ์ด '๊ณต๋ฐฑ'์ธ์ง€ ํŒ๋‹จ + + +# ๊ณต๋ฐฑ ์—ฌ๋ถ€ ํŒ๋‹จ ํ•จ์ˆ˜ +def is_blank_region(image, roi, mean_thresh=240, stddev_thresh=15, edge_ratio_thresh=0.005): + """ + ์ด๋ฏธ์ง€์—์„œ roi ์˜์—ญ์ด '๊ณต๋ฐฑ'์ธ์ง€ ํŒ๋‹จํ•˜๋Š” ํ•จ์ˆ˜. + - image: numpy array (H, W, 3) + - roi: (x_min, y_min, x_max, y_max) + - mean_thresh: ํ‰๊ท  ํ”ฝ์…€ ์ž„๊ณ„๊ฐ’ (default 240) + - stddev_thresh: ํ‘œ์ค€ํŽธ์ฐจ ์ž„๊ณ„๊ฐ’ (default 15) + - edge_ratio_thresh: ์—ฃ์ง€ ๋น„์œจ ์ž„๊ณ„๊ฐ’ (default 0.005 == 0.5%) + """ + import numpy as np + import cv2 + + x_min, y_min, x_max, y_max = roi + + # ROI๋ฅผ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๋‚ด๋กœ clip + h, w = image.shape[:2] + x_min = max(0, int(round(x_min))) + y_min = max(0, int(round(y_min))) + x_max = min(w, int(round(x_max))) + y_max = min(h, int(round(y_max))) + + if x_max <= x_min or y_max <= y_min: + return True # ์ž˜๋ชป๋œ ROI๋Š” ๊ณต๋ฐฑ์œผ๋กœ ๊ฐ„์ฃผ + + roi_img = image[y_min:y_max, x_min:x_max] + + # Gray ๋ณ€ํ™˜ + if len(roi_img.shape) == 3: + roi_gray = cv2.cvtColor(roi_img, cv2.COLOR_BGR2GRAY) + else: + roi_gray = roi_img + + mean = np.mean(roi_gray) + stddev = np.std(roi_gray) + + # Canny Edge + # ์ž๋™ ์ž„๊ณ„๊ฐ’ ์„ค์ •(๊ธฐ๋ณธ๊ฐ’ ์ œ๊ณต) + v = np.median(roi_gray) + lower = int(max(0, 0.66 * v)) + upper = int(min(255, 1.33 * v)) + edges = cv2.Canny(roi_gray, lower, upper) + edge_ratio = np.sum(edges > 0) / (roi_gray.shape[0]*roi_gray.shape[1]+1e-5) + + # ๊ณต๋ฐฑ ํŒ์ • + result = (mean >= mean_thresh and stddev <= stddev_thresh and edge_ratio <= edge_ratio_thresh) + return result + + + +# ํ•จ์ˆ˜ ์ •์˜ + # ํ•จ์ˆ˜ ์ด๋ฆ„: post_processing + # ํ•จ์ˆ˜ description: yolov8 ์ถ”๋ก  ๊ฒฐ๊ณผ๋ฅผ ํ›„์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜ + # ์ž…๋ ฅ: yolov8 ์ถ”๋ก  ๊ฒฐ๊ณผ (json ํŒŒ์ผ) + # ์ถœ๋ ฅ: ์ฒ˜๋ฆฌ๋œ yolov8 ์ถ”๋ก  ๊ฒฐ๊ณผ (json ํŒŒ์ผ) + +def post_processing(yolo_json_path, image_path, output_json_path): + import json + import cv2 + import numpy as np + + ROI_HEIGHT = 60 + + # yolov8 ๊ฒฐ๊ณผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + with open(yolo_json_path, "r", encoding="utf-8") as f: + yolo_result = json.load(f) + image = cv2.imread(image_path) + + if image is None: + raise ValueError(f"์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {image_path}") + + # detections ๋ฐฐ์—ด ๊ฐ€์ ธ์˜ค๊ธฐ + detections = yolo_result.get('detections', yolo_result) if isinstance(yolo_result, dict) else yolo_result + + # ์šฐ์„  ๋ชจ๋“  problem_number์˜ ์™ผ์ชฝ ์œ„ ์ขŒํ‘œ๋ฅผ ์ฐพ์•„ ๋ฐฐ์—ด์— ์ €์žฅํ•œ๋‹ค. (x_min, y_min) + question_numbers = [] + for obj in detections: + class_name = obj.get('class_name', obj.get('label', '')) + if class_name == 'problem_number': + question_numbers.append((obj['bbox'][0], obj['bbox'][1])) + + print(f"question_numbers: {question_numbers}\n") + + # ๋ฐ˜๋ณต๋ฌธ: ๋ชจ๋“  section์— ๋Œ€ํ•ด ๋ฐ˜๋ณตํ•œ๋‹ค. + # ๊ฐ section์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ๊ต์ •์ด ๋๋‚˜๋ฉด ์›๋ž˜ section(obj)๋ฅผ detections์—์„œ ์ฆ‰์‹œ ์‚ญ์ œ + sections_to_remove = [] + for obj in detections[:]: + class_name = obj.get('class_name', obj.get('label', '')) + if class_name != 'section': + continue + + import copy + original_section = obj + # original_section์„ deep copyํ•œ section ์ƒ์„ฑ + section = copy.deepcopy(obj) + + # INSERT_YOUR_CODE + original_section['class_name'] = "original_section" + + + x_min, y_min = section['bbox'][0], section['bbox'][1] + x_max, y_max = section['bbox'][2], section['bbox'][3] + + # 1. section์— ๋Œ€ํ•ด ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด question_number๋ฅผ ์ฐพ์•„ ์™ผ์ชฝ ์œ„ ๊ผญ์ง“์ ์„ ๋งž์ถ˜๋‹ค. + # - section ๊ฐ์ฒด์˜ ์™ผ์ชฝ ์œ„ ์ขŒํ‘œ๋ฅผ ์ฐพ๋Š”๋‹ค. (x_min, y_min) + # - ํ•ด๋‹น ์ขŒํ‘œ์™€ ๋ชจ๋“  question_number์˜ ์™ผ์ชฝ ์œ„ ์ขŒํ‘œ์™€์˜ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ๊ฐ€์žฅ ์ž‘์€ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐ€์ง„ question_number๋ฅผ ์ฐพ๋Š”๋‹ค. + # - section์˜ ์™ผ์ชฝ ์œ„ ๊ผญ์ง“์ ์„ ํ•ด๋‹น question_number์˜ ์™ผ์ชฝ ์œ„ ๊ผญ์ง“์ ์œผ๋กœ ๋งž์ถ˜๋‹ค. + # - ๋ชจ๋“  section์— ๋Œ€ํ•ด ๋ฐ˜๋ณตํ•œ๋‹ค. + min_dist = float('inf') + nearest_qn = None + for qn_x, qn_y in question_numbers: + dist = np.sqrt((qn_x - x_min)**2 + (qn_y - y_min)**2) + if dist < min_dist: + min_dist = dist + nearest_qn = (qn_x, qn_y) + if nearest_qn is not None: + print(f"\n\nํ˜„์žฌ x_min, y_min: {x_min, y_min}, ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด question_number: {nearest_qn}") + x_min = nearest_qn[0] + y_min = nearest_qn[1] + section['bbox'][0] = max(0, x_min - 20) # ์กฐ์ ˆ๊ฐ’ + section['bbox'][1] = y_min + print(f"question_number์— ๋งž๊ฒŒ ๋ณ€๊ฒฝ ํ›„ x_min, y_min: {x_min, y_min}\n") + + + # 2. section์— ๋Œ€ํ•ด Top_line_ROI์™€ Bottom_line_ROI๋ฅผ ํ†ตํ•œ ์˜์—ญ ์ถ”์ถœ ํ›„ ๊ณต๋ฐฑ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•œ๋‹ค. + # ํƒ‘๋ผ์ธ์—์„œ ์œ„๊ฐ€ ๊ณต๋ฐฑ์ด๋ฉด ๋ฉˆ์ถ”๊ณ , ๊ณต๋ฐฑ์ด ์•„๋‹ˆ๋ฉด ์˜ฌ๋ผ๊ฐ„๋‹ค. + # ๋ฐ”ํ…€๋ผ์ธ์—์„œ ์•„๋ž˜๊ฐ€ ๊ณต๋ฐฑ์ด๋ฉด ๋ฉˆ์ถ”๊ณ , ๊ณต๋ฐฑ์ด ์•„๋‹ˆ๋ฉด ๋‚ด๋ ค๊ฐ„๋‹ค. + + # ์œ„์ชฝ ํ™•์žฅ (iteration ๋ฐ max_iterations ์—†์Œ) + print("์œ„์ชฝ ํ™•์žฅ์‹œ์ž‘!!!!!\n\n") + while True: + if y_min - ROI_HEIGHT/2 < 0: + break + + top_upside_roi = [x_min, y_min - ROI_HEIGHT/2, x_max, y_min] + top_downside_roi = [x_min, y_min, x_max, y_min + ROI_HEIGHT/2] + top_upside_roi = [max(0, top_upside_roi[0]), max(0, top_upside_roi[1]), min(image.shape[1], top_upside_roi[2]), min(image.shape[0], top_upside_roi[3])] + top_downside_roi = [max(0, top_downside_roi[0]), max(0, top_downside_roi[1]), min(image.shape[1], top_downside_roi[2]), min(image.shape[0], top_downside_roi[3])] + is_top_upside_blank = is_blank_region(image, top_upside_roi) + is_top_downside_blank = is_blank_region(image, top_downside_roi) + print(f"is_top_upside_blank: {is_top_upside_blank}, is_top_downside_blank: {is_top_downside_blank}\n") + if not is_top_upside_blank: + print(f"์˜ฌ๋ผ๊ฐ„๋‹ค. y_min: {y_min} -> {y_min - ROI_HEIGHT/2}\n") + y_min -= ROI_HEIGHT/2 + section['bbox'][1] = y_min + continue + if is_top_upside_blank: + break + else: + break + + # ์•„๋ž˜์ชฝ ํ™•์žฅ (iteration ๋ฐ max_iterations ์—†์Œ) + while True: + if y_max + ROI_HEIGHT/2 > image.shape[0]: + break + bottom_upside_roi = [x_min, y_max-ROI_HEIGHT/2, x_max, y_max] + bottom_downside_roi = [x_min, y_max, x_max, y_max + ROI_HEIGHT/2] + bottom_upside_roi = [max(0, bottom_upside_roi[0]), max(0, bottom_upside_roi[1]), min(image.shape[1], bottom_upside_roi[2]), min(image.shape[0], bottom_upside_roi[3])] + bottom_downside_roi = [max(0, bottom_downside_roi[0]), max(0, bottom_downside_roi[1]), min(image.shape[1], bottom_downside_roi[2]), min(image.shape[0], bottom_downside_roi[3])] + is_bottom_upside_blank = is_blank_region(image, bottom_upside_roi) + is_bottom_downside_blank = is_blank_region(image, bottom_downside_roi) + + # ์•„๋ž˜์ชฝ ํ™•์žฅ ์กฐ๊ฑด: bottom ROI(upside, downside) ์˜์—ญ์ด ๋ชจ๋‘ ๊ณต๋ฐฑ์ด ์•„๋‹ˆ๋ผ๋ฉด ํ•ด๋‹น section์˜ y_max += ROI_HEIGHT/2๋ฅผ ํ•œ๋‹ค.(bbox๋ฅผ ์•„๋ž˜๋กœ ๋Š˜๋ฆฐ๋‹ค.) + if not is_bottom_downside_blank: + print("๋‚ด๋ ค๊ฐ‘๋‹ˆ๋‹ค. y_max: ", y_max) + y_max += ROI_HEIGHT/2 + section['bbox'][3] = y_max + print("๋‚ด๋ ค๊ฐ„ ํ›„ y_max: ", y_max) + continue + if is_bottom_downside_blank: + break + else: + break + + # # ๊ต์ •์ด ๋๋‚œ section์„ ๋ณต์‚ฌ๋ณธ์œผ๋กœ ๋งŒ๋“ค์–ด์„œ detections์— ์ถ”๊ฐ€ + # corrected_section = { + # 'class_name': section.get('class_name', section.get('label', 'section')), + # 'class_id': section.get('class_id', 0), + # 'confidence': section.get('confidence', 0.0), + # 'bbox': [x_min, y_min, x_max, y_max] # ๊ต์ •๋œ bbox + # } + # # ๋‹ค๋ฅธ ํ•„๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด ๋ณต์‚ฌ + # for key in section.keys(): + # if key not in corrected_section: + # corrected_section[key] = section[key] + + detections.append(section) + + + + # ๊ฒฐ๊ณผ ์ €์žฅ + if isinstance(yolo_result, dict): + # ์›๋ณธ ๊ตฌ์กฐ ์œ ์ง€ + yolo_result['detections'] = detections + output_data = yolo_result + else: + output_data = detections + + with open(output_json_path, "w", encoding="utf-8") as f: + json.dump(output_data, f, ensure_ascii=False, indent=4) + + +def visualize_detections(image_path, json_path, output_image_path): + """ + JSON ํŒŒ์ผ์˜ detection ๊ฒฐ๊ณผ๋ฅผ ์ด๋ฏธ์ง€์— ์‹œ๊ฐํ™”ํ•ฉ๋‹ˆ๋‹ค. + """ + import json + import cv2 + import numpy as np + + # ์ด๋ฏธ์ง€ ๋กœ๋“œ (๋ณต์‚ฌ๋ณธ ์‚ฌ์šฉ) + image = cv2.imread(image_path) + if image is None: + raise ValueError(f"์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {image_path}") + image = image.copy() # ์›๋ณธ ์ด๋ฏธ์ง€ ๋ณดํ˜ธ๋ฅผ ์œ„ํ•ด ๋ณต์‚ฌ + + # JSON ๋กœ๋“œ + with open(json_path, "r", encoding="utf-8") as f: + data = json.load(f) + + detections = data.get('detections', data) if isinstance(data, dict) else data + + # ํด๋ž˜์Šค๋ณ„ ์ƒ‰์ƒ ์ •์˜ (BGR ํ˜•์‹) + colors = { + # ํฐ ๊ฐ์ฒด ํด๋ž˜์Šค + 'section': (0, 255, 0), # ๋…น์ƒ‰ (๊ต์ •๋œ section, ๋” ๋ˆˆ์— ๋„๋Š” ์ƒ‰) + 'original_section': (0, 0, 255), # ์ง„ํ•œ ๋นจ๊ฐ„์ƒ‰ (original_section์€ ๋งค์šฐ ๋ˆˆ์— ๋„๊ฒŒ ํ‘œ์‹œ) + 'answer_option': (0, 255, 255), # ๋…ธ๋ž€์ƒ‰ (BGR: 0,255,255 = RGB: 255,255,0) + 'english_content': (255, 0, 0), # ๋นจ๊ฐ„์ƒ‰ + 'korean_content': (255, 0, 255), # ๋งˆ์  ํƒ€ + + # ์ž‘์€ ๊ฐ์ฒด ํด๋ž˜์Šค + 'problem_number': (255, 255, 0), # ์‹œ์•ˆ (BGR: 255,255,0 = RGB: 0,255,255) + 'page_number': (128, 0, 128), # ๋ณด๋ผ + 'answer_1': (255, 165, 0), # ์˜ค๋ Œ์ง€ + 'answer_2': (0, 128, 255), # ์ฃผํ™ฉ์ƒ‰ ๊ณ„์—ด + + # ์ˆซ์ž ํด๋ž˜์Šค + '1': (255, 200, 0), # ๋…ธ๋ž€์ƒ‰ ๊ณ„์—ด + '2': (200, 255, 0), # ์—ฐ๋‘์ƒ‰ ๊ณ„์—ด + '3': (0, 255, 200), # ์ฒญ๋ก์ƒ‰ ๊ณ„์—ด + '4': (0, 200, 255), # ํ•˜๋Š˜์ƒ‰ ๊ณ„์—ด + '5': (200, 0, 255), # ์ž์ฃผ์ƒ‰ ๊ณ„์—ด + } + + # ๊ฐ detection ๊ทธ๋ฆฌ๊ธฐ + for obj in detections: + class_name = obj.get('class_name', obj.get('label', 'unknown')) + bbox = obj['bbox'] + confidence = obj.get('confidence', 0.0) + + x_min, y_min, x_max, y_max = map(int, bbox) + + # ์ƒ‰์ƒ ์„ ํƒ + color = colors.get(class_name, (255, 255, 255)) # ๊ธฐ๋ณธ๊ฐ’: ๊ฒ€์ •์ƒ‰ + + # ๋ฐ•์Šค ๊ทธ๋ฆฌ๊ธฐ + cv2.rectangle(image, (x_min, y_min), (x_max, y_max), color, 2) + + # ๋ ˆ์ด๋ธ” ํ…์ŠคํŠธ + label_text = f"{class_name}: {confidence:.2f}" + (text_width, text_height), baseline = cv2.getTextSize( + label_text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1 + ) + + # ํ…์ŠคํŠธ ๋ฐฐ๊ฒฝ + cv2.rectangle( + image, + (x_min, y_min - text_height - baseline - 5), + (x_min + text_width, y_min), + color, + -1 + ) + + # ํ…์ŠคํŠธ + cv2.putText( + image, + label_text, + (x_min, y_min - baseline - 2), + cv2.FONT_HERSHEY_SIMPLEX, + 0.5, + (0, 0, 0), + 1 + ) + + # ๊ฒฐ๊ณผ ์ €์žฅ + cv2.imwrite(output_image_path, image) + print(f"์‹œ๊ฐํ™” ๊ฒฐ๊ณผ ์ €์žฅ: {output_image_path}") + + +def main(): + """ + post_processing ํ•จ์ˆ˜๋ฅผ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. + annotations ํด๋”์˜ ๋ชจ๋“  JSON ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. + """ + from pathlib import Path + + # ๊ฒฝ๋กœ ์„ค์ • + base_dir = Path(__file__).parent + annotations_dir = base_dir / "annotations" + images_dir = base_dir / "images" + output_json_dir = base_dir / "test_v15" + output_viz_dir = base_dir / "visualization_v15" + + # ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ + output_json_dir.mkdir(exist_ok=True) + output_viz_dir.mkdir(exist_ok=True) + + # JSON ํŒŒ์ผ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ + json_files = sorted(annotations_dir.glob("*.json")) + + if len(json_files) == 0: + print(f"โŒ JSON ํŒŒ์ผ์ด ์—†์Šต๋‹ˆ๋‹ค: {annotations_dir}") + return + + print("=" * 80) + print("post_processing ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธ") + print("=" * 80) + print(f"์ฒ˜๋ฆฌํ•  ํŒŒ์ผ ์ˆ˜: {len(json_files)}") + print() + + success_count = 0 + error_count = 0 + + for json_file in json_files: + try: + # ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ฐพ๊ธฐ (JSON ํŒŒ์ผ๋ช…์—์„œ "result_" ์ ‘๋‘์‚ฌ ์ œ๊ฑฐ) + json_stem = json_file.stem + if json_stem.startswith("result_"): + image_stem = json_stem[7:] # "result_" ์ œ๊ฑฐ (7๊ธ€์ž) + else: + image_stem = json_stem + image_name = image_stem + ".jpg" + image_path = images_dir / image_name + + if not image_path.exists(): + print(f"โš ๏ธ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {image_name}") + error_count += 1 + continue + + # ์ถœ๋ ฅ ํŒŒ์ผ ๊ฒฝ๋กœ + output_json_path = output_json_dir / json_file.name + output_image_path = output_viz_dir / image_name + + print(f"๐Ÿ“„ ์ฒ˜๋ฆฌ ์ค‘: {json_file.name}") + + # ํ›„์ฒ˜๋ฆฌ ์‹คํ–‰ + post_processing( + str(json_file), + str(image_path), + str(output_json_path) + ) + + # ์‹œ๊ฐํ™” + visualize_detections( + str(image_path), + str(output_json_path), + str(output_image_path) + ) + + print(f" โœ… ์™„๋ฃŒ: {json_file.name}") + success_count += 1 + + except Exception as e: + print(f" โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {json_file.name}") + print(f" {str(e)}") + error_count += 1 + + print() + print("=" * 80) + print(f"ํ…Œ์ŠคํŠธ ์™„๋ฃŒ: ์„ฑ๊ณต {success_count}๊ฐœ, ์‹คํŒจ {error_count}๊ฐœ") + print(f"๊ฒฐ๊ณผ JSON: {output_json_dir}") + print(f"์‹œ๊ฐํ™” ์ด๋ฏธ์ง€: {output_viz_dir}") + print("=" * 80) + + +if __name__ == "__main__": + main() + diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 79_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 79_routed.jpg" new file mode 100644 index 0000000..300f2a5 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 79_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 80_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 80_routed.jpg" new file mode 100644 index 0000000..e4c947f Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 80_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 81_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 81_routed.jpg" new file mode 100644 index 0000000..5e519f1 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 81_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 82_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 82_routed.jpg" new file mode 100644 index 0000000..eee5cff Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 82_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 83_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 83_routed.jpg" new file mode 100644 index 0000000..20bdfd6 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 83_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 84_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 84_routed.jpg" new file mode 100644 index 0000000..957875f Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 84_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 85_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 85_routed.jpg" new file mode 100644 index 0000000..1662751 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\213\244\354\240\204 \353\252\250\354\235\230\352\263\240\354\202\254) - 85_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 10_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 10_routed.jpg" new file mode 100644 index 0000000..5472784 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 10_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 11_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 11_routed.jpg" new file mode 100644 index 0000000..01eeced Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 11_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 1_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 1_routed.jpg" new file mode 100644 index 0000000..a68f407 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 1_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 2_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 2_routed.jpg" new file mode 100644 index 0000000..0f4ab75 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 2_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 3_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 3_routed.jpg" new file mode 100644 index 0000000..da6672c Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 3_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 4_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 4_routed.jpg" new file mode 100644 index 0000000..d44db44 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 4_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 5_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 5_routed.jpg" new file mode 100644 index 0000000..8e189da Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 5_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 6_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 6_routed.jpg" new file mode 100644 index 0000000..0926701 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 6_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 7_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 7_routed.jpg" new file mode 100644 index 0000000..869dc61 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 7_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 8_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 8_routed.jpg" new file mode 100644 index 0000000..6dc069b Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 8_routed.jpg" differ diff --git "a/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 9_routed.jpg" "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 9_routed.jpg" new file mode 100644 index 0000000..c793b70 Binary files /dev/null and "b/ai-service/models/Detection/experiment_routing_0930/inference_test_routing_0930/visualizations/\355\225\231\354\203\235\354\235\264 \355\221\274 \353\254\270\354\240\234(\354\234\240\355\230\225\355\216\270) - 9_routed.jpg" differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxF1_curve.png b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxF1_curve.png new file mode 100644 index 0000000..c69d3ad Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxF1_curve.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxPR_curve.png b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxPR_curve.png new file mode 100644 index 0000000..fc8ce57 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxPR_curve.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxP_curve.png b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxP_curve.png new file mode 100644 index 0000000..8df4fa0 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxP_curve.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxR_curve.png b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxR_curve.png new file mode 100644 index 0000000..0d48e25 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/BoxR_curve.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/confusion_matrix.png b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/confusion_matrix.png new file mode 100644 index 0000000..d84c361 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/confusion_matrix.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/confusion_matrix_normalized.png b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/confusion_matrix_normalized.png new file mode 100644 index 0000000..6eea7cb Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/confusion_matrix_normalized.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/labels.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/labels.jpg new file mode 100644 index 0000000..d190e9d Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/labels.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/results.png b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/results.png new file mode 100644 index 0000000..6ee7ff1 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/results.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch0.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch0.jpg new file mode 100644 index 0000000..04b810c Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch0.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch1.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch1.jpg new file mode 100644 index 0000000..4666128 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch1.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2.jpg new file mode 100644 index 0000000..eebc4fc Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2070.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2070.jpg new file mode 100644 index 0000000..1328172 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2070.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2071.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2071.jpg new file mode 100644 index 0000000..b85daa2 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2071.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2072.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2072.jpg new file mode 100644 index 0000000..9c8ecc9 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/train_batch2072.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch0_labels.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch0_labels.jpg new file mode 100644 index 0000000..027ff13 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch0_labels.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch0_pred.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch0_pred.jpg new file mode 100644 index 0000000..c9ad87b Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch0_pred.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch1_labels.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch1_labels.jpg new file mode 100644 index 0000000..1a2f3b3 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch1_labels.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch1_pred.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch1_pred.jpg new file mode 100644 index 0000000..6634c8f Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch1_pred.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch2_labels.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch2_labels.jpg new file mode 100644 index 0000000..66f2c2a Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch2_labels.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch2_pred.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch2_pred.jpg new file mode 100644 index 0000000..ae65459 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8n_imgsz_1280/train/val_batch2_pred.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxF1_curve.png b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxF1_curve.png new file mode 100644 index 0000000..f6400d2 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxF1_curve.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxPR_curve.png b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxPR_curve.png new file mode 100644 index 0000000..4342a17 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxPR_curve.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxP_curve.png b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxP_curve.png new file mode 100644 index 0000000..6fc5a31 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxP_curve.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxR_curve.png b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxR_curve.png new file mode 100644 index 0000000..68b5e2f Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/BoxR_curve.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/confusion_matrix.png b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/confusion_matrix.png new file mode 100644 index 0000000..c064374 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/confusion_matrix.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/confusion_matrix_normalized.png b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/confusion_matrix_normalized.png new file mode 100644 index 0000000..2a92763 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/confusion_matrix_normalized.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/labels.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/labels.jpg new file mode 100644 index 0000000..f717587 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/labels.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/results.png b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/results.png new file mode 100644 index 0000000..4eb5a8d Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/results.png differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch0.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch0.jpg new file mode 100644 index 0000000..eb8cd7e Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch0.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch1.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch1.jpg new file mode 100644 index 0000000..efd8d2f Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch1.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch2.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch2.jpg new file mode 100644 index 0000000..000a47d Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch2.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch4050.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch4050.jpg new file mode 100644 index 0000000..167b078 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch4050.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch4051.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch4051.jpg new file mode 100644 index 0000000..abe63cf Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch4051.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch4052.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch4052.jpg new file mode 100644 index 0000000..abffc0d Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/train_batch4052.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch0_labels.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch0_labels.jpg new file mode 100644 index 0000000..b5e32bc Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch0_labels.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch0_pred.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch0_pred.jpg new file mode 100644 index 0000000..587fe08 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch0_pred.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch1_labels.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch1_labels.jpg new file mode 100644 index 0000000..6a6fc52 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch1_labels.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch1_pred.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch1_pred.jpg new file mode 100644 index 0000000..9d9f490 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch1_pred.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch2_labels.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch2_labels.jpg new file mode 100644 index 0000000..ba46a3b Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch2_labels.jpg differ diff --git a/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch2_pred.jpg b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch2_pred.jpg new file mode 100644 index 0000000..5b35c10 Binary files /dev/null and b/ai-service/models/Detection/experiment_routing_0930/yolov8s_imgsz_2048/train/val_batch2_pred.jpg differ diff --git a/ai-service/models/Detection/legacy/0930_english_best_detection_yolov8n.pt b/ai-service/models/Detection/legacy/0930_english_best_detection_yolov8n.pt new file mode 100644 index 0000000..6aa63b9 Binary files /dev/null and b/ai-service/models/Detection/legacy/0930_english_best_detection_yolov8n.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/README.md b/ai-service/models/Detection/legacy/Model_routing_1004/README.md new file mode 100644 index 0000000..5afbd91 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/README.md @@ -0,0 +1,41 @@ +# Routing Experiment 1004 + +## ๊ฐœ์š” +์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ์…‹ (476๊ฐœ ์ด๋ฏธ์ง€)์„ ์‚ฌ์šฉํ•œ ๋ชจ๋ธ ๋ผ์šฐํŒ… ์‹คํ—˜ + +## ๋ชจ๋ธ ๊ตฌ์„ฑ + +### YOLOv8n @ 1280 (ํฐ ๊ฐ์ฒด) +- **๋Œ€์ƒ ํด๋ž˜์Šค**: answer_option, english_content, korean_content, section +- **GPU**: [0,1] +- **์ฆ๊ฐ•**: ์—†์Œ +- **์šฉ๋„**: ํฐ ๊ฐ์ฒด ๊ฒ€์ถœ + +### YOLOv8s @ 2048 (์ž‘์€ ๊ฐ์ฒด) +- **๋Œ€์ƒ ํด๋ž˜์Šค**: page_number, problem_number, answer_1, answer_2 +- **GPU**: [2,3] +- **์ฆ๊ฐ•**: translate, scale, degrees(ยฑ3ยฐ), shear(ยฑ1ยฐ) +- **cls_loss_weight**: 3.0 (ํด๋ž˜์Šค ๋ถˆ๊ท ํ˜• ๋Œ€์‘) +- **์šฉ๋„**: ์ž‘์€ ๊ฐ์ฒด ๊ฒ€์ถœ + +## ํด๋ž˜์Šค ๋ผ์šฐํŒ… + +| ํด๋ž˜์Šค | ๋ชจ๋ธ | ์ด์œ  | +|--------|------|------| +| answer_option | YOLOv8n | ํฐ ๊ฐ์ฒด | +| english_content | YOLOv8n | ํฐ ๊ฐ์ฒด | +| korean_content | YOLOv8n | ํฐ ๊ฐ์ฒด | +| section | YOLOv8n | ํฐ ๊ฐ์ฒด | +| page_number | YOLOv8s | ์ž‘์€ ๊ฐ์ฒด | +| problem_number | YOLOv8s | ์ž‘์€ ๊ฐ์ฒด | +| answer_1 | YOLOv8s | ์ž‘์€ ๊ฐ์ฒด | +| answer_2 | YOLOv8s | ์ž‘์€ ๊ฐ์ฒด | + +## ๋ฐ์ดํ„ฐ์…‹ +- **์›๋ณธ**: english_problem_data_251004 (476๊ฐœ ์ด๋ฏธ์ง€) +- **Large4**: english_large4_251004 (4๊ฐœ ํด๋ž˜์Šค) +- **Small4**: english_small4_251004 (4๊ฐœ ํด๋ž˜์Šค) + +## ์‹คํ–‰ ์ˆœ์„œ +1. `yolov8n_imgsz_1280/START_TRAINING_UV.sh` (ํฐ ๊ฐ์ฒด ๋ชจ๋ธ) +2. `yolov8s_imgsz_2048/START_TRAINING_UV.sh` (์ž‘์€ ๊ฐ์ฒด ๋ชจ๋ธ) diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/__pycache__/run_routed_inference.cpython-311.pyc b/ai-service/models/Detection/legacy/Model_routing_1004/__pycache__/run_routed_inference.cpython-311.pyc new file mode 100644 index 0000000..77f8fd5 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/__pycache__/run_routed_inference.cpython-311.pyc differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/__pycache__/run_routed_inference.cpython-312.pyc b/ai-service/models/Detection/legacy/Model_routing_1004/__pycache__/run_routed_inference.cpython-312.pyc new file mode 100644 index 0000000..abcb4f9 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/__pycache__/run_routed_inference.cpython-312.pyc differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/run_routed_inference.py b/ai-service/models/Detection/legacy/Model_routing_1004/run_routed_inference.py new file mode 100644 index 0000000..4ffd779 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/run_routed_inference.py @@ -0,0 +1,707 @@ +# Model_routing_1004/run_routed_inference.py +""" +๋ผ์šฐํŒ… ์ถ”๋ก  ์Šคํฌ๋ฆฝํŠธ (Post-processing ํ†ตํ•ฉ) +YOLOv8n (ํฐ ๊ฐ์ฒด)๊ณผ YOLOv8s (์ž‘์€ ๊ฐ์ฒด) ๋ชจ๋ธ์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์ถ”๋ก ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. +section ๊ฒ€์ถœ ํ›„ post-processing์„ ์ ์šฉํ•˜์—ฌ ์˜์—ญ์„ ์ •๊ตํ•˜๊ฒŒ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค. +""" + +import os +import sys +import json +import cv2 +import numpy as np +from pathlib import Path +from typing import List, Dict, Tuple +from ultralytics import YOLO +from datetime import datetime +import copy + +# ํด๋ž˜์Šค ๋ผ์šฐํŒ… ์ •์˜ (1, 2, 3, 4, 5 ์ถ”๊ฐ€) +SMALL_CLASSES = {"page_number", "problem_number", "answer_1", "answer_2", "1", "2", "3", "4", "5"} +LARGE_CLASSES = {"korean_content", "english_content", "section", "answer_option"} + +# ํด๋ž˜์Šค๋ณ„ ์ƒ‰์ƒ ์ •์˜ +CLASS_COLORS = { + # ํฐ ๊ฐ์ฒด ํด๋ž˜์Šค + 'answer_option': (0, 255, 0), # ๋…น์ƒ‰ + 'english_content': (255, 0, 0), # ๋นจ๊ฐ„์ƒ‰ + 'korean_content': (0, 0, 255), # ํŒŒ๋ž€์ƒ‰ + 'section': (255, 255, 0), # ๋…ธ๋ž€์ƒ‰ + 'original_section': (0, 165, 255), # ์ฃผํ™ฉ์ƒ‰ (์›๋ณธ section) + + # ์ž‘์€ ๊ฐ์ฒด ํด๋ž˜์Šค + 'page_number': (255, 0, 255), # ๋งˆ์  ํƒ€ + 'problem_number': (0, 255, 255), # ์‹œ์•ˆ + 'answer_1': (255, 165, 0), # ์˜ค๋ Œ์ง€ + 'answer_2': (128, 0, 128), # ๋ณด๋ผ + + # ์ˆซ์ž ํด๋ž˜์Šค + '1': (255, 192, 203), # ํ•‘ํฌ + '2': (144, 238, 144), # ๋ผ์ดํŠธ๊ทธ๋ฆฐ + '3': (173, 216, 230), # ๋ผ์ดํŠธ๋ธ”๋ฃจ + '4': (255, 218, 185), # ํ”ผ์น˜ + '5': (221, 160, 221) # ํ”Œ๋Ÿผ +} + + +def is_blank_region(image, roi, mean_thresh=240, stddev_thresh=15, edge_ratio_thresh=0.005): + """ + ์ด๋ฏธ์ง€์—์„œ roi ์˜์—ญ์ด '๊ณต๋ฐฑ'์ธ์ง€ ํŒ๋‹จํ•˜๋Š” ํ•จ์ˆ˜. + - image: numpy array (H, W, 3) + - roi: (x_min, y_min, x_max, y_max) + - mean_thresh: ํ‰๊ท  ํ”ฝ์…€ ์ž„๊ณ„๊ฐ’ (default 240) + - stddev_thresh: ํ‘œ์ค€ํŽธ์ฐจ ์ž„๊ณ„๊ฐ’ (default 15) + - edge_ratio_thresh: ์—ฃ์ง€ ๋น„์œจ ์ž„๊ณ„๊ฐ’ (default 0.005 == 0.5%) + """ + x_min, y_min, x_max, y_max = roi + + # ROI๋ฅผ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ๋‚ด๋กœ clip + h, w = image.shape[:2] + x_min = max(0, int(round(x_min))) + y_min = max(0, int(round(y_min))) + x_max = min(w, int(round(x_max))) + y_max = min(h, int(round(y_max))) + + if x_max <= x_min or y_max <= y_min: + return True # ์ž˜๋ชป๋œ ROI๋Š” ๊ณต๋ฐฑ์œผ๋กœ ๊ฐ„์ฃผ + + roi_img = image[y_min:y_max, x_min:x_max] + + # Gray ๋ณ€ํ™˜ + if len(roi_img.shape) == 3: + roi_gray = cv2.cvtColor(roi_img, cv2.COLOR_BGR2GRAY) + else: + roi_gray = roi_img + + mean = np.mean(roi_gray) + stddev = np.std(roi_gray) + + # Canny Edge + v = np.median(roi_gray) + lower = int(max(0, 0.66 * v)) + upper = int(min(255, 1.33 * v)) + edges = cv2.Canny(roi_gray, lower, upper) + edge_ratio = np.sum(edges > 0) / (roi_gray.shape[0]*roi_gray.shape[1]+1e-5) + + # ๊ณต๋ฐฑ ํŒ์ • + result = (mean >= mean_thresh and stddev <= stddev_thresh and edge_ratio <= edge_ratio_thresh) + return result + + +class RoutedInference: + def __init__(self, base_dir: str): + self.base_dir = Path(base_dir) + self.small_model_dir = self.base_dir / "yolov8s_imgsz_2048" + self.large_model_dir = self.base_dir / "yolov8n_imgsz_1280" + + # ๋ชจ๋ธ ๊ฒฝ๋กœ + self.small_model_path = self.small_model_dir / "train" / "weights" / "best.pt" + self.large_model_path = self.large_model_dir / "train" / "weights" / "best.pt" + + # ๋ชจ๋ธ ๋กœ๋“œ + self.small_model = self._load_model(self.small_model_path, "yolov8s.pt") + self.large_model = self._load_model(self.large_model_path, "yolov8n.pt") + + # ์ถ”๋ก  ํŒŒ๋ผ๋ฏธํ„ฐ + self.small_conf = 0.22 + self.large_conf = 0.12 + + # Post-processing ํŒŒ๋ผ๋ฏธํ„ฐ + self.roi_height = 60 # ์ฒซ ๋ฒˆ์งธ ํ™•์žฅ์€ 60px, ์ดํ›„๋Š” 5px์”ฉ + + print(f"โœ… Small model loaded: {self.small_model_path}") + print(f"โœ… Large model loaded: {self.large_model_path}") + + def _load_model(self, model_path: Path, fallback: str): + """๋ชจ๋ธ ๋กœ๋“œ""" + if model_path.exists(): + return YOLO(str(model_path)) + else: + print(f"โš ๏ธ Model not found: {model_path}, using {fallback}") + return YOLO(fallback) + + def get_all_detections(self, results, class_names: List[str]) -> List[Dict]: + """ + ๋ชจ๋“  ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ + """ + all_detections = [] + + if results.boxes is not None: + for box in results.boxes: + cls_id = int(box.cls[0]) + confidence = float(box.conf[0]) + xyxy = box.xyxy[0].tolist() + + if cls_id < len(class_names): + class_name = class_names[cls_id] + + all_detections.append({ + 'class_name': class_name, + 'class_id': cls_id, + 'confidence': confidence, + 'bbox': xyxy + }) + + return all_detections + + def apply_section_postprocessing(self, image: np.ndarray, detections: List[Dict]) -> List[Dict]: + """ + Section์— ๋Œ€ํ•ด post-processing ์ ์šฉ + - section์ด ์—†์œผ๋ฉด problem_number ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑ + - section ํ™•์žฅ ์‹œ ๋‹ค๋ฅธ problem_number๋ฅผ ์นจ๋ฒ”ํ•˜์ง€ ์•Š๋„๋ก ์ œํ•œ + """ + # problem_number์˜ ์™ผ์ชฝ ์œ„ ์ขŒํ‘œ ์ˆ˜์ง‘ ๋ฐ Y ์ขŒํ‘œ ๊ธฐ์ค€ ์ •๋ ฌ + question_numbers = [] + for det in detections: + if det['class_name'] == 'problem_number': + question_numbers.append({ + 'bbox': det['bbox'], + 'confidence': det['confidence'] + }) + + # Y ์ขŒํ‘œ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ (์œ„์—์„œ ์•„๋ž˜๋กœ) + question_numbers.sort(key=lambda x: x['bbox'][1]) + + # section ๊ฒ€์ถœ ๊ฒฐ๊ณผ + section_detections = [det for det in detections if det['class_name'] == 'section'] + + print(f" ๐Ÿ“Œ ๋ฐœ๊ฒฌ๋œ problem_number: {len(question_numbers)}๊ฐœ") + print(f" ๐Ÿ“ฆ ๋ฐœ๊ฒฌ๋œ section: {len(section_detections)}๊ฐœ") + + # section์ด ์—†์ง€๋งŒ problem_number๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ โ†’ section ์ƒ์„ฑ + if len(section_detections) == 0 and len(question_numbers) > 0: + print(f" โš ๏ธ Section์ด ์—†์ง€๋งŒ problem_number๊ฐ€ ์žˆ์Œ โ†’ Section ์ž๋™ ์ƒ์„ฑ") + + for idx, qn in enumerate(question_numbers): + qn_bbox = qn['bbox'] + qn_x1, qn_y1, qn_x2, qn_y2 = qn_bbox + + # 1. problem_number์˜ ์™ผ์ชฝ ์ƒ๋‹จ ๊ผญ์ง“์  ๊ธฐ์ค€์œผ๋กœ ์ดˆ๊ธฐ ํ™•์žฅ (์ขŒ์ธก 10px, ์ƒ๋‹จ 10px) + section_x1 = max(0, qn_x1 - 10) + section_y1 = max(0, qn_y1 - 10) + + # 2. ์˜ค๋ฅธ์ชฝ์œผ๋กœ 600px, ์•„๋ž˜์ชฝ์œผ๋กœ 900px ํ™•์žฅ + h, w = image.shape[:2] + section_x2 = min(w, section_x1 + 600) + section_y2 = min(h, section_y1 + 900) + + # ๋‹ค์Œ problem_number์˜ ์ƒ๋‹จ Y ์ขŒํ‘œ ์ฐพ๊ธฐ + next_pn_y = h # ๊ธฐ๋ณธ๊ฐ’: ์ด๋ฏธ์ง€ ํ•˜๋‹จ + if idx + 1 < len(question_numbers): + next_pn_y = question_numbers[idx + 1]['bbox'][1] + print(f" ๐Ÿ“ ๋‹ค์Œ problem_number ์œ„์น˜: y={next_pn_y:.1f}") + + # 3. ROI ๊ธฐ๋ฐ˜ ์˜ค๋ฅธ์ชฝ ํ™•์žฅ (5px์”ฉ) + right_expansion_count = 0 + max_expansions = 1000 # ์ตœ๋Œ€ ํ™•์žฅ ํšŸ์ˆ˜ + + while right_expansion_count < max_expansions: + if section_x2 + 5 > w: + break + + right_roi = [section_x2, section_y1, section_x2 + 5, section_y2] + + if not is_blank_region(image, right_roi): + section_x2 += 5 + right_expansion_count += 1 + else: + break + + # 4. ROI ๊ธฐ๋ฐ˜ ์•„๋ž˜์ชฝ ํ™•์žฅ (5px์”ฉ) - ๋‹ค์Œ problem_number ๊ณ ๋ ค + bottom_expansion_count = 0 + + while bottom_expansion_count < max_expansions: + if section_y2 + 5 > h: + break + + # ๋‹ค์Œ problem_number์˜ ์ƒ๋‹จ์„ ์นจ๋ฒ”ํ•˜์ง€ ์•Š๋„๋ก ํ™•์ธ + if section_y2 + 5 > next_pn_y: + print(f" โ›” ๋‹ค์Œ problem_number ์˜์—ญ ๋„๋‹ฌ (y={next_pn_y:.1f})") + break + + bottom_roi = [section_x1, section_y2, section_x2, section_y2 + 5] + + if not is_blank_region(image, bottom_roi): + section_y2 += 5 + bottom_expansion_count += 1 + else: + break + + # ์ƒ์„ฑ๋œ section์„ detections์— ์ถ”๊ฐ€ + generated_section = { + 'class_name': 'section', + 'class_id': 3, # section์˜ class_id + 'confidence': qn['confidence'], # problem_number์˜ confidence ์‚ฌ์šฉ + 'bbox': [section_x1, section_y1, section_x2, section_y2], + 'generated': True # ์ƒ์„ฑ๋œ section์ž„์„ ํ‘œ์‹œ + } + + section_detections.append(generated_section) + print(f" โœ… Section ์ƒ์„ฑ ์™„๋ฃŒ: [{section_x1:.1f}, {section_y1:.1f}, {section_x2:.1f}, {section_y2:.1f}]") + + # ๊ฒฐ๊ณผ ์ €์žฅ์šฉ ๋ฆฌ์ŠคํŠธ + processed_detections = [] + + # section ์ด์™ธ์˜ ๊ฐ์ฒด๋“ค์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€ + for det in detections: + if det['class_name'] != 'section': + processed_detections.append(det) + + # section์— ๋Œ€ํ•ด post-processing ์ ์šฉ + for det in section_detections: + if det.get('generated', False): + # ์ƒ์„ฑ๋œ section์€ ์ด๋ฏธ ํ™•์žฅ์ด ์™„๋ฃŒ๋จ + processed_detections.append(det) + print(f" โœจ ์ƒ์„ฑ๋œ Section ์ถ”๊ฐ€ ์™„๋ฃŒ") + continue + + # ์›๋ณธ section ์ €์žฅ + original_section = copy.deepcopy(det) + original_section['class_name'] = 'original_section' + processed_detections.append(original_section) + + # ์ฒ˜๋ฆฌํ•  section ๋ณต์‚ฌ + section = copy.deepcopy(det) + x_min, y_min, x_max, y_max = section['bbox'] + + print(f" ๐Ÿ”ง Section ์ฒ˜๋ฆฌ ์‹œ์ž‘: bbox=({x_min:.1f}, {y_min:.1f}, {x_max:.1f}, {y_max:.1f})") + + # ํ˜„์žฌ section๊ณผ ์—ฐ๊ด€๋œ problem_number ์ฐพ๊ธฐ + current_pn_idx = -1 + next_pn_y = image.shape[0] # ๊ธฐ๋ณธ๊ฐ’: ์ด๋ฏธ์ง€ ํ•˜๋‹จ + + for idx, qn in enumerate(question_numbers): + qn_y = qn['bbox'][1] + # section ์˜์—ญ ๋‚ด์— ์žˆ๋Š” problem_number ์ฐพ๊ธฐ + if y_min <= qn_y <= y_max: + current_pn_idx = idx + break + + # ๋‹ค์Œ problem_number์˜ Y ์ขŒํ‘œ ์ฐพ๊ธฐ + if current_pn_idx != -1 and current_pn_idx + 1 < len(question_numbers): + next_pn_y = question_numbers[current_pn_idx + 1]['bbox'][1] + print(f" ๐Ÿ“ ๋‹ค์Œ problem_number ์œ„์น˜: y={next_pn_y:.1f}") + + # 1. ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด problem_number์— ์™ผ์ชฝ ์œ„ ๋งž์ถ”๊ธฐ + if question_numbers: + min_dist = float('inf') + nearest_qn = None + for qn in question_numbers: + qn_x, qn_y = qn['bbox'][0], qn['bbox'][1] + dist = np.sqrt((qn_x - x_min)**2 + (qn_y - y_min)**2) + if dist < min_dist: + min_dist = dist + nearest_qn = (qn_x, qn_y) + + if nearest_qn is not None: + x_min = max(0, nearest_qn[0] - 20) # ์กฐ์ •๊ฐ’ + y_min = nearest_qn[1] + print(f" โ†”๏ธ problem_number ์ •๋ ฌ: ({nearest_qn[0]:.1f}, {nearest_qn[1]:.1f})") + + # 2. ์œ„์ชฝ ํ™•์žฅ (์ฒซ ๋ฒˆ์งธ: 60px, ์ดํ›„: 5px์”ฉ) + print(f" โฌ†๏ธ ์œ„์ชฝ ํ™•์žฅ ์‹œ์ž‘ (์ฒซ ๋ฒˆ์งธ: {self.roi_height}px, ์ดํ›„: 5px์”ฉ)") + expansion_count = 0 + stopped_by_boundary_top = False # ๊ฒฝ๊ณ„๋กœ ์ธํ•ด ์ค‘๋‹จ๋˜์—ˆ๋Š”์ง€ ์ถ”์  + + while True: + # ์ฒซ ๋ฒˆ์งธ ํ™•์žฅ์€ roi_height, ์ดํ›„๋Š” 5px์”ฉ + if expansion_count == 0: + expansion_size = self.roi_height + else: + expansion_size = 5 + + if y_min - expansion_size < 0: + print(f" โ›” ์ด๋ฏธ์ง€ ์ƒ๋‹จ ๊ฒฝ๊ณ„ ๋„๋‹ฌ ({expansion_count}๋ฒˆ ํ™•์žฅ ํ›„)") + stopped_by_boundary_top = True + break + + top_upside_roi = [x_min, y_min - expansion_size, x_max, y_min] + + if not is_blank_region(image, top_upside_roi): + y_min -= expansion_size + expansion_count += 1 + if expansion_count == 1: + print(f" โฌ†๏ธ ์œ„๋กœ ํ™•์žฅ (1์ฐจ: {self.roi_height}px): y_min={y_min:.1f}") + else: + print(f" โฌ†๏ธ ์œ„๋กœ ํ™•์žฅ ({expansion_count}์ฐจ: 5px): y_min={y_min:.1f}") + else: + print(f" โน๏ธ ๊ณต๋ฐฑ ์˜์—ญ ๋„๋‹ฌ ({expansion_count}๋ฒˆ ํ™•์žฅ ํ›„)") + break + + # ์œ„์ชฝ์ด ๊ฒฝ๊ณ„๋กœ ์ค‘๋‹จ๋˜์ง€ ์•Š์•˜๊ณ , ์ฒซ ํ™•์žฅ์ด ์•ˆ ๋œ ๊ฒฝ์šฐ padding ๋ฏธ์ ์šฉ + if expansion_count == 0: + print(f" โš ๏ธ ์œ„์ชฝ ํ™•์žฅ ์—†์Œ โ†’ padding ๋ฏธ์ ์šฉ") + + # 3. ์•„๋ž˜์ชฝ ํ™•์žฅ (์ฒซ ๋ฒˆ์งธ: 60px, ์ดํ›„: 5px์”ฉ) - ๋‹ค์Œ problem_number ๊ณ ๋ ค + print(f" โฌ‡๏ธ ์•„๋ž˜์ชฝ ํ™•์žฅ ์‹œ์ž‘ (์ฒซ ๋ฒˆ์งธ: {self.roi_height}px, ์ดํ›„: 5px์”ฉ)") + expansion_count = 0 + stopped_by_pn_bottom = False # problem_number๋กœ ์ธํ•ด ์ค‘๋‹จ๋˜์—ˆ๋Š”์ง€ ์ถ”์  + + while True: + # ์ฒซ ๋ฒˆ์งธ ํ™•์žฅ์€ roi_height, ์ดํ›„๋Š” 5px์”ฉ + if expansion_count == 0: + expansion_size = self.roi_height + else: + expansion_size = 5 + + if y_max + expansion_size > image.shape[0]: + print(f" โ›” ์ด๋ฏธ์ง€ ํ•˜๋‹จ ๊ฒฝ๊ณ„ ๋„๋‹ฌ ({expansion_count}๋ฒˆ ํ™•์žฅ ํ›„)") + break + + # ๋‹ค์Œ problem_number์˜ ์ƒ๋‹จ์„ ์นจ๋ฒ”ํ•˜์ง€ ์•Š๋„๋ก ํ™•์ธ + if y_max + expansion_size > next_pn_y: + print(f" โ›” ๋‹ค์Œ problem_number ์˜์—ญ ๋„๋‹ฌ (y={next_pn_y:.1f}, {expansion_count}๋ฒˆ ํ™•์žฅ ํ›„)") + stopped_by_pn_bottom = True + break + + bottom_downside_roi = [x_min, y_max, x_max, y_max + expansion_size] + + if not is_blank_region(image, bottom_downside_roi): + y_max += expansion_size + expansion_count += 1 + if expansion_count == 1: + print(f" โฌ‡๏ธ ์•„๋ž˜๋กœ ํ™•์žฅ (1์ฐจ: {self.roi_height}px): y_max={y_max:.1f}") + else: + print(f" โฌ‡๏ธ ์•„๋ž˜๋กœ ํ™•์žฅ ({expansion_count}์ฐจ: 5px): y_max={y_max:.1f}") + else: + print(f" โน๏ธ ๊ณต๋ฐฑ ์˜์—ญ ๋„๋‹ฌ ({expansion_count}๋ฒˆ ํ™•์žฅ ํ›„)") + break + + # ์•„๋ž˜์ชฝ์ด problem_number๋กœ ์ค‘๋‹จ๋œ ๊ฒฝ์šฐ padding ๋ฏธ์ ์šฉ + if stopped_by_pn_bottom: + print(f" โš ๏ธ ์•„๋ž˜์ชฝ์ด problem_number๋กœ ์ค‘๋‹จ๋จ โ†’ padding ๋ฏธ์ ์šฉ") + + # ๊ต์ •๋œ section ์ €์žฅ + section['bbox'] = [x_min, y_min, x_max, y_max] + processed_detections.append(section) + + print(f" โœ… Section ์ฒ˜๋ฆฌ ์™„๋ฃŒ: bbox=({x_min:.1f}, {y_min:.1f}, {x_max:.1f}, {y_max:.1f})") + + return processed_detections + + def route_infer_single_image(self, image_path: str) -> Dict: + """ + ๋‹จ์ผ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ๋ผ์šฐํŒ… ์ถ”๋ก  ์ˆ˜ํ–‰ (post-processing ํฌํ•จ) + """ + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + image = cv2.imread(str(image_path)) + if image is None: + raise ValueError(f"์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {image_path}") + + # ์ž‘์€ ๊ฐ์ฒด ๋ชจ๋ธ ์ถ”๋ก  (YOLOv8s @ 2048) + small_results = self.small_model(str(image_path), imgsz=2048, conf=self.small_conf, verbose=False)[0] + small_class_names = ['page_number', 'problem_number', 'answer_1', 'answer_2', '1', '2', '3', '4', '5'] + small_detections = self.get_all_detections(small_results, small_class_names) + + # ํฐ ๊ฐ์ฒด ๋ชจ๋ธ ์ถ”๋ก  (YOLOv8n @ 1280) + large_results = self.large_model(str(image_path), imgsz=1280, conf=self.large_conf, verbose=False)[0] + large_class_names = ['answer_option', 'english_content', 'korean_content', 'section'] + large_detections = self.get_all_detections(large_results, large_class_names) + + # ๊ฒฐ๊ณผ ๋ณ‘ํ•ฉ + all_detections = small_detections + large_detections + + # Section์— ๋Œ€ํ•ด post-processing ์ ์šฉ + print(f" ๐Ÿ”„ Section post-processing ์ ์šฉ") + processed_detections = self.apply_section_postprocessing(image, all_detections) + + return { + 'image_path': str(image_path), + 'detections': processed_detections, + 'small_detections': small_detections, + 'large_detections': large_detections, + 'timestamp': datetime.now().isoformat() + } + + def visualize_detections(self, image_path: str, detections: List[Dict], output_path: str): + """ + ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐํ™”ํ•˜์—ฌ ์ €์žฅ + """ + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + image = cv2.imread(str(image_path)) + if image is None: + print(f"โŒ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return + + # ๊ฐ ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ + for det in detections: + class_name = det['class_name'] + confidence = det['confidence'] + bbox = det['bbox'] + color = CLASS_COLORS.get(class_name, (255, 255, 255)) + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ์ขŒํ‘œ + x1, y1, x2, y2 = map(int, bbox) + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ๊ทธ๋ฆฌ๊ธฐ (original_section์€ ์ ์„ ์œผ๋กœ) + if class_name == 'original_section': + # ์ ์„  ํšจ๊ณผ (์„ ๋ถ„์„ ์—ฌ๋Ÿฌ ๊ฐœ ๊ทธ๋ ค์„œ ์ ์„ ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ) + dash_length = 10 + for i in range(x1, x2, dash_length * 2): + cv2.line(image, (i, y1), (min(i + dash_length, x2), y1), color, 2) + cv2.line(image, (i, y2), (min(i + dash_length, x2), y2), color, 2) + for i in range(y1, y2, dash_length * 2): + cv2.line(image, (x1, i), (x1, min(i + dash_length, y2)), color, 2) + cv2.line(image, (x2, i), (x2, min(i + dash_length, y2)), color, 2) + else: + cv2.rectangle(image, (x1, y1), (x2, y2), color, 3) + + # ๋ผ๋ฒจ ํ…์ŠคํŠธ + label = f"{class_name}: {confidence:.3f}" + + # ํ…์ŠคํŠธ ๋ฐฐ๊ฒฝ ๊ทธ๋ฆฌ๊ธฐ + (text_width, text_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2) + cv2.rectangle(image, (x1, y1 - text_height - 10), (x1 + text_width, y1), color, -1) + + # ํ…์ŠคํŠธ ๊ทธ๋ฆฌ๊ธฐ + cv2.putText(image, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + + # ๋ฒ”๋ก€ ์ถ”๊ฐ€ + self.add_legend(image) + + # ์ด๋ฏธ์ง€ ์ €์žฅ + cv2.imwrite(str(output_path), image) + + def crop_and_save_detections(self, image_path: str, detections: List[Dict], output_dir: Path): + """๊ฐ ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๊ฐœ๋ณ„ ์ด๋ฏธ์ง€๋กœ ํฌ๋กญํ•˜์—ฌ ์ €์žฅ""" + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + image = cv2.imread(str(image_path)) + if image is None: + print(f"โŒ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return + + image_name = Path(image_path).stem + + # ํด๋ž˜์Šค๋ณ„ ์นด์šดํ„ฐ + class_counters = {} + + for det in detections: + class_name = det['class_name'] + confidence = det['confidence'] + bbox = det['bbox'] + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ์ขŒํ‘œ + x1, y1, x2, y2 = map(int, bbox) + + # ์ขŒํ‘œ ๋ณด์ • + h, w = image.shape[:2] + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 <= x1 or y2 <= y1: + continue + + # ํฌ๋กญ + cropped = image[y1:y2, x1:x2] + + # ํด๋ž˜์Šค๋ณ„ ํด๋” ์ƒ์„ฑ + class_dir = output_dir / image_name / class_name + class_dir.mkdir(parents=True, exist_ok=True) + + # ์นด์šดํ„ฐ ์ฆ๊ฐ€ + if class_name not in class_counters: + class_counters[class_name] = 0 + else: + class_counters[class_name] += 1 + + # ํŒŒ์ผ๋ช… ์ƒ์„ฑ ๋ฐ ์ €์žฅ + crop_filename = f"{class_name}_{class_counters[class_name]:02d}_conf{confidence:.3f}.jpg" + cv2.imwrite(str(class_dir / crop_filename), cropped) + + def crop_by_class_only(self, image_path: str, detections: List[Dict], output_dir: Path, class_counters: Dict[str, int]): + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + image = cv2.imread(str(image_path)) + if image is None: + print(f"โŒ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return class_counters + + image_name = Path(image_path).stem + + for det in detections: + class_name = det['class_name'] + confidence = det['confidence'] + bbox = det['bbox'] + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ์ขŒํ‘œ + x1, y1, x2, y2 = map(int, bbox) + + # ์ขŒํ‘œ ๋ณด์ • + h, w = image.shape[:2] + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 <= x1 or y2 <= y1: + continue + + # ํฌ๋กญ + cropped = image[y1:y2, x1:x2] + + # ํด๋ž˜์Šค๋ณ„ ํด๋” ์ƒ์„ฑ (ํŽ˜์ด์ง€ ๊ตฌ๋ถ„ ์—†์Œ) + class_dir = output_dir / class_name + class_dir.mkdir(parents=True, exist_ok=True) + + # ์ „์—ญ ์นด์šดํ„ฐ ์ฆ๊ฐ€ + if class_name not in class_counters: + class_counters[class_name] = 0 + + # ํŒŒ์ผ๋ช…: ํŽ˜์ด์ง€๋ช…_์นด์šดํ„ฐ_์‹ ๋ขฐ๋„ + crop_filename = f"{image_name}_{class_name}_{class_counters[class_name]:03d}_conf{confidence:.3f}.jpg" + cv2.imwrite(str(class_dir / crop_filename), cropped) + + class_counters[class_name] += 1 + + return class_counters + + def add_legend(self, image): + """๋ฒ”๋ก€ ์ถ”๊ฐ€""" + legend_y = 30 + all_classes = list(CLASS_COLORS.keys()) + + for i, class_name in enumerate(all_classes): + color = CLASS_COLORS[class_name] + # ์ƒ‰์ƒ ๋ฐ•์Šค + cv2.rectangle(image, (10, legend_y + i * 30), (30, legend_y + i * 30 + 25), color, -1) + # ํด๋ž˜์Šค ์ด๋ฆ„ + cv2.putText(image, class_name, (35, legend_y + i * 30 + 18), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2) + + def process_test_images(self, test_data_root: str, output_dir: str): + """ + ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€๋“ค์— ๋Œ€ํ•ด ๋ผ์šฐํŒ… ์ถ”๋ก  ์ˆ˜ํ–‰ + """ + test_data_path = Path(test_data_root) + output_path = Path(output_dir) + + # ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ + (output_path / "images").mkdir(parents=True, exist_ok=True) + (output_path / "annotations").mkdir(parents=True, exist_ok=True) + + # ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ + test_images_dir = test_data_path + if not test_images_dir.exists(): + print(f"โŒ ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {test_images_dir}") + return + + image_extensions = ['.jpg', '.jpeg', '.png', '.bmp'] + image_files = [] + for ext in image_extensions: + image_files.extend(test_images_dir.glob(f"*{ext}")) + image_files.extend(test_images_dir.glob(f"*{ext.upper()}")) + + image_files = sorted(image_files) + print(f"๐Ÿ“Š ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ {len(image_files)}๊ฐœ ๋ฐœ๊ฒฌ") + + # ๊ฒฐ๊ณผ ์ €์žฅ์šฉ + all_results = [] + total_detections = 0 + class_counts = {name: 0 for name in CLASS_COLORS.keys()} + total_confidence = 0 + + global_class_counters = {} # ์ „์—ญ ์นด์šดํ„ฐ + + print(f"๐Ÿ” {len(image_files)}๊ฐœ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ๋ผ์šฐํŒ… ์ถ”๋ก  ์‹œ์ž‘...") + + for i, image_path in enumerate(image_files): + print(f"\n์ฒ˜๋ฆฌ ์ค‘: {i+1}/{len(image_files)} - {image_path.name}") + + # ๋ผ์šฐํŒ… ์ถ”๋ก  ์ˆ˜ํ–‰ (post-processing ํฌํ•จ) + result = self.route_infer_single_image(str(image_path)) + all_results.append(result) + + # ์‹œ๊ฐํ™” ์ด๋ฏธ์ง€ ์ €์žฅ + output_image_path = output_path / "images" / f"routed_result_{image_path.stem}.jpg" + self.visualize_detections(str(image_path), result['detections'], str(output_image_path)) + + # ํฌ๋กญ๋œ ์ด๋ฏธ์ง€ ์ €์žฅ + detailed_output_dir = output_path / "detailed_images" + self.crop_and_save_detections(str(image_path), result['detections'], detailed_output_dir) + + # ํด๋ž˜์Šค๋ณ„ ํฌ๋กญ ์ €์žฅ (ํŽ˜์ด์ง€ ๊ตฌ๋ถ„ ์—†์Œ) + class_output_dir = output_path / "class_images" + global_class_counters = self.crop_by_class_only(str(image_path), result['detections'], class_output_dir, global_class_counters) + + # JSON ์ €์žฅ + output_json_path = output_path / "annotations" / f"routed_result_{image_path.stem}.json" + with open(output_json_path, 'w', encoding='utf-8') as f: + json.dump(result, f, indent=2, ensure_ascii=False) + + # ํ†ต๊ณ„ ์—…๋ฐ์ดํŠธ + for det in result['detections']: + total_detections += 1 + class_name = det['class_name'] + if class_name in class_counts: + class_counts[class_name] += 1 + total_confidence += det['confidence'] + + # ๊ฒฐ๊ณผ ์š”์•ฝ ์ €์žฅ + avg_confidence = total_confidence / total_detections if total_detections > 0 else 0 + summary = { + "total_images": len(image_files), + "processed_images": len(image_files), + "total_detections": total_detections, + "average_detections_per_image": total_detections / len(image_files) if image_files else 0, + "class_counts": class_counts, + "average_confidence": avg_confidence, + "routing_strategy": { + "small_objects": list(SMALL_CLASSES), + "large_objects": list(LARGE_CLASSES), + "small_model_conf": self.small_conf, + "large_model_conf": self.large_conf + }, + "postprocessing_applied": True, + "roi_height": self.roi_height + } + + summary_path = output_path / "routing_results_summary.json" + with open(summary_path, 'w', encoding='utf-8') as f: + json.dump(summary, f, indent=2, ensure_ascii=False) + + # ๊ฒฐ๊ณผ ์ถœ๋ ฅ + print("\n" + "=" * 60) + print("๐Ÿ“Š ๋ผ์šฐํŒ… ์ถ”๋ก  ๊ฒฐ๊ณผ ์š”์•ฝ:") + print(f" - ์ฒ˜๋ฆฌ๋œ ์ด๋ฏธ์ง€: {summary['processed_images']}/{summary['total_images']}") + print(f" - ์ด ๊ฒ€์ถœ ์ˆ˜: {summary['total_detections']}") + print(f" - ์ด๋ฏธ์ง€๋‹น ํ‰๊ท  ๊ฒ€์ถœ ์ˆ˜: {summary['average_detections_per_image']:.1f}") + print(f" - ํ‰๊ท  ์‹ ๋ขฐ๋„: {summary['average_confidence']:.3f}") + print(f" - Post-processing ์ ์šฉ: โœ…") + print("\n๐Ÿ“ˆ ํด๋ž˜์Šค๋ณ„ ๊ฒ€์ถœ ์ˆ˜:") + for class_name, count in summary['class_counts'].items(): + print(f" - {class_name}: {count}") + + print(f"\nโœ… ๊ฒฐ๊ณผ ์ €์žฅ ์™„๋ฃŒ: {output_path}") + print(f" - ์‹œ๊ฐํ™” ์ด๋ฏธ์ง€: {output_path}/images/") + print(f" - ๊ฒ€์ถœ ๋ฐ์ดํ„ฐ: {output_path}/annotations/") + print(f" - ๊ฒฐ๊ณผ ์š”์•ฝ: {output_path}/routing_results_summary.json") + + return all_results + + +def main(): + # ๊ฒฝ๋กœ ์„ค์ • + current_dir = Path(__file__).parent + test_data_root = current_dir.parent.parent / "recognition" / "exp_images" + output_dir = current_dir / "routed_inference_results" + + print("๐Ÿš€ ๋ผ์šฐํŒ… ์ถ”๋ก  ์‹œ์ž‘ (Post-processing ํฌํ•จ)") + print(f"๐Ÿ“ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ: {test_data_root}") + print(f"๐Ÿ“ ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ: {output_dir}") + print("=" * 60) + + try: + # ๋ผ์šฐํŒ… ์ถ”๋ก  ์‹คํ–‰ + router = RoutedInference(str(current_dir)) + results = router.process_test_images(str(test_data_root), str(output_dir)) + + print("\nโœ… ๋ผ์šฐํŒ… ์ถ”๋ก  ์™„๋ฃŒ!") + + except Exception as e: + print(f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}") + import traceback + traceback.print_exc() + return 1 + + return 0 + + +if __name__ == "__main__": + exit(main()) \ No newline at end of file diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/run_routing.sh b/ai-service/models/Detection/legacy/Model_routing_1004/run_routing.sh new file mode 100644 index 0000000..bc5d039 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/run_routing.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +echo "๐Ÿš€ ๋ผ์šฐํŒ… ์ถ”๋ก  ๋ฐ ์‹œ๊ฐํ™” ์‹œ์ž‘" +echo "๐ŸŽฏ ๋ชจ๋ธ: YOLOv8n (ํฐ ๊ฐ์ฒด) + YOLOv8s (์ž‘์€ ๊ฐ์ฒด)" +echo "๐Ÿ“Š ์ „๋žต: ๋ชจ๋“  ๊ฒ€์ถœ ๊ฒฐ๊ณผ ์‚ฌ์šฉ (๋ผ์šฐํŒ… ๊ธฐ๋ฐ˜)" +echo "=" * 60 + +# UV ํ™˜๊ฒฝ ํ™œ์„ฑํ™” +source /home/jdh251425/2509\ Gradi-Detection/gradi-detection/bin/activate + +# ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ +cd "/home/jdh251425/2509 Gradi-Detection/Exp/experiment_routing_1004" + +# GPU ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ +echo "๐Ÿ“Š GPU ์ƒํƒœ ํ™•์ธ:" +nvidia-smi + +echo "๐Ÿ”ฅ ๋ผ์šฐํŒ… ์ถ”๋ก  ์‹œ์ž‘..." +python run_routed_inference.py + +echo "โœ… ๋ผ์šฐํŒ… ์ถ”๋ก  ๋ฐ ์‹œ๊ฐํ™” ์™„๋ฃŒ!" diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/README.md b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/README.md new file mode 100644 index 0000000..d2e3817 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/README.md @@ -0,0 +1,21 @@ +# YOLOv8n @ 1280 - ํฐ ๊ฐ์ฒด ์ „์šฉ + +## ๋ชฉ์  +ํฐ ๊ฐ์ฒด๋“ค์„ ์œ„ํ•œ ์ „์šฉ ๋ชจ๋ธ (answer_option, english_content, korean_content, section) + +## ์„ค์ • +- **๋ชจ๋ธ**: YOLOv8n +- **์ด๋ฏธ์ง€ ํฌ๊ธฐ**: 1280x1280 +- **GPU**: [0,1] +- **๋ฐฐ์น˜ ํฌ๊ธฐ**: 8 +- **์ฆ๊ฐ•**: ์—†์Œ (๋ชจ๋“  ์ฆ๊ฐ• ๋น„ํ™œ์„ฑํ™”) + +## ๋ฐ์ดํ„ฐ์…‹ +- **๊ฒฝ๋กœ**: `/home/jdh251425/2509 Gradi-Detection/Data/english_large4_251004/` +- **ํด๋ž˜์Šค**: 4๊ฐœ (answer_option, english_content, korean_content, section) +- **์ด ์ด๋ฏธ์ง€**: 476๊ฐœ (333 train, 95 valid, 48 test) + +## ์‹คํ–‰ +```bash +bash START_TRAINING_UV.sh +``` diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/START_TRAINING_UV.sh b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/START_TRAINING_UV.sh new file mode 100644 index 0000000..b183c62 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/START_TRAINING_UV.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "๐Ÿš€ Routing Experiment 1004 - YOLOv8n @ 1280 ์‹œ์ž‘" +echo "๐ŸŽฏ ๋Œ€์ƒ: ํฐ ๊ฐ์ฒด (answer_option, english_content, korean_content, section)" +echo "๐Ÿ–ฅ๏ธ GPU: [0,1]" +echo "๐Ÿ”„ ์ฆ๊ฐ•: ์—†์Œ" +echo "๐Ÿ“Š ๋ฐ์ดํ„ฐ: english_large4_251004" +echo "=" * 60 + +# UV ํ™˜๊ฒฝ ํ™œ์„ฑํ™” +source /home/jdh251425/2509\ Gradi-Detection/gradi-detection/bin/activate + +# ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ +cd "/home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280" + +# GPU ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ +echo "๐Ÿ“Š GPU ์ƒํƒœ ํ™•์ธ:" +nvidia-smi + +echo "๐Ÿ”ฅ ํ•™์Šต ์‹œ์ž‘..." +python run_optimized_training.py + +echo "โœ… ํ•™์Šต ์™„๋ฃŒ!" diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/config_optimized.yaml b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/config_optimized.yaml new file mode 100644 index 0000000..2c2f605 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/config_optimized.yaml @@ -0,0 +1,70 @@ +# Routing Experiment 1004 - YOLOv8n @ 1280 (ํฐ ๊ฐ์ฒด ์ „์šฉ) + +task: detect +mode: train +model: yolov8n.pt +data: /home/jdh251425/2509 Gradi-Detection/Data/english_large4_251004/data.yaml + +# ํ•™์Šต +epochs: 100 +patience: 25 +batch: 8 +imgsz: 1280 +device: [0,1] # GPU 0,1 ์‚ฌ์šฉ +workers: 8 + +# ํ”„๋กœ์ ํŠธ +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280 +name: train +exist_ok: true + +# ์˜ตํ‹ฐ๋งˆ์ด์ € +optimizer: AdamW +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 + +# Loss +box: 7.5 +cls: 1.5 +dfl: 1.5 + +# ์Šค์บ” ์ด๋ฏธ์ง€ ์นœํ™” +rect: true +multi_scale: false + +# ์ฆ๊ฐ• ์—†์Œ (๋ชจ๋“  ์ฆ๊ฐ• ๋น„ํ™œ์„ฑํ™”) +degrees: 0 +perspective: 0.0 +translate: 0.0 +scale: 0.0 +shear: 0.0 +flipud: 0.0 +fliplr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +auto_augment: null +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +erasing: 0.0 + +# ๊ฒ€์ฆ/์ถ”๋ก  +iou: 0.7 +conf: 0.12 +max_det: 300 +val: true +amp: true +plots: true +verbose: true +seed: 0 +deterministic: true +single_cls: false +cos_lr: false +cache: false diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/run_optimized_training.py b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/run_optimized_training.py new file mode 100644 index 0000000..c0ad6c3 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/run_optimized_training.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +""" +Routing Experiment 1004 - YOLOv8n @ 1280 (ํฐ ๊ฐ์ฒด ์ „์šฉ) +GPU 0,1 ์‚ฌ์šฉ, ์ฆ๊ฐ• ์—†์Œ +""" + +import os +import sys +from pathlib import Path + +def main(): + # ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ ์„ค์ • + current_dir = Path(__file__).parent + os.chdir(current_dir) + + # ์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ + config_path = current_dir / "config_optimized.yaml" + + if not config_path.exists(): + print(f"โŒ ์„ค์ • ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {config_path}") + sys.exit(1) + + print("๐Ÿš€ Routing Experiment 1004 - YOLOv8n @ 1280 ์‹œ์ž‘") + print(f"๐Ÿ“ ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ: {current_dir}") + print(f"โš™๏ธ ์„ค์ • ํŒŒ์ผ: {config_path}") + print("๐ŸŽฏ ๋Œ€์ƒ: ํฐ ๊ฐ์ฒด (answer_option, english_content, korean_content, section)") + print("๐Ÿ–ฅ๏ธ GPU: [0,1]") + print("๐Ÿ”„ ์ฆ๊ฐ•: ์—†์Œ") + print("=" * 60) + + # YOLO ํ•™์Šต ์‹คํ–‰ + from ultralytics import YOLO + + model = YOLO('yolov8n.pt') + results = model.train( + cfg=str(config_path), + data=str(config_path.parent.parent.parent / "Data" / "english_large4_251004" / "data.yaml") + ) + + print("โœ… ํ•™์Šต ์™„๋ฃŒ!") + return results + +if __name__ == "__main__": + main() diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/args.yaml b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/args.yaml new file mode 100644 index 0000000..c4284e7 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: /home/jdh251425/2509 Gradi-Detection/Data/english_large4_251004/data.yaml +epochs: 100 +time: null +patience: 25 +batch: 8 +imgsz: 1280 +save: true +save_period: -1 +cache: false +device: 0,1 +workers: 8 +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280 +name: train +exist_ok: true +pretrained: true +optimizer: AdamW +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +compile: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +conf: 0.12 +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: true +opset: null +workspace: null +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 1.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +nbs: 64 +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +degrees: 0 +translate: 0.0 +scale: 0.0 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.0 +bgr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +copy_paste_mode: flip +auto_augment: null +erasing: 0.0 +cfg: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280/config_optimized.yaml +tracker: botsort.yaml +save_dir: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280/train diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/results.csv b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/results.csv new file mode 100644 index 0000000..6c81561 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/results.csv @@ -0,0 +1,80 @@ +epoch,time,train/box_loss,train/cls_loss,train/dfl_loss,metrics/precision(B),metrics/recall(B),metrics/mAP50(B),metrics/mAP50-95(B),val/box_loss,val/cls_loss,val/dfl_loss,lr/pg0,lr/pg1,lr/pg2 +1,15.7641,1.95165,9.0524,2.26858,0.01926,0.28354,0.01583,0.00279,3.42604,338.509,16.6775,0.0631,0.0041,0.0041 +2,25.6949,1.48773,4.66582,1.95396,0.00232,0.10532,0.00123,0.00036,3.68832,inf,40.4564,0.0252178,0.00821783,0.00821783 +3,35.4795,1.44495,3.86399,1.8541,0.00018,0.0266,0.0001,3e-05,3.62613,inf,9.54428,0.009802,0.009802,0.009802 +4,45.2807,1.32481,3.5132,1.7643,1e-05,0.00133,0,0,3.68236,429.754,5.03996,0.009703,0.009703,0.009703 +5,54.8734,1.22741,2.96123,1.6577,0.00839,0.04508,0.0022,0.00053,4.33331,78.9387,9.18064,0.009604,0.009604,0.009604 +6,64.5252,1.14465,2.68712,1.5962,0.2591,0.25465,0.20646,0.08515,3.22109,13.88,6.36841,0.009505,0.009505,0.009505 +7,74.2218,1.11353,2.52339,1.55541,0.00768,0.02958,0.00405,0.00088,4.04607,29.238,8.10263,0.009406,0.009406,0.009406 +8,83.9297,1.06002,2.36351,1.47681,0.28825,0.14266,0.15472,0.04611,2.74646,12.0797,3.77771,0.009307,0.009307,0.009307 +9,93.649,1.00933,2.18672,1.43358,0.7999,0.75693,0.82504,0.56111,1.18812,3.36741,1.58085,0.009208,0.009208,0.009208 +10,103.385,1.0003,2.08258,1.4022,0.67293,0.79329,0.79793,0.53526,1.24032,3.51808,1.68971,0.009109,0.009109,0.009109 +11,113.141,0.92976,1.99864,1.34533,0.89493,0.90304,0.93389,0.66444,1.09503,2.38621,1.44603,0.00901,0.00901,0.00901 +12,122.837,0.90354,1.81467,1.3395,0.87334,0.95352,0.96066,0.70726,1.02639,2.10754,1.40762,0.008911,0.008911,0.008911 +13,132.638,0.91078,1.82076,1.32164,0.44862,0.19693,0.27996,0.08607,2.77598,13.331,3.68255,0.008812,0.008812,0.008812 +14,142.475,0.8613,1.76749,1.29813,0.49086,0.58757,0.59581,0.30799,2.0747,5.81972,3.25064,0.008713,0.008713,0.008713 +15,152.242,0.86073,1.75312,1.26539,0.9238,0.94451,0.96653,0.74862,0.93899,1.89009,1.28867,0.008614,0.008614,0.008614 +16,162.125,0.80358,1.59723,1.20263,0.92451,0.97547,0.97739,0.76307,0.87462,1.7369,1.25039,0.008515,0.008515,0.008515 +17,172.052,0.78719,1.57787,1.22138,0.86052,0.91707,0.94203,0.7029,1.04448,2.14735,1.42395,0.008416,0.008416,0.008416 +18,181.899,0.78855,1.51744,1.1873,0.87156,0.90883,0.94673,0.72874,0.95124,2.062,1.35794,0.008317,0.008317,0.008317 +19,191.7,0.76299,1.4862,1.17135,0.94903,0.92981,0.96034,0.7436,0.90504,1.83814,1.27014,0.008218,0.008218,0.008218 +20,201.404,0.75353,1.47135,1.17301,0.92322,0.95708,0.97172,0.75718,0.90472,1.7063,1.29137,0.008119,0.008119,0.008119 +21,211.118,0.73721,1.42299,1.15443,0.76074,0.63305,0.73355,0.45956,1.50679,5.60623,1.95026,0.00802,0.00802,0.00802 +22,220.873,0.71982,1.38186,1.13022,0.40181,0.19756,0.16137,0.05982,3.09707,11.6649,6.07238,0.007921,0.007921,0.007921 +23,230.546,0.71098,1.36205,1.11113,0.87359,0.91621,0.93907,0.71683,0.97016,2.26083,1.40269,0.007822,0.007822,0.007822 +24,240.257,0.70029,1.33468,1.10078,0.89024,0.85405,0.90598,0.67121,1.01789,2.63405,1.44926,0.007723,0.007723,0.007723 +25,249.947,0.6718,1.31203,1.09626,0.11321,0.23233,0.13679,0.04957,3.2123,12.1834,7.5067,0.007624,0.007624,0.007624 +26,259.678,0.66923,1.30123,1.08444,0.61793,0.54906,0.6187,0.36843,1.86402,5.98971,2.71371,0.007525,0.007525,0.007525 +27,269.237,0.67458,1.27035,1.08118,0.51399,0.02164,0.26687,0.14118,3.18965,19.8266,4.0179,0.007426,0.007426,0.007426 +28,278.911,0.65669,1.25545,1.06396,0.92389,0.93797,0.96225,0.74474,0.918,1.73129,1.33263,0.007327,0.007327,0.007327 +29,288.484,0.63879,1.23113,1.05859,0.51043,0.66615,0.6482,0.42878,1.54141,4.8672,2.4262,0.007228,0.007228,0.007228 +30,297.949,0.63796,1.22327,1.05558,0,0,0,0,4.03115,21.7273,5.38702,0.007129,0.007129,0.007129 +31,307.433,0.59455,1.17447,1.03836,0,0,0,0,4.04404,23.381,4.94939,0.00703,0.00703,0.00703 +32,317.06,0.60603,1.20392,1.01841,0.8863,0.91237,0.93815,0.70317,1.00156,2.03874,1.4632,0.006931,0.006931,0.006931 +33,326.827,0.62787,1.20583,1.03024,0.89678,0.9372,0.95168,0.74263,0.90045,1.72388,1.29979,0.006832,0.006832,0.006832 +34,336.549,0.59398,1.15952,1.01587,0.75514,0.80625,0.81689,0.51944,1.34474,2.95464,1.77881,0.006733,0.006733,0.006733 +35,346.183,0.59963,1.1547,1.01737,0.92878,0.96576,0.97038,0.78109,0.82491,1.53421,1.19163,0.006634,0.006634,0.006634 +36,355.641,0.59099,1.1431,1.01051,0.73766,0.24339,0.4895,0.27577,2.16908,11.5203,2.69805,0.006535,0.006535,0.006535 +37,365.21,0.58363,1.13201,1.00442,0.94702,0.96023,0.97699,0.77978,0.84427,1.52573,1.21495,0.006436,0.006436,0.006436 +38,374.922,0.56115,1.07623,0.98266,0.93045,0.96674,0.96926,0.78319,0.81184,1.49264,1.19236,0.006337,0.006337,0.006337 +39,384.768,0.54454,1.08724,0.97331,0.17319,0.12065,0.11965,0.05305,3.38054,15.607,5.81235,0.006238,0.006238,0.006238 +40,394.351,0.54558,1.0689,0.96955,0.25472,0.12828,0.17029,0.08223,3.31489,14.5401,5.27477,0.006139,0.006139,0.006139 +41,404.181,0.53146,1.07295,0.96254,0.72954,0.83868,0.82623,0.58211,1.13398,3.15557,1.62428,0.00604,0.00604,0.00604 +42,414.055,0.51973,1.02812,0.95864,0.53585,0.48426,0.50361,0.26469,1.99455,7.86568,3.90154,0.005941,0.005941,0.005941 +43,424.054,0.54016,1.04761,0.95225,0.90929,0.95073,0.95243,0.76139,0.8476,1.55854,1.2279,0.005842,0.005842,0.005842 +44,433.667,0.51384,1.02007,0.94526,0.9471,0.95467,0.97266,0.77669,0.82436,1.53241,1.20812,0.005743,0.005743,0.005743 +45,443.668,0.49792,1.00846,0.93029,0.94349,0.96525,0.97104,0.7859,0.81535,1.46345,1.19977,0.005644,0.005644,0.005644 +46,453.498,0.48938,0.98291,0.93698,0.94852,0.95967,0.9681,0.77727,0.81917,1.47466,1.21732,0.005545,0.005545,0.005545 +47,463.395,0.48342,0.9833,0.91653,0.93352,0.97067,0.97089,0.77743,0.83739,1.54,1.26506,0.005446,0.005446,0.005446 +48,473.257,0.46823,0.96456,0.91638,0.90857,0.94386,0.95122,0.75992,0.84624,1.63687,1.2691,0.005347,0.005347,0.005347 +49,482.972,0.47307,0.96215,0.91079,0.08439,0.06432,0.05514,0.01813,3.60023,19.8078,6.17244,0.005248,0.005248,0.005248 +50,492.823,0.45681,0.94262,0.91095,0.94271,0.97138,0.9725,0.77782,0.825,1.48302,1.22073,0.005149,0.005149,0.005149 +51,502.697,0.45316,0.93877,0.90811,0.96026,0.95239,0.9686,0.76256,0.86637,1.51751,1.26556,0.00505,0.00505,0.00505 +52,512.541,0.45199,0.94126,0.89854,0.94602,0.97093,0.97717,0.78421,0.82279,1.47367,1.22901,0.004951,0.004951,0.004951 +53,522.342,0.42977,0.904,0.89389,0.94083,0.95944,0.97706,0.77817,0.82311,1.48065,1.26742,0.004852,0.004852,0.004852 +54,532.23,0.43049,0.9085,0.88732,0.96136,0.97002,0.9766,0.79184,0.81248,1.41689,1.22239,0.004753,0.004753,0.004753 +55,542.052,0.42174,0.88915,0.88289,0.48023,0.44337,0.42071,0.23004,2.11434,10.0685,4.4139,0.004654,0.004654,0.004654 +56,551.848,0.42716,0.88306,0.88508,0.95155,0.9723,0.97529,0.7866,0.80069,1.42691,1.21373,0.004555,0.004555,0.004555 +57,561.98,0.40636,0.8791,0.88397,0.80965,0.82867,0.87401,0.62908,1.05214,3.0016,1.65175,0.004456,0.004456,0.004456 +58,571.958,0.40044,0.85885,0.87194,0.91586,0.94118,0.96471,0.75076,0.86819,1.66858,1.34325,0.004357,0.004357,0.004357 +59,581.687,0.38478,0.83225,0.86416,0.95284,0.97243,0.97109,0.78333,0.80833,1.42069,1.21988,0.004258,0.004258,0.004258 +60,591.662,0.40116,0.85258,0.86991,0.92504,0.95698,0.95601,0.7508,0.85828,1.61146,1.28263,0.004159,0.004159,0.004159 +61,601.641,0.38492,0.83834,0.86876,0.94356,0.96285,0.96947,0.77601,0.81627,1.47128,1.24057,0.00406,0.00406,0.00406 +62,611.587,0.38327,0.82459,0.86395,0.84891,0.93046,0.93832,0.70665,0.92966,1.94707,1.44155,0.003961,0.003961,0.003961 +63,621.575,0.36841,0.80949,0.85703,0.9269,0.97076,0.97086,0.77446,0.82889,1.47733,1.26107,0.003862,0.003862,0.003862 +64,631.542,0.35844,0.79269,0.8501,0.96116,0.96698,0.97546,0.78251,0.8023,1.42707,1.22686,0.003763,0.003763,0.003763 +65,641.602,0.3571,0.78529,0.84677,0.75879,0.73521,0.78031,0.53382,1.20871,3.8655,1.81436,0.003664,0.003664,0.003664 +66,651.625,0.34448,0.78281,0.83898,0.95669,0.97302,0.97658,0.78376,0.81709,1.44339,1.22903,0.003565,0.003565,0.003565 +67,661.583,0.3464,0.77218,0.83703,0.95382,0.97399,0.97248,0.78382,0.81436,1.43796,1.24598,0.003466,0.003466,0.003466 +68,671.733,0.32543,0.73843,0.83208,0.87207,0.92001,0.94383,0.71414,0.91457,1.88286,1.41618,0.003367,0.003367,0.003367 +69,681.745,0.33578,0.74758,0.83409,0.95003,0.9753,0.9688,0.77164,0.81317,1.47766,1.26534,0.003268,0.003268,0.003268 +70,691.783,0.32499,0.73884,0.83193,0.93722,0.95752,0.97204,0.76449,0.84174,1.53926,1.30505,0.003169,0.003169,0.003169 +71,701.738,0.31047,0.71038,0.82437,0.95564,0.96308,0.97325,0.78072,0.81295,1.46247,1.24459,0.00307,0.00307,0.00307 +72,711.742,0.30514,0.71158,0.82087,0.95442,0.96872,0.96979,0.78013,0.80471,1.45039,1.23816,0.002971,0.002971,0.002971 +73,721.752,0.30198,0.70259,0.82107,0.96694,0.96908,0.9758,0.78644,0.80529,1.43877,1.24732,0.002872,0.002872,0.002872 +74,731.724,0.28524,0.67381,0.81213,0.94749,0.96523,0.97387,0.78373,0.80366,1.46203,1.25418,0.002773,0.002773,0.002773 +75,741.757,0.28916,0.68112,0.8156,0.94065,0.9484,0.96939,0.76742,0.82716,1.50244,1.30441,0.002674,0.002674,0.002674 +76,751.744,0.27852,0.66671,0.8048,0.95829,0.96989,0.97479,0.78408,0.7967,1.44276,1.24761,0.002575,0.002575,0.002575 +77,761.659,0.27273,0.65724,0.80327,0.94882,0.97493,0.97327,0.783,0.80581,1.44648,1.25086,0.002476,0.002476,0.002476 +78,771.765,0.28166,0.66726,0.80666,0.95342,0.96883,0.96989,0.78176,0.80402,1.47001,1.25144,0.002377,0.002377,0.002377 +79,781.738,0.2628,0.64764,0.80769,0.94795,0.96226,0.97405,0.78139,0.80075,1.47605,1.24299,0.002278,0.002278,0.002278 diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/weights/best.pt b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/weights/best.pt new file mode 100644 index 0000000..d5cc2f9 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/weights/best.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/weights/last.pt b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/weights/last.pt new file mode 100644 index 0000000..311603a Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/train/weights/last.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/yolo11n.pt b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/yolo11n.pt new file mode 100644 index 0000000..45b273b Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/yolo11n.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/yolov8n.pt b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/yolov8n.pt new file mode 100644 index 0000000..0db4ca4 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8n_imgsz_1280/yolov8n.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/README.md b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/README.md new file mode 100644 index 0000000..e1f002b --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/README.md @@ -0,0 +1,27 @@ +# YOLOv8s @ 2048 - ์ž‘์€ ๊ฐ์ฒด ์ „์šฉ + +## ๋ชฉ์  +์ž‘์€ ๊ฐ์ฒด๋“ค์„ ์œ„ํ•œ ์ „์šฉ ๋ชจ๋ธ (page_number, problem_number, answer_1, answer_2) + +## ์„ค์ • +- **๋ชจ๋ธ**: YOLOv8s +- **์ด๋ฏธ์ง€ ํฌ๊ธฐ**: 2048x2048 +- **GPU**: [2,3] +- **๋ฐฐ์น˜ ํฌ๊ธฐ**: 4 +- **์ฆ๊ฐ•**: translate(0.02), scale(0.05), degrees(ยฑ3ยฐ), shear(ยฑ1ยฐ) + +## Loss ์„ค์ • +- **cls_loss_weight**: 3.0 (ํด๋ž˜์Šค ๋ถˆ๊ท ํ˜• ๋Œ€์‘) +- **box_loss_weight**: 7.5 +- **dfl_loss_weight**: 1.5 + +## ๋ฐ์ดํ„ฐ์…‹ +- **๊ฒฝ๋กœ**: `/home/jdh251425/2509 Gradi-Detection/Data/english_small4_251004/` +- **ํด๋ž˜์Šค**: 4๊ฐœ (page_number, problem_number, answer_1, answer_2) +- **ํด๋ž˜์Šค ๋ถ„ํฌ**: problem_number(1188), answer_1(845), answer_2(861), page_number(506) +- **์ด ์ด๋ฏธ์ง€**: 476๊ฐœ (333 train, 95 valid, 48 test) + +## ์‹คํ–‰ +```bash +bash START_TRAINING_UV.sh +``` diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/START_TRAINING_UV.sh b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/START_TRAINING_UV.sh new file mode 100644 index 0000000..1dcf974 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/START_TRAINING_UV.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +echo "๐Ÿš€ Routing Experiment 1004 - YOLOv8s @ 2048 ์‹œ์ž‘" +echo "๐ŸŽฏ ๋Œ€์ƒ: ์ž‘์€ ๊ฐ์ฒด (page_number, problem_number, answer_1, answer_2)" +echo "๐Ÿ–ฅ๏ธ GPU: [2,3]" +echo "๐Ÿ”„ ์ฆ๊ฐ•: translate, scale, degrees(ยฑ3ยฐ), shear(ยฑ1ยฐ)" +echo "โš–๏ธ cls_loss_weight: 3.0 (ํด๋ž˜์Šค ๋ถˆ๊ท ํ˜• ๋Œ€์‘)" +echo "๐Ÿ“Š ๋ฐ์ดํ„ฐ: english_small4_251004" +echo "=" * 60 + +# UV ํ™˜๊ฒฝ ํ™œ์„ฑํ™” +source /home/jdh251425/2509\ Gradi-Detection/gradi-detection/bin/activate + +# ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ +cd "/home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8s_imgsz_2048" + +# GPU ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ +echo "๐Ÿ“Š GPU ์ƒํƒœ ํ™•์ธ:" +nvidia-smi + +echo "๐Ÿ”ฅ ํ•™์Šต ์‹œ์ž‘..." +python run_optimized_training.py + +echo "โœ… ํ•™์Šต ์™„๋ฃŒ!" diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/config_optimized.yaml b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/config_optimized.yaml new file mode 100644 index 0000000..15de4a4 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/config_optimized.yaml @@ -0,0 +1,70 @@ +# Routing Experiment 1004 - YOLOv8s @ 2048 (์ž‘์€ ๊ฐ์ฒด ์ „์šฉ) + +task: detect +mode: train +model: yolov8s.pt +data: /home/jdh251425/2509 Gradi-Detection/Data/english_small4_251004/data.yaml + +# ํ•™์Šต +epochs: 100 +patience: 25 +batch: 4 +imgsz: 2048 +device: [2,3] # GPU 2,3 ์‚ฌ์šฉ +workers: 8 + +# ํ”„๋กœ์ ํŠธ +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8s_imgsz_2048 +name: train +exist_ok: true + +# ์˜ตํ‹ฐ๋งˆ์ด์ € +optimizer: AdamW +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 + +# Loss - cls ๊ฐ€์ค‘์น˜ ์ฆ๊ฐ€ (ํด๋ž˜์Šค ๋ถˆ๊ท ํ˜• ๋Œ€์‘) +box: 7.5 +cls: 3.0 # 1.5 -> 3.0์œผ๋กœ ์ฆ๊ฐ€ (ํด๋ž˜์Šค ๋ถ„๋ฅ˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ) +dfl: 1.5 + +# ์Šค์บ” ์ด๋ฏธ์ง€ ์นœํ™” +rect: true +multi_scale: false + +# ์ฆ๊ฐ• ์„ค์ • (translate, scale, degrees, shear๋งŒ ์‚ฌ์šฉ) +degrees: 3.0 # ยฑ3๋„ ํšŒ์ „ +perspective: 0.0 +translate: 0.02 +scale: 0.05 +shear: 1.0 # ยฑ1๋„ ์ „๋‹จ +flipud: 0.0 +fliplr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +auto_augment: null +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +erasing: 0.0 + +# ๊ฒ€์ฆ/์ถ”๋ก  +iou: 0.7 +conf: 0.22 +max_det: 300 +val: true +amp: true +plots: true +verbose: true +seed: 0 +deterministic: true +single_cls: false +cos_lr: false +cache: false diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/run_optimized_training.py b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/run_optimized_training.py new file mode 100644 index 0000000..e2b33a8 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/run_optimized_training.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +""" +Routing Experiment 1004 - YOLOv8s @ 2048 (์ž‘์€ ๊ฐ์ฒด ์ „์šฉ) +GPU 2,3 ์‚ฌ์šฉ, ์ฆ๊ฐ• + cls_loss_weight ์ฆ๊ฐ€ +""" + +import os +import sys +from pathlib import Path + +def main(): + # ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ ์„ค์ • + current_dir = Path(__file__).parent + os.chdir(current_dir) + + # ์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ + config_path = current_dir / "config_optimized.yaml" + + if not config_path.exists(): + print(f"โŒ ์„ค์ • ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {config_path}") + sys.exit(1) + + print("๐Ÿš€ Routing Experiment 1004 - YOLOv8s @ 2048 ์‹œ์ž‘") + print(f"๐Ÿ“ ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ: {current_dir}") + print(f"โš™๏ธ ์„ค์ • ํŒŒ์ผ: {config_path}") + print("๐ŸŽฏ ๋Œ€์ƒ: ์ž‘์€ ๊ฐ์ฒด (page_number, problem_number, answer_1, answer_2)") + print("๐Ÿ–ฅ๏ธ GPU: [2,3]") + print("๐Ÿ”„ ์ฆ๊ฐ•: translate, scale, degrees(ยฑ3ยฐ), shear(ยฑ1ยฐ)") + print("โš–๏ธ cls_loss_weight: 3.0 (ํด๋ž˜์Šค ๋ถˆ๊ท ํ˜• ๋Œ€์‘)") + print("=" * 60) + + # YOLO ํ•™์Šต ์‹คํ–‰ + from ultralytics import YOLO + + model = YOLO('yolov8s.pt') + results = model.train( + cfg=str(config_path), + data=str(config_path.parent.parent.parent / "Data" / "english_small4_251004" / "data.yaml") + ) + + print("โœ… ํ•™์Šต ์™„๋ฃŒ!") + return results + +if __name__ == "__main__": + main() diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/args.yaml b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/args.yaml new file mode 100644 index 0000000..89f40d3 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8s.pt +data: /home/jdh251425/2509 Gradi-Detection/Data/english_small4_251004/data.yaml +epochs: 100 +time: null +patience: 25 +batch: 4 +imgsz: 2048 +save: true +save_period: -1 +cache: false +device: 2,3 +workers: 8 +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8s_imgsz_2048 +name: train +exist_ok: true +pretrained: true +optimizer: AdamW +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +compile: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +conf: 0.22 +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: true +opset: null +workspace: null +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 3.0 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +nbs: 64 +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +degrees: 3.0 +translate: 0.02 +scale: 0.05 +shear: 1.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.0 +bgr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +copy_paste_mode: flip +auto_augment: null +erasing: 0.0 +cfg: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8s_imgsz_2048/config_optimized.yaml +tracker: botsort.yaml +save_dir: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8s_imgsz_2048/train diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/results.csv b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/results.csv new file mode 100644 index 0000000..253ba0c --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/results.csv @@ -0,0 +1,101 @@ +epoch,time,train/box_loss,train/cls_loss,train/dfl_loss,metrics/precision(B),metrics/recall(B),metrics/mAP50(B),metrics/mAP50-95(B),val/box_loss,val/cls_loss,val/dfl_loss,lr/pg0,lr/pg1,lr/pg2 +1,50.1493,2.26524,101.778,2.12247,0,0,0,0,nan,nan,nan,0.0555357,0.00494048,0.00494048 +2,97.1832,2.28955,23.1778,2.69915,0,0,0,0,nan,nan,nan,0.0104373,0.00984207,0.00984207 +3,144.71,2.20231,15.1292,2.41155,2e-05,0.00222,1e-05,0,3.24887,inf,9.44258,0.009802,0.009802,0.009802 +4,189.654,2.23352,14.8608,2.28949,0.31481,0.06486,0.16055,0.05254,2.94955,1353.76,6.58021,0.009703,0.009703,0.009703 +5,236.522,2.0894,10.887,2.06677,0.28409,0.00333,0.13374,0.06537,2.74822,inf,2.58697,0.009604,0.009604,0.009604 +6,282.329,2.01837,9.18363,1.9958,0.3064,0.32717,0.32897,0.12944,2.10086,17.0313,2.01859,0.009505,0.009505,0.009505 +7,328.549,1.86127,8.14927,1.88095,0.69091,0.72784,0.75848,0.35577,1.84413,8.44436,1.85764,0.009406,0.009406,0.009406 +8,374.962,1.83055,7.68534,1.80917,0.13176,0.1605,0.15128,0.05462,2.03208,22.6867,1.92567,0.009307,0.009307,0.009307 +9,421.2,1.7902,6.95343,1.79119,0.77286,0.78908,0.84743,0.39564,1.76282,7.46278,1.7453,0.009208,0.009208,0.009208 +10,467.873,1.75115,6.70533,1.74377,0.88158,0.67615,0.8069,0.38148,1.82714,8.09072,1.76128,0.009109,0.009109,0.009109 +11,514.508,1.6706,6.45484,1.65956,0.86402,0.878,0.91581,0.4573,1.68351,6.20995,1.67753,0.00901,0.00901,0.00901 +12,561.251,1.63841,6.30956,1.64502,0.76345,0.95419,0.94134,0.48698,1.60399,5.87618,1.61126,0.008911,0.008911,0.008911 +13,608.627,1.62533,5.93488,1.6131,0.9041,0.93244,0.94683,0.48489,1.60396,5.64602,1.60016,0.008812,0.008812,0.008812 +14,655.094,1.71425,5.97655,1.71497,0.78444,0.95776,0.94595,0.46344,1.69254,5.73183,1.68818,0.008713,0.008713,0.008713 +15,701.878,1.66831,6.1133,1.69309,0.78077,0.9597,0.95015,0.42599,1.81409,6.15901,1.73858,0.008614,0.008614,0.008614 +16,748.843,1.76617,6.01498,1.73984,0.87154,0.94012,0.93155,0.45968,1.69632,5.77917,1.66994,0.008515,0.008515,0.008515 +17,795.173,1.64859,5.7346,1.65113,0.85416,0.87754,0.94964,0.49216,1.60487,5.76576,1.59841,0.008416,0.008416,0.008416 +18,841.678,1.67802,5.69073,1.66798,0.68113,0.62544,0.66729,0.2854,1.88969,8.99424,1.78814,0.008317,0.008317,0.008317 +19,887.463,1.64201,5.594,1.63876,0.4312,0.41067,0.44954,0.21613,1.76107,13.1956,1.70494,0.008218,0.008218,0.008218 +20,933.687,1.62727,5.60623,1.64975,0.83252,0.78234,0.87234,0.43843,1.68811,6.17955,1.6665,0.008119,0.008119,0.008119 +21,979.71,1.61658,5.44135,1.62817,0.90771,0.9426,0.95457,0.48185,1.62089,5.18509,1.60209,0.00802,0.00802,0.00802 +22,1025.15,1.58833,5.37245,1.60322,0.91372,0.97475,0.97996,0.51383,1.58715,5.15877,1.59072,0.007921,0.007921,0.007921 +23,1071.32,1.67283,5.90179,1.73076,0.88433,0.86367,0.92026,0.4565,1.62828,5.96713,1.65473,0.007822,0.007822,0.007822 +24,1117.24,1.61052,5.55728,1.62097,0.81083,0.95344,0.95555,0.50697,1.5822,5.2472,1.58259,0.007723,0.007723,0.007723 +25,1162.89,1.57865,5.06621,1.58278,0.94606,0.97053,0.97431,0.50903,1.59752,4.98703,1.58704,0.007624,0.007624,0.007624 +26,1208.67,1.55765,5.06324,1.57176,0.33823,0.41435,0.40132,0.18247,1.94234,17.9916,1.83192,0.007525,0.007525,0.007525 +27,1254.56,1.55766,5.07803,1.56604,0.33618,0.16758,0.24893,0.13137,2.03289,21.9616,1.96016,0.007426,0.007426,0.007426 +28,1299.93,1.53378,5.08096,1.5528,0.39361,0.45062,0.42969,0.20677,1.7413,14.7133,1.6689,0.007327,0.007327,0.007327 +29,1346.02,1.53039,4.77861,1.56245,0.95742,0.96676,0.97688,0.5294,1.53405,4.73748,1.53914,0.007228,0.007228,0.007228 +30,1391.91,1.53822,4.97626,1.55647,0.69979,0.67629,0.71907,0.34543,1.73401,8.92919,1.66864,0.007129,0.007129,0.007129 +31,1437.83,1.51678,5.00087,1.54089,0.42783,0.364,0.40751,0.19619,1.893,20.0931,1.84462,0.00703,0.00703,0.00703 +32,1483.64,1.50408,4.80439,1.52817,0.25758,0.1919,0.24057,0.11491,2.23831,18.5391,2.14022,0.006931,0.006931,0.006931 +33,1529.18,1.52229,4.8655,1.5529,0.95783,0.9673,0.96834,0.53014,1.54917,4.70871,1.53789,0.006832,0.006832,0.006832 +34,1574.9,1.51405,4.73829,1.55278,0.9507,0.96185,0.97473,0.52416,1.53716,4.56938,1.53691,0.006733,0.006733,0.006733 +35,1620.94,1.50692,4.70944,1.53466,0.91261,0.93031,0.948,0.51276,1.54801,4.79982,1.54219,0.006634,0.006634,0.006634 +36,1666.94,1.51465,4.66621,1.53951,0.91391,0.90554,0.93873,0.51803,1.5391,4.89262,1.53676,0.006535,0.006535,0.006535 +37,1713.3,1.5143,4.70618,1.54366,0.93515,0.95451,0.9799,0.53809,1.54212,4.51065,1.53871,0.006436,0.006436,0.006436 +38,1759.45,1.48839,4.47873,1.51802,0.44546,0.44056,0.46464,0.23329,1.78154,11.3369,1.73903,0.006337,0.006337,0.006337 +39,1804.94,1.45524,4.47244,1.49237,0.93662,0.97361,0.97467,0.53191,1.51543,4.5898,1.52453,0.006238,0.006238,0.006238 +40,1850.21,1.47793,4.51307,1.50381,0.94755,0.94646,0.97501,0.54593,1.50641,4.26737,1.51317,0.006139,0.006139,0.006139 +41,1896.2,1.50966,4.59223,1.51159,0.95779,0.96703,0.97858,0.54352,1.51163,4.37903,1.51683,0.00604,0.00604,0.00604 +42,1941.81,1.47441,4.376,1.49717,0.69718,0.71792,0.7247,0.37666,1.69654,7.91494,1.64863,0.005941,0.005941,0.005941 +43,1988.01,1.51608,4.59102,1.54091,0.94563,0.96686,0.975,0.545,1.50671,4.39649,1.51735,0.005842,0.005842,0.005842 +44,2033.54,1.49336,4.37836,1.52659,0.94521,0.95652,0.97677,0.55368,1.49148,4.26754,1.51166,0.005743,0.005743,0.005743 +45,2080.44,1.50828,4.37788,1.53406,0.92793,0.95005,0.96417,0.53659,1.51312,4.31148,1.51875,0.005644,0.005644,0.005644 +46,2126.51,1.46615,4.4023,1.50624,0.97037,0.97502,0.98238,0.53492,1.53906,4.43229,1.5248,0.005545,0.005545,0.005545 +47,2172.46,1.5302,4.46605,1.54401,0.43096,0.37855,0.43248,0.20276,1.8779,11.7846,1.76834,0.005446,0.005446,0.005446 +48,2218.47,1.47857,4.43731,1.50809,0.95659,0.95969,0.97862,0.54472,1.5465,4.37242,1.54148,0.005347,0.005347,0.005347 +49,2264.2,1.469,4.33514,1.49406,0.96503,0.95706,0.98018,0.55582,1.50657,4.21592,1.51556,0.005248,0.005248,0.005248 +50,2310,1.45868,4.32756,1.49707,0.31727,0.28231,0.31099,0.13864,1.83466,13.6374,1.73947,0.005149,0.005149,0.005149 +51,2356.07,1.44297,4.51071,1.49192,0.89125,0.96068,0.95272,0.5111,1.53845,4.79185,1.53338,0.00505,0.00505,0.00505 +52,2401.92,1.46654,4.66197,1.48921,0.95569,0.9647,0.97837,0.53563,1.51798,4.40865,1.51991,0.004951,0.004951,0.004951 +53,2447.62,1.46282,4.38046,1.50251,0.94882,0.95689,0.96783,0.552,1.49024,4.36027,1.51347,0.004852,0.004852,0.004852 +54,2493.4,1.4683,4.49337,1.49682,0.94745,0.97135,0.97869,0.52963,1.55845,4.49197,1.54975,0.004753,0.004753,0.004753 +55,2538.93,1.48725,4.55949,1.51618,0.96932,0.95157,0.97922,0.54971,1.4949,4.40486,1.51622,0.004654,0.004654,0.004654 +56,2584.99,1.45161,4.50229,1.48675,0.947,0.93217,0.97146,0.50911,1.58309,4.67256,1.56281,0.004555,0.004555,0.004555 +57,2630.38,1.44755,4.45745,1.48798,0.94554,0.96894,0.96883,0.54317,1.51463,4.2692,1.52468,0.004456,0.004456,0.004456 +58,2676.1,1.46072,4.31507,1.49262,0.45582,0.21651,0.34798,0.17631,1.96724,14.8254,1.79904,0.004357,0.004357,0.004357 +59,2721.87,1.45042,4.19232,1.47457,0.97515,0.96826,0.98224,0.55492,1.50882,4.13278,1.51456,0.004258,0.004258,0.004258 +60,2767.7,1.45406,4.18366,1.50761,0.65681,0.66532,0.69353,0.37193,1.6202,7.85996,1.59885,0.004159,0.004159,0.004159 +61,2813.27,1.44037,4.26318,1.47486,0.95163,0.94757,0.97513,0.54032,1.50443,4.19317,1.51329,0.00406,0.00406,0.00406 +62,2859.1,1.43808,4.18579,1.48627,0.40683,0.17023,0.30763,0.12505,2.59855,17.4222,2.28028,0.003961,0.003961,0.003961 +63,2904.8,1.42482,4.07806,1.46981,0.97282,0.95259,0.97754,0.54844,1.53451,4.07492,1.53375,0.003862,0.003862,0.003862 +64,2950.51,1.43752,4.05777,1.49401,0.9597,0.96513,0.97595,0.54213,1.51722,4.06696,1.52291,0.003763,0.003763,0.003763 +65,2996.64,1.42807,4.01347,1.48482,0.95944,0.9699,0.97433,0.54726,1.49247,4.03254,1.51184,0.003664,0.003664,0.003664 +66,3042.63,1.40942,4.0417,1.4699,0.9492,0.72435,0.85489,0.49622,1.59865,5.94737,1.58302,0.003565,0.003565,0.003565 +67,3088.57,1.41163,3.93455,1.46288,0.69514,0.67431,0.7024,0.38299,1.65022,7.70157,1.61304,0.003466,0.003466,0.003466 +68,3134.33,1.40807,3.9385,1.46247,0.96042,0.96381,0.97515,0.55641,1.51911,4.02687,1.51968,0.003367,0.003367,0.003367 +69,3180.64,1.40582,3.96866,1.4697,0.96655,0.95266,0.97185,0.55498,1.49213,3.96526,1.50349,0.003268,0.003268,0.003268 +70,3227.02,1.39094,3.87673,1.43399,0.97571,0.96705,0.97959,0.55352,1.51143,3.97741,1.51894,0.003169,0.003169,0.003169 +71,3272.52,1.41882,3.88567,1.47326,0.47693,0.09919,0.28681,0.12054,2.17603,22.1633,1.93537,0.00307,0.00307,0.00307 +72,3318.1,1.39264,3.83659,1.44707,0.70448,0.70455,0.7146,0.38467,1.59666,6.34257,1.5839,0.002971,0.002971,0.002971 +73,3363.98,1.40646,3.97608,1.4528,0.96433,0.97308,0.97175,0.53486,1.53203,3.96677,1.53434,0.002872,0.002872,0.002872 +74,3409.91,1.40664,3.866,1.4548,0.95902,0.96694,0.97209,0.54558,1.51625,4.03429,1.52269,0.002773,0.002773,0.002773 +75,3455.74,1.39427,3.87246,1.44892,0.97277,0.95778,0.97565,0.55002,1.51108,3.91337,1.52374,0.002674,0.002674,0.002674 +76,3501.3,1.41208,3.76556,1.46046,0.96502,0.97157,0.97796,0.54864,1.52299,3.91447,1.52674,0.002575,0.002575,0.002575 +77,3546.98,1.38741,3.68459,1.46003,0.96696,0.96871,0.97345,0.558,1.49675,3.88221,1.50815,0.002476,0.002476,0.002476 +78,3593.3,1.38189,3.77311,1.44942,0.95087,0.9562,0.9629,0.53955,1.5402,4.03608,1.53344,0.002377,0.002377,0.002377 +79,3639.09,1.37058,3.69854,1.42748,0.96066,0.95546,0.96529,0.55905,1.49455,3.82945,1.51047,0.002278,0.002278,0.002278 +80,3685,1.39814,3.70035,1.44729,0.96473,0.96107,0.97076,0.54689,1.52267,3.84827,1.52675,0.002179,0.002179,0.002179 +81,3731.26,1.37409,3.54678,1.4265,0.96408,0.96537,0.97702,0.54974,1.5182,3.83776,1.5267,0.00208,0.00208,0.00208 +82,3777.08,1.3649,3.65435,1.42579,0.71172,0.61923,0.68675,0.35837,1.70704,8.35537,1.64921,0.001981,0.001981,0.001981 +83,3822.5,1.36866,3.72887,1.43281,0.97147,0.96292,0.97211,0.54434,1.51256,3.78382,1.521,0.001882,0.001882,0.001882 +84,3868.05,1.3511,3.60254,1.42433,0.96672,0.96096,0.96533,0.55289,1.52814,3.89249,1.52271,0.001783,0.001783,0.001783 +85,3913.89,1.37795,3.6734,1.43245,0.95698,0.97012,0.97168,0.5481,1.49474,3.84685,1.50443,0.001684,0.001684,0.001684 +86,3959.74,1.36002,3.63763,1.41867,0.97044,0.9633,0.97367,0.54218,1.52479,3.84155,1.52675,0.001585,0.001585,0.001585 +87,4005.53,1.34523,3.52575,1.40972,0.69411,0.19437,0.44768,0.22355,2.13868,17.8571,1.92863,0.001486,0.001486,0.001486 +88,4052.14,1.33244,3.55509,1.40798,0.97169,0.96608,0.96983,0.54528,1.51278,3.83282,1.52462,0.001387,0.001387,0.001387 +89,4098.5,1.39199,3.66911,1.46083,0.96197,0.95338,0.96058,0.54133,1.55297,3.94817,1.55602,0.001288,0.001288,0.001288 +90,4144.4,1.35914,3.60113,1.43953,0.9299,0.91407,0.94415,0.52486,1.57214,4.21695,1.5676,0.001189,0.001189,0.001189 +91,4191.82,1.34699,3.50162,1.40831,0.96716,0.95886,0.97403,0.54235,1.5477,3.80499,1.5463,0.00109,0.00109,0.00109 +92,4238.28,1.34698,3.42383,1.40918,0.97392,0.96578,0.97641,0.55103,1.51617,3.72771,1.52235,0.000991,0.000991,0.000991 +93,4284.34,1.33195,3.45839,1.40905,0.97112,0.96179,0.97161,0.55679,1.50472,3.67517,1.51925,0.000892,0.000892,0.000892 +94,4329.7,1.33697,3.42391,1.41229,0.94592,0.92223,0.94723,0.52505,1.59602,4.0038,1.58808,0.000793,0.000793,0.000793 +95,4376.91,1.3316,3.48075,1.39725,0.93554,0.95833,0.95753,0.52199,1.60298,4.07801,1.59342,0.000694,0.000694,0.000694 +96,4423.43,1.31651,3.42523,1.39143,0.67119,0.56783,0.62522,0.31738,1.8661,7.49253,1.78354,0.000595,0.000595,0.000595 +97,4469.28,1.33959,3.40527,1.41499,0.69533,0.63796,0.67075,0.34843,1.77896,6.81472,1.71799,0.000496,0.000496,0.000496 +98,4515.32,1.32726,3.3286,1.39526,0.96998,0.96374,0.9776,0.55296,1.5222,3.63221,1.53441,0.000397,0.000397,0.000397 +99,4561.52,1.33729,3.46256,1.42474,0.96424,0.96178,0.97352,0.5499,1.52289,3.70713,1.53515,0.000298,0.000298,0.000298 +100,4606.81,1.3186,3.36051,1.42139,0.97433,0.96412,0.97781,0.5504,1.5232,3.71572,1.53515,0.000199,0.000199,0.000199 diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/weights/best.pt b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/weights/best.pt new file mode 100644 index 0000000..fd8463a Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/weights/best.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/weights/last.pt b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/weights/last.pt new file mode 100644 index 0000000..ae59dc6 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/train/weights/last.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/yolo11n.pt b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/yolo11n.pt new file mode 100644 index 0000000..45b273b Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/yolo11n.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/yolov8s.pt b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/yolov8s.pt new file mode 100644 index 0000000..90b4a2c Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1004/yolov8s_imgsz_2048/yolov8s.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/__pycache__/run_routed_inference.cpython-311.pyc b/ai-service/models/Detection/legacy/Model_routing_1104/__pycache__/run_routed_inference.cpython-311.pyc new file mode 100644 index 0000000..343bc44 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1104/__pycache__/run_routed_inference.cpython-311.pyc differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/__pycache__/run_routed_inference.cpython-312.pyc b/ai-service/models/Detection/legacy/Model_routing_1104/__pycache__/run_routed_inference.cpython-312.pyc new file mode 100644 index 0000000..f9d7576 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1104/__pycache__/run_routed_inference.cpython-312.pyc differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/run_routed_inference.py b/ai-service/models/Detection/legacy/Model_routing_1104/run_routed_inference.py new file mode 100644 index 0000000..f603812 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1104/run_routed_inference.py @@ -0,0 +1,400 @@ +# Model_routing_1104/run_routed_inference.py +""" +๋ผ์šฐํŒ… ์ถ”๋ก  ์Šคํฌ๋ฆฝํŠธ +YOLOv8n (ํฐ ๊ฐ์ฒด)๊ณผ YOLOv8s (์ž‘์€ ๊ฐ์ฒด) ๋ชจ๋ธ์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์ถ”๋ก ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. +๊ฐ ํด๋ž˜์Šค๋ณ„๋กœ ๊ฐ€์žฅ ๋†’์€ ์‹ ๋ขฐ๋„์˜ ๋ฐ”์šด๋”ฉ๋ฐ•์Šค๋งŒ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. +""" + +import os +import sys +import json +import cv2 +import numpy as np +from pathlib import Path +from typing import List, Dict, Tuple +from ultralytics import YOLO +from datetime import datetime + +# ํด๋ž˜์Šค ๋ผ์šฐํŒ… ์ •์˜ (1, 2, 3, 4, 5 ์ถ”๊ฐ€) +SMALL_CLASSES = {"page_number", "problem_number", "answer_1", "answer_2", "1", "2", "3", "4", "5"} +LARGE_CLASSES = {"korean_content", "english_content", "section", "answer_option"} + +# ํด๋ž˜์Šค๋ณ„ ์ƒ‰์ƒ ์ •์˜ +CLASS_COLORS = { + # ํฐ ๊ฐ์ฒด ํด๋ž˜์Šค + 'answer_option': (0, 255, 0), # ๋…น์ƒ‰ + 'english_content': (255, 0, 0), # ๋นจ๊ฐ„์ƒ‰ + 'korean_content': (0, 0, 255), # ํŒŒ๋ž€์ƒ‰ + 'section': (255, 255, 0), # ๋…ธ๋ž€์ƒ‰ + + # ์ž‘์€ ๊ฐ์ฒด ํด๋ž˜์Šค + 'page_number': (255, 0, 255), # ๋งˆ์  ํƒ€ + 'problem_number': (0, 255, 255), # ์‹œ์•ˆ + 'answer_1': (255, 165, 0), # ์˜ค๋ Œ์ง€ + 'answer_2': (128, 0, 128), # ๋ณด๋ผ + + # ์ˆซ์ž ํด๋ž˜์Šค + '1': (255, 192, 203), # ํ•‘ํฌ + '2': (144, 238, 144), # ๋ผ์ดํŠธ๊ทธ๋ฆฐ + '3': (173, 216, 230), # ๋ผ์ดํŠธ๋ธ”๋ฃจ + '4': (255, 218, 185), # ํ”ผ์น˜ + '5': (221, 160, 221) # ํ”Œ๋Ÿผ +} + +class RoutedInference: + def __init__(self, base_dir: str): + self.base_dir = Path(base_dir) + self.small_model_dir = self.base_dir / "yolov8s_imgsz_2048" + self.large_model_dir = self.base_dir / "yolov8n_imgsz_1280" + + # ๋ชจ๋ธ ๊ฒฝ๋กœ + self.small_model_path = self.small_model_dir / "train" / "weights" / "best.pt" + self.large_model_path = self.large_model_dir / "train" / "weights" / "best.pt" + + # ๋ชจ๋ธ ๋กœ๋“œ + self.small_model = self._load_model(self.small_model_path, "yolov8s.pt") + self.large_model = self._load_model(self.large_model_path, "yolov8n.pt") + + # ์ถ”๋ก  ํŒŒ๋ผ๋ฏธํ„ฐ + self.small_conf = 0.22 + self.large_conf = 0.12 + + print(f"โœ… Small model loaded: {self.small_model_path}") + print(f"โœ… Large model loaded: {self.large_model_path}") + + def _load_model(self, model_path: Path, fallback: str): + """๋ชจ๋ธ ๋กœ๋“œ""" + if model_path.exists(): + return YOLO(str(model_path)) + else: + print(f"โš ๏ธ Model not found: {model_path}, using {fallback}") + return YOLO(fallback) + + def get_all_detections(self, results, class_names: List[str]) -> List[Dict]: + """ + ๋ชจ๋“  ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ (ํด๋ž˜์Šค๋ณ„ ์ตœ๊ณ  ์‹ ๋ขฐ๋„ ์„ ํƒ ์ œ๊ฑฐ) + """ + all_detections = [] + + if results.boxes is not None: + for box in results.boxes: + cls_id = int(box.cls[0]) + confidence = float(box.conf[0]) + xyxy = box.xyxy[0].tolist() + + if cls_id < len(class_names): + class_name = class_names[cls_id] + + all_detections.append({ + 'class_name': class_name, + 'class_id': cls_id, + 'confidence': confidence, + 'bbox': xyxy + }) + + return all_detections + + def route_infer_single_image(self, image_path: str) -> Dict: + """ + ๋‹จ์ผ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ๋ผ์šฐํŒ… ์ถ”๋ก  ์ˆ˜ํ–‰ + """ + # ์ž‘์€ ๊ฐ์ฒด ๋ชจ๋ธ ์ถ”๋ก  (YOLOv8s @ 2048) - 1, 2, 3, 4, 5 ํด๋ž˜์Šค ์ถ”๊ฐ€ + small_results = self.small_model(str(image_path), imgsz=2048, conf=self.small_conf, verbose=False)[0] + small_class_names = ['page_number', 'problem_number', 'answer_1', 'answer_2', '1', '2', '3', '4', '5'] + small_detections = self.get_all_detections(small_results, small_class_names) + + # ํฐ ๊ฐ์ฒด ๋ชจ๋ธ ์ถ”๋ก  (YOLOv8n @ 1280) + large_results = self.large_model(str(image_path), imgsz=1280, conf=self.large_conf, verbose=False)[0] + large_class_names = ['answer_option', 'english_content', 'korean_content', 'section'] + large_detections = self.get_all_detections(large_results, large_class_names) + + # ๊ฒฐ๊ณผ ๋ณ‘ํ•ฉ + all_detections = small_detections + large_detections + + return { + 'image_path': str(image_path), + 'detections': all_detections, + 'small_detections': small_detections, + 'large_detections': large_detections, + 'timestamp': datetime.now().isoformat() + } + + def visualize_detections(self, image_path: str, detections: List[Dict], output_path: str): + """ + ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐํ™”ํ•˜์—ฌ ์ €์žฅ + """ + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + image = cv2.imread(str(image_path)) + if image is None: + print(f"โŒ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return + + # ๊ฐ ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ + for det in detections: + class_name = det['class_name'] + confidence = det['confidence'] + bbox = det['bbox'] + color = CLASS_COLORS.get(class_name, (255, 255, 255)) + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ์ขŒํ‘œ + x1, y1, x2, y2 = map(int, bbox) + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ๊ทธ๋ฆฌ๊ธฐ + cv2.rectangle(image, (x1, y1), (x2, y2), color, 3) + + # ๋ผ๋ฒจ ํ…์ŠคํŠธ + label = f"{class_name}: {confidence:.3f}" + + # ํ…์ŠคํŠธ ๋ฐฐ๊ฒฝ ๊ทธ๋ฆฌ๊ธฐ + (text_width, text_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.7, 2) + cv2.rectangle(image, (x1, y1 - text_height - 10), (x1 + text_width, y1), color, -1) + + # ํ…์ŠคํŠธ ๊ทธ๋ฆฌ๊ธฐ + cv2.putText(image, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + + # ๋ฒ”๋ก€ ์ถ”๊ฐ€ + self.add_legend(image) + + # ์ด๋ฏธ์ง€ ์ €์žฅ + cv2.imwrite(str(output_path), image) + + def crop_and_save_detections(self, image_path: str, detections: List[Dict], output_dir: Path): + """๊ฐ ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๊ฐœ๋ณ„ ์ด๋ฏธ์ง€๋กœ ํฌ๋กญํ•˜์—ฌ ์ €์žฅ""" + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + image = cv2.imread(str(image_path)) + if image is None: + print(f"โŒ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return + + image_name = Path(image_path).stem + + # ํด๋ž˜์Šค๋ณ„ ์นด์šดํ„ฐ + class_counters = {} + + for det in detections: + class_name = det['class_name'] + confidence = det['confidence'] + bbox = det['bbox'] + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ์ขŒํ‘œ + x1, y1, x2, y2 = map(int, bbox) + + # ์ขŒํ‘œ ๋ณด์ • + h, w = image.shape[:2] + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 <= x1 or y2 <= y1: + continue + + # ํฌ๋กญ + cropped = image[y1:y2, x1:x2] + + # ํด๋ž˜์Šค๋ณ„ ํด๋” ์ƒ์„ฑ + class_dir = output_dir / image_name / class_name + class_dir.mkdir(parents=True, exist_ok=True) + + # ์นด์šดํ„ฐ ์ฆ๊ฐ€ + if class_name not in class_counters: + class_counters[class_name] = 0 + else: + class_counters[class_name] += 1 + + # ํŒŒ์ผ๋ช… ์ƒ์„ฑ ๋ฐ ์ €์žฅ + crop_filename = f"{class_name}_{class_counters[class_name]:02d}_conf{confidence:.3f}.jpg" + cv2.imwrite(str(class_dir / crop_filename), cropped) + + def crop_by_class_only(self, image_path: str, detections: List[Dict], output_dir: Path, class_counters: Dict[str, int]): + # ์ด๋ฏธ์ง€ ๋กœ๋“œ + image = cv2.imread(str(image_path)) + if image is None: + print(f"โŒ ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return class_counters + + image_name = Path(image_path).stem + + for det in detections: + class_name = det['class_name'] + confidence = det['confidence'] + bbox = det['bbox'] + + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ์ขŒํ‘œ + x1, y1, x2, y2 = map(int, bbox) + + # ์ขŒํ‘œ ๋ณด์ • + h, w = image.shape[:2] + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 <= x1 or y2 <= y1: + continue + + # ํฌ๋กญ + cropped = image[y1:y2, x1:x2] + + # ํด๋ž˜์Šค๋ณ„ ํด๋” ์ƒ์„ฑ (ํŽ˜์ด์ง€ ๊ตฌ๋ถ„ ์—†์Œ) + class_dir = output_dir / class_name + class_dir.mkdir(parents=True, exist_ok=True) + + # ์ „์—ญ ์นด์šดํ„ฐ ์ฆ๊ฐ€ + if class_name not in class_counters: + class_counters[class_name] = 0 + + # ํŒŒ์ผ๋ช…: ํŽ˜์ด์ง€๋ช…_์นด์šดํ„ฐ_์‹ ๋ขฐ๋„ + crop_filename = f"{image_name}_{class_name}_{class_counters[class_name]:03d}_conf{confidence:.3f}.jpg" + cv2.imwrite(str(class_dir / crop_filename), cropped) + + class_counters[class_name] += 1 + + return class_counters + + def add_legend(self, image): + """๋ฒ”๋ก€ ์ถ”๊ฐ€""" + legend_y = 30 + all_classes = list(CLASS_COLORS.keys()) + + for i, class_name in enumerate(all_classes): + color = CLASS_COLORS[class_name] + # ์ƒ‰์ƒ ๋ฐ•์Šค + cv2.rectangle(image, (10, legend_y + i * 30), (30, legend_y + i * 30 + 25), color, -1) + # ํด๋ž˜์Šค ์ด๋ฆ„ + cv2.putText(image, class_name, (35, legend_y + i * 30 + 18), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2) + + def process_test_images(self, test_data_root: str, output_dir: str): + """ + ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€๋“ค์— ๋Œ€ํ•ด ๋ผ์šฐํŒ… ์ถ”๋ก  ์ˆ˜ํ–‰ + """ + test_data_path = Path(test_data_root) + output_path = Path(output_dir) + + # ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ + (output_path / "images").mkdir(parents=True, exist_ok=True) + (output_path / "annotations").mkdir(parents=True, exist_ok=True) + + # ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ + test_images_dir = test_data_path + if not test_images_dir.exists(): + print(f"โŒ ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {test_images_dir}") + return + + image_extensions = ['.jpg', '.jpeg', '.png', '.bmp'] + image_files = [] + for ext in image_extensions: + image_files.extend(test_images_dir.glob(f"*{ext}")) + image_files.extend(test_images_dir.glob(f"*{ext.upper()}")) + + image_files = sorted(image_files) + print(f"๐Ÿ“Š ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€ {len(image_files)}๊ฐœ ๋ฐœ๊ฒฌ") + + # ๊ฒฐ๊ณผ ์ €์žฅ์šฉ + all_results = [] + total_detections = 0 + class_counts = {name: 0 for name in CLASS_COLORS.keys()} + total_confidence = 0 + + global_class_counters = {} # ์ „์—ญ ์นด์šดํ„ฐ + + print(f"๐Ÿ” {len(image_files)}๊ฐœ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ๋ผ์šฐํŒ… ์ถ”๋ก  ์‹œ์ž‘...") + + for i, image_path in enumerate(image_files): + print(f"์ฒ˜๋ฆฌ ์ค‘: {i+1}/{len(image_files)} - {image_path.name}") + + # ๋ผ์šฐํŒ… ์ถ”๋ก  ์ˆ˜ํ–‰ + result = self.route_infer_single_image(str(image_path)) + all_results.append(result) + + # ์‹œ๊ฐํ™” ์ด๋ฏธ์ง€ ์ €์žฅ + output_image_path = output_path / "images" / f"routed_result_{image_path.stem}.jpg" + self.visualize_detections(str(image_path), result['detections'], str(output_image_path)) + + # ํฌ๋กญ๋œ ์ด๋ฏธ์ง€ ์ €์žฅ + detailed_output_dir = output_path / "detailed_images" + self.crop_and_save_detections(str(image_path), result['detections'], detailed_output_dir) + + # ํด๋ž˜์Šค๋ณ„ ํฌ๋กญ ์ €์žฅ (ํŽ˜์ด์ง€ ๊ตฌ๋ถ„ ์—†์Œ) + class_output_dir = output_path / "class_images" + global_class_counters = self.crop_by_class_only(str(image_path), result['detections'], class_output_dir, global_class_counters) + + # JSON ์ €์žฅ + output_json_path = output_path / "annotations" / f"routed_result_{image_path.stem}.json" + with open(output_json_path, 'w', encoding='utf-8') as f: + json.dump(result, f, indent=2, ensure_ascii=False) + + # ํ†ต๊ณ„ ์—…๋ฐ์ดํŠธ + for det in result['detections']: + total_detections += 1 + class_name = det['class_name'] + if class_name in class_counts: + class_counts[class_name] += 1 + total_confidence += det['confidence'] + + # ๊ฒฐ๊ณผ ์š”์•ฝ ์ €์žฅ + avg_confidence = total_confidence / total_detections if total_detections > 0 else 0 + summary = { + "total_images": len(image_files), + "processed_images": len(image_files), + "total_detections": total_detections, + "average_detections_per_image": total_detections / len(image_files) if image_files else 0, + "class_counts": class_counts, + "average_confidence": avg_confidence, + "routing_strategy": { + "small_objects": list(SMALL_CLASSES), + "large_objects": list(LARGE_CLASSES), + "small_model_conf": self.small_conf, + "large_model_conf": self.large_conf + } + } + + summary_path = output_path / "routing_results_summary.json" + with open(summary_path, 'w', encoding='utf-8') as f: + json.dump(summary, f, indent=2, ensure_ascii=False) + + # ๊ฒฐ๊ณผ ์ถœ๋ ฅ + print("\n" + "=" * 60) + print("๐Ÿ“Š ๋ผ์šฐํŒ… ์ถ”๋ก  ๊ฒฐ๊ณผ ์š”์•ฝ:") + print(f" - ์ฒ˜๋ฆฌ๋œ ์ด๋ฏธ์ง€: {summary['processed_images']}/{summary['total_images']}") + print(f" - ์ด ๊ฒ€์ถœ ์ˆ˜: {summary['total_detections']}") + print(f" - ์ด๋ฏธ์ง€๋‹น ํ‰๊ท  ๊ฒ€์ถœ ์ˆ˜: {summary['average_detections_per_image']:.1f}") + print(f" - ํ‰๊ท  ์‹ ๋ขฐ๋„: {summary['average_confidence']:.3f}") + print("\n๐Ÿ“ˆ ํด๋ž˜์Šค๋ณ„ ๊ฒ€์ถœ ์ˆ˜:") + for class_name, count in summary['class_counts'].items(): + print(f" - {class_name}: {count}") + + print(f"\nโœ… ๊ฒฐ๊ณผ ์ €์žฅ ์™„๋ฃŒ: {output_path}") + print(f" - ์‹œ๊ฐํ™” ์ด๋ฏธ์ง€: {output_path}/images/") + print(f" - ๊ฒ€์ถœ ๋ฐ์ดํ„ฐ: {output_path}/annotations/") + print(f" - ๊ฒฐ๊ณผ ์š”์•ฝ: {output_path}/routing_results_summary.json") + + return all_results + + +def main(): + # ๊ฒฝ๋กœ ์„ค์ • + current_dir = Path(__file__).parent + test_data_root = current_dir.parent.parent / "recognition" / "exp_images" + output_dir = current_dir / "routed_inference_results" + + print("๐Ÿš€ ๋ผ์šฐํŒ… ์ถ”๋ก  ์‹œ์ž‘") + print(f"๐Ÿ“ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ: {test_data_root}") + print(f"๐Ÿ“ ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ: {output_dir}") + print("=" * 60) + + try: + # ๋ผ์šฐํŒ… ์ถ”๋ก  ์‹คํ–‰ + router = RoutedInference(str(current_dir)) + results = router.process_test_images(str(test_data_root), str(output_dir)) + + print("โœ… ๋ผ์šฐํŒ… ์ถ”๋ก  ์™„๋ฃŒ!") + + except Exception as e: + print(f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}") + import traceback + traceback.print_exc() + return 1 + + return 0 + + +if __name__ == "__main__": + exit(main()) \ No newline at end of file diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/README.md b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/README.md new file mode 100644 index 0000000..d2e3817 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/README.md @@ -0,0 +1,21 @@ +# YOLOv8n @ 1280 - ํฐ ๊ฐ์ฒด ์ „์šฉ + +## ๋ชฉ์  +ํฐ ๊ฐ์ฒด๋“ค์„ ์œ„ํ•œ ์ „์šฉ ๋ชจ๋ธ (answer_option, english_content, korean_content, section) + +## ์„ค์ • +- **๋ชจ๋ธ**: YOLOv8n +- **์ด๋ฏธ์ง€ ํฌ๊ธฐ**: 1280x1280 +- **GPU**: [0,1] +- **๋ฐฐ์น˜ ํฌ๊ธฐ**: 8 +- **์ฆ๊ฐ•**: ์—†์Œ (๋ชจ๋“  ์ฆ๊ฐ• ๋น„ํ™œ์„ฑํ™”) + +## ๋ฐ์ดํ„ฐ์…‹ +- **๊ฒฝ๋กœ**: `/home/jdh251425/2509 Gradi-Detection/Data/english_large4_251004/` +- **ํด๋ž˜์Šค**: 4๊ฐœ (answer_option, english_content, korean_content, section) +- **์ด ์ด๋ฏธ์ง€**: 476๊ฐœ (333 train, 95 valid, 48 test) + +## ์‹คํ–‰ +```bash +bash START_TRAINING_UV.sh +``` diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/START_TRAINING_UV.sh b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/START_TRAINING_UV.sh new file mode 100644 index 0000000..b183c62 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/START_TRAINING_UV.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "๐Ÿš€ Routing Experiment 1004 - YOLOv8n @ 1280 ์‹œ์ž‘" +echo "๐ŸŽฏ ๋Œ€์ƒ: ํฐ ๊ฐ์ฒด (answer_option, english_content, korean_content, section)" +echo "๐Ÿ–ฅ๏ธ GPU: [0,1]" +echo "๐Ÿ”„ ์ฆ๊ฐ•: ์—†์Œ" +echo "๐Ÿ“Š ๋ฐ์ดํ„ฐ: english_large4_251004" +echo "=" * 60 + +# UV ํ™˜๊ฒฝ ํ™œ์„ฑํ™” +source /home/jdh251425/2509\ Gradi-Detection/gradi-detection/bin/activate + +# ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ +cd "/home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280" + +# GPU ๋ฉ”๋ชจ๋ฆฌ ํ™•์ธ +echo "๐Ÿ“Š GPU ์ƒํƒœ ํ™•์ธ:" +nvidia-smi + +echo "๐Ÿ”ฅ ํ•™์Šต ์‹œ์ž‘..." +python run_optimized_training.py + +echo "โœ… ํ•™์Šต ์™„๋ฃŒ!" diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/config_optimized.yaml b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/config_optimized.yaml new file mode 100644 index 0000000..2c2f605 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/config_optimized.yaml @@ -0,0 +1,70 @@ +# Routing Experiment 1004 - YOLOv8n @ 1280 (ํฐ ๊ฐ์ฒด ์ „์šฉ) + +task: detect +mode: train +model: yolov8n.pt +data: /home/jdh251425/2509 Gradi-Detection/Data/english_large4_251004/data.yaml + +# ํ•™์Šต +epochs: 100 +patience: 25 +batch: 8 +imgsz: 1280 +device: [0,1] # GPU 0,1 ์‚ฌ์šฉ +workers: 8 + +# ํ”„๋กœ์ ํŠธ +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280 +name: train +exist_ok: true + +# ์˜ตํ‹ฐ๋งˆ์ด์ € +optimizer: AdamW +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 + +# Loss +box: 7.5 +cls: 1.5 +dfl: 1.5 + +# ์Šค์บ” ์ด๋ฏธ์ง€ ์นœํ™” +rect: true +multi_scale: false + +# ์ฆ๊ฐ• ์—†์Œ (๋ชจ๋“  ์ฆ๊ฐ• ๋น„ํ™œ์„ฑํ™”) +degrees: 0 +perspective: 0.0 +translate: 0.0 +scale: 0.0 +shear: 0.0 +flipud: 0.0 +fliplr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +auto_augment: null +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +erasing: 0.0 + +# ๊ฒ€์ฆ/์ถ”๋ก  +iou: 0.7 +conf: 0.12 +max_det: 300 +val: true +amp: true +plots: true +verbose: true +seed: 0 +deterministic: true +single_cls: false +cos_lr: false +cache: false diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/run_optimized_training.py b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/run_optimized_training.py new file mode 100644 index 0000000..c0ad6c3 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/run_optimized_training.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +""" +Routing Experiment 1004 - YOLOv8n @ 1280 (ํฐ ๊ฐ์ฒด ์ „์šฉ) +GPU 0,1 ์‚ฌ์šฉ, ์ฆ๊ฐ• ์—†์Œ +""" + +import os +import sys +from pathlib import Path + +def main(): + # ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ ์„ค์ • + current_dir = Path(__file__).parent + os.chdir(current_dir) + + # ์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ + config_path = current_dir / "config_optimized.yaml" + + if not config_path.exists(): + print(f"โŒ ์„ค์ • ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {config_path}") + sys.exit(1) + + print("๐Ÿš€ Routing Experiment 1004 - YOLOv8n @ 1280 ์‹œ์ž‘") + print(f"๐Ÿ“ ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ: {current_dir}") + print(f"โš™๏ธ ์„ค์ • ํŒŒ์ผ: {config_path}") + print("๐ŸŽฏ ๋Œ€์ƒ: ํฐ ๊ฐ์ฒด (answer_option, english_content, korean_content, section)") + print("๐Ÿ–ฅ๏ธ GPU: [0,1]") + print("๐Ÿ”„ ์ฆ๊ฐ•: ์—†์Œ") + print("=" * 60) + + # YOLO ํ•™์Šต ์‹คํ–‰ + from ultralytics import YOLO + + model = YOLO('yolov8n.pt') + results = model.train( + cfg=str(config_path), + data=str(config_path.parent.parent.parent / "Data" / "english_large4_251004" / "data.yaml") + ) + + print("โœ… ํ•™์Šต ์™„๋ฃŒ!") + return results + +if __name__ == "__main__": + main() diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/args.yaml b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/args.yaml new file mode 100644 index 0000000..c4284e7 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: /home/jdh251425/2509 Gradi-Detection/Data/english_large4_251004/data.yaml +epochs: 100 +time: null +patience: 25 +batch: 8 +imgsz: 1280 +save: true +save_period: -1 +cache: false +device: 0,1 +workers: 8 +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280 +name: train +exist_ok: true +pretrained: true +optimizer: AdamW +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +compile: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +conf: 0.12 +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: true +opset: null +workspace: null +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 1.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +nbs: 64 +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +degrees: 0 +translate: 0.0 +scale: 0.0 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.0 +bgr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +copy_paste_mode: flip +auto_augment: null +erasing: 0.0 +cfg: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280/config_optimized.yaml +tracker: botsort.yaml +save_dir: /home/jdh251425/2509 Gradi-Detection/experiment_routing_1004/yolov8n_imgsz_1280/train diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/results.csv b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/results.csv new file mode 100644 index 0000000..6c81561 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/results.csv @@ -0,0 +1,80 @@ +epoch,time,train/box_loss,train/cls_loss,train/dfl_loss,metrics/precision(B),metrics/recall(B),metrics/mAP50(B),metrics/mAP50-95(B),val/box_loss,val/cls_loss,val/dfl_loss,lr/pg0,lr/pg1,lr/pg2 +1,15.7641,1.95165,9.0524,2.26858,0.01926,0.28354,0.01583,0.00279,3.42604,338.509,16.6775,0.0631,0.0041,0.0041 +2,25.6949,1.48773,4.66582,1.95396,0.00232,0.10532,0.00123,0.00036,3.68832,inf,40.4564,0.0252178,0.00821783,0.00821783 +3,35.4795,1.44495,3.86399,1.8541,0.00018,0.0266,0.0001,3e-05,3.62613,inf,9.54428,0.009802,0.009802,0.009802 +4,45.2807,1.32481,3.5132,1.7643,1e-05,0.00133,0,0,3.68236,429.754,5.03996,0.009703,0.009703,0.009703 +5,54.8734,1.22741,2.96123,1.6577,0.00839,0.04508,0.0022,0.00053,4.33331,78.9387,9.18064,0.009604,0.009604,0.009604 +6,64.5252,1.14465,2.68712,1.5962,0.2591,0.25465,0.20646,0.08515,3.22109,13.88,6.36841,0.009505,0.009505,0.009505 +7,74.2218,1.11353,2.52339,1.55541,0.00768,0.02958,0.00405,0.00088,4.04607,29.238,8.10263,0.009406,0.009406,0.009406 +8,83.9297,1.06002,2.36351,1.47681,0.28825,0.14266,0.15472,0.04611,2.74646,12.0797,3.77771,0.009307,0.009307,0.009307 +9,93.649,1.00933,2.18672,1.43358,0.7999,0.75693,0.82504,0.56111,1.18812,3.36741,1.58085,0.009208,0.009208,0.009208 +10,103.385,1.0003,2.08258,1.4022,0.67293,0.79329,0.79793,0.53526,1.24032,3.51808,1.68971,0.009109,0.009109,0.009109 +11,113.141,0.92976,1.99864,1.34533,0.89493,0.90304,0.93389,0.66444,1.09503,2.38621,1.44603,0.00901,0.00901,0.00901 +12,122.837,0.90354,1.81467,1.3395,0.87334,0.95352,0.96066,0.70726,1.02639,2.10754,1.40762,0.008911,0.008911,0.008911 +13,132.638,0.91078,1.82076,1.32164,0.44862,0.19693,0.27996,0.08607,2.77598,13.331,3.68255,0.008812,0.008812,0.008812 +14,142.475,0.8613,1.76749,1.29813,0.49086,0.58757,0.59581,0.30799,2.0747,5.81972,3.25064,0.008713,0.008713,0.008713 +15,152.242,0.86073,1.75312,1.26539,0.9238,0.94451,0.96653,0.74862,0.93899,1.89009,1.28867,0.008614,0.008614,0.008614 +16,162.125,0.80358,1.59723,1.20263,0.92451,0.97547,0.97739,0.76307,0.87462,1.7369,1.25039,0.008515,0.008515,0.008515 +17,172.052,0.78719,1.57787,1.22138,0.86052,0.91707,0.94203,0.7029,1.04448,2.14735,1.42395,0.008416,0.008416,0.008416 +18,181.899,0.78855,1.51744,1.1873,0.87156,0.90883,0.94673,0.72874,0.95124,2.062,1.35794,0.008317,0.008317,0.008317 +19,191.7,0.76299,1.4862,1.17135,0.94903,0.92981,0.96034,0.7436,0.90504,1.83814,1.27014,0.008218,0.008218,0.008218 +20,201.404,0.75353,1.47135,1.17301,0.92322,0.95708,0.97172,0.75718,0.90472,1.7063,1.29137,0.008119,0.008119,0.008119 +21,211.118,0.73721,1.42299,1.15443,0.76074,0.63305,0.73355,0.45956,1.50679,5.60623,1.95026,0.00802,0.00802,0.00802 +22,220.873,0.71982,1.38186,1.13022,0.40181,0.19756,0.16137,0.05982,3.09707,11.6649,6.07238,0.007921,0.007921,0.007921 +23,230.546,0.71098,1.36205,1.11113,0.87359,0.91621,0.93907,0.71683,0.97016,2.26083,1.40269,0.007822,0.007822,0.007822 +24,240.257,0.70029,1.33468,1.10078,0.89024,0.85405,0.90598,0.67121,1.01789,2.63405,1.44926,0.007723,0.007723,0.007723 +25,249.947,0.6718,1.31203,1.09626,0.11321,0.23233,0.13679,0.04957,3.2123,12.1834,7.5067,0.007624,0.007624,0.007624 +26,259.678,0.66923,1.30123,1.08444,0.61793,0.54906,0.6187,0.36843,1.86402,5.98971,2.71371,0.007525,0.007525,0.007525 +27,269.237,0.67458,1.27035,1.08118,0.51399,0.02164,0.26687,0.14118,3.18965,19.8266,4.0179,0.007426,0.007426,0.007426 +28,278.911,0.65669,1.25545,1.06396,0.92389,0.93797,0.96225,0.74474,0.918,1.73129,1.33263,0.007327,0.007327,0.007327 +29,288.484,0.63879,1.23113,1.05859,0.51043,0.66615,0.6482,0.42878,1.54141,4.8672,2.4262,0.007228,0.007228,0.007228 +30,297.949,0.63796,1.22327,1.05558,0,0,0,0,4.03115,21.7273,5.38702,0.007129,0.007129,0.007129 +31,307.433,0.59455,1.17447,1.03836,0,0,0,0,4.04404,23.381,4.94939,0.00703,0.00703,0.00703 +32,317.06,0.60603,1.20392,1.01841,0.8863,0.91237,0.93815,0.70317,1.00156,2.03874,1.4632,0.006931,0.006931,0.006931 +33,326.827,0.62787,1.20583,1.03024,0.89678,0.9372,0.95168,0.74263,0.90045,1.72388,1.29979,0.006832,0.006832,0.006832 +34,336.549,0.59398,1.15952,1.01587,0.75514,0.80625,0.81689,0.51944,1.34474,2.95464,1.77881,0.006733,0.006733,0.006733 +35,346.183,0.59963,1.1547,1.01737,0.92878,0.96576,0.97038,0.78109,0.82491,1.53421,1.19163,0.006634,0.006634,0.006634 +36,355.641,0.59099,1.1431,1.01051,0.73766,0.24339,0.4895,0.27577,2.16908,11.5203,2.69805,0.006535,0.006535,0.006535 +37,365.21,0.58363,1.13201,1.00442,0.94702,0.96023,0.97699,0.77978,0.84427,1.52573,1.21495,0.006436,0.006436,0.006436 +38,374.922,0.56115,1.07623,0.98266,0.93045,0.96674,0.96926,0.78319,0.81184,1.49264,1.19236,0.006337,0.006337,0.006337 +39,384.768,0.54454,1.08724,0.97331,0.17319,0.12065,0.11965,0.05305,3.38054,15.607,5.81235,0.006238,0.006238,0.006238 +40,394.351,0.54558,1.0689,0.96955,0.25472,0.12828,0.17029,0.08223,3.31489,14.5401,5.27477,0.006139,0.006139,0.006139 +41,404.181,0.53146,1.07295,0.96254,0.72954,0.83868,0.82623,0.58211,1.13398,3.15557,1.62428,0.00604,0.00604,0.00604 +42,414.055,0.51973,1.02812,0.95864,0.53585,0.48426,0.50361,0.26469,1.99455,7.86568,3.90154,0.005941,0.005941,0.005941 +43,424.054,0.54016,1.04761,0.95225,0.90929,0.95073,0.95243,0.76139,0.8476,1.55854,1.2279,0.005842,0.005842,0.005842 +44,433.667,0.51384,1.02007,0.94526,0.9471,0.95467,0.97266,0.77669,0.82436,1.53241,1.20812,0.005743,0.005743,0.005743 +45,443.668,0.49792,1.00846,0.93029,0.94349,0.96525,0.97104,0.7859,0.81535,1.46345,1.19977,0.005644,0.005644,0.005644 +46,453.498,0.48938,0.98291,0.93698,0.94852,0.95967,0.9681,0.77727,0.81917,1.47466,1.21732,0.005545,0.005545,0.005545 +47,463.395,0.48342,0.9833,0.91653,0.93352,0.97067,0.97089,0.77743,0.83739,1.54,1.26506,0.005446,0.005446,0.005446 +48,473.257,0.46823,0.96456,0.91638,0.90857,0.94386,0.95122,0.75992,0.84624,1.63687,1.2691,0.005347,0.005347,0.005347 +49,482.972,0.47307,0.96215,0.91079,0.08439,0.06432,0.05514,0.01813,3.60023,19.8078,6.17244,0.005248,0.005248,0.005248 +50,492.823,0.45681,0.94262,0.91095,0.94271,0.97138,0.9725,0.77782,0.825,1.48302,1.22073,0.005149,0.005149,0.005149 +51,502.697,0.45316,0.93877,0.90811,0.96026,0.95239,0.9686,0.76256,0.86637,1.51751,1.26556,0.00505,0.00505,0.00505 +52,512.541,0.45199,0.94126,0.89854,0.94602,0.97093,0.97717,0.78421,0.82279,1.47367,1.22901,0.004951,0.004951,0.004951 +53,522.342,0.42977,0.904,0.89389,0.94083,0.95944,0.97706,0.77817,0.82311,1.48065,1.26742,0.004852,0.004852,0.004852 +54,532.23,0.43049,0.9085,0.88732,0.96136,0.97002,0.9766,0.79184,0.81248,1.41689,1.22239,0.004753,0.004753,0.004753 +55,542.052,0.42174,0.88915,0.88289,0.48023,0.44337,0.42071,0.23004,2.11434,10.0685,4.4139,0.004654,0.004654,0.004654 +56,551.848,0.42716,0.88306,0.88508,0.95155,0.9723,0.97529,0.7866,0.80069,1.42691,1.21373,0.004555,0.004555,0.004555 +57,561.98,0.40636,0.8791,0.88397,0.80965,0.82867,0.87401,0.62908,1.05214,3.0016,1.65175,0.004456,0.004456,0.004456 +58,571.958,0.40044,0.85885,0.87194,0.91586,0.94118,0.96471,0.75076,0.86819,1.66858,1.34325,0.004357,0.004357,0.004357 +59,581.687,0.38478,0.83225,0.86416,0.95284,0.97243,0.97109,0.78333,0.80833,1.42069,1.21988,0.004258,0.004258,0.004258 +60,591.662,0.40116,0.85258,0.86991,0.92504,0.95698,0.95601,0.7508,0.85828,1.61146,1.28263,0.004159,0.004159,0.004159 +61,601.641,0.38492,0.83834,0.86876,0.94356,0.96285,0.96947,0.77601,0.81627,1.47128,1.24057,0.00406,0.00406,0.00406 +62,611.587,0.38327,0.82459,0.86395,0.84891,0.93046,0.93832,0.70665,0.92966,1.94707,1.44155,0.003961,0.003961,0.003961 +63,621.575,0.36841,0.80949,0.85703,0.9269,0.97076,0.97086,0.77446,0.82889,1.47733,1.26107,0.003862,0.003862,0.003862 +64,631.542,0.35844,0.79269,0.8501,0.96116,0.96698,0.97546,0.78251,0.8023,1.42707,1.22686,0.003763,0.003763,0.003763 +65,641.602,0.3571,0.78529,0.84677,0.75879,0.73521,0.78031,0.53382,1.20871,3.8655,1.81436,0.003664,0.003664,0.003664 +66,651.625,0.34448,0.78281,0.83898,0.95669,0.97302,0.97658,0.78376,0.81709,1.44339,1.22903,0.003565,0.003565,0.003565 +67,661.583,0.3464,0.77218,0.83703,0.95382,0.97399,0.97248,0.78382,0.81436,1.43796,1.24598,0.003466,0.003466,0.003466 +68,671.733,0.32543,0.73843,0.83208,0.87207,0.92001,0.94383,0.71414,0.91457,1.88286,1.41618,0.003367,0.003367,0.003367 +69,681.745,0.33578,0.74758,0.83409,0.95003,0.9753,0.9688,0.77164,0.81317,1.47766,1.26534,0.003268,0.003268,0.003268 +70,691.783,0.32499,0.73884,0.83193,0.93722,0.95752,0.97204,0.76449,0.84174,1.53926,1.30505,0.003169,0.003169,0.003169 +71,701.738,0.31047,0.71038,0.82437,0.95564,0.96308,0.97325,0.78072,0.81295,1.46247,1.24459,0.00307,0.00307,0.00307 +72,711.742,0.30514,0.71158,0.82087,0.95442,0.96872,0.96979,0.78013,0.80471,1.45039,1.23816,0.002971,0.002971,0.002971 +73,721.752,0.30198,0.70259,0.82107,0.96694,0.96908,0.9758,0.78644,0.80529,1.43877,1.24732,0.002872,0.002872,0.002872 +74,731.724,0.28524,0.67381,0.81213,0.94749,0.96523,0.97387,0.78373,0.80366,1.46203,1.25418,0.002773,0.002773,0.002773 +75,741.757,0.28916,0.68112,0.8156,0.94065,0.9484,0.96939,0.76742,0.82716,1.50244,1.30441,0.002674,0.002674,0.002674 +76,751.744,0.27852,0.66671,0.8048,0.95829,0.96989,0.97479,0.78408,0.7967,1.44276,1.24761,0.002575,0.002575,0.002575 +77,761.659,0.27273,0.65724,0.80327,0.94882,0.97493,0.97327,0.783,0.80581,1.44648,1.25086,0.002476,0.002476,0.002476 +78,771.765,0.28166,0.66726,0.80666,0.95342,0.96883,0.96989,0.78176,0.80402,1.47001,1.25144,0.002377,0.002377,0.002377 +79,781.738,0.2628,0.64764,0.80769,0.94795,0.96226,0.97405,0.78139,0.80075,1.47605,1.24299,0.002278,0.002278,0.002278 diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/weights/best.pt b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/weights/best.pt new file mode 100644 index 0000000..d5cc2f9 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/weights/best.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/weights/last.pt b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/weights/last.pt new file mode 100644 index 0000000..311603a Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/train/weights/last.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/yolo11n.pt b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/yolo11n.pt new file mode 100644 index 0000000..45b273b Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/yolo11n.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/yolov8n.pt b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/yolov8n.pt new file mode 100644 index 0000000..0db4ca4 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8n_imgsz_1280/yolov8n.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/args.yaml b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/args.yaml new file mode 100644 index 0000000..29375d1 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8s.pt +data: /home/jdh251425/2509 Gradi-Detection/Data/english_small9_251104/data.yaml +epochs: 100 +time: null +patience: 25 +batch: 4 +imgsz: 2048 +save: true +save_period: -1 +cache: false +device: 0,1,2,3 +workers: 8 +project: /home/jdh251425/2509 Gradi-Detection/Exp/experiment_routing_251104/yolov8s_imgsz_2048 +name: train +exist_ok: true +pretrained: true +optimizer: AdamW +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +compile: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +conf: 0.22 +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: true +opset: null +workspace: null +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 1.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +nbs: 64 +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +degrees: 0 +translate: 0.02 +scale: 0.05 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.0 +bgr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +copy_paste_mode: flip +auto_augment: null +erasing: 0.0 +cfg: /home/jdh251425/2509 Gradi-Detection/Exp/experiment_routing_251104/yolov8s_imgsz_2048/config_optimized.yaml +tracker: botsort.yaml +save_dir: /home/jdh251425/2509 Gradi-Detection/Exp/experiment_routing_251104/yolov8s_imgsz_2048/train diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/results.csv b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/results.csv new file mode 100644 index 0000000..e5174e6 --- /dev/null +++ b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/results.csv @@ -0,0 +1,84 @@ +epoch,time,train/box_loss,train/cls_loss,train/dfl_loss,metrics/precision(B),metrics/recall(B),metrics/mAP50(B),metrics/mAP50-95(B),val/box_loss,val/cls_loss,val/dfl_loss,lr/pg0,lr/pg1,lr/pg2 +1,41.3539,2.02126,14.8851,1.47753,0,0,0,0,nan,nan,nan,0.0554839,0.00494624,0.00494624 +2,74.7133,1.92033,7.33912,1.41452,0.24183,0.01587,0.01029,0.00531,3.01192,51.0464,4.62826,0.0103854,0.00984777,0.00984777 +3,108.017,1.75322,6.41449,1.33081,0.11111,0.00067,0.05589,0.02236,2.19536,18.3477,1.64705,0.009802,0.009802,0.009802 +4,141.575,1.67801,5.29759,1.27145,0.48871,0.34401,0.38852,0.19846,1.67234,5.5937,1.30003,0.009703,0.009703,0.009703 +5,175.046,1.6621,5.18936,1.28449,0.09259,0.00149,0.0469,0.01559,1.97456,14.454,1.46337,0.009604,0.009604,0.009604 +6,208.406,1.63513,4.86576,1.24442,0.4454,0.76569,0.62329,0.31487,1.53095,5.6395,1.2153,0.009505,0.009505,0.009505 +7,241.932,1.52757,3.98478,1.18559,0.59769,0.72611,0.64523,0.34149,1.54717,3.91717,1.21208,0.009406,0.009406,0.009406 +8,275.445,1.58956,3.93416,1.20925,0.11111,0.00074,0.05592,0.03355,2.69436,17.5292,1.88876,0.009307,0.009307,0.009307 +9,309.068,1.49263,3.59782,1.16984,0.63245,0.70489,0.6483,0.35837,1.49082,4.48913,1.18755,0.009208,0.009208,0.009208 +10,342.74,1.49455,3.36041,1.17798,0.70956,0.75957,0.72008,0.40063,1.52163,3.71715,1.20668,0.009109,0.009109,0.009109 +11,376.469,1.4671,3.1599,1.17072,0.7294,0.78713,0.80896,0.44577,1.48196,3.5349,1.2052,0.00901,0.00901,0.00901 +12,410.309,1.48247,3.00159,1.17055,0.85402,0.90173,0.93644,0.51185,1.4184,2.83523,1.16177,0.008911,0.008911,0.008911 +13,444.011,1.51261,2.95596,1.17479,0.75602,0.87673,0.8888,0.48889,1.42536,3.11672,1.16613,0.008812,0.008812,0.008812 +14,477.547,1.45655,2.82401,1.1712,0.89846,0.86859,0.93348,0.53405,1.4021,2.77477,1.16043,0.008713,0.008713,0.008713 +15,511.328,1.4777,2.83033,1.16259,0.90901,0.90183,0.95571,0.52119,1.50968,2.74593,1.19223,0.008614,0.008614,0.008614 +16,544.855,1.45235,2.6776,1.16528,0.91937,0.91895,0.95398,0.53824,1.43077,2.61145,1.16075,0.008515,0.008515,0.008515 +17,578.59,1.43528,2.66297,1.1556,0.92952,0.92703,0.96376,0.55716,1.41621,2.5509,1.16115,0.008416,0.008416,0.008416 +18,612.352,1.42502,2.51592,1.15247,0.90267,0.91998,0.96037,0.5534,1.43182,2.49769,1.15248,0.008317,0.008317,0.008317 +19,645.866,1.4296,2.58555,1.14769,0.89901,0.90026,0.9478,0.53574,1.44026,2.57337,1.16968,0.008218,0.008218,0.008218 +20,679.515,1.44062,2.509,1.1458,0.90352,0.93579,0.96086,0.55317,1.44062,2.46131,1.15718,0.008119,0.008119,0.008119 +21,713.051,1.46199,2.54182,1.15597,0.92143,0.91914,0.96274,0.54697,1.43843,2.47058,1.16044,0.00802,0.00802,0.00802 +22,746.854,1.40549,2.38185,1.13177,0.96057,0.94053,0.97191,0.56396,1.42497,2.32154,1.1504,0.007921,0.007921,0.007921 +23,780.72,1.41702,2.44671,1.15213,0.94606,0.95793,0.97616,0.55723,1.41403,2.3503,1.15435,0.007822,0.007822,0.007822 +24,814.24,1.41289,2.33712,1.14357,0.84669,0.83655,0.86364,0.49057,1.48887,2.80993,1.18258,0.007723,0.007723,0.007723 +25,847.738,1.42644,2.2862,1.13598,0.96307,0.95463,0.97883,0.55733,1.41382,2.29062,1.14472,0.007624,0.007624,0.007624 +26,881.164,1.42638,2.32385,1.12761,0.82466,0.77732,0.82197,0.46183,1.56554,3.12601,1.22717,0.007525,0.007525,0.007525 +27,915.008,1.40811,2.22405,1.12388,0.92906,0.9471,0.97531,0.56032,1.42946,2.31602,1.15145,0.007426,0.007426,0.007426 +28,948.762,1.39554,2.25851,1.12901,0.95598,0.95275,0.97742,0.57247,1.39304,2.23674,1.14188,0.007327,0.007327,0.007327 +29,982.988,1.37606,2.36267,1.11975,0.94154,0.9464,0.97775,0.55548,1.43257,2.32041,1.16028,0.007228,0.007228,0.007228 +30,1016.59,1.38465,2.25961,1.12091,0.94719,0.9485,0.97532,0.57353,1.40614,2.1929,1.15101,0.007129,0.007129,0.007129 +31,1050.29,1.37835,2.16221,1.11889,0.96047,0.95481,0.97576,0.55846,1.41985,2.17373,1.15703,0.00703,0.00703,0.00703 +32,1083.94,1.38787,2.28711,1.12418,0.87687,0.9064,0.94128,0.53395,1.44587,2.42616,1.15861,0.006931,0.006931,0.006931 +33,1117.47,1.42196,2.35197,1.13139,0.93261,0.95012,0.97153,0.5548,1.45478,2.37869,1.17413,0.006832,0.006832,0.006832 +34,1151,1.40966,2.26364,1.13648,0.80771,0.72704,0.78101,0.44469,1.54508,3.38462,1.26155,0.006733,0.006733,0.006733 +35,1184.76,1.39544,2.25037,1.14406,0.84674,0.8427,0.86633,0.50874,1.45606,2.72085,1.18218,0.006634,0.006634,0.006634 +36,1218.64,1.39893,2.14686,1.11821,0.86851,0.79052,0.85196,0.49178,1.49163,2.89677,1.19753,0.006535,0.006535,0.006535 +37,1252.23,1.3923,2.13318,1.12824,0.97006,0.95142,0.97493,0.56825,1.41304,2.10793,1.14912,0.006436,0.006436,0.006436 +38,1286.04,1.354,2.05808,1.11135,0.85539,0.84287,0.86913,0.50932,1.45587,2.54191,1.16902,0.006337,0.006337,0.006337 +39,1319.88,1.34897,2.02156,1.10757,0.96244,0.93098,0.96025,0.561,1.42237,2.07412,1.1539,0.006238,0.006238,0.006238 +40,1353.58,1.34912,1.96074,1.10791,0.92883,0.89642,0.93102,0.52162,1.5125,2.32323,1.19251,0.006139,0.006139,0.006139 +41,1387.51,1.34606,1.92696,1.0993,0.96197,0.93519,0.96612,0.55488,1.45487,2.05975,1.16778,0.00604,0.00604,0.00604 +42,1421.13,1.38818,2.04365,1.11813,0.95858,0.94076,0.96505,0.55678,1.44317,2.09552,1.16186,0.005941,0.005941,0.005941 +43,1454.69,1.36925,1.9981,1.11216,0.65257,0.14499,0.40402,0.1975,2.25699,10.1103,1.68488,0.005842,0.005842,0.005842 +44,1488.43,1.30399,1.91864,1.07973,0.96816,0.94135,0.96654,0.56891,1.45625,1.98187,1.165,0.005743,0.005743,0.005743 +45,1522.13,1.30937,1.9257,1.09671,0.96664,0.95986,0.97703,0.56698,1.44941,1.97958,1.16687,0.005644,0.005644,0.005644 +46,1555.57,1.33169,1.89636,1.09723,0.22222,0.00198,0.1121,0.06445,2.72984,12.6366,2.87831,0.005545,0.005545,0.005545 +47,1589.28,1.36529,1.97517,1.12266,0.95756,0.96084,0.97789,0.56676,1.47036,1.98304,1.16716,0.005446,0.005446,0.005446 +48,1623.06,1.29237,1.8831,1.08221,0.9596,0.94447,0.96277,0.55692,1.4778,2.05019,1.19223,0.005347,0.005347,0.005347 +49,1656.96,1.32477,1.82717,1.09675,0.94539,0.92343,0.96633,0.55851,1.49848,2.04313,1.17711,0.005248,0.005248,0.005248 +50,1690.87,1.31365,1.87151,1.09075,0.96618,0.96269,0.97854,0.57119,1.4769,1.91992,1.17083,0.005149,0.005149,0.005149 +51,1724.61,1.30735,1.85786,1.09406,0.95461,0.94761,0.96987,0.5628,1.48756,1.93513,1.18045,0.00505,0.00505,0.00505 +52,1758.32,1.3364,1.8256,1.10911,0.8381,0.71683,0.7962,0.45362,1.6246,2.89954,1.28692,0.004951,0.004951,0.004951 +53,1791.89,1.32513,1.77015,1.09773,0.96104,0.96024,0.97476,0.57614,1.46687,1.80103,1.1643,0.004852,0.004852,0.004852 +54,1825.73,1.31081,1.71436,1.09529,0.96612,0.95998,0.97778,0.56792,1.4968,1.82432,1.19205,0.004753,0.004753,0.004753 +55,1859.53,1.31739,1.73926,1.08433,0.55976,0.16025,0.35623,0.17373,2.47919,9.04452,1.6685,0.004654,0.004654,0.004654 +56,1893.82,1.31823,1.71233,1.09816,0.9627,0.95865,0.97394,0.56755,1.49391,1.7985,1.17166,0.004555,0.004555,0.004555 +57,1927.5,1.30717,1.68922,1.0898,0.96847,0.95536,0.97326,0.56732,1.48896,1.80777,1.17906,0.004456,0.004456,0.004456 +58,1961.02,1.2933,1.69816,1.07896,0.97008,0.96098,0.97888,0.57652,1.4795,1.7779,1.1779,0.004357,0.004357,0.004357 +59,1995.03,1.2948,1.67135,1.08618,0.97502,0.95563,0.97535,0.57496,1.48353,1.76161,1.17749,0.004258,0.004258,0.004258 +60,2028.85,1.29792,1.68212,1.08057,0.96194,0.94469,0.96856,0.56958,1.48675,1.79968,1.17883,0.004159,0.004159,0.004159 +61,2062.7,1.26497,1.63384,1.0655,0.83015,0.70164,0.77449,0.42503,1.75421,2.51261,1.33505,0.00406,0.00406,0.00406 +62,2096.34,1.2726,1.6322,1.07845,0.92953,0.9041,0.93431,0.55408,1.50682,1.84716,1.20354,0.003961,0.003961,0.003961 +63,2129.81,1.24598,1.6332,1.05218,0.97625,0.9579,0.97811,0.57538,1.48284,1.74814,1.17854,0.003862,0.003862,0.003862 +64,2163.46,1.20233,1.60331,1.04853,0.76034,0.7077,0.70735,0.39247,1.68309,4.90131,1.31507,0.003763,0.003763,0.003763 +65,2197.05,1.24353,1.59403,1.06502,0.9741,0.95299,0.97686,0.57129,1.49038,1.73028,1.18359,0.003664,0.003664,0.003664 +66,2230.73,1.227,1.54093,1.05119,0.97266,0.96361,0.97865,0.56791,1.50951,1.73477,1.19312,0.003565,0.003565,0.003565 +67,2264.42,1.22836,1.56189,1.05315,0.96683,0.86546,0.929,0.54285,1.53522,1.98234,1.21455,0.003466,0.003466,0.003466 +68,2298.1,1.22064,1.5362,1.04869,0.97318,0.95898,0.97579,0.56414,1.50557,1.70857,1.20019,0.003367,0.003367,0.003367 +69,2331.66,1.19752,1.50254,1.0448,0.95519,0.89398,0.93476,0.55202,1.51574,1.86916,1.20268,0.003268,0.003268,0.003268 +70,2365.26,1.19562,1.51351,1.04795,0.97846,0.95872,0.97733,0.5724,1.4967,1.70299,1.18878,0.003169,0.003169,0.003169 +71,2398.91,1.19573,1.52999,1.04237,0.95198,0.80894,0.8958,0.52113,1.5437,2.28714,1.22557,0.00307,0.00307,0.00307 +72,2432.49,1.18947,1.51233,1.03623,0.96625,0.97063,0.97529,0.56756,1.49267,1.71052,1.19141,0.002971,0.002971,0.002971 +73,2466.07,1.19859,1.51846,1.05045,0.83488,0.78163,0.82847,0.48051,1.54324,2.35171,1.22511,0.002872,0.002872,0.002872 +74,2499.64,1.20744,1.50424,1.04848,0.95796,0.95886,0.96979,0.56435,1.52903,1.72983,1.21446,0.002773,0.002773,0.002773 +75,2533.24,1.16053,1.44523,1.03904,0.97678,0.9711,0.97873,0.56468,1.51358,1.65948,1.20894,0.002674,0.002674,0.002674 +76,2566.8,1.15607,1.44287,1.02976,0.96885,0.96539,0.97611,0.57033,1.51544,1.65492,1.201,0.002575,0.002575,0.002575 +77,2600.45,1.17951,1.45695,1.04424,0.62051,0.4821,0.57996,0.28942,1.94748,3.62311,1.46019,0.002476,0.002476,0.002476 +78,2634.01,1.17409,1.46442,1.03575,0.95495,0.93997,0.96331,0.55828,1.51716,1.80325,1.22077,0.002377,0.002377,0.002377 +79,2667.67,1.17149,1.44708,1.04162,0.93637,0.79857,0.8803,0.5088,1.53846,2.27174,1.22753,0.002278,0.002278,0.002278 +80,2701.24,1.15795,1.44246,1.02817,0.96902,0.97064,0.97642,0.56154,1.53121,1.66431,1.22638,0.002179,0.002179,0.002179 +81,2734.93,1.13876,1.41415,1.03577,0.97545,0.96174,0.97778,0.55917,1.54418,1.69833,1.22124,0.00208,0.00208,0.00208 +82,2768.63,1.12338,1.40846,1.01536,0.97896,0.9614,0.97606,0.56638,1.53437,1.64964,1.2233,0.001981,0.001981,0.001981 +83,2802.27,1.14035,1.40931,1.02835,0.96947,0.94523,0.96689,0.55765,1.55274,1.75002,1.21195,0.001882,0.001882,0.001882 diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/weights/best.pt b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/weights/best.pt new file mode 100644 index 0000000..032a233 Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/weights/best.pt differ diff --git a/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/weights/last.pt b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/weights/last.pt new file mode 100644 index 0000000..f2690dd Binary files /dev/null and b/ai-service/models/Detection/legacy/Model_routing_1104/yolov8s_imgsz_2048/train/weights/last.pt differ diff --git "a/ai-service/models/Detection/legacy/best_0927_\354\210\230\353\212\245\354\231\204\354\204\261\354\230\201\354\226\264.pt" "b/ai-service/models/Detection/legacy/best_0927_\354\210\230\353\212\245\354\231\204\354\204\261\354\230\201\354\226\264.pt" new file mode 100644 index 0000000..58be91e Binary files /dev/null and "b/ai-service/models/Detection/legacy/best_0927_\354\210\230\353\212\245\354\231\204\354\204\261\354\230\201\354\226\264.pt" differ diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/README.md b/ai-service/models/Detection/legacy/experiment_routing_0930/README.md new file mode 100644 index 0000000..262b3f0 --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/README.md @@ -0,0 +1,27 @@ +# experiment_routing_0930 + +## ๋ชฉ์  +- ํฐ ๊ฐ์ฒด: YOLOv8n @ 1280 +- ์ž‘์€ ๊ฐ์ฒด: YOLOv8s @ 2048 +- ๊ฒฝ๋Ÿ‰ ์ฆ๊ฐ•(translate=0.02, scale=0.05) ์ ์šฉ + +## ํ•™์Šต ์‹œ์ž‘ +```bash +# ํฐ ๊ฐ์ฒด ๋ชจ๋ธ +cd /home/jdh251425/2509\ Gradi-Detection/experiment_routing_0930/yolov8n_imgsz_1280 +bash START_TRAINING_UV.sh + +# ์ž‘์€ ๊ฐ์ฒด ๋ชจ๋ธ +cd /home/jdh251425/2509\ Gradi-Detection/experiment_routing_0930/yolov8s_imgsz_2048 +bash START_TRAINING_UV.sh +``` + +## ๋ผ์šฐํŒ… ์ถ”๋ก  +```bash +cd /home/jdh251425/2509\ Gradi-Detection/experiment_routing_0930 +uv run python run_routed_inference.py /path/to/image.jpg +``` + +## ํด๋ž˜์Šค ๋ผ์šฐํŒ… +- ์ž‘์€ ๊ฐ์ฒด: page_number, problem_number, answer_1, answer_2 โ†’ YOLOv8s@2048 (conf=0.22) +- ํฐ ๊ฐ์ฒด: korean_content, english_content, section, answer_option โ†’ YOLOv8n@1280 (conf=0.12) diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/inference_test_routing_0930/predictions/predictions.json b/ai-service/models/Detection/legacy/experiment_routing_0930/inference_test_routing_0930/predictions/predictions.json new file mode 100644 index 0000000..ae879ba --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/inference_test_routing_0930/predictions/predictions.json @@ -0,0 +1,2154 @@ +{ + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7457752823829651, + "xyxy": [ + 280.9862060546875, + 374.98193359375, + 416.6506652832031, + 470.4385986328125 + ] + }, + { + "cls": "answer_2", + "conf": 0.47267091274261475, + "xyxy": [ + 1070.621337890625, + 410.5097351074219, + 1164.2470703125, + 491.65155029296875 + ] + }, + { + "cls": "page_number", + "conf": 0.43010130524635315, + "xyxy": [ + 2036.549072265625, + 2954.678466796875, + 2133.597900390625, + 3021.529052734375 + ] + }, + { + "cls": "answer_1", + "conf": 0.3510739803314209, + "xyxy": [ + 467.0968322753906, + 1501.7603759765625, + 554.958740234375, + 1582.8729248046875 + ] + }, + { + "cls": "answer_option", + "conf": 0.9070940613746643, + "xyxy": [ + 441.7535095214844, + 1495.3504638671875, + 1535.6805419921875, + 1863.7862548828125 + ] + }, + { + "cls": "korean_content", + "conf": 0.7235857844352722, + "xyxy": [ + 448.2806091308594, + 405.7116394042969, + 1086.8580322265625, + 472.48785400390625 + ] + }, + { + "cls": "english_content", + "conf": 0.22772853076457977, + "xyxy": [ + 675.7651977539062, + 76.08967590332031, + 2081.17626953125, + 2018.79541015625 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.8253733515739441, + "xyxy": [ + 1246.6116943359375, + 400.4558410644531, + 1348.6329345703125, + 480.4715576171875 + ] + }, + { + "cls": "answer_2", + "conf": 0.6928882598876953, + "xyxy": [ + 290.9462890625, + 367.6073913574219, + 433.4360656738281, + 459.12664794921875 + ] + }, + { + "cls": "page_number", + "conf": 0.5792934894561768, + "xyxy": [ + 172.3461456298828, + 2933.5068359375, + 259.4443664550781, + 2998.505615234375 + ] + }, + { + "cls": "page_number", + "conf": 0.28378602862358093, + "xyxy": [ + 1995.4840087890625, + 2597.833251953125, + 2104.699951171875, + 2657.1943359375 + ] + }, + { + "cls": "answer_1", + "conf": 0.28250065445899963, + "xyxy": [ + 478.619873046875, + 1432.487548828125, + 564.2974243164062, + 1506.839599609375 + ] + }, + { + "cls": "page_number", + "conf": 0.2674630880355835, + "xyxy": [ + 156.43609619140625, + 2927.22900390625, + 270.0206298828125, + 3003.25341796875 + ] + }, + { + "cls": "answer_option", + "conf": 0.9075124859809875, + "xyxy": [ + 457.7655334472656, + 1371.5819091796875, + 1626.7298583984375, + 1714.05126953125 + ] + }, + { + "cls": "korean_content", + "conf": 0.6853130459785461, + "xyxy": [ + 459.57232666015625, + 394.5106201171875, + 1229.568359375, + 461.7806701660156 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3.jpg": { + "detections": [ + { + "cls": "page_number", + "conf": 0.5293256640434265, + "xyxy": [ + 1927.9879150390625, + 2855.5693359375, + 2017.024169921875, + 2914.59814453125 + ] + }, + { + "cls": "answer_2", + "conf": 0.49306103587150574, + "xyxy": [ + 247.24655151367188, + 365.672607421875, + 389.4436950683594, + 459.9100646972656 + ] + }, + { + "cls": "answer_1", + "conf": 0.4006403684616089, + "xyxy": [ + 424.3099060058594, + 1344.0294189453125, + 503.50732421875, + 1418.916748046875 + ] + }, + { + "cls": "page_number", + "conf": 0.36993157863616943, + "xyxy": [ + 405.0384826660156, + 1555.4656982421875, + 509.65411376953125, + 1617.2406005859375 + ] + }, + { + "cls": "page_number", + "conf": 0.27475160360336304, + "xyxy": [ + 1906.6649169921875, + 2853.58447265625, + 2008.7476806640625, + 2917.8896484375 + ] + }, + { + "cls": "answer_1", + "conf": 0.26883286237716675, + "xyxy": [ + 965.1317749023438, + 402.9082336425781, + 1056.1593017578125, + 479.4559020996094 + ] + }, + { + "cls": "answer_2", + "conf": 0.2631033957004547, + "xyxy": [ + 964.9306030273438, + 397.012451171875, + 1057.4647216796875, + 480.00604248046875 + ] + }, + { + "cls": "answer_option", + "conf": 0.8941190838813782, + "xyxy": [ + 408.38018798828125, + 1285.6903076171875, + 1283.70556640625, + 1621.1898193359375 + ] + }, + { + "cls": "korean_content", + "conf": 0.6986511945724487, + "xyxy": [ + 406.2796325683594, + 397.5697937011719, + 994.4220581054688, + 463.2677307128906 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7519018054008484, + "xyxy": [ + 264.95849609375, + 331.8077697753906, + 395.37982177734375, + 417.1409606933594 + ] + }, + { + "cls": "page_number", + "conf": 0.5714989304542542, + "xyxy": [ + 140.7537841796875, + 2669.72119140625, + 223.0894317626953, + 2728.2158203125 + ] + }, + { + "cls": "answer_1", + "conf": 0.4228462278842926, + "xyxy": [ + 1478.3978271484375, + 374.8919372558594, + 1562.77783203125, + 441.642333984375 + ] + }, + { + "cls": "page_number", + "conf": 0.39020848274230957, + "xyxy": [ + 424.3347473144531, + 1448.762939453125, + 496.7853698730469, + 1504.2904052734375 + ] + }, + { + "cls": "answer_1", + "conf": 0.33185213804244995, + "xyxy": [ + 423.40869140625, + 1436.731689453125, + 504.2967834472656, + 1505.422607421875 + ] + }, + { + "cls": "answer_option", + "conf": 0.9259529709815979, + "xyxy": [ + 399.675537109375, + 1187.2940673828125, + 1755.2330322265625, + 1521.5362548828125 + ] + }, + { + "cls": "korean_content", + "conf": 0.6978557109832764, + "xyxy": [ + 471.4816589355469, + 365.1439208984375, + 1516.082275390625, + 434.84674072265625 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7414188385009766, + "xyxy": [ + 223.01455688476562, + 356.9763488769531, + 352.2073974609375, + 447.6913757324219 + ] + }, + { + "cls": "page_number", + "conf": 0.5707650184631348, + "xyxy": [ + 1874.402587890625, + 2800.31103515625, + 1951.7928466796875, + 2858.1279296875 + ] + }, + { + "cls": "page_number", + "conf": 0.5017478466033936, + "xyxy": [ + 1855.3489990234375, + 2798.088623046875, + 1949.5587158203125, + 2864.531982421875 + ] + }, + { + "cls": "answer_1", + "conf": 0.38121798634529114, + "xyxy": [ + 1637.7669677734375, + 386.12451171875, + 1730.752197265625, + 458.5982971191406 + ] + }, + { + "cls": "answer_1", + "conf": 0.36998704075813293, + "xyxy": [ + 388.7870178222656, + 1509.43603515625, + 469.3056945800781, + 1581.8013916015625 + ] + }, + { + "cls": "page_number", + "conf": 0.3314400315284729, + "xyxy": [ + 1677.319580078125, + 2662.16650390625, + 1791.3284912109375, + 2718.15185546875 + ] + }, + { + "cls": "answer_option", + "conf": 0.9163646101951599, + "xyxy": [ + 366.431884765625, + 1317.1221923828125, + 1904.4517822265625, + 1660.7718505859375 + ] + }, + { + "cls": "korean_content", + "conf": 0.6395296454429626, + "xyxy": [ + 484.5362854003906, + 382.0957336425781, + 1591.5953369140625, + 461.2261657714844 + ] + }, + { + "cls": "english_content", + "conf": 0.1674789935350418, + "xyxy": [ + 514.1989135742188, + 217.85069274902344, + 1903.8931884765625, + 1582.9837646484375 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4.jpg": { + "detections": [ + { + "cls": "page_number", + "conf": 0.5776307582855225, + "xyxy": [ + 152.91835021972656, + 2605.3505859375, + 226.8046875, + 2659.089599609375 + ] + }, + { + "cls": "answer_2", + "conf": 0.5181771516799927, + "xyxy": [ + 255.28424072265625, + 329.1479797363281, + 382.9975280761719, + 410.27734375 + ] + }, + { + "cls": "answer_2", + "conf": 0.2899368107318878, + "xyxy": [ + 1068.1021728515625, + 353.9906311035156, + 1155.682861328125, + 434.2432861328125 + ] + }, + { + "cls": "answer_1", + "conf": 0.28948044776916504, + "xyxy": [ + 407.3065490722656, + 1270.19140625, + 489.8841247558594, + 1341.3743896484375 + ] + }, + { + "cls": "answer_option", + "conf": 0.917131245136261, + "xyxy": [ + 395.60699462890625, + 1114.5025634765625, + 1425.0596923828125, + 1414.88671875 + ] + }, + { + "cls": "korean_content", + "conf": 0.6959987282752991, + "xyxy": [ + 409.76141357421875, + 356.6389465332031, + 1059.68701171875, + 414.0007019042969 + ] + }, + { + "cls": "english_content", + "conf": 0.2438928335905075, + "xyxy": [ + 520.6014404296875, + 407.16156005859375, + 1788.71728515625, + 1240.7872314453125 + ] + }, + { + "cls": "answer_option", + "conf": 0.1887015402317047, + "xyxy": [ + 441.1197814941406, + 380.5945739746094, + 1821.85546875, + 1411.97607421875 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.6978219151496887, + "xyxy": [ + 191.56312561035156, + 339.1814880371094, + 314.2369079589844, + 426.0461730957031 + ] + }, + { + "cls": "page_number", + "conf": 0.5694820880889893, + "xyxy": [ + 1714.740478515625, + 2595.92919921875, + 1789.16552734375, + 2648.742919921875 + ] + }, + { + "cls": "answer_2", + "conf": 0.5576044321060181, + "xyxy": [ + 846.9984130859375, + 369.20098876953125, + 929.09228515625, + 441.3328857421875 + ] + }, + { + "cls": "answer_1", + "conf": 0.5059701800346375, + "xyxy": [ + 345.24163818359375, + 1154.436767578125, + 419.0201416015625, + 1227.352294921875 + ] + }, + { + "cls": "page_number", + "conf": 0.341762900352478, + "xyxy": [ + 1690.9417724609375, + 2591.14453125, + 1787.9537353515625, + 2655.27001953125 + ] + }, + { + "cls": "answer_option", + "conf": 0.9067538976669312, + "xyxy": [ + 326.5629577636719, + 1161.836669921875, + 1289.4278564453125, + 1470.47412109375 + ] + }, + { + "cls": "korean_content", + "conf": 0.661972165107727, + "xyxy": [ + 334.9973449707031, + 364.87652587890625, + 842.1162719726562, + 424.3623352050781 + ] + }, + { + "cls": "english_content", + "conf": 0.289799302816391, + "xyxy": [ + 450.289794921875, + 241.8941650390625, + 1738.6688232421875, + 1367.6240234375 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.5874196887016296, + "xyxy": [ + 205.4775390625, + 324.54779052734375, + 333.98150634765625, + 407.01812744140625 + ] + }, + { + "cls": "page_number", + "conf": 0.5616213083267212, + "xyxy": [ + 1715.33544921875, + 2564.44873046875, + 1783.0615234375, + 2614.68896484375 + ] + }, + { + "cls": "page_number", + "conf": 0.5108906626701355, + "xyxy": [ + 1572.202880859375, + 2182.35205078125, + 1664.9691162109375, + 2233.447021484375 + ] + }, + { + "cls": "answer_1", + "conf": 0.38229480385780334, + "xyxy": [ + 352.1468505859375, + 1133.13134765625, + 423.0880432128906, + 1205.3736572265625 + ] + }, + { + "cls": "page_number", + "conf": 0.3376193046569824, + "xyxy": [ + 1690.0888671875, + 2560.278564453125, + 1783.249267578125, + 2622.256103515625 + ] + }, + { + "cls": "answer_2", + "conf": 0.2986970841884613, + "xyxy": [ + 1185.7457275390625, + 352.0570373535156, + 1268.7427978515625, + 420.958984375 + ] + }, + { + "cls": "page_number", + "conf": 0.297036349773407, + "xyxy": [ + 340.41900634765625, + 1389.028076171875, + 452.4635925292969, + 1443.1241455078125 + ] + }, + { + "cls": "answer_1", + "conf": 0.2900526821613312, + "xyxy": [ + 1186.5826416015625, + 356.9837341308594, + 1261.118896484375, + 422.677001953125 + ] + }, + { + "cls": "answer_option", + "conf": 0.9192760586738586, + "xyxy": [ + 324.84515380859375, + 1140.7559814453125, + 1414.1820068359375, + 1457.6177978515625 + ] + }, + { + "cls": "korean_content", + "conf": 0.7452226281166077, + "xyxy": [ + 360.42254638671875, + 352.45489501953125, + 1172.6912841796875, + 414.819091796875 + ] + }, + { + "cls": "answer_option", + "conf": 0.14611662924289703, + "xyxy": [ + 440.217529296875, + 379.55401611328125, + 1760.651611328125, + 1311.8780517578125 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 84.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7190234661102295, + "xyxy": [ + 1048.5767822265625, + 251.4025115966797, + 1169.59130859375, + 332.22454833984375 + ] + }, + { + "cls": "answer_2", + "conf": 0.6859681606292725, + "xyxy": [ + 1577.53515625, + 323.16754150390625, + 1679.5460205078125, + 399.3185119628906 + ] + }, + { + "cls": "page_number", + "conf": 0.6027507185935974, + "xyxy": [ + 1815.552490234375, + 2650.1708984375, + 1887.906982421875, + 2702.7060546875 + ] + }, + { + "cls": "answer_2", + "conf": 0.5476365685462952, + "xyxy": [ + 1048.726318359375, + 1674.6273193359375, + 1162.937744140625, + 1753.4063720703125 + ] + }, + { + "cls": "answer_1", + "conf": 0.49961042404174805, + "xyxy": [ + 1219.994873046875, + 1823.758544921875, + 1300.595703125, + 1889.138671875 + ] + }, + { + "cls": "answer_1", + "conf": 0.4869273900985718, + "xyxy": [ + 1044.42578125, + 738.0822143554688, + 1126.6513671875, + 812.3458862304688 + ] + }, + { + "cls": "page_number", + "conf": 0.42302340269088745, + "xyxy": [ + 1560.4342041015625, + 1842.277099609375, + 1676.350830078125, + 1897.4219970703125 + ] + }, + { + "cls": "page_number", + "conf": 0.25746268033981323, + "xyxy": [ + 1805.2930908203125, + 2647.364501953125, + 1894.6986083984375, + 2708.7724609375 + ] + }, + { + "cls": "answer_option", + "conf": 0.9122396111488342, + "xyxy": [ + 1051.9178466796875, + 450.60400390625, + 1907.560791015625, + 974.072265625 + ] + }, + { + "cls": "korean_content", + "conf": 0.7195655107498169, + "xyxy": [ + 1046.476806640625, + 333.5016784667969, + 1547.962890625, + 394.28485107421875 + ] + }, + { + "cls": "section", + "conf": 0.3942517340183258, + "xyxy": [ + 990.9769287109375, + 1652.2509765625, + 1909.763671875, + 1949.4002685546875 + ] + }, + { + "cls": "section", + "conf": 0.30213040113449097, + "xyxy": [ + 1042.2440185546875, + 247.40977478027344, + 1995.1817626953125, + 893.5934448242188 + ] + }, + { + "cls": "section", + "conf": 0.21833065152168274, + "xyxy": [ + 78.37725830078125, + 125.15675354003906, + 1169.2784423828125, + 2094.865234375 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 85.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7723139524459839, + "xyxy": [ + 1360.6265869140625, + 1823.9713134765625, + 1469.4915771484375, + 1908.5234375 + ] + }, + { + "cls": "answer_2", + "conf": 0.6818151473999023, + "xyxy": [ + 1154.847412109375, + 2203.231201171875, + 1285.9261474609375, + 2286.176513671875 + ] + }, + { + "cls": "answer_2", + "conf": 0.6654090881347656, + "xyxy": [ + 1162.6600341796875, + 1822.057373046875, + 1288.965087890625, + 1902.2633056640625 + ] + }, + { + "cls": "page_number", + "conf": 0.623207151889801, + "xyxy": [ + 1580.8944091796875, + 272.1981201171875, + 1690.0587158203125, + 332.14111328125 + ] + }, + { + "cls": "page_number", + "conf": 0.5625292658805847, + "xyxy": [ + 164.2840576171875, + 2895.879638671875, + 262.8609924316406, + 2961.517333984375 + ] + }, + { + "cls": "answer_1", + "conf": 0.543847382068634, + "xyxy": [ + 1700.7432861328125, + 1979.9161376953125, + 1782.2705078125, + 2056.146240234375 + ] + }, + { + "cls": "page_number", + "conf": 0.5336224436759949, + "xyxy": [ + 2003.0755615234375, + 2750.2236328125, + 2105.852783203125, + 2808.896240234375 + ] + }, + { + "cls": "answer_2", + "conf": 0.5315427184104919, + "xyxy": [ + 1781.8243408203125, + 2282.0185546875, + 1883.0855712890625, + 2358.777587890625 + ] + }, + { + "cls": "answer_1", + "conf": 0.4410976469516754, + "xyxy": [ + 1163.3785400390625, + 1598.718994140625, + 1252.469482421875, + 1678.3134765625 + ] + }, + { + "cls": "page_number", + "conf": 0.4410821199417114, + "xyxy": [ + 2018.3082275390625, + 1340.8753662109375, + 2120.138916015625, + 1399.135986328125 + ] + }, + { + "cls": "answer_1", + "conf": 0.40289029479026794, + "xyxy": [ + 1161.44384765625, + 2732.629150390625, + 1245.9930419921875, + 2814.43359375 + ] + }, + { + "cls": "answer_1", + "conf": 0.3168486952781677, + "xyxy": [ + 1791.25341796875, + 2291.638671875, + 1875.4312744140625, + 2363.102294921875 + ] + }, + { + "cls": "page_number", + "conf": 0.22126391530036926, + "xyxy": [ + 570.5570678710938, + 2004.8359375, + 678.7704467773438, + 2069.756591796875 + ] + }, + { + "cls": "answer_option", + "conf": 0.9248332977294922, + "xyxy": [ + 1145.2239990234375, + 2393.0107421875, + 2140.735595703125, + 2853.071044921875 + ] + }, + { + "cls": "section", + "conf": 0.88969486951828, + "xyxy": [ + 1126.09326171875, + 2180.5166015625, + 2147.15966796875, + 2833.089599609375 + ] + }, + { + "cls": "answer_option", + "conf": 0.8778812885284424, + "xyxy": [ + 1153.95556640625, + 1494.330322265625, + 2069.58154296875, + 1695.4193115234375 + ] + }, + { + "cls": "korean_content", + "conf": 0.7078502178192139, + "xyxy": [ + 938.790283203125, + 1353.4608154296875, + 2096.745849609375, + 1451.34033203125 + ] + }, + { + "cls": "korean_content", + "conf": 0.6979081630706787, + "xyxy": [ + 1140.7547607421875, + 2288.613037109375, + 1737.6937255859375, + 2357.3896484375 + ] + }, + { + "cls": "section", + "conf": 0.6881424784660339, + "xyxy": [ + 1088.395751953125, + 1786.17333984375, + 2114.638671875, + 2095.377685546875 + ] + }, + { + "cls": "section", + "conf": 0.2505786418914795, + "xyxy": [ + 1051.426513671875, + 1251.799072265625, + 2077.887939453125, + 1710.0531005859375 + ] + }, + { + "cls": "answer_option", + "conf": 0.2318672090768814, + "xyxy": [ + 1121.5352783203125, + 1345.50146484375, + 2078.42578125, + 1696.625 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.6250153183937073, + "xyxy": [ + 269.2182312011719, + 321.7676086425781, + 401.1786193847656, + 408.7950439453125 + ] + }, + { + "cls": "answer_2", + "conf": 0.621895968914032, + "xyxy": [ + 1461.94140625, + 357.69775390625, + 1555.39208984375, + 438.9454040527344 + ] + }, + { + "cls": "page_number", + "conf": 0.5777864456176758, + "xyxy": [ + 155.31759643554688, + 2686.714111328125, + 233.3048095703125, + 2744.938720703125 + ] + }, + { + "cls": "page_number", + "conf": 0.3804883658885956, + "xyxy": [ + 437.8955078125, + 1175.2247314453125, + 543.7546997070312, + 1231.816162109375 + ] + }, + { + "cls": "page_number", + "conf": 0.32311609387397766, + "xyxy": [ + 420.5715026855469, + 1395.821044921875, + 498.90716552734375, + 1452.749267578125 + ] + }, + { + "cls": "answer_1", + "conf": 0.3183719217777252, + "xyxy": [ + 1466.87255859375, + 374.9493103027344, + 1551.360107421875, + 443.75244140625 + ] + }, + { + "cls": "page_number", + "conf": 0.26231759786605835, + "xyxy": [ + 1624.7645263671875, + 2450.83642578125, + 1727.396728515625, + 2504.906005859375 + ] + }, + { + "cls": "answer_option", + "conf": 0.9185537695884705, + "xyxy": [ + 399.677001953125, + 1280.4444580078125, + 1556.7120361328125, + 1600.7821044921875 + ] + }, + { + "cls": "korean_content", + "conf": 0.6802680492401123, + "xyxy": [ + 440.14239501953125, + 359.6470642089844, + 1494.1212158203125, + 431.7674255371094 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 79.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7718170881271362, + "xyxy": [ + 161.68609619140625, + 388.81121826171875, + 299.28173828125, + 484.2388000488281 + ] + }, + { + "cls": "answer_2", + "conf": 0.7636880874633789, + "xyxy": [ + 1188.9322509765625, + 259.6833190917969, + 1322.0418701171875, + 351.8324279785156 + ] + }, + { + "cls": "answer_2", + "conf": 0.7526907324790955, + "xyxy": [ + 612.6768188476562, + 2020.93408203125, + 725.0399780273438, + 2103.214599609375 + ] + }, + { + "cls": "answer_2", + "conf": 0.6553189754486084, + "xyxy": [ + 1684.093017578125, + 1971.0047607421875, + 1793.3463134765625, + 2060.290771484375 + ] + }, + { + "cls": "page_number", + "conf": 0.5409771203994751, + "xyxy": [ + 183.17335510253906, + 2918.8193359375, + 276.5805969238281, + 2981.85400390625 + ] + }, + { + "cls": "page_number", + "conf": 0.522003710269928, + "xyxy": [ + 1665.658203125, + 1825.526611328125, + 1785.90771484375, + 1892.14599609375 + ] + }, + { + "cls": "answer_1", + "conf": 0.5096386671066284, + "xyxy": [ + 181.2745819091797, + 2307.5, + 266.0617980957031, + 2376.615478515625 + ] + }, + { + "cls": "answer_1", + "conf": 0.4650132358074188, + "xyxy": [ + 1192.174072265625, + 2037.8062744140625, + 1276.0301513671875, + 2118.830810546875 + ] + }, + { + "cls": "answer_option", + "conf": 0.8994016051292419, + "xyxy": [ + 164.69314575195312, + 2176.41015625, + 530.9606323242188, + 2518.125732421875 + ] + }, + { + "cls": "section", + "conf": 0.8580106496810913, + "xyxy": [ + 91.0650863647461, + 366.56268310546875, + 1183.224853515625, + 2164.98828125 + ] + }, + { + "cls": "section", + "conf": 0.8430482149124146, + "xyxy": [ + 1156.9102783203125, + 279.8765869140625, + 2219.856689453125, + 1925.5799560546875 + ] + }, + { + "cls": "english_content", + "conf": 0.8029910326004028, + "xyxy": [ + 1069.19287109375, + 384.65325927734375, + 2164.520751953125, + 1930.82080078125 + ] + }, + { + "cls": "answer_option", + "conf": 0.7288334965705872, + "xyxy": [ + 1185.5572509765625, + 1973.221435546875, + 2028.555908203125, + 2351.376220703125 + ] + }, + { + "cls": "english_content", + "conf": 0.6897521018981934, + "xyxy": [ + 56.504852294921875, + 478.6210632324219, + 1125.5550537109375, + 2104.063720703125 + ] + }, + { + "cls": "korean_content", + "conf": 0.37309569120407104, + "xyxy": [ + 165.71981811523438, + 259.7998962402344, + 1085.9940185546875, + 327.97052001953125 + ] + }, + { + "cls": "answer_option", + "conf": 0.12479598075151443, + "xyxy": [ + 1177.54443359375, + 1985.002685546875, + 1660.804931640625, + 2330.430419921875 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 82.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.6634243130683899, + "xyxy": [ + 1071.528076171875, + 419.13775634765625, + 1196.0196533203125, + 504.287841796875 + ] + }, + { + "cls": "answer_2", + "conf": 0.6583342552185059, + "xyxy": [ + 1398.99658203125, + 444.8269958496094, + 1513.47314453125, + 527.996826171875 + ] + }, + { + "cls": "answer_2", + "conf": 0.6502545475959778, + "xyxy": [ + 123.3419418334961, + 243.40719604492188, + 252.13739013671875, + 327.066650390625 + ] + }, + { + "cls": "answer_1", + "conf": 0.642614483833313, + "xyxy": [ + 1776.2261962890625, + 1575.0440673828125, + 1854.040771484375, + 1641.6256103515625 + ] + }, + { + "cls": "answer_2", + "conf": 0.6187666058540344, + "xyxy": [ + 477.89239501953125, + 265.6585998535156, + 576.67578125, + 348.33856201171875 + ] + }, + { + "cls": "page_number", + "conf": 0.5672517418861389, + "xyxy": [ + 1863.825439453125, + 2743.157470703125, + 1943.20849609375, + 2797.9052734375 + ] + }, + { + "cls": "page_number", + "conf": 0.5631454586982727, + "xyxy": [ + 537.05517578125, + 1763.6021728515625, + 642.1231689453125, + 1820.1617431640625 + ] + }, + { + "cls": "answer_1", + "conf": 0.524071455001831, + "xyxy": [ + 552.6734619140625, + 1900.02001953125, + 627.791748046875, + 1973.724365234375 + ] + }, + { + "cls": "section", + "conf": 0.9373368620872498, + "xyxy": [ + 1047.4298095703125, + 396.9608154296875, + 2039.9442138671875, + 1918.11181640625 + ] + }, + { + "cls": "answer_option", + "conf": 0.8259888291358948, + "xyxy": [ + 102.97822570800781, + 1917.57861328125, + 975.224365234375, + 2107.8896484375 + ] + }, + { + "cls": "english_content", + "conf": 0.5242165327072144, + "xyxy": [ + 963.8446044921875, + 502.186279296875, + 1989.966064453125, + 1919.23388671875 + ] + }, + { + "cls": "english_content", + "conf": 0.5103406310081482, + "xyxy": [ + 0.0, + 299.66900634765625, + 1014.4801635742188, + 1899.44775390625 + ] + }, + { + "cls": "section", + "conf": 0.365836501121521, + "xyxy": [ + 89.9980239868164, + 250.2306671142578, + 1043.7740478515625, + 1921.5478515625 + ] + }, + { + "cls": "english_content", + "conf": 0.14401982724666595, + "xyxy": [ + 87.32072448730469, + 211.31866455078125, + 1293.01220703125, + 1895.352294921875 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 83.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7075649499893188, + "xyxy": [ + 1477.957275390625, + 267.5834655761719, + 1599.2999267578125, + 353.9102478027344 + ] + }, + { + "cls": "answer_2", + "conf": 0.5900384187698364, + "xyxy": [ + 565.5224609375, + 274.1451721191406, + 697.3352661132812, + 368.4912109375 + ] + }, + { + "cls": "page_number", + "conf": 0.560408890247345, + "xyxy": [ + 426.0503845214844, + 2050.9853515625, + 529.6316528320312, + 2110.54248046875 + ] + }, + { + "cls": "page_number", + "conf": 0.5516157150268555, + "xyxy": [ + 1571.04150390625, + 2565.93115234375, + 1679.736083984375, + 2629.48046875 + ] + }, + { + "cls": "page_number", + "conf": 0.5436995625495911, + "xyxy": [ + 167.8948974609375, + 2925.353515625, + 253.8811798095703, + 2988.66943359375 + ] + }, + { + "cls": "answer_1", + "conf": 0.5352441072463989, + "xyxy": [ + 836.031982421875, + 1906.3751220703125, + 920.9569702148438, + 1978.5020751953125 + ] + }, + { + "cls": "answer_2", + "conf": 0.48694244027137756, + "xyxy": [ + 153.5811004638672, + 275.3562927246094, + 289.9334716796875, + 365.6216125488281 + ] + }, + { + "cls": "answer_1", + "conf": 0.42453452944755554, + "xyxy": [ + 1168.1593017578125, + 2546.996826171875, + 1254.7584228515625, + 2626.05419921875 + ] + }, + { + "cls": "page_number", + "conf": 0.3757874369621277, + "xyxy": [ + 1622.1375732421875, + 2499.55615234375, + 1735.203857421875, + 2559.885986328125 + ] + }, + { + "cls": "problem_number", + "conf": 0.3228696882724762, + "xyxy": [ + 1173.313232421875, + 256.43585205078125, + 1303.808837890625, + 342.26971435546875 + ] + }, + { + "cls": "page_number", + "conf": 0.24859778583049774, + "xyxy": [ + 155.67904663085938, + 2921.86962890625, + 264.9152526855469, + 2993.781005859375 + ] + }, + { + "cls": "page_number", + "conf": 0.24457603693008423, + "xyxy": [ + 1605.4166259765625, + 417.5728759765625, + 1734.2103271484375, + 479.8260803222656 + ] + }, + { + "cls": "answer_option", + "conf": 0.9028952121734619, + "xyxy": [ + 1160.229248046875, + 2489.5009765625, + 1869.165771484375, + 2903.45361328125 + ] + }, + { + "cls": "korean_content", + "conf": 0.7594562768936157, + "xyxy": [ + 1171.1480712890625, + 359.02008056640625, + 2156.932861328125, + 470.3647155761719 + ] + }, + { + "cls": "english_content", + "conf": 0.5396810173988342, + "xyxy": [ + 17.82056427001953, + 335.61614990234375, + 1113.9774169921875, + 2232.26708984375 + ] + }, + { + "cls": "english_content", + "conf": 0.33890479803085327, + "xyxy": [ + 1095.2037353515625, + 390.58642578125, + 2158.637451171875, + 2375.62890625 + ] + }, + { + "cls": "section", + "conf": 0.3264928460121155, + "xyxy": [ + 48.286319732666016, + 270.5555419921875, + 1124.3265380859375, + 2236.9228515625 + ] + }, + { + "cls": "section", + "conf": 0.2512664198875427, + "xyxy": [ + 1106.5078125, + 292.10504150390625, + 2174.3681640625, + 2385.2744140625 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7623734474182129, + "xyxy": [ + 230.33587646484375, + 349.0881652832031, + 353.50921630859375, + 436.72723388671875 + ] + }, + { + "cls": "page_number", + "conf": 0.5698614120483398, + "xyxy": [ + 1824.451416015625, + 2730.73486328125, + 1903.7083740234375, + 2786.340576171875 + ] + }, + { + "cls": "page_number", + "conf": 0.5625076293945312, + "xyxy": [ + 1076.39501953125, + 2325.491943359375, + 1167.749267578125, + 2384.30078125 + ] + }, + { + "cls": "answer_1", + "conf": 0.43463000655174255, + "xyxy": [ + 387.5523986816406, + 1335.426025390625, + 467.5732421875, + 1416.306884765625 + ] + }, + { + "cls": "answer_1", + "conf": 0.4323365092277527, + "xyxy": [ + 915.4586791992188, + 383.4090576171875, + 999.9244995117188, + 451.4867248535156 + ] + }, + { + "cls": "page_number", + "conf": 0.3499426543712616, + "xyxy": [ + 369.16375732421875, + 1609.6065673828125, + 478.36614990234375, + 1669.439697265625 + ] + }, + { + "cls": "page_number", + "conf": 0.3161174952983856, + "xyxy": [ + 1813.6285400390625, + 2726.119384765625, + 1911.762451171875, + 2790.909912109375 + ] + }, + { + "cls": "page_number", + "conf": 0.2564792037010193, + "xyxy": [ + 1053.5186767578125, + 2645.682373046875, + 1158.444091796875, + 2700.21337890625 + ] + }, + { + "cls": "answer_option", + "conf": 0.8700782656669617, + "xyxy": [ + 362.78948974609375, + 1358.3458251953125, + 1649.8248291015625, + 1686.7313232421875 + ] + }, + { + "cls": "korean_content", + "conf": 0.7179117798805237, + "xyxy": [ + 379.6926574707031, + 377.1794738769531, + 996.0636596679688, + 439.89703369140625 + ] + }, + { + "cls": "english_content", + "conf": 0.4790656268596649, + "xyxy": [ + 508.2983093261719, + 166.4995880126953, + 1866.586181640625, + 1714.8709716796875 + ] + }, + { + "cls": "english_content", + "conf": 0.23219774663448334, + "xyxy": [ + 365.9074401855469, + 1343.5814208984375, + 1673.2191162109375, + 1689.45654296875 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 81.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.8414685726165771, + "xyxy": [ + 876.371826171875, + 360.51361083984375, + 974.8168334960938, + 441.2420959472656 + ] + }, + { + "cls": "answer_2", + "conf": 0.7216428518295288, + "xyxy": [ + 1159.774658203125, + 431.07269287109375, + 1291.018310546875, + 520.6409301757812 + ] + }, + { + "cls": "answer_2", + "conf": 0.5892632007598877, + "xyxy": [ + 1387.419921875, + 446.490478515625, + 1495.0404052734375, + 536.280029296875 + ] + }, + { + "cls": "page_number", + "conf": 0.5829392671585083, + "xyxy": [ + 167.88967895507812, + 2894.025390625, + 259.5096435546875, + 2958.946533203125 + ] + }, + { + "cls": "answer_1", + "conf": 0.5009829998016357, + "xyxy": [ + 923.4779663085938, + 1411.6153564453125, + 1007.9035034179688, + 1490.2689208984375 + ] + }, + { + "cls": "answer_1", + "conf": 0.4212650954723358, + "xyxy": [ + 1154.77392578125, + 2317.160888671875, + 1249.388671875, + 2403.178955078125 + ] + }, + { + "cls": "answer_2", + "conf": 0.41358837485313416, + "xyxy": [ + 149.0869598388672, + 265.71173095703125, + 284.8064270019531, + 357.3053894042969 + ] + }, + { + "cls": "page_number", + "conf": 0.23684820532798767, + "xyxy": [ + 154.09658813476562, + 2887.967041015625, + 269.2870178222656, + 2963.114990234375 + ] + }, + { + "cls": "section", + "conf": 0.870175302028656, + "xyxy": [ + 1158.1817626953125, + 413.9051208496094, + 2174.49853515625, + 2315.69091796875 + ] + }, + { + "cls": "section", + "conf": 0.8680208921432495, + "xyxy": [ + 145.94789123535156, + 328.9202575683594, + 1170.822509765625, + 1823.916748046875 + ] + }, + { + "cls": "answer_option", + "conf": 0.7925763726234436, + "xyxy": [ + 1151.218017578125, + 2338.2412109375, + 2051.418701171875, + 2549.47509765625 + ] + }, + { + "cls": "korean_content", + "conf": 0.6836703419685364, + "xyxy": [ + 139.9319610595703, + 361.67864990234375, + 828.1868286132812, + 433.6409912109375 + ] + }, + { + "cls": "english_content", + "conf": 0.6373912692070007, + "xyxy": [ + 49.94208908081055, + 429.8011474609375, + 1111.8857421875, + 1839.7982177734375 + ] + }, + { + "cls": "english_content", + "conf": 0.2139301747083664, + "xyxy": [ + 1119.5504150390625, + 450.3816223144531, + 2194.90380859375, + 2243.0869140625 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 80.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7772570848464966, + "xyxy": [ + 1365.8843994140625, + 1781.4498291015625, + 1468.978515625, + 1858.6461181640625 + ] + }, + { + "cls": "answer_2", + "conf": 0.7254477143287659, + "xyxy": [ + 834.8954467773438, + 1410.0374755859375, + 936.7784423828125, + 1489.0736083984375 + ] + }, + { + "cls": "answer_2", + "conf": 0.6497186422348022, + "xyxy": [ + 1115.3507080078125, + 268.7676086425781, + 1242.899169921875, + 357.4487609863281 + ] + }, + { + "cls": "page_number", + "conf": 0.6078432202339172, + "xyxy": [ + 1932.7928466796875, + 2827.921630859375, + 2009.1907958984375, + 2884.520263671875 + ] + }, + { + "cls": "page_number", + "conf": 0.5021216869354248, + "xyxy": [ + 670.7504272460938, + 1393.6641845703125, + 782.3683471679688, + 1451.387939453125 + ] + }, + { + "cls": "page_number", + "conf": 0.4915669560432434, + "xyxy": [ + 1858.6353759765625, + 1705.99072265625, + 1960.27783203125, + 1766.017333984375 + ] + }, + { + "cls": "answer_1", + "conf": 0.3927748203277588, + "xyxy": [ + 145.38783264160156, + 1590.6710205078125, + 226.47415161132812, + 1668.8916015625 + ] + }, + { + "cls": "answer_2", + "conf": 0.3438269793987274, + "xyxy": [ + 134.5985107421875, + 258.4563903808594, + 267.61834716796875, + 349.6998291015625 + ] + }, + { + "cls": "answer_1", + "conf": 0.33156219124794006, + "xyxy": [ + 1115.3138427734375, + 2150.128662109375, + 1192.099853515625, + 2223.255615234375 + ] + }, + { + "cls": "page_number", + "conf": 0.28202390670776367, + "xyxy": [ + 1928.9185791015625, + 2296.47119140625, + 2034.339599609375, + 2353.662353515625 + ] + }, + { + "cls": "page_number", + "conf": 0.24091322720050812, + "xyxy": [ + 1918.2713623046875, + 2058.07470703125, + 2032.490234375, + 2117.657958984375 + ] + }, + { + "cls": "page_number", + "conf": 0.2315407395362854, + "xyxy": [ + 1915.2655029296875, + 2819.38232421875, + 2016.853515625, + 2888.566162109375 + ] + }, + { + "cls": "answer_option", + "conf": 0.9003075361251831, + "xyxy": [ + 105.99090576171875, + 1498.4140625, + 1061.2091064453125, + 2089.295654296875 + ] + }, + { + "cls": "section", + "conf": 0.898718535900116, + "xyxy": [ + 1074.1064453125, + 254.46807861328125, + 2130.214111328125, + 2323.8974609375 + ] + }, + { + "cls": "answer_option", + "conf": 0.8767768144607544, + "xyxy": [ + 1076.3046875, + 1844.03466796875, + 2039.8277587890625, + 2402.78125 + ] + }, + { + "cls": "section", + "conf": 0.758375883102417, + "xyxy": [ + 81.35298156738281, + 226.32225036621094, + 1063.9698486328125, + 2013.2086181640625 + ] + }, + { + "cls": "english_content", + "conf": 0.1473204642534256, + "xyxy": [ + 1043.5628662109375, + 342.9071960449219, + 2058.70361328125, + 1869.589111328125 + ] + } + ] + }, + "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10.jpg": { + "detections": [ + { + "cls": "answer_2", + "conf": 0.7003360390663147, + "xyxy": [ + 198.504150390625, + 334.5887451171875, + 329.7089538574219, + 420.0470886230469 + ] + }, + { + "cls": "page_number", + "conf": 0.5658992528915405, + "xyxy": [ + 1761.2998046875, + 2658.76953125, + 1830.2501220703125, + 2710.26318359375 + ] + }, + { + "cls": "answer_1", + "conf": 0.48320427536964417, + "xyxy": [ + 1812.805908203125, + 365.0426330566406, + 1901.5419921875, + 439.91827392578125 + ] + }, + { + "cls": "page_number", + "conf": 0.375986784696579, + "xyxy": [ + 1745.411376953125, + 2658.66845703125, + 1823.260498046875, + 2714.404541015625 + ] + }, + { + "cls": "page_number", + "conf": 0.2952463924884796, + "xyxy": [ + 343.63531494140625, + 1232.99462890625, + 423.4169921875, + 1290.1507568359375 + ] + }, + { + "cls": "answer_option", + "conf": 0.9413660764694214, + "xyxy": [ + 328.037109375, + 1152.9267578125, + 1653.8533935546875, + 1500.9349365234375 + ] + }, + { + "cls": "korean_content", + "conf": 0.6053799390792847, + "xyxy": [ + 447.5520324707031, + 361.7781982421875, + 1500.2359619140625, + 436.7353820800781 + ] + } + ] + } +} \ No newline at end of file diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/run_routed_inference.py b/ai-service/models/Detection/legacy/experiment_routing_0930/run_routed_inference.py new file mode 100644 index 0000000..e86d59c --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/run_routed_inference.py @@ -0,0 +1,175 @@ +from __future__ import annotations +import sys +import json +import logging +from pathlib import Path +from typing import List, Dict +import cv2 +import numpy as np +from ultralytics import YOLO + +# ๋กœ๊น… ์„ค์ • +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +# ํด๋ž˜์Šค ๋ผ์šฐํŒ… ์ •์˜ +SMALL_CLASSES = {"page_number", "problem_number", "answer_1", "answer_2"} +LARGE_CLASSES = {"korean_content", "english_content", "section", "answer_option"} + +ROOT = Path(__file__).resolve().parent +S_DIR = ROOT / "yolov8s_imgsz_2048" +N_DIR = ROOT / "yolov8n_imgsz_1280" + +# ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ +OUTPUT_DIR = ROOT / "inference_test_routing_0930" +VIS_DIR = OUTPUT_DIR / "visualizations" +JSON_DIR = OUTPUT_DIR / "predictions" + +# ๊ฐ€์ค‘์น˜ ๊ฒฝ๋กœ: ์—†์œผ๋ฉด ๊ธฐ๋ณธ pt ์‚ฌ์šฉ +S_WEIGHTS = (S_DIR / "train" / "weights" / "best.pt") +N_WEIGHTS = (N_DIR / "train" / "weights" / "best.pt") + +s_model = YOLO(str(S_WEIGHTS if S_WEIGHTS.exists() else "yolov8s.pt")) +n_model = YOLO(str(N_WEIGHTS if N_WEIGHTS.exists() else "yolov8n.pt")) + +# ์ถ”๋ก  ํŒŒ๋ผ๋ฏธํ„ฐ +S_CONF = 0.22 +N_CONF = 0.12 + + +def route_infer(images: List[str]) -> Dict[str, Dict[str, list]]: + """๋ผ์šฐํŒ… ๊ธฐ๋ฐ˜ ์ถ”๋ก  ์ˆ˜ํ–‰.""" + logger.info(f"Starting inference on {len(images)} images") + s_preds = s_model.predict(source=images, imgsz=2048, conf=S_CONF, device='cpu', verbose=False) + n_preds = n_model.predict(source=images, imgsz=1280, conf=N_CONF, device='cpu', verbose=False) + + results: Dict[str, Dict[str, list]] = {} + for img_path, sp, np in zip(images, s_preds, n_preds): + merged = [] + # ์ž‘์€ ํด๋ž˜์Šค๋งŒ s์—์„œ ์ทจํ•ฉ + for b in sp.boxes: + cls_name = sp.names[int(b.cls.item())] + if cls_name in SMALL_CLASSES: + merged.append({ + "cls": cls_name, + "conf": float(b.conf.item()), + "xyxy": [float(x) for x in b.xyxy[0].tolist()], + }) + # ํฐ ํด๋ž˜์Šค๋งŒ n์—์„œ ์ทจํ•ฉ + for b in np.boxes: + cls_name = np.names[int(b.cls.item())] + if cls_name in LARGE_CLASSES: + merged.append({ + "cls": cls_name, + "conf": float(b.conf.item()), + "xyxy": [float(x) for x in b.xyxy[0].tolist()], + }) + results[img_path] = {"detections": merged} + return results + + +def visualize_results(image_path: str, detections: List[Dict], output_path: Path) -> None: + """๊ฒ€์ถœ ๊ฒฐ๊ณผ ์‹œ๊ฐํ™”.""" + img = cv2.imread(image_path) + if img is None: + logger.error(f"Failed to load image: {image_path}") + return + + # ํด๋ž˜์Šค๋ณ„ ์ƒ‰์ƒ ์ •์˜ + color_map = { + "page_number": (255, 0, 0), # ํŒŒ๋ž‘ + "problem_number": (0, 255, 0), # ์ดˆ๋ก + "answer_1": (0, 0, 255), # ๋นจ๊ฐ• + "answer_2": (255, 255, 0), # ์‹œ์•ˆ + "korean_content": (255, 0, 255), # ๋งˆ์  ํƒ€ + "english_content": (0, 255, 255),# ๋…ธ๋ž‘ + "section": (128, 0, 128), # ๋ณด๋ผ + "answer_option": (255, 165, 0), # ์ฃผํ™ฉ + } + + for det in detections: + x1, y1, x2, y2 = [int(v) for v in det["xyxy"]] + cls_name = det["cls"] + conf = det["conf"] + color = color_map.get(cls_name, (255, 255, 255)) + + # ๋ฐ•์Šค ๊ทธ๋ฆฌ๊ธฐ + cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) + + # ๋ ˆ์ด๋ธ” ๊ทธ๋ฆฌ๊ธฐ + label = f"{cls_name}: {conf:.2f}" + (text_width, text_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1) + cv2.rectangle(img, (x1, y1 - text_height - 4), (x1 + text_width, y1), color, -1) + cv2.putText(img, label, (x1, y1 - 2), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) + + cv2.imwrite(str(output_path), img) + logger.info(f"Visualization saved: {output_path}") + + +def save_predictions(results: Dict[str, Dict[str, list]], output_path: Path) -> None: + """์˜ˆ์ธก ๊ฒฐ๊ณผ๋ฅผ JSON ํŒŒ์ผ๋กœ ์ €์žฅ.""" + # ๊ฒฝ๋กœ๋ฅผ ์ƒ๋Œ€ ๊ฒฝ๋กœ๋กœ ๋ณ€ํ™˜ + simplified_results = {} + for img_path, data in results.items(): + img_name = Path(img_path).name + simplified_results[img_name] = data + + with open(output_path, 'w', encoding='utf-8') as f: + json.dump(simplified_results, f, indent=2, ensure_ascii=False) + logger.info(f"Predictions saved: {output_path}") + + +if __name__ == "__main__": + # ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ + VIS_DIR.mkdir(parents=True, exist_ok=True) + JSON_DIR.mkdir(parents=True, exist_ok=True) + + # exp_images ํด๋”์—์„œ ์ด๋ฏธ์ง€ ์ˆ˜์ง‘ (ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ ์ œ์™ธ) + exp_images_dir = ROOT.parent.parent / "recognition" / "exp_images" + logger.info(f"Searching for images in: {exp_images_dir}") + + image_extensions = {'.jpg', '.jpeg', '.png', '.bmp'} + image_paths = [] + + for file in exp_images_dir.iterdir(): + if file.is_file() and file.suffix.lower() in image_extensions: + image_paths.append(str(file)) + + if not image_paths: + logger.error("No images found in exp_images directory") + sys.exit(1) + + logger.info(f"Found {len(image_paths)} images") + + # ์ถ”๋ก  ์‹คํ–‰ + results = route_infer(image_paths) + + # ์‹œ๊ฐํ™” ์ƒ์„ฑ + logger.info("Generating visualizations...") + for img_path, data in results.items(): + img_name = Path(img_path).stem + vis_output = VIS_DIR / f"{img_name}_routed.jpg" + visualize_results(img_path, data["detections"], vis_output) + + # ์˜ˆ์ธก ๊ฒฐ๊ณผ ์ €์žฅ + json_output = JSON_DIR / "predictions.json" + save_predictions(results, json_output) + + # ํ†ต๊ณ„ ์ถœ๋ ฅ + logger.info("\n=== Inference Summary ===") + total_detections = 0 + for img_path, data in results.items(): + img_name = Path(img_path).name + num_dets = len(data["detections"]) + total_detections += num_dets + logger.info(f"{img_name}: {num_dets} detections") + + logger.info(f"\nTotal images processed: {len(results)}") + logger.info(f"Total detections: {total_detections}") + logger.info(f"Average detections per image: {total_detections/len(results):.2f}") + logger.info(f"\nResults saved to: {OUTPUT_DIR}") + + diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/README.md b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/README.md new file mode 100644 index 0000000..f5d220c --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/README.md @@ -0,0 +1,5 @@ +# YOLOv8n @ 1280 (ํฐ ๊ฐ์ฒด) + +- Start: `bash START_TRAINING_UV.sh` +- Config: `config_optimized.yaml` +- ๋Œ€์ƒ ํด๋ž˜์Šค: `korean_content`, `english_content`, `section`, `answer_option` diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/START_TRAINING_UV.sh b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/START_TRAINING_UV.sh new file mode 100644 index 0000000..4a92b9c --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/START_TRAINING_UV.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -e +source /home/jdh251425/2509\ Gradi-Detection/gradi-detection/bin/activate +python - <<'PY' +import torch +print('โœ… Torch', torch.__version__, 'CUDA', torch.cuda.is_available(), 'GPUs', torch.cuda.device_count()) +PY +python - <<'PY' +from ultralytics import YOLO +print('๐Ÿš€ Train YOLOv8n @1280 (large4, multi-GPU)') +YOLO('yolov8n.pt').train(cfg='/home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8n_imgsz_1280/config_optimized.yaml') +print('โœ… Done') +PY diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/config_optimized.yaml b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/config_optimized.yaml new file mode 100644 index 0000000..134c2d2 --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/config_optimized.yaml @@ -0,0 +1,141 @@ +# Routing Experiment - YOLOv8n @ 1280 (ํฐ ๊ฐ์ฒด ์ „์šฉ) + +task: detect +mode: train +model: yolov8n.pt +data: /home/jdh251425/2509 Gradi-Detection/english_problems_data_large4/data.yaml + +# ํ•™์Šต +epochs: 100 +patience: 25 +batch: 8 +imgsz: 1280 +device: [0,1,2,3] +workers: 8 + +# ํ”„๋กœ์ ํŠธ +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8n_imgsz_1280 +name: train +exist_ok: true + +# ์˜ตํ‹ฐ๋งˆ์ด์ € +optimizer: AdamW +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 + +# Loss +box: 7.5 +cls: 1.5 +dfl: 1.5 + +# ์Šค์บ” ์ด๋ฏธ์ง€ ์นœํ™” +rect: true +multi_scale: false + +# ๊ฒฝ๋Ÿ‰ ์ฆ๊ฐ• (ํ•ฉ์˜ ๋ฒ”์œ„) +degrees: 0 +perspective: 0.0 +translate: 0.02 +scale: 0.05 +shear: 0.0 +flipud: 0.0 +fliplr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +auto_augment: null +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +erasing: 0.0 + +# ๊ฒ€์ฆ/์ถ”๋ก  +iou: 0.7 +conf: 0.12 +max_det: 300 +val: true +amp: true +plots: true +verbose: true +seed: 0 +deterministic: true +single_cls: false +cos_lr: false +cache: false + +# Routing Experiment - YOLOv8n @ 1280 (ํฐ ๊ฐ์ฒด ์ „์šฉ) + +task: detect +mode: train +model: yolov8n.pt +data: /home/jdh251425/2509 Gradi-Detection/english_problems_data_large4/data.yaml + +# ํ•™์Šต +epochs: 100 +patience: 25 +batch: 8 +imgsz: 1280 +device: [0,1,2,3] +workers: 8 + +# ํ”„๋กœ์ ํŠธ +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8n_imgsz_1280 +name: train +exist_ok: true + +# ์˜ตํ‹ฐ๋งˆ์ด์ € +optimizer: AdamW +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 + +# Loss +box: 7.5 +cls: 1.5 +dfl: 1.5 + +# ์Šค์บ” ์ด๋ฏธ์ง€ ์นœํ™” +rect: true +multi_scale: false + +# ๊ฒฝ๋Ÿ‰ ์ฆ๊ฐ• (ํ•ฉ์˜ ๋ฒ”์œ„) +degrees: 0 +perspective: 0.0 +translate: 0.02 +scale: 0.05 +shear: 0.0 +flipud: 0.0 +fliplr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +auto_augment: null +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +erasing: 0.0 + +# ๊ฒ€์ฆ/์ถ”๋ก  +iou: 0.7 +conf: 0.12 +max_det: 300 +val: true +amp: true +plots: true +verbose: true +seed: 0 +deterministic: true +single_cls: false +cos_lr: false +cache: false diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/args.yaml b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/args.yaml new file mode 100644 index 0000000..a9fab33 --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8n.pt +data: /home/jdh251425/2509 Gradi-Detection/english_problems_data_large4/data.yaml +epochs: 100 +time: null +patience: 25 +batch: 8 +imgsz: 1280 +save: true +save_period: -1 +cache: false +device: 0,1,2,3 +workers: 8 +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8n_imgsz_1280 +name: train +exist_ok: true +pretrained: true +optimizer: AdamW +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +compile: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +conf: 0.12 +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: true +opset: null +workspace: null +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 1.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +nbs: 64 +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +degrees: 0 +translate: 0.02 +scale: 0.05 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.0 +bgr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +copy_paste_mode: flip +auto_augment: null +erasing: 0.0 +cfg: /home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8n_imgsz_1280/config_optimized.yaml +tracker: botsort.yaml +save_dir: /home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8n_imgsz_1280/train diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/results.csv b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/results.csv new file mode 100644 index 0000000..5d478c3 --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/results.csv @@ -0,0 +1,101 @@ +epoch,time,train/box_loss,train/cls_loss,train/dfl_loss,metrics/precision(B),metrics/recall(B),metrics/mAP50(B),metrics/mAP50-95(B),val/box_loss,val/cls_loss,val/dfl_loss,lr/pg0,lr/pg1,lr/pg2 +1,12.6423,3.05133,14.1894,3.2407,0.29184,0.03333,0.03827,0.01102,3.03158,18.8711,11.3543,0.0802,0.0022,0.0022 +2,17.9248,1.84018,6.77397,2.26771,0,0,0,0,3.74109,inf,1401.22,0.0594554,0.00445545,0.00445545 +3,23.1327,1.65349,5.70585,2.03983,0,0,0,0,3.87977,inf,153.772,0.0386654,0.00666536,0.00666536 +4,28.2839,1.58759,4.6224,2.02694,4e-05,0.00278,2e-05,2e-05,3.40522,94.6864,4.87851,0.0178297,0.00882973,0.00882973 +5,33.3734,1.56457,4.33528,2.02137,0,0,0,0,3.22426,19.1763,7.62368,0.009604,0.009604,0.009604 +6,38.4714,1.57064,4.08528,1.87645,0,0,0,0,3.10693,12.6605,5.40276,0.009505,0.009505,0.009505 +7,43.6495,1.47775,3.7654,1.852,0.35742,0.12491,0.06519,0.01936,3.13016,13.0138,4.42239,0.009406,0.009406,0.009406 +8,48.8715,1.31595,3.62393,1.69514,0.08485,0.13373,0.06505,0.02016,3.25815,11.0461,4.91798,0.009307,0.009307,0.009307 +9,54.0175,1.25702,3.15984,1.72306,0.08246,0.08305,0.05758,0.01373,3.22803,11.0405,4.81102,0.009208,0.009208,0.009208 +10,58.9502,1.32638,3.42119,1.76881,0.16467,0.09111,0.10239,0.05223,2.91409,13.6137,3.756,0.009109,0.009109,0.009109 +11,63.849,1.35213,3.13611,1.68105,0.2394,0.04468,0.1307,0.06341,3.1661,12.7184,4.65657,0.00901,0.00901,0.00901 +12,68.9375,1.22966,2.8932,1.63849,0.00237,0.01389,0.00125,0.00037,3.41735,12.6461,6.33354,0.008911,0.008911,0.008911 +13,73.8843,1.21086,2.84739,1.5971,0.36705,0.3983,0.26605,0.1057,2.35064,9.37838,2.836,0.008812,0.008812,0.008812 +14,78.8022,1.18531,2.66888,1.56604,0.17563,0.29531,0.22161,0.07848,2.89475,9.94302,4.47747,0.008713,0.008713,0.008713 +15,83.6531,1.13841,2.48431,1.52732,0.10724,0.06663,0.04771,0.02021,2.90378,12.7754,4.21692,0.008614,0.008614,0.008614 +16,88.5244,1.16094,2.50069,1.51704,0.74239,0.54071,0.6611,0.39759,1.44492,4.27943,1.82483,0.008515,0.008515,0.008515 +17,93.3904,1.0838,2.30567,1.52369,0.00075,0.00347,0.0002,2e-05,3.49772,18.3035,6.10285,0.008416,0.008416,0.008416 +18,98.3084,1.16249,2.63688,1.52107,0.00176,0.00225,0.00089,0.00018,3.88015,17.6522,6.54295,0.008317,0.008317,0.008317 +19,103.246,1.08453,2.27128,1.49238,0.00252,0.00676,0.0013,0.00026,3.57752,18.7876,6.39837,0.008218,0.008218,0.008218 +20,108.162,0.97716,2.11178,1.41056,0.0017,0.0045,0.00087,9e-05,3.72021,19.5536,6.72528,0.008119,0.008119,0.008119 +21,113.047,1.02028,2.14834,1.38003,0.46132,0.43738,0.50234,0.24429,2.00735,6.65541,2.74061,0.00802,0.00802,0.00802 +22,117.884,0.97778,2.07012,1.42234,0.83577,0.88906,0.92555,0.65186,1.10012,2.60361,1.48884,0.007921,0.007921,0.007921 +23,122.846,0.98372,2.01596,1.34908,0.8459,0.94246,0.94711,0.67836,1.06944,2.43707,1.46359,0.007822,0.007822,0.007822 +24,127.841,0.8779,1.76198,1.36786,0.87629,0.89153,0.93632,0.68672,1.02312,2.25523,1.44021,0.007723,0.007723,0.007723 +25,132.816,0.93292,1.88884,1.34775,0.01699,0.12528,0.01427,0.00197,4.07084,16.9324,9.24305,0.007624,0.007624,0.007624 +26,137.83,0.86304,1.8047,1.29705,0.06798,0.11712,0.04664,0.00668,3.71807,12.6058,6.8752,0.007525,0.007525,0.007525 +27,142.707,0.9339,1.83981,1.33383,0.46352,0.23292,0.33439,0.14612,2.90667,12.7674,4.72686,0.007426,0.007426,0.007426 +28,147.62,0.93085,1.83081,1.31238,0.17305,0.18572,0.15066,0.05001,3.10673,14.1928,5.30896,0.007327,0.007327,0.007327 +29,152.57,0.82724,1.71194,1.28986,0.86879,0.27947,0.55154,0.36172,2.37136,9.02579,3.4166,0.007228,0.007228,0.007228 +30,157.418,0.93376,1.77993,1.28702,0.75581,0.2827,0.47744,0.26488,1.91475,8.47121,2.6163,0.007129,0.007129,0.007129 +31,162.324,0.88549,1.75246,1.26303,0.84962,0.91029,0.91583,0.67327,1.05745,2.26935,1.43108,0.00703,0.00703,0.00703 +32,167.219,0.81571,1.6837,1.21513,0.47437,0.21809,0.33244,0.14239,2.44488,10.608,3.27802,0.006931,0.006931,0.006931 +33,172.069,0.85706,1.66213,1.20624,0.08153,0.03801,0.03216,0.00994,3.94729,15.3193,6.87589,0.006832,0.006832,0.006832 +34,176.973,0.84484,1.61453,1.24068,0.81858,0.65206,0.77987,0.53765,1.21492,3.43262,1.68444,0.006733,0.006733,0.006733 +35,181.823,0.78331,1.56308,1.22142,0.63868,0.5519,0.62518,0.34637,1.66592,5.80539,2.35545,0.006634,0.006634,0.006634 +36,186.703,0.8224,1.55777,1.20387,0.73051,0.36861,0.45169,0.25109,1.77962,7.34569,2.36899,0.006535,0.006535,0.006535 +37,191.699,0.81201,1.73206,1.18506,0.69431,0.66129,0.71735,0.47507,1.33344,4.29542,1.88022,0.006436,0.006436,0.006436 +38,196.52,0.80084,1.50634,1.18679,0.52356,0.28744,0.35409,0.19403,2.21416,8.68048,3.25213,0.006337,0.006337,0.006337 +39,201.326,0.76702,1.48957,1.11072,0.15365,0.03069,0.0913,0.03305,3.0059,14.8459,4.35953,0.006238,0.006238,0.006238 +40,206.204,0.77545,1.48393,1.17713,0.55436,0.26128,0.39895,0.21681,2.25518,8.87665,3.32579,0.006139,0.006139,0.006139 +41,211.092,0.72531,1.42766,1.13988,0.90618,0.92265,0.9546,0.74865,0.91642,1.91073,1.30248,0.00604,0.00604,0.00604 +42,215.959,0.72491,1.44589,1.16249,0.08246,0.02534,0.04501,0.01077,3.53091,15.6007,6.53199,0.005941,0.005941,0.005941 +43,220.781,0.74787,1.47074,1.12408,0,0,0,0,3.50744,18.0858,6.27078,0.005842,0.005842,0.005842 +44,225.627,0.74821,1.48423,1.13539,0.39009,0.07044,0.2001,0.03339,3.24814,14.307,5.42175,0.005743,0.005743,0.005743 +45,230.52,0.80068,1.52533,1.122,0.67624,0.35919,0.50627,0.27336,2.09094,8.82572,3.00668,0.005644,0.005644,0.005644 +46,235.316,0.7527,1.44187,1.10891,0.01974,0.01042,0.01028,0.00172,4.08194,17.3096,7.51871,0.005545,0.005545,0.005545 +47,240.184,0.76808,1.50248,1.10398,0.03557,0.02778,0.01723,0.00398,4.06626,15.8002,8.49486,0.005446,0.005446,0.005446 +48,245.11,0.68162,1.35374,1.07505,0.05889,0.04617,0.04173,0.00785,4.11156,13.5495,9.49831,0.005347,0.005347,0.005347 +49,249.95,0.75788,1.42392,1.10342,0.24731,0.2657,0.22627,0.10873,2.84466,12.3255,4.66034,0.005248,0.005248,0.005248 +50,254.926,0.73199,1.39603,1.07177,0.94821,0.94489,0.97127,0.77671,0.84295,1.58316,1.22078,0.005149,0.005149,0.005149 +51,259.881,0.71186,1.34663,1.06287,0.8551,0.90841,0.93173,0.66647,1.09258,2.29208,1.58471,0.00505,0.00505,0.00505 +52,264.739,0.7201,1.42411,1.09099,0.91309,0.93335,0.95919,0.72643,0.95336,1.90211,1.34193,0.004951,0.004951,0.004951 +53,269.623,0.75719,1.36561,1.09264,0.89968,0.92454,0.95645,0.74754,0.90963,1.88425,1.28135,0.004852,0.004852,0.004852 +54,274.55,0.77236,1.42286,1.09218,0.92661,0.88692,0.94837,0.74696,0.92348,1.90835,1.32196,0.004753,0.004753,0.004753 +55,279.463,0.66828,1.27565,1.06434,0.67865,0.23856,0.3804,0.18837,2.49999,10.901,4.01765,0.004654,0.004654,0.004654 +56,284.438,0.68603,1.2437,1.04389,0.91577,0.93036,0.95121,0.74637,0.89056,1.77485,1.27448,0.004555,0.004555,0.004555 +57,289.31,0.67359,1.27311,1.04782,0.88766,0.92737,0.93656,0.73095,0.92819,1.91809,1.28983,0.004456,0.004456,0.004456 +58,294.289,0.74204,1.34207,1.05605,0.05531,0.09581,0.0426,0.01414,3.47999,17.0905,5.73147,0.004357,0.004357,0.004357 +59,299.146,0.68173,1.28917,1.00909,0.03509,0.04514,0.02048,0.00509,4.05678,15.8933,7.27198,0.004258,0.004258,0.004258 +60,303.996,0.62695,1.21114,1.05178,0.03758,0.05903,0.02077,0.0048,4.05639,15.253,7.38424,0.004159,0.004159,0.004159 +61,308.853,0.71949,1.28583,1.02942,0.05279,0.08662,0.05276,0.01418,3.41028,17.0735,5.56216,0.00406,0.00406,0.00406 +62,313.821,0.69378,1.27442,1.05192,0.06384,0.11055,0.0578,0.0182,3.32405,16.6643,5.41054,0.003961,0.003961,0.003961 +63,318.735,0.67679,1.26535,1.00248,0.88263,0.87554,0.92026,0.65183,1.07618,2.36935,1.46861,0.003862,0.003862,0.003862 +64,323.64,0.66167,1.21238,1.02629,0.00714,0.00694,0.00372,0.00112,3.58479,17.8054,5.41572,0.003763,0.003763,0.003763 +65,328.564,0.67277,1.21724,1.01112,0.15317,0.13842,0.12091,0.04196,2.99211,14.2682,4.09384,0.003664,0.003664,0.003664 +66,333.458,0.71454,1.29364,1.007,0.18964,0.11637,0.1352,0.0525,3.00401,15.5007,4.0139,0.003565,0.003565,0.003565 +67,338.353,0.69106,1.25486,1.02362,0.67325,0.31329,0.502,0.26485,2.04926,9.291,3.02649,0.003466,0.003466,0.003466 +68,343.234,0.6939,1.30299,0.96448,0.27134,0.1664,0.11405,0.02799,2.97429,15.509,4.87494,0.003367,0.003367,0.003367 +69,348.196,0.63931,1.21537,1.00411,0.03137,0.07864,0.01977,0.00627,3.38933,18.3971,6.07272,0.003268,0.003268,0.003268 +70,353.052,0.62978,1.21724,1.0141,0.01245,0.04167,0.0073,0.00181,3.75499,18.7128,6.92644,0.003169,0.003169,0.003169 +71,357.881,0.65102,1.19114,0.9837,0.03097,0.1083,0.02149,0.00708,3.38358,19.1735,5.97459,0.00307,0.00307,0.00307 +72,362.769,0.6467,1.21175,0.98815,0.73258,0.60022,0.71728,0.45401,1.47802,4.81569,2.42944,0.002971,0.002971,0.002971 +73,367.672,0.65373,1.18775,0.98936,0.92171,0.97298,0.96631,0.78151,0.82788,1.50866,1.21166,0.002872,0.002872,0.002872 +74,372.602,0.65824,1.21812,1.00147,0.87443,0.84125,0.90766,0.65413,1.05319,2.36259,1.60674,0.002773,0.002773,0.002773 +75,377.669,0.60796,1.13558,0.96826,0.61586,0.45195,0.54202,0.2872,2.00051,6.65177,3.11031,0.002674,0.002674,0.002674 +76,382.566,0.62156,1.16438,0.94828,0.45155,0.15208,0.12931,0.02697,3.20924,13.9199,5.78749,0.002575,0.002575,0.002575 +77,387.419,0.64477,1.21024,1.00577,0.80468,0.75311,0.82299,0.59074,1.16051,3.11502,1.80742,0.002476,0.002476,0.002476 +78,392.234,0.6296,1.14107,0.96039,0.92684,0.95291,0.96064,0.76605,0.8986,1.75148,1.32472,0.002377,0.002377,0.002377 +79,397.101,0.62675,1.12216,0.95169,0.91139,0.93302,0.95271,0.75507,0.89287,1.71554,1.28703,0.002278,0.002278,0.002278 +80,401.944,0.55802,1.05239,0.94031,0.83218,0.93719,0.92425,0.69458,1.00793,2.11752,1.52056,0.002179,0.002179,0.002179 +81,406.849,0.60731,1.1214,0.95524,0.92214,0.9616,0.96656,0.76244,0.9046,1.64009,1.28644,0.00208,0.00208,0.00208 +82,411.696,0.63803,1.13156,0.97262,0.66604,0.66456,0.69834,0.40119,1.62313,4.38468,2.67506,0.001981,0.001981,0.001981 +83,416.552,0.61468,1.14336,0.93568,0.898,0.9382,0.9512,0.72762,0.96033,1.9047,1.40141,0.001882,0.001882,0.001882 +84,421.39,0.61916,1.14963,0.96928,0.94857,0.97199,0.97514,0.79211,0.80694,1.43298,1.16511,0.001783,0.001783,0.001783 +85,426.384,0.57751,1.14017,0.92099,0.95114,0.96447,0.97913,0.79648,0.79355,1.39584,1.16829,0.001684,0.001684,0.001684 +86,431.288,0.63667,1.14235,0.95238,0.94969,0.94882,0.97519,0.78509,0.82038,1.45053,1.1926,0.001585,0.001585,0.001585 +87,436.152,0.58386,1.07792,0.93221,0.94361,0.9429,0.96554,0.76468,0.86195,1.53637,1.24403,0.001486,0.001486,0.001486 +88,441.098,0.60428,1.10315,0.94628,0.91752,0.93102,0.95301,0.74603,0.90709,1.75501,1.28451,0.001387,0.001387,0.001387 +89,445.937,0.54824,1.04505,0.93502,0.72534,0.77993,0.79788,0.5565,1.21918,3.10712,1.88887,0.001288,0.001288,0.001288 +90,450.797,0.5717,1.11594,0.92429,0.93563,0.95339,0.96917,0.78114,0.82794,1.52206,1.21232,0.001189,0.001189,0.001189 +91,456.947,0.58283,1.10608,0.90127,0.94727,0.9641,0.972,0.76912,0.87536,1.62776,1.2788,0.00109,0.00109,0.00109 +92,461.978,0.56265,1.09327,0.89914,0.85705,0.78209,0.87474,0.61323,1.18848,2.86711,1.90443,0.000991,0.000991,0.000991 +93,466.894,0.58015,1.09968,0.89498,0.95205,0.96664,0.9648,0.77689,0.83797,1.52856,1.22629,0.000892,0.000892,0.000892 +94,471.886,0.51512,0.99421,0.93827,0.94913,0.96884,0.96829,0.78011,0.83569,1.48994,1.22745,0.000793,0.000793,0.000793 +95,476.916,0.5778,1.07037,0.9504,0.93246,0.92539,0.95128,0.73825,0.92969,1.73553,1.34936,0.000694,0.000694,0.000694 +96,481.947,0.51976,1.00056,0.93197,0.94086,0.92836,0.95616,0.75043,0.89172,1.65161,1.28806,0.000595,0.000595,0.000595 +97,486.899,0.53081,1.02006,0.91842,0.94004,0.9689,0.96926,0.78769,0.81406,1.46631,1.20691,0.000496,0.000496,0.000496 +98,491.827,0.53427,1.03989,0.89779,0.95613,0.97455,0.97589,0.7985,0.79688,1.38088,1.18823,0.000397,0.000397,0.000397 +99,496.822,0.51791,0.98089,0.92913,0.95753,0.96177,0.97499,0.79209,0.81353,1.45216,1.20494,0.000298,0.000298,0.000298 +100,501.911,0.55883,1.06249,0.90283,0.94009,0.96263,0.97139,0.77775,0.86216,1.56701,1.28325,0.000199,0.000199,0.000199 diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/weights/best.pt b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/weights/best.pt new file mode 100644 index 0000000..5b8d250 Binary files /dev/null and b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/weights/best.pt differ diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/weights/last.pt b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/weights/last.pt new file mode 100644 index 0000000..612f2ce Binary files /dev/null and b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/train/weights/last.pt differ diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/yolo11n.pt b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/yolo11n.pt new file mode 100644 index 0000000..45b273b Binary files /dev/null and b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/yolo11n.pt differ diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/yolov8n.pt b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/yolov8n.pt new file mode 100644 index 0000000..0db4ca4 Binary files /dev/null and b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8n_imgsz_1280/yolov8n.pt differ diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/README.md b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/README.md new file mode 100644 index 0000000..2ff46ae --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/README.md @@ -0,0 +1,5 @@ +# YOLOv8s @ 2048 (์ž‘์€ ๊ฐ์ฒด) + +- Start: `bash START_TRAINING_UV.sh` +- Config: `config_optimized.yaml` +- ๋Œ€์ƒ ํด๋ž˜์Šค: `page_number`, `problem_number`, `answer_1`, `answer_2` diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/START_TRAINING_UV.sh b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/START_TRAINING_UV.sh new file mode 100644 index 0000000..2b35395 --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/START_TRAINING_UV.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -e +source /home/jdh251425/2509\ Gradi-Detection/gradi-detection/bin/activate +python - <<'PY' +import torch +print('โœ… Torch', torch.__version__, 'CUDA', torch.cuda.is_available(), 'GPUs', torch.cuda.device_count()) +PY +python - <<'PY' +from ultralytics import YOLO +print('๐Ÿš€ Train YOLOv8s @2048') +YOLO('yolov8s.pt').train(cfg='/home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8s_imgsz_2048/config_optimized.yaml') +print('โœ… Done') +PY + + diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/config_optimized.yaml b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/config_optimized.yaml new file mode 100644 index 0000000..b02b4ed --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/config_optimized.yaml @@ -0,0 +1,72 @@ +# Routing Experiment - YOLOv8s @ 2048 (์ž‘์€ ๊ฐ์ฒด ์ „์šฉ) + +task: detect +mode: train +model: yolov8s.pt +data: /home/jdh251425/2509 Gradi-Detection/english_problems_data_small4/data.yaml + +# ํ•™์Šต +epochs: 100 +patience: 25 +batch: 4 +imgsz: 2048 +device: [0,1,2,3] +workers: 8 + +# ํ”„๋กœ์ ํŠธ +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8s_imgsz_2048 +name: train +exist_ok: true + +# ์˜ตํ‹ฐ๋งˆ์ด์ € +optimizer: AdamW +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 + +# Loss +box: 7.5 +cls: 1.5 +dfl: 1.5 + +# ์Šค์บ” ์ด๋ฏธ์ง€ ์นœํ™” +rect: true +multi_scale: false + +# ๊ฒฝ๋Ÿ‰ ์ฆ๊ฐ• (ํ•ฉ์˜ ๋ฒ”์œ„) +degrees: 0 +perspective: 0.0 +translate: 0.02 +scale: 0.05 +shear: 0.0 +flipud: 0.0 +fliplr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +auto_augment: null +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +erasing: 0.0 + +# ๊ฒ€์ฆ/์ถ”๋ก  +iou: 0.7 +conf: 0.22 +max_det: 300 +val: true +amp: true +plots: true +verbose: true +seed: 0 +deterministic: true +single_cls: false +cos_lr: false +cache: false + + diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/args.yaml b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/args.yaml new file mode 100644 index 0000000..0f35104 --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/args.yaml @@ -0,0 +1,106 @@ +task: detect +mode: train +model: yolov8s.pt +data: /home/jdh251425/2509 Gradi-Detection/english_problems_data_small4/data.yaml +epochs: 100 +time: null +patience: 25 +batch: 4 +imgsz: 2048 +save: true +save_period: -1 +cache: false +device: 0,1,2,3 +workers: 8 +project: /home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8s_imgsz_2048 +name: train +exist_ok: true +pretrained: true +optimizer: AdamW +verbose: true +seed: 0 +deterministic: true +single_cls: false +rect: false +cos_lr: false +close_mosaic: 10 +resume: false +amp: true +fraction: 1.0 +profile: false +freeze: null +multi_scale: false +compile: false +overlap_mask: true +mask_ratio: 4 +dropout: 0.0 +val: true +split: val +save_json: false +conf: 0.22 +iou: 0.7 +max_det: 300 +half: false +dnn: false +plots: true +source: null +vid_stride: 1 +stream_buffer: false +visualize: false +augment: false +agnostic_nms: false +classes: null +retina_masks: false +embed: null +show: false +save_frames: false +save_txt: false +save_conf: false +save_crop: false +show_labels: true +show_conf: true +show_boxes: true +line_width: null +format: torchscript +keras: false +optimize: false +int8: false +dynamic: false +simplify: true +opset: null +workspace: null +nms: false +lr0: 0.01 +lrf: 0.01 +momentum: 0.937 +weight_decay: 0.0005 +warmup_epochs: 2.0 +warmup_momentum: 0.8 +warmup_bias_lr: 0.1 +box: 7.5 +cls: 1.5 +dfl: 1.5 +pose: 12.0 +kobj: 1.0 +nbs: 64 +hsv_h: 0.0 +hsv_s: 0.0 +hsv_v: 0.0 +degrees: 0 +translate: 0.02 +scale: 0.05 +shear: 0.0 +perspective: 0.0 +flipud: 0.0 +fliplr: 0.0 +bgr: 0.0 +mosaic: 0.0 +mixup: 0.0 +cutmix: 0.0 +copy_paste: 0.0 +copy_paste_mode: flip +auto_augment: null +erasing: 0.0 +cfg: /home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8s_imgsz_2048/config_optimized.yaml +tracker: botsort.yaml +save_dir: /home/jdh251425/2509 Gradi-Detection/experiment_routing_0930/yolov8s_imgsz_2048/train diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/results.csv b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/results.csv new file mode 100644 index 0000000..bdc869d --- /dev/null +++ b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/results.csv @@ -0,0 +1,94 @@ +epoch,time,train/box_loss,train/cls_loss,train/dfl_loss,metrics/precision(B),metrics/recall(B),metrics/mAP50(B),metrics/mAP50-95(B),val/box_loss,val/cls_loss,val/dfl_loss,lr/pg0,lr/pg1,lr/pg2 +1,20.6538,2.92701,66.7785,2.44693,0,0,0,0,nan,nan,nan,0.0604,0.0044,0.0044 +2,38.0629,2.89426,107.861,2.43372,0,0,0,0,nan,nan,nan,0.0198119,0.00881189,0.00881189 +3,55.7142,2.52882,15.3667,2.30248,0,0,0,0,nan,nan,nan,0.009802,0.009802,0.009802 +4,73.2848,2.44717,13.76,2.17091,0,0,0,0,nan,nan,nan,0.009703,0.009703,0.009703 +5,91.1471,2.39494,11.3846,2.12096,0,0,0,0,nan,nan,nan,0.009604,0.009604,0.009604 +6,108.948,2.19317,10.24,1.87672,0,0,0,0,nan,nan,nan,0.009505,0.009505,0.009505 +7,127.007,2.22422,10.7526,1.96884,0,0,0,0,nan,nan,nan,0.009406,0.009406,0.009406 +8,145.191,2.16005,7.91878,1.82227,0.10654,0.18912,0.0987,0.03541,nan,nan,nan,0.009307,0.009307,0.009307 +9,163.319,2.13826,7.6661,1.8014,0.0873,0.10938,0.0743,0.02933,2.38348,nan,3.0289,0.009208,0.009208,0.009208 +10,181.465,2.0585,6.75859,1.77109,0.17081,0.34903,0.15831,0.06111,2.20959,6.50503,1.84549,0.009109,0.009109,0.009109 +11,199.81,2.03727,6.12068,1.74583,0.16743,0.29525,0.22392,0.11227,2.10814,9.76637,1.77918,0.00901,0.00901,0.00901 +12,218.003,1.89468,8.00962,1.66608,0,0,0,0,2.42498,18.6305,2.13273,0.008911,0.008911,0.008911 +13,236.323,1.92067,5.91982,1.67456,0,0,0,0,2.27978,12.9709,1.95237,0.008812,0.008812,0.008812 +14,254.552,1.79581,5.25917,1.55673,0,0,0,0,2.27174,14.1635,1.97086,0.008713,0.008713,0.008713 +15,272.293,1.79142,5.24355,1.58285,0,0,0,0,2.52882,14.6158,2.37189,0.008614,0.008614,0.008614 +16,290.375,1.77147,4.87319,1.54206,0.125,0.01852,0.06999,0.02859,1.90632,7.06305,1.68856,0.008515,0.008515,0.008515 +17,308.829,1.77801,4.74678,1.56003,0.25149,0.12175,0.15833,0.07893,1.97551,6.76268,1.76576,0.008416,0.008416,0.008416 +18,326.918,1.68263,4.42589,1.50444,0.25,0.0547,0.14664,0.06883,1.94989,7.93156,1.71481,0.008317,0.008317,0.008317 +19,345.317,1.63984,4.46978,1.46473,0.47403,0.30006,0.41078,0.20454,1.62848,4.2789,1.46428,0.008218,0.008218,0.008218 +20,363.547,1.63749,4.31966,1.49079,0.46203,0.23884,0.262,0.1543,1.70056,4.17457,1.50562,0.008119,0.008119,0.008119 +21,381.867,1.71904,4.16156,1.5204,0.64244,0.60966,0.68974,0.33497,1.63202,3.89844,1.474,0.00802,0.00802,0.00802 +22,400.452,1.71257,4.13601,1.49887,0.43107,0.59447,0.52484,0.23463,1.94188,5.44839,1.65493,0.007921,0.007921,0.007921 +23,418.335,1.71927,4.14546,1.53103,0.76292,0.46557,0.61869,0.30909,1.85568,4.64728,1.62775,0.007822,0.007822,0.007822 +24,436.645,1.65932,3.89063,1.50002,0.63248,0.83942,0.81589,0.43004,1.67375,3.65787,1.49731,0.007723,0.007723,0.007723 +25,454.961,1.62088,3.71653,1.44212,0.51185,0.40972,0.4315,0.21538,1.7451,5.43459,1.56784,0.007624,0.007624,0.007624 +26,472.979,1.70135,3.45049,1.50682,0.48251,0.31602,0.36307,0.18298,1.85474,6.22716,1.62488,0.007525,0.007525,0.007525 +27,491.522,1.70777,3.39699,1.5094,0.84564,0.85196,0.89202,0.44406,1.61925,3.08634,1.45693,0.007426,0.007426,0.007426 +28,509.599,1.66736,3.15043,1.44428,0.88904,0.87847,0.90385,0.45506,1.69985,2.96138,1.48422,0.007327,0.007327,0.007327 +29,527.903,1.65464,3.12368,1.44653,0.91892,0.86673,0.90884,0.47508,1.65247,2.8895,1.46741,0.007228,0.007228,0.007228 +30,546.473,1.67875,2.99338,1.4738,0.91091,0.90057,0.92821,0.48694,1.63505,2.78067,1.44912,0.007129,0.007129,0.007129 +31,565.424,1.61752,2.70673,1.44111,0.26038,0.14829,0.18669,0.09081,1.86691,9.00201,1.63698,0.00703,0.00703,0.00703 +32,583.342,1.63192,3.04755,1.45638,0.17297,0.1773,0.16676,0.07747,1.94703,9.04957,1.72734,0.006931,0.006931,0.006931 +33,601.552,1.60879,2.87851,1.43512,0.63845,0.35931,0.50723,0.24581,1.99875,6.08118,1.68192,0.006832,0.006832,0.006832 +34,619.439,1.61994,2.85463,1.45252,0.86323,0.66345,0.81285,0.43094,1.61217,3.69207,1.45868,0.006733,0.006733,0.006733 +35,637.774,1.52548,2.92342,1.39149,0.80198,0.63929,0.73729,0.36908,1.68839,4.10651,1.50694,0.006634,0.006634,0.006634 +36,655.769,1.56502,2.80696,1.4032,0.86377,0.82232,0.88561,0.4554,1.63149,3.05077,1.46045,0.006535,0.006535,0.006535 +37,673.778,1.51704,2.77599,1.37554,0.76781,0.80168,0.84656,0.43344,1.57053,3.53895,1.44722,0.006436,0.006436,0.006436 +38,691.904,1.57649,2.8032,1.41405,0.74674,0.58755,0.69737,0.35685,1.63249,5.00197,1.48431,0.006337,0.006337,0.006337 +39,709.979,1.57357,2.60073,1.41915,0.82298,0.81005,0.87364,0.45506,1.57137,3.33008,1.43842,0.006238,0.006238,0.006238 +40,727.725,1.5722,2.4979,1.39092,0.83269,0.7663,0.85331,0.43608,1.58395,3.63501,1.43218,0.006139,0.006139,0.006139 +41,745.936,1.57363,2.64774,1.37951,0.67948,0.51608,0.57472,0.28721,1.72017,5.45296,1.52676,0.00604,0.00604,0.00604 +42,764.005,1.56642,2.79519,1.3851,0.80716,0.68277,0.78437,0.37977,1.57658,4.80965,1.45529,0.005941,0.005941,0.005941 +43,781.82,1.58002,2.54059,1.4167,0.77776,0.35311,0.53655,0.26217,1.79071,7.16327,1.58926,0.005842,0.005842,0.005842 +44,800.152,1.49984,2.46961,1.34773,0.81569,0.48656,0.58366,0.30638,1.72366,6.69741,1.53247,0.005743,0.005743,0.005743 +45,818.121,1.51798,2.46542,1.35921,0.79443,0.53177,0.60227,0.30479,1.73193,5.77226,1.54475,0.005644,0.005644,0.005644 +46,835.943,1.58363,2.36084,1.40797,0.89835,0.82532,0.92376,0.47705,1.61267,2.77277,1.43973,0.005545,0.005545,0.005545 +47,854.146,1.47461,2.37462,1.33392,0.91436,0.86451,0.92323,0.48251,1.58895,2.52364,1.42975,0.005446,0.005446,0.005446 +48,872.271,1.48395,2.45277,1.36574,0.89617,0.89765,0.91941,0.48325,1.57109,2.74883,1.45417,0.005347,0.005347,0.005347 +49,890.26,1.50665,2.45754,1.38123,0.94391,0.86365,0.92542,0.47839,1.58406,2.72875,1.43784,0.005248,0.005248,0.005248 +50,908.282,1.53195,2.37453,1.36997,0.88782,0.87986,0.90753,0.48195,1.59994,3.01788,1.44296,0.005149,0.005149,0.005149 +51,926.414,1.51255,2.51399,1.37862,0.95385,0.92904,0.96424,0.50878,1.56676,2.4659,1.42473,0.00505,0.00505,0.00505 +52,944.477,1.56435,2.41839,1.39598,0.97004,0.93935,0.97423,0.51873,1.54348,2.3759,1.42196,0.004951,0.004951,0.004951 +53,962.502,1.48476,2.48426,1.38311,0.85757,0.81471,0.86765,0.453,1.57986,3.52577,1.48375,0.004852,0.004852,0.004852 +54,980.717,1.48571,2.4099,1.35541,0.88748,0.85185,0.89957,0.46867,1.56234,3.13651,1.44108,0.004753,0.004753,0.004753 +55,998.551,1.44649,2.23005,1.35073,0.85212,0.78717,0.85572,0.46707,1.58276,3.51966,1.43854,0.004654,0.004654,0.004654 +56,1016.62,1.50948,2.30169,1.35768,0.81279,0.60658,0.70586,0.37457,1.64309,5.36406,1.49208,0.004555,0.004555,0.004555 +57,1034.86,1.45268,2.18834,1.32786,0.55283,0.50542,0.46995,0.24786,1.6738,7.71998,1.55101,0.004456,0.004456,0.004456 +58,1052.83,1.45859,2.27211,1.34575,0.73894,0.52201,0.63823,0.32806,1.66909,7.19034,1.52354,0.004357,0.004357,0.004357 +59,1070.9,1.49804,2.25831,1.37712,0.83375,0.76518,0.82235,0.43009,1.57996,4.22188,1.45115,0.004258,0.004258,0.004258 +60,1089.43,1.45914,2.21258,1.35938,0.82405,0.75297,0.80961,0.40215,1.5874,4.90701,1.49466,0.004159,0.004159,0.004159 +61,1107.59,1.48459,2.19911,1.35517,0.85877,0.83979,0.85987,0.47611,1.51989,3.50357,1.42183,0.00406,0.00406,0.00406 +62,1125.72,1.45743,2.34802,1.33751,0.82015,0.71814,0.76432,0.38992,1.62624,4.49183,1.48593,0.003961,0.003961,0.003961 +63,1143.82,1.38983,2.14333,1.31406,0.80211,0.72458,0.79677,0.41424,1.57982,5.04357,1.48832,0.003862,0.003862,0.003862 +64,1161.9,1.45244,2.17064,1.34778,0.89258,0.87519,0.93094,0.48856,1.57262,2.9776,1.4513,0.003763,0.003763,0.003763 +65,1179.84,1.42405,2.15621,1.32498,0.86358,0.83535,0.88901,0.47506,1.56971,3.2727,1.4396,0.003664,0.003664,0.003664 +66,1198.05,1.43359,2.11092,1.34076,0.81998,0.6196,0.66492,0.35703,1.65117,5.85055,1.5349,0.003565,0.003565,0.003565 +67,1216.3,1.39761,2.16936,1.31361,0.86798,0.82988,0.86555,0.46135,1.56876,3.71314,1.45998,0.003466,0.003466,0.003466 +68,1234.76,1.46714,2.17909,1.35492,0.92274,0.8784,0.93902,0.523,1.51032,2.71814,1.42819,0.003367,0.003367,0.003367 +69,1253.05,1.36398,2.02869,1.2888,0.92074,0.91702,0.95246,0.50695,1.52514,2.64523,1.42193,0.003268,0.003268,0.003268 +70,1271.22,1.38858,2.28082,1.32616,0.87935,0.83897,0.89653,0.47573,1.52022,3.16894,1.44814,0.003169,0.003169,0.003169 +71,1289.53,1.42049,2.11731,1.32364,0.76884,0.64401,0.65012,0.33652,1.72668,6.49146,1.66313,0.00307,0.00307,0.00307 +72,1307.67,1.44232,2.31185,1.33941,0.90492,0.87083,0.92142,0.48634,1.51305,2.96546,1.43374,0.002971,0.002971,0.002971 +73,1325.67,1.42833,2.17811,1.33066,0.91643,0.86346,0.92912,0.4896,1.54041,2.90412,1.44789,0.002872,0.002872,0.002872 +74,1343.82,1.35517,2.03937,1.29341,0.95316,0.91629,0.96822,0.51284,1.52988,2.49312,1.42483,0.002773,0.002773,0.002773 +75,1361.98,1.38414,2.07105,1.31251,0.82233,0.7994,0.83623,0.43128,1.591,4.2067,1.51526,0.002674,0.002674,0.002674 +76,1379.87,1.43517,2.06044,1.33591,0.80462,0.65864,0.7651,0.40132,1.65844,4.7403,1.56686,0.002575,0.002575,0.002575 +77,1398.04,1.38946,2.0037,1.29711,0.83661,0.71389,0.73749,0.38655,1.65396,5.08539,1.57027,0.002476,0.002476,0.002476 +78,1416,1.4312,2.00675,1.3289,0.84657,0.80819,0.82288,0.42628,1.58653,4.42258,1.53798,0.002377,0.002377,0.002377 +79,1434.06,1.38192,2.09338,1.2915,0.86096,0.82727,0.84175,0.44101,1.61621,4.01727,1.57246,0.002278,0.002278,0.002278 +80,1451.93,1.36893,1.97566,1.32005,0.90418,0.85989,0.91468,0.49009,1.54877,2.91086,1.4687,0.002179,0.002179,0.002179 +81,1470.17,1.40376,1.93321,1.2886,0.92723,0.8738,0.93335,0.49581,1.57295,2.65027,1.4486,0.00208,0.00208,0.00208 +82,1488.72,1.33671,2.05542,1.28871,0.88467,0.81794,0.83601,0.44118,1.57696,3.53273,1.50622,0.001981,0.001981,0.001981 +83,1506.72,1.38392,2.05193,1.3068,0.88361,0.83973,0.89086,0.46864,1.54074,3.54784,1.45695,0.001882,0.001882,0.001882 +84,1524.99,1.30115,1.95438,1.23475,0.87891,0.82747,0.88546,0.46589,1.55168,3.53993,1.47545,0.001783,0.001783,0.001783 +85,1543.04,1.35304,2.03624,1.28831,0.85439,0.80547,0.86674,0.44296,1.60554,3.84254,1.55018,0.001684,0.001684,0.001684 +86,1561,1.39118,2.02006,1.31916,0.85472,0.80996,0.86455,0.455,1.58125,3.82364,1.50952,0.001585,0.001585,0.001585 +87,1579.47,1.30732,2.00222,1.26794,0.79887,0.71076,0.7698,0.39825,1.70313,5.77416,1.67835,0.001486,0.001486,0.001486 +88,1597.76,1.35372,1.99967,1.29692,0.84974,0.81767,0.80475,0.43199,1.55782,4.09987,1.50083,0.001387,0.001387,0.001387 +89,1615.64,1.35426,1.9484,1.27944,0.86263,0.82632,0.81893,0.43739,1.54835,3.86319,1.49147,0.001288,0.001288,0.001288 +90,1633.75,1.27081,1.82391,1.23845,0.88336,0.8488,0.90894,0.47199,1.58548,3.13864,1.53885,0.001189,0.001189,0.001189 +91,1652.99,1.29288,1.91678,1.26652,0.92775,0.87753,0.93923,0.50842,1.53303,2.57166,1.45843,0.00109,0.00109,0.00109 +92,1670.93,1.29317,1.89029,1.26653,0.92372,0.91288,0.9437,0.50657,1.53974,2.39245,1.47106,0.000991,0.000991,0.000991 +93,1689.06,1.3069,1.87945,1.26083,0.9295,0.92881,0.95613,0.51459,1.55218,2.38621,1.47733,0.000892,0.000892,0.000892 diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/weights/best.pt b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/weights/best.pt new file mode 100644 index 0000000..2a75b53 Binary files /dev/null and b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/weights/best.pt differ diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/weights/last.pt b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/weights/last.pt new file mode 100644 index 0000000..55a7824 Binary files /dev/null and b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/train/weights/last.pt differ diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/yolo11n.pt b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/yolo11n.pt new file mode 100644 index 0000000..45b273b Binary files /dev/null and b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/yolo11n.pt differ diff --git a/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/yolov8s.pt b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/yolov8s.pt new file mode 100644 index 0000000..90b4a2c Binary files /dev/null and b/ai-service/models/Detection/legacy/experiment_routing_0930/yolov8s_imgsz_2048/yolov8s.pt differ diff --git a/ai-service/models/Detection/legacy/yolov8l_best_0904.pt b/ai-service/models/Detection/legacy/yolov8l_best_0904.pt new file mode 100644 index 0000000..9b8270d Binary files /dev/null and b/ai-service/models/Detection/legacy/yolov8l_best_0904.pt differ diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 1.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 1.json" new file mode 100644 index 0000000..83b83bb --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 1.json" @@ -0,0 +1,736 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 1.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7842864394187927, + "bbox": [ + 209.82127380371094, + 983.5015869140625, + 315.1547546386719, + 1077.3642578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7796093821525574, + "bbox": [ + 194.84866333007812, + 2530.756103515625, + 299.7784423828125, + 2619.1904296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7758496999740601, + "bbox": [ + 1201.541259765625, + 2547.717529296875, + 1306.71240234375, + 2636.89111328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7748382687568665, + "bbox": [ + 204.1857452392578, + 1762.2987060546875, + 311.1451416015625, + 1853.1903076171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.760775625705719, + "bbox": [ + 1229.2142333984375, + 506.0862121582031, + 1330.3555908203125, + 593.1375732421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6700394749641418, + "bbox": [ + 982.4317016601562, + 1175.0797119140625, + 1097.6727294921875, + 1290.3974609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6694291830062866, + "bbox": [ + 1984.017333984375, + 1458.207275390625, + 2108.075927734375, + 1578.694091796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6627236008644104, + "bbox": [ + 205.47837829589844, + 2216.375732421875, + 293.70159912109375, + 2319.92724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6498438119888306, + "bbox": [ + 1793.1846923828125, + 2874.021728515625, + 1916.0955810546875, + 2990.895263671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6435327529907227, + "bbox": [ + 934.218994140625, + 1955.9635009765625, + 1058.0439453125, + 2096.315673828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6288009881973267, + "bbox": [ + 868.28271484375, + 2731.48095703125, + 993.3394165039062, + 2859.762939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6076654195785522, + "bbox": [ + 187.42324829101562, + 2808.025390625, + 264.7101135253906, + 2894.24853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5182301998138428, + "bbox": [ + 212.46214294433594, + 1307.2203369140625, + 298.7174072265625, + 1418.5716552734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48577332496643066, + "bbox": [ + 1198.943359375, + 2959.239501953125, + 1282.6090087890625, + 3065.4677734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.29050731658935547, + "bbox": [ + 192.86740112304688, + 3054.283935546875, + 278.1156921386719, + 3124.05908203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9364607930183411, + "bbox": [ + 1183.287353515625, + 473.7222595214844, + 2210.54150390625, + 1497.5501708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9210142493247986, + "bbox": [ + 152.06390380859375, + 1719.4591064453125, + 1157.144287109375, + 2398.49658203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9079030156135559, + "bbox": [ + 212.20230102539062, + 1212.751220703125, + 1055.266357421875, + 1566.6224365234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9016505479812622, + "bbox": [ + 199.58111572265625, + 949.6400146484375, + 1167.95068359375, + 1607.5753173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8950299024581909, + "bbox": [ + 200.73915100097656, + 1986.2904052734375, + 877.3661499023438, + 2338.2509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8821834325790405, + "bbox": [ + 1191.2994384765625, + 2730.24365234375, + 1996.87744140625, + 3072.180419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8723593950271606, + "bbox": [ + 1163.6500244140625, + 2516.7265625, + 2219.306884765625, + 3105.668701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8393189907073975, + "bbox": [ + 1262.1522216796875, + 681.9396362304688, + 2138.0703125, + 1407.77294921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8269436955451965, + "bbox": [ + 120.31210327148438, + 2468.3427734375, + 1172.5150146484375, + 3188.714599609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8134581446647644, + "bbox": [ + 192.9573974609375, + 2688.423828125, + 677.4232788085938, + 3070.353515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8019182682037354, + "bbox": [ + 208.113525390625, + 1077.8402099609375, + 1138.860595703125, + 1198.867919921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7849441766738892, + "bbox": [ + 1230.732421875, + 597.2572021484375, + 2136.079833984375, + 677.7405395507812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7762291431427002, + "bbox": [ + 196.7760772705078, + 1854.8236083984375, + 1123.649169921875, + 1981.5537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6008186936378479, + "bbox": [ + 195.57530212402344, + 2625.833740234375, + 1057.8720703125, + 2689.551513671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5075584650039673, + "bbox": [ + 195.4400634765625, + 2614.5849609375, + 1060.255615234375, + 2710.299560546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.47797083854675293, + "bbox": [ + 1204.70361328125, + 2647.417724609375, + 2055.885009765625, + 2710.023193359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.3939492106437683, + "bbox": [ + 1125.26025390625, + 2515.19677734375, + 2429.0, + 3146.61279296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.32467153668403625, + "bbox": [ + 1236.76025390625, + 611.8999633789062, + 2103.35107421875, + 663.91162109375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7842864394187927, + "bbox": [ + 209.82127380371094, + 983.5015869140625, + 315.1547546386719, + 1077.3642578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7796093821525574, + "bbox": [ + 194.84866333007812, + 2530.756103515625, + 299.7784423828125, + 2619.1904296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7758496999740601, + "bbox": [ + 1201.541259765625, + 2547.717529296875, + 1306.71240234375, + 2636.89111328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7748382687568665, + "bbox": [ + 204.1857452392578, + 1762.2987060546875, + 311.1451416015625, + 1853.1903076171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.760775625705719, + "bbox": [ + 1229.2142333984375, + 506.0862121582031, + 1330.3555908203125, + 593.1375732421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6700394749641418, + "bbox": [ + 982.4317016601562, + 1175.0797119140625, + 1097.6727294921875, + 1290.3974609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6694291830062866, + "bbox": [ + 1984.017333984375, + 1458.207275390625, + 2108.075927734375, + 1578.694091796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6627236008644104, + "bbox": [ + 205.47837829589844, + 2216.375732421875, + 293.70159912109375, + 2319.92724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6498438119888306, + "bbox": [ + 1793.1846923828125, + 2874.021728515625, + 1916.0955810546875, + 2990.895263671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6435327529907227, + "bbox": [ + 934.218994140625, + 1955.9635009765625, + 1058.0439453125, + 2096.315673828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6288009881973267, + "bbox": [ + 868.28271484375, + 2731.48095703125, + 993.3394165039062, + 2859.762939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6076654195785522, + "bbox": [ + 187.42324829101562, + 2808.025390625, + 264.7101135253906, + 2894.24853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5182301998138428, + "bbox": [ + 212.46214294433594, + 1307.2203369140625, + 298.7174072265625, + 1418.5716552734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48577332496643066, + "bbox": [ + 1198.943359375, + 2959.239501953125, + 1282.6090087890625, + 3065.4677734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.29050731658935547, + "bbox": [ + 192.86740112304688, + 3054.283935546875, + 278.1156921386719, + 3124.05908203125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9364607930183411, + "bbox": [ + 1183.287353515625, + 473.7222595214844, + 2210.54150390625, + 1497.5501708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9210142493247986, + "bbox": [ + 152.06390380859375, + 1719.4591064453125, + 1157.144287109375, + 2398.49658203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9079030156135559, + "bbox": [ + 212.20230102539062, + 1212.751220703125, + 1055.266357421875, + 1566.6224365234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9016505479812622, + "bbox": [ + 199.58111572265625, + 949.6400146484375, + 1167.95068359375, + 1607.5753173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8950299024581909, + "bbox": [ + 200.73915100097656, + 1986.2904052734375, + 877.3661499023438, + 2338.2509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8821834325790405, + "bbox": [ + 1191.2994384765625, + 2730.24365234375, + 1996.87744140625, + 3072.180419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8723593950271606, + "bbox": [ + 1163.6500244140625, + 2516.7265625, + 2219.306884765625, + 3105.668701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8393189907073975, + "bbox": [ + 1262.1522216796875, + 681.9396362304688, + 2138.0703125, + 1407.77294921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8269436955451965, + "bbox": [ + 120.31210327148438, + 2468.3427734375, + 1172.5150146484375, + 3188.714599609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8134581446647644, + "bbox": [ + 192.9573974609375, + 2688.423828125, + 677.4232788085938, + 3070.353515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8019182682037354, + "bbox": [ + 208.113525390625, + 1077.8402099609375, + 1138.860595703125, + 1198.867919921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7849441766738892, + "bbox": [ + 1230.732421875, + 597.2572021484375, + 2136.079833984375, + 677.7405395507812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7762291431427002, + "bbox": [ + 196.7760772705078, + 1854.8236083984375, + 1123.649169921875, + 1981.5537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6008186936378479, + "bbox": [ + 195.57530212402344, + 2625.833740234375, + 1057.8720703125, + 2689.551513671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5075584650039673, + "bbox": [ + 195.4400634765625, + 2614.5849609375, + 1060.255615234375, + 2710.299560546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.47797083854675293, + "bbox": [ + 1204.70361328125, + 2647.417724609375, + 2055.885009765625, + 2710.023193359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.3939492106437683, + "bbox": [ + 1125.26025390625, + 2515.19677734375, + 2429.0, + 3146.61279296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.32467153668403625, + "bbox": [ + 1236.76025390625, + 611.8999633789062, + 2103.35107421875, + 663.91162109375 + ] + } + ], + "timestamp": "2025-10-15T21:42:07.425684" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 10.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 10.json" new file mode 100644 index 0000000..3de221b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 10.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 10.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7653053998947144, + "bbox": [ + 1335.1885986328125, + 473.2847595214844, + 1444.0208740234375, + 571.9437866210938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7515062689781189, + "bbox": [ + 264.93951416015625, + 449.0201721191406, + 387.2547302246094, + 556.3081665039062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6523391604423523, + "bbox": [ + 1627.788330078125, + 1220.8560791015625, + 1734.173583984375, + 1341.718505859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6165726780891418, + "bbox": [ + 1801.0130615234375, + 2369.959228515625, + 1947.3907470703125, + 2514.678955078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5832147002220154, + "bbox": [ + 883.0390625, + 1590.44140625, + 960.6878662109375, + 1682.2232666015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5786518454551697, + "bbox": [ + 726.6168823242188, + 1861.361083984375, + 897.37548828125, + 2025.74951171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.527641236782074, + "bbox": [ + 2213.706787109375, + 3238.08837890625, + 2304.36962890625, + 3313.344482421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9310768842697144, + "bbox": [ + 255.3965301513672, + 621.7555541992188, + 1254.7518310546875, + 1828.46630859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9298466444015503, + "bbox": [ + 1324.8475341796875, + 718.0027465820312, + 2315.462158203125, + 2326.831298828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9169687628746033, + "bbox": [ + 206.598388671875, + 400.14007568359375, + 1279.3929443359375, + 2265.59814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9040104150772095, + "bbox": [ + 1304.7769775390625, + 410.1015625, + 2412.81103515625, + 2588.61083984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8365683555603027, + "bbox": [ + 1328.4508056640625, + 571.41845703125, + 2317.35205078125, + 704.6746826171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6994885802268982, + "bbox": [ + 288.2322692871094, + 548.0073852539062, + 1055.132568359375, + 650.0685424804688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7653053998947144, + "bbox": [ + 1335.1885986328125, + 473.2847595214844, + 1444.0208740234375, + 571.9437866210938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7515062689781189, + "bbox": [ + 264.93951416015625, + 449.0201721191406, + 387.2547302246094, + 556.3081665039062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6523391604423523, + "bbox": [ + 1627.788330078125, + 1220.8560791015625, + 1734.173583984375, + 1341.718505859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6165726780891418, + "bbox": [ + 1801.0130615234375, + 2369.959228515625, + 1947.3907470703125, + 2514.678955078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5832147002220154, + "bbox": [ + 883.0390625, + 1590.44140625, + 960.6878662109375, + 1682.2232666015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5786518454551697, + "bbox": [ + 726.6168823242188, + 1861.361083984375, + 897.37548828125, + 2025.74951171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.527641236782074, + "bbox": [ + 2213.706787109375, + 3238.08837890625, + 2304.36962890625, + 3313.344482421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9310768842697144, + "bbox": [ + 255.3965301513672, + 621.7555541992188, + 1254.7518310546875, + 1828.46630859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9298466444015503, + "bbox": [ + 1324.8475341796875, + 718.0027465820312, + 2315.462158203125, + 2326.831298828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9169687628746033, + "bbox": [ + 206.598388671875, + 400.14007568359375, + 1279.3929443359375, + 2265.59814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9040104150772095, + "bbox": [ + 1304.7769775390625, + 410.1015625, + 2412.81103515625, + 2588.61083984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8365683555603027, + "bbox": [ + 1328.4508056640625, + 571.41845703125, + 2317.35205078125, + 704.6746826171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6994885802268982, + "bbox": [ + 288.2322692871094, + 548.0073852539062, + 1055.132568359375, + 650.0685424804688 + ] + } + ], + "timestamp": "2025-10-15T21:42:07.823214" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 11.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 11.json" new file mode 100644 index 0000000..dcd974e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 11.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 11.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7643402814865112, + "bbox": [ + 1359.9254150390625, + 494.22344970703125, + 1481.3714599609375, + 603.9540405273438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7294407486915588, + "bbox": [ + 238.2257537841797, + 602.3335571289062, + 363.9731140136719, + 718.8900756835938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6631203889846802, + "bbox": [ + 2164.05615234375, + 2165.859375, + 2300.899169921875, + 2298.61328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6480240821838379, + "bbox": [ + 733.7203979492188, + 2151.0556640625, + 885.5621948242188, + 2300.496337890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5725988149642944, + "bbox": [ + 1355.4454345703125, + 2125.122314453125, + 1464.3118896484375, + 2233.203857421875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5007991790771484, + "bbox": [ + 237.26341247558594, + 2271.555419921875, + 321.5048522949219, + 2374.010009765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4629310965538025, + "bbox": [ + 220.8455047607422, + 3383.128173828125, + 322.3902282714844, + 3464.67529296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2334883213043213, + "bbox": [ + 209.8589630126953, + 3373.67724609375, + 325.4581298828125, + 3481.084716796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.933046817779541, + "bbox": [ + 209.1478271484375, + 709.8484497070312, + 1278.4327392578125, + 2061.591796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9282971024513245, + "bbox": [ + 1292.234130859375, + 390.7762145996094, + 2578.676513671875, + 2752.066162109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9254588484764099, + "bbox": [ + 1343.6204833984375, + 611.84423828125, + 2404.65185546875, + 2082.94189453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9247848987579346, + "bbox": [ + 149.21279907226562, + 445.5929260253906, + 1316.418212890625, + 2585.745849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8934788107872009, + "bbox": [ + 1344.14990234375, + 2109.83642578125, + 2224.857666015625, + 2574.1376953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8265691995620728, + "bbox": [ + 213.9228973388672, + 2069.004150390625, + 607.4859619140625, + 2479.982421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7405682802200317, + "bbox": [ + 222.30398559570312, + 459.6543273925781, + 1230.0869140625, + 570.4458618164062 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7643402814865112, + "bbox": [ + 1359.9254150390625, + 494.22344970703125, + 1481.3714599609375, + 603.9540405273438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7294407486915588, + "bbox": [ + 238.2257537841797, + 602.3335571289062, + 363.9731140136719, + 718.8900756835938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6631203889846802, + "bbox": [ + 2164.05615234375, + 2165.859375, + 2300.899169921875, + 2298.61328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6480240821838379, + "bbox": [ + 733.7203979492188, + 2151.0556640625, + 885.5621948242188, + 2300.496337890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5725988149642944, + "bbox": [ + 1355.4454345703125, + 2125.122314453125, + 1464.3118896484375, + 2233.203857421875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5007991790771484, + "bbox": [ + 237.26341247558594, + 2271.555419921875, + 321.5048522949219, + 2374.010009765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4629310965538025, + "bbox": [ + 220.8455047607422, + 3383.128173828125, + 322.3902282714844, + 3464.67529296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2334883213043213, + "bbox": [ + 209.8589630126953, + 3373.67724609375, + 325.4581298828125, + 3481.084716796875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.933046817779541, + "bbox": [ + 209.1478271484375, + 709.8484497070312, + 1278.4327392578125, + 2061.591796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9282971024513245, + "bbox": [ + 1292.234130859375, + 390.7762145996094, + 2578.676513671875, + 2752.066162109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9254588484764099, + "bbox": [ + 1343.6204833984375, + 611.84423828125, + 2404.65185546875, + 2082.94189453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9247848987579346, + "bbox": [ + 149.21279907226562, + 445.5929260253906, + 1316.418212890625, + 2585.745849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8934788107872009, + "bbox": [ + 1344.14990234375, + 2109.83642578125, + 2224.857666015625, + 2574.1376953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8265691995620728, + "bbox": [ + 213.9228973388672, + 2069.004150390625, + 607.4859619140625, + 2479.982421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7405682802200317, + "bbox": [ + 222.30398559570312, + 459.6543273925781, + 1230.0869140625, + 570.4458618164062 + ] + } + ], + "timestamp": "2025-10-15T21:42:08.180740" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 12.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 12.json" new file mode 100644 index 0000000..1dc6633 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 12.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 12.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7468553185462952, + "bbox": [ + 1303.35693359375, + 474.560302734375, + 1413.9576416015625, + 573.5556030273438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.743333637714386, + "bbox": [ + 266.29180908203125, + 444.13360595703125, + 384.87127685546875, + 554.2145385742188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6878947615623474, + "bbox": [ + 858.9346313476562, + 2338.166259765625, + 972.7527465820312, + 2456.422119140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.609759509563446, + "bbox": [ + 1840.326416015625, + 2247.04296875, + 1974.393310546875, + 2374.877197265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.574940025806427, + "bbox": [ + 2148.958251953125, + 3183.304931640625, + 2236.269287109375, + 3255.7392578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5190994739532471, + "bbox": [ + 1288.8978271484375, + 2063.99169921875, + 1374.2425537109375, + 2163.8310546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5038196444511414, + "bbox": [ + 258.90240478515625, + 1718.33837890625, + 366.2701110839844, + 1838.8165283203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3262196481227875, + "bbox": [ + 1823.564453125, + 2234.002197265625, + 1990.3455810546875, + 2390.14208984375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.24487733840942383, + "bbox": [ + 1291.2572021484375, + 2076.20361328125, + 1358.3148193359375, + 2159.2080078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9450184106826782, + "bbox": [ + 254.3839111328125, + 1724.6357421875, + 1218.76953125, + 2361.24462890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9308471083641052, + "bbox": [ + 1299.9635009765625, + 587.5728759765625, + 2258.749755859375, + 1657.2542724609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9247321486473083, + "bbox": [ + 267.0700378417969, + 576.1969604492188, + 1226.2620849609375, + 1714.6993408203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9033681750297546, + "bbox": [ + 1253.46484375, + 416.5853576660156, + 2287.47119140625, + 2378.7509765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9000604152679443, + "bbox": [ + 198.62510681152344, + 415.2583312988281, + 1238.20849609375, + 2536.2900390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8977319002151489, + "bbox": [ + 1291.826171875, + 1750.477294921875, + 2260.676513671875, + 2211.61572265625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7468553185462952, + "bbox": [ + 1303.35693359375, + 474.560302734375, + 1413.9576416015625, + 573.5556030273438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.743333637714386, + "bbox": [ + 266.29180908203125, + 444.13360595703125, + 384.87127685546875, + 554.2145385742188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6878947615623474, + "bbox": [ + 858.9346313476562, + 2338.166259765625, + 972.7527465820312, + 2456.422119140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.609759509563446, + "bbox": [ + 1840.326416015625, + 2247.04296875, + 1974.393310546875, + 2374.877197265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.574940025806427, + "bbox": [ + 2148.958251953125, + 3183.304931640625, + 2236.269287109375, + 3255.7392578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5190994739532471, + "bbox": [ + 1288.8978271484375, + 2063.99169921875, + 1374.2425537109375, + 2163.8310546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5038196444511414, + "bbox": [ + 258.90240478515625, + 1718.33837890625, + 366.2701110839844, + 1838.8165283203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3262196481227875, + "bbox": [ + 1823.564453125, + 2234.002197265625, + 1990.3455810546875, + 2390.14208984375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.24487733840942383, + "bbox": [ + 1291.2572021484375, + 2076.20361328125, + 1358.3148193359375, + 2159.2080078125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9450184106826782, + "bbox": [ + 254.3839111328125, + 1724.6357421875, + 1218.76953125, + 2361.24462890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9308471083641052, + "bbox": [ + 1299.9635009765625, + 587.5728759765625, + 2258.749755859375, + 1657.2542724609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9247321486473083, + "bbox": [ + 267.0700378417969, + 576.1969604492188, + 1226.2620849609375, + 1714.6993408203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9033681750297546, + "bbox": [ + 1253.46484375, + 416.5853576660156, + 2287.47119140625, + 2378.7509765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9000604152679443, + "bbox": [ + 198.62510681152344, + 415.2583312988281, + 1238.20849609375, + 2536.2900390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8977319002151489, + "bbox": [ + 1291.826171875, + 1750.477294921875, + 2260.676513671875, + 2211.61572265625 + ] + } + ], + "timestamp": "2025-10-15T21:42:08.548719" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 13.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 13.json" new file mode 100644 index 0000000..b6b7a58 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 13.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 13.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7539030909538269, + "bbox": [ + 226.65045166015625, + 436.5482177734375, + 336.9461364746094, + 533.13232421875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7358774542808533, + "bbox": [ + 1261.66943359375, + 618.375244140625, + 1377.0872802734375, + 723.4207153320312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6378952264785767, + "bbox": [ + 1781.2056884765625, + 2619.267333984375, + 1906.25927734375, + 2743.0087890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6156203746795654, + "bbox": [ + 811.2224731445312, + 2233.1611328125, + 943.4743041992188, + 2363.2109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5854724049568176, + "bbox": [ + 1787.4603271484375, + 2429.828857421875, + 1890.47119140625, + 2532.645751953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.49399974942207336, + "bbox": [ + 206.4445037841797, + 3156.03857421875, + 298.3339538574219, + 3228.31640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4745909571647644, + "bbox": [ + 609.5523681640625, + 1265.285400390625, + 696.9658813476562, + 1379.5419921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.23185904324054718, + "bbox": [ + 796.2357788085938, + 2223.01611328125, + 958.38818359375, + 2377.260009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9576107859611511, + "bbox": [ + 223.9379119873047, + 597.4452514648438, + 1190.8133544921875, + 2160.656982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9423897862434387, + "bbox": [ + 1246.1944580078125, + 552.9278564453125, + 2264.4462890625, + 2786.99755859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9403762221336365, + "bbox": [ + 188.3887176513672, + 422.1142883300781, + 1205.0401611328125, + 2193.403564453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9352357983589172, + "bbox": [ + 1260.1524658203125, + 738.2506103515625, + 2235.455078125, + 2452.466552734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9004422426223755, + "bbox": [ + 1254.08935546875, + 2443.832275390625, + 2141.1533203125, + 2691.5478515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8053814768791199, + "bbox": [ + 237.9296417236328, + 533.0311889648438, + 880.7869873046875, + 617.3201293945312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7539030909538269, + "bbox": [ + 226.65045166015625, + 436.5482177734375, + 336.9461364746094, + 533.13232421875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7358774542808533, + "bbox": [ + 1261.66943359375, + 618.375244140625, + 1377.0872802734375, + 723.4207153320312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6378952264785767, + "bbox": [ + 1781.2056884765625, + 2619.267333984375, + 1906.25927734375, + 2743.0087890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6156203746795654, + "bbox": [ + 811.2224731445312, + 2233.1611328125, + 943.4743041992188, + 2363.2109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5854724049568176, + "bbox": [ + 1787.4603271484375, + 2429.828857421875, + 1890.47119140625, + 2532.645751953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.49399974942207336, + "bbox": [ + 206.4445037841797, + 3156.03857421875, + 298.3339538574219, + 3228.31640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4745909571647644, + "bbox": [ + 609.5523681640625, + 1265.285400390625, + 696.9658813476562, + 1379.5419921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.23185904324054718, + "bbox": [ + 796.2357788085938, + 2223.01611328125, + 958.38818359375, + 2377.260009765625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9576107859611511, + "bbox": [ + 223.9379119873047, + 597.4452514648438, + 1190.8133544921875, + 2160.656982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9423897862434387, + "bbox": [ + 1246.1944580078125, + 552.9278564453125, + 2264.4462890625, + 2786.99755859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9403762221336365, + "bbox": [ + 188.3887176513672, + 422.1142883300781, + 1205.0401611328125, + 2193.403564453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9352357983589172, + "bbox": [ + 1260.1524658203125, + 738.2506103515625, + 2235.455078125, + 2452.466552734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9004422426223755, + "bbox": [ + 1254.08935546875, + 2443.832275390625, + 2141.1533203125, + 2691.5478515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8053814768791199, + "bbox": [ + 237.9296417236328, + 533.0311889648438, + 880.7869873046875, + 617.3201293945312 + ] + } + ], + "timestamp": "2025-10-15T21:42:08.936856" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 14.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 14.json" new file mode 100644 index 0000000..18daace --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 14.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 14.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7595505714416504, + "bbox": [ + 1346.3468017578125, + 647.7832641601562, + 1462.1785888671875, + 748.4773559570312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7329692244529724, + "bbox": [ + 270.8448791503906, + 452.4239807128906, + 395.484619140625, + 565.8150024414062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6492832899093628, + "bbox": [ + 1840.446044921875, + 616.318359375, + 1975.78955078125, + 741.5443115234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5978890657424927, + "bbox": [ + 2122.638671875, + 1821.96435546875, + 2198.71923828125, + 1905.0386962890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5505934357643127, + "bbox": [ + 805.83935546875, + 416.22467041015625, + 944.9745483398438, + 560.6581420898438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5403531193733215, + "bbox": [ + 788.4834594726562, + 413.8154296875, + 962.0928955078125, + 579.7442016601562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5387457609176636, + "bbox": [ + 2236.574951171875, + 3281.37548828125, + 2328.183837890625, + 3355.042236328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5325353145599365, + "bbox": [ + 807.6753540039062, + 2689.809326171875, + 906.0247802734375, + 2795.542236328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2643180191516876, + "bbox": [ + 2231.086669921875, + 3271.66064453125, + 2334.06201171875, + 3366.62548828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9354086518287659, + "bbox": [ + 273.001220703125, + 594.9843139648438, + 1261.5015869140625, + 2714.177001953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9212610721588135, + "bbox": [ + 1321.295166015625, + 502.48590087890625, + 2384.5517578125, + 2614.390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9196062684059143, + "bbox": [ + 208.19671630859375, + 360.1167907714844, + 1280.9722900390625, + 3056.80322265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9168121218681335, + "bbox": [ + 1327.8677978515625, + 789.0895385742188, + 2357.0478515625, + 2530.500244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8972429633140564, + "bbox": [ + 243.51612854003906, + 2712.170654296875, + 1179.3507080078125, + 2952.126953125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7595505714416504, + "bbox": [ + 1346.3468017578125, + 647.7832641601562, + 1462.1785888671875, + 748.4773559570312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7329692244529724, + "bbox": [ + 270.8448791503906, + 452.4239807128906, + 395.484619140625, + 565.8150024414062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6492832899093628, + "bbox": [ + 1840.446044921875, + 616.318359375, + 1975.78955078125, + 741.5443115234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5978890657424927, + "bbox": [ + 2122.638671875, + 1821.96435546875, + 2198.71923828125, + 1905.0386962890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5505934357643127, + "bbox": [ + 805.83935546875, + 416.22467041015625, + 944.9745483398438, + 560.6581420898438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5403531193733215, + "bbox": [ + 788.4834594726562, + 413.8154296875, + 962.0928955078125, + 579.7442016601562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5387457609176636, + "bbox": [ + 2236.574951171875, + 3281.37548828125, + 2328.183837890625, + 3355.042236328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5325353145599365, + "bbox": [ + 807.6753540039062, + 2689.809326171875, + 906.0247802734375, + 2795.542236328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2643180191516876, + "bbox": [ + 2231.086669921875, + 3271.66064453125, + 2334.06201171875, + 3366.62548828125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9354086518287659, + "bbox": [ + 273.001220703125, + 594.9843139648438, + 1261.5015869140625, + 2714.177001953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9212610721588135, + "bbox": [ + 1321.295166015625, + 502.48590087890625, + 2384.5517578125, + 2614.390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9196062684059143, + "bbox": [ + 208.19671630859375, + 360.1167907714844, + 1280.9722900390625, + 3056.80322265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9168121218681335, + "bbox": [ + 1327.8677978515625, + 789.0895385742188, + 2357.0478515625, + 2530.500244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8972429633140564, + "bbox": [ + 243.51612854003906, + 2712.170654296875, + 1179.3507080078125, + 2952.126953125 + ] + } + ], + "timestamp": "2025-10-15T21:42:09.300964" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 15.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 15.json" new file mode 100644 index 0000000..a6f6b60 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 15.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 15.jpg", + "detections": [ + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7709265947341919, + "bbox": [ + 757.7011108398438, + 1642.23828125, + 831.4276123046875, + 1723.648681640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7512796521186829, + "bbox": [ + 1250.7691650390625, + 449.2054443359375, + 1369.477783203125, + 552.7395629882812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.746095597743988, + "bbox": [ + 1727.1451416015625, + 451.3596496582031, + 1837.5162353515625, + 555.0620727539062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7332658767700195, + "bbox": [ + 217.3208465576172, + 430.0409240722656, + 337.3678283691406, + 538.7100219726562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7135115265846252, + "bbox": [ + 1239.494873046875, + 2946.19091796875, + 1300.6754150390625, + 3019.131591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5977818965911865, + "bbox": [ + 642.9950561523438, + 409.12738037109375, + 806.7240600585938, + 566.059814453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5201202034950256, + "bbox": [ + 177.28924560546875, + 3136.826171875, + 272.313232421875, + 3215.5986328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4174672067165375, + "bbox": [ + 658.50048828125, + 412.24029541015625, + 787.9365234375, + 549.4918212890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467200636863708, + "bbox": [ + 193.93765258789062, + 556.6621704101562, + 1172.0560302734375, + 2345.81298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9338167905807495, + "bbox": [ + 1227.8487548828125, + 2673.30615234375, + 1939.58251953125, + 3123.354736328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9334197640419006, + "bbox": [ + 181.73133850097656, + 377.7413024902344, + 1195.246826171875, + 2412.146728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9282165169715881, + "bbox": [ + 1240.0458984375, + 692.778076171875, + 2242.693115234375, + 2681.3818359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8594691753387451, + "bbox": [ + 1253.1800537109375, + 550.5917358398438, + 2215.42626953125, + 672.3336181640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7580432891845703, + "bbox": [ + 1218.0592041015625, + 485.32421875, + 2242.52490234375, + 3119.447021484375 + ] + } + ], + "small_detections": [ + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7709265947341919, + "bbox": [ + 757.7011108398438, + 1642.23828125, + 831.4276123046875, + 1723.648681640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7512796521186829, + "bbox": [ + 1250.7691650390625, + 449.2054443359375, + 1369.477783203125, + 552.7395629882812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.746095597743988, + "bbox": [ + 1727.1451416015625, + 451.3596496582031, + 1837.5162353515625, + 555.0620727539062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7332658767700195, + "bbox": [ + 217.3208465576172, + 430.0409240722656, + 337.3678283691406, + 538.7100219726562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7135115265846252, + "bbox": [ + 1239.494873046875, + 2946.19091796875, + 1300.6754150390625, + 3019.131591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5977818965911865, + "bbox": [ + 642.9950561523438, + 409.12738037109375, + 806.7240600585938, + 566.059814453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5201202034950256, + "bbox": [ + 177.28924560546875, + 3136.826171875, + 272.313232421875, + 3215.5986328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4174672067165375, + "bbox": [ + 658.50048828125, + 412.24029541015625, + 787.9365234375, + 549.4918212890625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467200636863708, + "bbox": [ + 193.93765258789062, + 556.6621704101562, + 1172.0560302734375, + 2345.81298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9338167905807495, + "bbox": [ + 1227.8487548828125, + 2673.30615234375, + 1939.58251953125, + 3123.354736328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9334197640419006, + "bbox": [ + 181.73133850097656, + 377.7413024902344, + 1195.246826171875, + 2412.146728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9282165169715881, + "bbox": [ + 1240.0458984375, + 692.778076171875, + 2242.693115234375, + 2681.3818359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8594691753387451, + "bbox": [ + 1253.1800537109375, + 550.5917358398438, + 2215.42626953125, + 672.3336181640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7580432891845703, + "bbox": [ + 1218.0592041015625, + 485.32421875, + 2242.52490234375, + 3119.447021484375 + ] + } + ], + "timestamp": "2025-10-15T21:42:09.696829" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 16.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 16.json" new file mode 100644 index 0000000..0309333 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 16.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 16.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7394245862960815, + "bbox": [ + 1319.5382080078125, + 441.8236389160156, + 1444.5771484375, + 549.0018310546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7383383512496948, + "bbox": [ + 1317.24462890625, + 1973.5938720703125, + 1438.3150634765625, + 2076.056640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6485133171081543, + "bbox": [ + 1845.4642333984375, + 1959.1015625, + 1977.4010009765625, + 2080.37109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6381608247756958, + "bbox": [ + 1961.736328125, + 517.8731689453125, + 2087.7841796875, + 633.8662109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6209801435470581, + "bbox": [ + 2208.62939453125, + 3186.538818359375, + 2294.36376953125, + 3261.06298828125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5827338099479675, + "bbox": [ + 1327.644775390625, + 1066.6015625, + 1408.052734375, + 1156.60888671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5392507314682007, + "bbox": [ + 1694.02587890625, + 2178.87451171875, + 1808.8529052734375, + 2306.447509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9416528344154358, + "bbox": [ + 1324.2122802734375, + 624.6874389648438, + 2321.627685546875, + 1243.6190185546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9395679235458374, + "bbox": [ + 242.77822875976562, + 467.1435546875, + 1253.210205078125, + 2805.60107421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9366462826728821, + "bbox": [ + 1292.594970703125, + 403.25653076171875, + 2358.701416015625, + 1350.2135009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9223382472991943, + "bbox": [ + 1297.19384765625, + 1973.437255859375, + 2315.1337890625, + 2339.700439453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8365064263343811, + "bbox": [ + 1320.27294921875, + 2069.30224609375, + 2289.273193359375, + 2194.34326171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7927699685096741, + "bbox": [ + 1328.95849609375, + 530.7588500976562, + 1901.698486328125, + 622.0433349609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6997930407524109, + "bbox": [ + 1311.615234375, + 2202.505859375, + 2236.17529296875, + 2310.228271484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.12609320878982544, + "bbox": [ + 1277.857666015625, + 1952.2440185546875, + 2360.20654296875, + 2681.72265625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7394245862960815, + "bbox": [ + 1319.5382080078125, + 441.8236389160156, + 1444.5771484375, + 549.0018310546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7383383512496948, + "bbox": [ + 1317.24462890625, + 1973.5938720703125, + 1438.3150634765625, + 2076.056640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6485133171081543, + "bbox": [ + 1845.4642333984375, + 1959.1015625, + 1977.4010009765625, + 2080.37109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6381608247756958, + "bbox": [ + 1961.736328125, + 517.8731689453125, + 2087.7841796875, + 633.8662109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6209801435470581, + "bbox": [ + 2208.62939453125, + 3186.538818359375, + 2294.36376953125, + 3261.06298828125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5827338099479675, + "bbox": [ + 1327.644775390625, + 1066.6015625, + 1408.052734375, + 1156.60888671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5392507314682007, + "bbox": [ + 1694.02587890625, + 2178.87451171875, + 1808.8529052734375, + 2306.447509765625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9416528344154358, + "bbox": [ + 1324.2122802734375, + 624.6874389648438, + 2321.627685546875, + 1243.6190185546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9395679235458374, + "bbox": [ + 242.77822875976562, + 467.1435546875, + 1253.210205078125, + 2805.60107421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9366462826728821, + "bbox": [ + 1292.594970703125, + 403.25653076171875, + 2358.701416015625, + 1350.2135009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9223382472991943, + "bbox": [ + 1297.19384765625, + 1973.437255859375, + 2315.1337890625, + 2339.700439453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8365064263343811, + "bbox": [ + 1320.27294921875, + 2069.30224609375, + 2289.273193359375, + 2194.34326171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7927699685096741, + "bbox": [ + 1328.95849609375, + 530.7588500976562, + 1901.698486328125, + 622.0433349609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6997930407524109, + "bbox": [ + 1311.615234375, + 2202.505859375, + 2236.17529296875, + 2310.228271484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.12609320878982544, + "bbox": [ + 1277.857666015625, + 1952.2440185546875, + 2360.20654296875, + 2681.72265625 + ] + } + ], + "timestamp": "2025-10-15T21:42:10.082442" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 17.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 17.json" new file mode 100644 index 0000000..051682e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 17.json" @@ -0,0 +1,538 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 17.jpg", + "detections": [ + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7553172707557678, + "bbox": [ + 1904.0810546875, + 2652.21484375, + 1999.6212158203125, + 2752.388427734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7405208349227905, + "bbox": [ + 1228.488525390625, + 2560.163330078125, + 1348.9630126953125, + 2663.23291015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7378954887390137, + "bbox": [ + 1232.9552001953125, + 2060.12255859375, + 1348.1224365234375, + 2161.304443359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7348079085350037, + "bbox": [ + 1234.5758056640625, + 1367.315185546875, + 1352.947021484375, + 1472.8436279296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6704397797584534, + "bbox": [ + 1818.5050048828125, + 2040.3316650390625, + 1943.7882080078125, + 2161.420654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6310093998908997, + "bbox": [ + 1671.664306640625, + 1329.9208984375, + 1801.4307861328125, + 1450.3365478515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.514884352684021, + "bbox": [ + 200.9347381591797, + 3168.342529296875, + 289.3312683105469, + 3238.86572265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5119954347610474, + "bbox": [ + 1241.677734375, + 1665.2855224609375, + 1310.2342529296875, + 1748.99951171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4803646504878998, + "bbox": [ + 1233.292724609375, + 2798.07470703125, + 1306.5723876953125, + 2883.75537109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.41963425278663635, + "bbox": [ + 1787.5924072265625, + 2210.290771484375, + 1894.63037109375, + 2324.00146484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3070087134838104, + "bbox": [ + 1792.1875, + 2219.70947265625, + 1867.9805908203125, + 2315.359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.24295583367347717, + "bbox": [ + 187.42868041992188, + 3156.55322265625, + 294.78070068359375, + 3252.2138671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9328781366348267, + "bbox": [ + 169.57785034179688, + 548.7540893554688, + 1177.3165283203125, + 3100.60791015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9176549911499023, + "bbox": [ + 1228.684326171875, + 422.03265380859375, + 2255.84326171875, + 1284.239501953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.909488320350647, + "bbox": [ + 1180.44873046875, + 1977.3375244140625, + 2291.776611328125, + 2435.398193359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9030292630195618, + "bbox": [ + 1225.3302001953125, + 2740.937255859375, + 2235.19970703125, + 3171.450439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9014828205108643, + "bbox": [ + 1224.3828125, + 1596.2593994140625, + 2165.94921875, + 1845.5018310546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8685874342918396, + "bbox": [ + 1211.3822021484375, + 1262.552001953125, + 2268.720947265625, + 1932.6785888671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8626507520675659, + "bbox": [ + 1182.16064453125, + 2516.91748046875, + 2261.010986328125, + 3244.611083984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8117498755455017, + "bbox": [ + 1216.327880859375, + 1476.62060546875, + 2189.8271484375, + 1599.65576171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7215481996536255, + "bbox": [ + 1234.3970947265625, + 2650.897216796875, + 1907.3302001953125, + 2741.4833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7190080285072327, + "bbox": [ + 1236.6243896484375, + 2154.9111328125, + 2196.468994140625, + 2251.61474609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6263931393623352, + "bbox": [ + 1216.1605224609375, + 2229.458251953125, + 2154.37890625, + 2369.947509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.2010408490896225, + "bbox": [ + 1220.49951171875, + 2231.757080078125, + 2180.56982421875, + 2323.49658203125 + ] + } + ], + "small_detections": [ + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7553172707557678, + "bbox": [ + 1904.0810546875, + 2652.21484375, + 1999.6212158203125, + 2752.388427734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7405208349227905, + "bbox": [ + 1228.488525390625, + 2560.163330078125, + 1348.9630126953125, + 2663.23291015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7378954887390137, + "bbox": [ + 1232.9552001953125, + 2060.12255859375, + 1348.1224365234375, + 2161.304443359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7348079085350037, + "bbox": [ + 1234.5758056640625, + 1367.315185546875, + 1352.947021484375, + 1472.8436279296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6704397797584534, + "bbox": [ + 1818.5050048828125, + 2040.3316650390625, + 1943.7882080078125, + 2161.420654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6310093998908997, + "bbox": [ + 1671.664306640625, + 1329.9208984375, + 1801.4307861328125, + 1450.3365478515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.514884352684021, + "bbox": [ + 200.9347381591797, + 3168.342529296875, + 289.3312683105469, + 3238.86572265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5119954347610474, + "bbox": [ + 1241.677734375, + 1665.2855224609375, + 1310.2342529296875, + 1748.99951171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4803646504878998, + "bbox": [ + 1233.292724609375, + 2798.07470703125, + 1306.5723876953125, + 2883.75537109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.41963425278663635, + "bbox": [ + 1787.5924072265625, + 2210.290771484375, + 1894.63037109375, + 2324.00146484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3070087134838104, + "bbox": [ + 1792.1875, + 2219.70947265625, + 1867.9805908203125, + 2315.359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.24295583367347717, + "bbox": [ + 187.42868041992188, + 3156.55322265625, + 294.78070068359375, + 3252.2138671875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9328781366348267, + "bbox": [ + 169.57785034179688, + 548.7540893554688, + 1177.3165283203125, + 3100.60791015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9176549911499023, + "bbox": [ + 1228.684326171875, + 422.03265380859375, + 2255.84326171875, + 1284.239501953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.909488320350647, + "bbox": [ + 1180.44873046875, + 1977.3375244140625, + 2291.776611328125, + 2435.398193359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9030292630195618, + "bbox": [ + 1225.3302001953125, + 2740.937255859375, + 2235.19970703125, + 3171.450439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9014828205108643, + "bbox": [ + 1224.3828125, + 1596.2593994140625, + 2165.94921875, + 1845.5018310546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8685874342918396, + "bbox": [ + 1211.3822021484375, + 1262.552001953125, + 2268.720947265625, + 1932.6785888671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8626507520675659, + "bbox": [ + 1182.16064453125, + 2516.91748046875, + 2261.010986328125, + 3244.611083984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8117498755455017, + "bbox": [ + 1216.327880859375, + 1476.62060546875, + 2189.8271484375, + 1599.65576171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7215481996536255, + "bbox": [ + 1234.3970947265625, + 2650.897216796875, + 1907.3302001953125, + 2741.4833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7190080285072327, + "bbox": [ + 1236.6243896484375, + 2154.9111328125, + 2196.468994140625, + 2251.61474609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6263931393623352, + "bbox": [ + 1216.1605224609375, + 2229.458251953125, + 2154.37890625, + 2369.947509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.2010408490896225, + "bbox": [ + 1220.49951171875, + 2231.757080078125, + 2180.56982421875, + 2323.49658203125 + ] + } + ], + "timestamp": "2025-10-15T21:42:10.440306" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 2.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 2.json" new file mode 100644 index 0000000..8cd7645 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 2.json" @@ -0,0 +1,802 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 2.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7761788964271545, + "bbox": [ + 266.99273681640625, + 1558.7828369140625, + 383.18426513671875, + 1656.45751953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7647627592086792, + "bbox": [ + 248.6532745361328, + 2730.1572265625, + 362.35321044921875, + 2825.101806640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.759023129940033, + "bbox": [ + 289.3776550292969, + 450.9398193359375, + 405.08209228515625, + 545.6597900390625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7449226379394531, + "bbox": [ + 1333.320556640625, + 2388.941162109375, + 1448.6380615234375, + 2494.62744140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7373238801956177, + "bbox": [ + 1364.1485595703125, + 465.3263244628906, + 1480.4686279296875, + 566.6741333007812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7221008539199829, + "bbox": [ + 2084.166259765625, + 2581.75927734375, + 2209.69580078125, + 2700.759521484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.643187940120697, + "bbox": [ + 1361.0081787109375, + 881.2794799804688, + 1458.28076171875, + 1000.9185791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254684925079346, + "bbox": [ + 867.2763671875, + 739.5374755859375, + 994.551513671875, + 858.9783935546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6105570793151855, + "bbox": [ + 838.1183471679688, + 3006.087890625, + 982.9075317382812, + 3151.343505859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.605405867099762, + "bbox": [ + 279.5609436035156, + 810.837158203125, + 382.6033935546875, + 927.8025512695312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6026655435562134, + "bbox": [ + 1798.0853271484375, + 1257.5687255859375, + 1942.20849609375, + 1399.855712890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5937169790267944, + "bbox": [ + 955.8529052734375, + 1969.0958251953125, + 1076.17431640625, + 2084.57373046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5857372283935547, + "bbox": [ + 2237.54296875, + 3322.159423828125, + 2328.824951171875, + 3397.091064453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5852604508399963, + "bbox": [ + 1326.194580078125, + 3076.443115234375, + 1413.85595703125, + 3207.711669921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5764795541763306, + "bbox": [ + 267.99298095703125, + 1752.395263671875, + 365.58203125, + 1882.5455322265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5486968755722046, + "bbox": [ + 243.95086669921875, + 2965.39697265625, + 320.57720947265625, + 3057.10791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4284059703350067, + "bbox": [ + 940.7259521484375, + 1959.599365234375, + 1101.253173828125, + 2112.238525390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3805253505706787, + "bbox": [ + 1331.4544677734375, + 3071.6142578125, + 1400.8343505859375, + 3188.0625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3261685073375702, + "bbox": [ + 858.0497436523438, + 733.5635986328125, + 1012.0326538085938, + 878.7215576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9215754270553589, + "bbox": [ + 1314.7261962890625, + 2627.35546875, + 2341.076904296875, + 3300.589599609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9131869077682495, + "bbox": [ + 1289.9248046875, + 2345.0859375, + 2386.544921875, + 3362.467041015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.877517819404602, + "bbox": [ + 1309.8182373046875, + 424.8322448730469, + 2466.941162109375, + 1356.65625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8768096566200256, + "bbox": [ + 1349.5880126953125, + 705.5388793945312, + 2371.05224609375, + 1102.4268798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8741651773452759, + "bbox": [ + 181.15310668945312, + 395.4048156738281, + 1300.0750732421875, + 1241.311767578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8677266836166382, + "bbox": [ + 161.9854278564453, + 2660.0302734375, + 1284.8515625, + 3384.88525390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8651233315467834, + "bbox": [ + 229.70944213867188, + 1786.194091796875, + 958.8402709960938, + 2194.424072265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8435643315315247, + "bbox": [ + 162.44256591796875, + 1491.2109375, + 1303.119140625, + 2295.40087890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.842098593711853, + "bbox": [ + 216.950927734375, + 2894.42236328125, + 815.963134765625, + 3296.249267578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8274424076080322, + "bbox": [ + 1360.77197265625, + 570.7152099609375, + 2366.440185546875, + 702.28173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8246386647224426, + "bbox": [ + 239.35411071777344, + 1660.4132080078125, + 1292.6300048828125, + 1802.973388671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8238803744316101, + "bbox": [ + 1329.432861328125, + 2488.91064453125, + 2375.02880859375, + 2627.652099609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7948890328407288, + "bbox": [ + 295.4638366699219, + 538.1303100585938, + 1063.72265625, + 638.1751708984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7100364565849304, + "bbox": [ + 253.65850830078125, + 2817.990966796875, + 1219.7672119140625, + 2923.89404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.47947999835014343, + "bbox": [ + 269.66802978515625, + 633.0128173828125, + 704.3484497070312, + 1049.5858154296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.28664639592170715, + "bbox": [ + 265.0177001953125, + 629.5206298828125, + 574.70654296875, + 1055.244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.1540307253599167, + "bbox": [ + 169.15061950683594, + 1783.506103515625, + 1328.599365234375, + 2202.476806640625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7761788964271545, + "bbox": [ + 266.99273681640625, + 1558.7828369140625, + 383.18426513671875, + 1656.45751953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7647627592086792, + "bbox": [ + 248.6532745361328, + 2730.1572265625, + 362.35321044921875, + 2825.101806640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.759023129940033, + "bbox": [ + 289.3776550292969, + 450.9398193359375, + 405.08209228515625, + 545.6597900390625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7449226379394531, + "bbox": [ + 1333.320556640625, + 2388.941162109375, + 1448.6380615234375, + 2494.62744140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7373238801956177, + "bbox": [ + 1364.1485595703125, + 465.3263244628906, + 1480.4686279296875, + 566.6741333007812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7221008539199829, + "bbox": [ + 2084.166259765625, + 2581.75927734375, + 2209.69580078125, + 2700.759521484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.643187940120697, + "bbox": [ + 1361.0081787109375, + 881.2794799804688, + 1458.28076171875, + 1000.9185791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254684925079346, + "bbox": [ + 867.2763671875, + 739.5374755859375, + 994.551513671875, + 858.9783935546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6105570793151855, + "bbox": [ + 838.1183471679688, + 3006.087890625, + 982.9075317382812, + 3151.343505859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.605405867099762, + "bbox": [ + 279.5609436035156, + 810.837158203125, + 382.6033935546875, + 927.8025512695312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6026655435562134, + "bbox": [ + 1798.0853271484375, + 1257.5687255859375, + 1942.20849609375, + 1399.855712890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5937169790267944, + "bbox": [ + 955.8529052734375, + 1969.0958251953125, + 1076.17431640625, + 2084.57373046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5857372283935547, + "bbox": [ + 2237.54296875, + 3322.159423828125, + 2328.824951171875, + 3397.091064453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5852604508399963, + "bbox": [ + 1326.194580078125, + 3076.443115234375, + 1413.85595703125, + 3207.711669921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5764795541763306, + "bbox": [ + 267.99298095703125, + 1752.395263671875, + 365.58203125, + 1882.5455322265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5486968755722046, + "bbox": [ + 243.95086669921875, + 2965.39697265625, + 320.57720947265625, + 3057.10791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4284059703350067, + "bbox": [ + 940.7259521484375, + 1959.599365234375, + 1101.253173828125, + 2112.238525390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3805253505706787, + "bbox": [ + 1331.4544677734375, + 3071.6142578125, + 1400.8343505859375, + 3188.0625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3261685073375702, + "bbox": [ + 858.0497436523438, + 733.5635986328125, + 1012.0326538085938, + 878.7215576171875 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9215754270553589, + "bbox": [ + 1314.7261962890625, + 2627.35546875, + 2341.076904296875, + 3300.589599609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9131869077682495, + "bbox": [ + 1289.9248046875, + 2345.0859375, + 2386.544921875, + 3362.467041015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.877517819404602, + "bbox": [ + 1309.8182373046875, + 424.8322448730469, + 2466.941162109375, + 1356.65625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8768096566200256, + "bbox": [ + 1349.5880126953125, + 705.5388793945312, + 2371.05224609375, + 1102.4268798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8741651773452759, + "bbox": [ + 181.15310668945312, + 395.4048156738281, + 1300.0750732421875, + 1241.311767578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8677266836166382, + "bbox": [ + 161.9854278564453, + 2660.0302734375, + 1284.8515625, + 3384.88525390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8651233315467834, + "bbox": [ + 229.70944213867188, + 1786.194091796875, + 958.8402709960938, + 2194.424072265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8435643315315247, + "bbox": [ + 162.44256591796875, + 1491.2109375, + 1303.119140625, + 2295.40087890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.842098593711853, + "bbox": [ + 216.950927734375, + 2894.42236328125, + 815.963134765625, + 3296.249267578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8274424076080322, + "bbox": [ + 1360.77197265625, + 570.7152099609375, + 2366.440185546875, + 702.28173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8246386647224426, + "bbox": [ + 239.35411071777344, + 1660.4132080078125, + 1292.6300048828125, + 1802.973388671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8238803744316101, + "bbox": [ + 1329.432861328125, + 2488.91064453125, + 2375.02880859375, + 2627.652099609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7948890328407288, + "bbox": [ + 295.4638366699219, + 538.1303100585938, + 1063.72265625, + 638.1751708984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7100364565849304, + "bbox": [ + 253.65850830078125, + 2817.990966796875, + 1219.7672119140625, + 2923.89404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.47947999835014343, + "bbox": [ + 269.66802978515625, + 633.0128173828125, + 704.3484497070312, + 1049.5858154296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.28664639592170715, + "bbox": [ + 265.0177001953125, + 629.5206298828125, + 574.70654296875, + 1055.244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.1540307253599167, + "bbox": [ + 169.15061950683594, + 1783.506103515625, + 1328.599365234375, + 2202.476806640625 + ] + } + ], + "timestamp": "2025-10-15T21:42:10.827434" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 3.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 3.json" new file mode 100644 index 0000000..7bca90f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 3.json" @@ -0,0 +1,758 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 3.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7696303725242615, + "bbox": [ + 223.0105743408203, + 1340.7686767578125, + 333.165771484375, + 1439.1741943359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7662075161933899, + "bbox": [ + 227.72108459472656, + 453.09716796875, + 341.2016296386719, + 557.6080932617188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491800785064697, + "bbox": [ + 1271.42578125, + 2272.972900390625, + 1384.8057861328125, + 2376.00341796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7473263144493103, + "bbox": [ + 213.26458740234375, + 2228.923828125, + 326.3470458984375, + 2332.885986328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7375100255012512, + "bbox": [ + 1284.90478515625, + 465.6437683105469, + 1391.51513671875, + 564.97607421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6880739331245422, + "bbox": [ + 1078.7891845703125, + 628.5864868164062, + 1185.00830078125, + 731.3709106445312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6850149631500244, + "bbox": [ + 1282.54833984375, + 2669.095458984375, + 1391.5721435546875, + 2772.88916015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6587640047073364, + "bbox": [ + 922.0879516601562, + 3183.639892578125, + 1056.18994140625, + 3320.46484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6501002907752991, + "bbox": [ + 1286.0626220703125, + 1248.363037109375, + 1391.0321044921875, + 1355.641845703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6441842317581177, + "bbox": [ + 1690.89990234375, + 1374.8173828125, + 1839.9354248046875, + 1525.0179443359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6410592794418335, + "bbox": [ + 873.2308959960938, + 2128.321533203125, + 1018.5245361328125, + 2266.60546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5732426047325134, + "bbox": [ + 1773.8692626953125, + 3221.498291015625, + 1907.4022216796875, + 3347.53515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.56553053855896, + "bbox": [ + 219.10939025878906, + 3265.025146484375, + 305.9117431640625, + 3339.4951171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5392040610313416, + "bbox": [ + 214.8755340576172, + 2011.581298828125, + 306.24462890625, + 2126.156494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5277695655822754, + "bbox": [ + 216.8645477294922, + 2937.44677734375, + 296.99237060546875, + 3037.490966796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5114830732345581, + "bbox": [ + 231.13966369628906, + 837.8092651367188, + 340.0629577636719, + 971.8974609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.944679856300354, + "bbox": [ + 1276.1063232421875, + 2602.904541015625, + 2303.22314453125, + 3250.145751953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9415110945701599, + "bbox": [ + 1283.3656005859375, + 799.0108642578125, + 2308.63525390625, + 1438.8958740234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9394901394844055, + "bbox": [ + 197.43211364746094, + 2558.8935546875, + 1190.1873779296875, + 3229.662109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9179395437240601, + "bbox": [ + 147.7063751220703, + 1289.9468994140625, + 1215.0191650390625, + 2329.81494140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9115380048751831, + "bbox": [ + 145.92544555664062, + 2201.862060546875, + 1218.2733154296875, + 3327.82568359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9063612222671509, + "bbox": [ + 210.1962432861328, + 680.5601196289062, + 1203.97314453125, + 1300.6231689453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8994267582893372, + "bbox": [ + 1246.04931640625, + 406.2789611816406, + 2393.520263671875, + 1609.38232421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8859707117080688, + "bbox": [ + 1220.1680908203125, + 2209.14404296875, + 2388.92529296875, + 3449.989990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8798978924751282, + "bbox": [ + 204.82620239257812, + 1565.3433837890625, + 1189.9580078125, + 2188.39892578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8601134419441223, + "bbox": [ + 1281.376708984375, + 565.7146606445312, + 2298.846435546875, + 702.8644409179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.825463593006134, + "bbox": [ + 213.14068603515625, + 546.3707885742188, + 1201.7559814453125, + 685.4963989257812 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8183915019035339, + "bbox": [ + 174.32371520996094, + 424.7967224121094, + 1209.0806884765625, + 1374.72216796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.807461678981781, + "bbox": [ + 192.3368377685547, + 1439.521728515625, + 1190.0751953125, + 1575.1380615234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7986094951629639, + "bbox": [ + 199.4864959716797, + 2458.625244140625, + 1223.9398193359375, + 2571.09912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7752985954284668, + "bbox": [ + 1243.1365966796875, + 2500.671142578125, + 2285.529052734375, + 2612.31689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7662193775177002, + "bbox": [ + 186.5366668701172, + 2328.260009765625, + 1199.236083984375, + 2468.15283203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7596904039382935, + "bbox": [ + 1243.0107421875, + 2366.3681640625, + 2287.01513671875, + 2507.69677734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6811506152153015, + "bbox": [ + 1278.707275390625, + 704.9971313476562, + 2293.896728515625, + 801.86767578125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7696303725242615, + "bbox": [ + 223.0105743408203, + 1340.7686767578125, + 333.165771484375, + 1439.1741943359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7662075161933899, + "bbox": [ + 227.72108459472656, + 453.09716796875, + 341.2016296386719, + 557.6080932617188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491800785064697, + "bbox": [ + 1271.42578125, + 2272.972900390625, + 1384.8057861328125, + 2376.00341796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7473263144493103, + "bbox": [ + 213.26458740234375, + 2228.923828125, + 326.3470458984375, + 2332.885986328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7375100255012512, + "bbox": [ + 1284.90478515625, + 465.6437683105469, + 1391.51513671875, + 564.97607421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6880739331245422, + "bbox": [ + 1078.7891845703125, + 628.5864868164062, + 1185.00830078125, + 731.3709106445312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6850149631500244, + "bbox": [ + 1282.54833984375, + 2669.095458984375, + 1391.5721435546875, + 2772.88916015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6587640047073364, + "bbox": [ + 922.0879516601562, + 3183.639892578125, + 1056.18994140625, + 3320.46484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6501002907752991, + "bbox": [ + 1286.0626220703125, + 1248.363037109375, + 1391.0321044921875, + 1355.641845703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6441842317581177, + "bbox": [ + 1690.89990234375, + 1374.8173828125, + 1839.9354248046875, + 1525.0179443359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6410592794418335, + "bbox": [ + 873.2308959960938, + 2128.321533203125, + 1018.5245361328125, + 2266.60546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5732426047325134, + "bbox": [ + 1773.8692626953125, + 3221.498291015625, + 1907.4022216796875, + 3347.53515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.56553053855896, + "bbox": [ + 219.10939025878906, + 3265.025146484375, + 305.9117431640625, + 3339.4951171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5392040610313416, + "bbox": [ + 214.8755340576172, + 2011.581298828125, + 306.24462890625, + 2126.156494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5277695655822754, + "bbox": [ + 216.8645477294922, + 2937.44677734375, + 296.99237060546875, + 3037.490966796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5114830732345581, + "bbox": [ + 231.13966369628906, + 837.8092651367188, + 340.0629577636719, + 971.8974609375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.944679856300354, + "bbox": [ + 1276.1063232421875, + 2602.904541015625, + 2303.22314453125, + 3250.145751953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9415110945701599, + "bbox": [ + 1283.3656005859375, + 799.0108642578125, + 2308.63525390625, + 1438.8958740234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9394901394844055, + "bbox": [ + 197.43211364746094, + 2558.8935546875, + 1190.1873779296875, + 3229.662109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9179395437240601, + "bbox": [ + 147.7063751220703, + 1289.9468994140625, + 1215.0191650390625, + 2329.81494140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9115380048751831, + "bbox": [ + 145.92544555664062, + 2201.862060546875, + 1218.2733154296875, + 3327.82568359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9063612222671509, + "bbox": [ + 210.1962432861328, + 680.5601196289062, + 1203.97314453125, + 1300.6231689453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8994267582893372, + "bbox": [ + 1246.04931640625, + 406.2789611816406, + 2393.520263671875, + 1609.38232421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8859707117080688, + "bbox": [ + 1220.1680908203125, + 2209.14404296875, + 2388.92529296875, + 3449.989990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8798978924751282, + "bbox": [ + 204.82620239257812, + 1565.3433837890625, + 1189.9580078125, + 2188.39892578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8601134419441223, + "bbox": [ + 1281.376708984375, + 565.7146606445312, + 2298.846435546875, + 702.8644409179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.825463593006134, + "bbox": [ + 213.14068603515625, + 546.3707885742188, + 1201.7559814453125, + 685.4963989257812 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8183915019035339, + "bbox": [ + 174.32371520996094, + 424.7967224121094, + 1209.0806884765625, + 1374.72216796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.807461678981781, + "bbox": [ + 192.3368377685547, + 1439.521728515625, + 1190.0751953125, + 1575.1380615234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7986094951629639, + "bbox": [ + 199.4864959716797, + 2458.625244140625, + 1223.9398193359375, + 2571.09912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7752985954284668, + "bbox": [ + 1243.1365966796875, + 2500.671142578125, + 2285.529052734375, + 2612.31689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7662193775177002, + "bbox": [ + 186.5366668701172, + 2328.260009765625, + 1199.236083984375, + 2468.15283203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7596904039382935, + "bbox": [ + 1243.0107421875, + 2366.3681640625, + 2287.01513671875, + 2507.69677734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6811506152153015, + "bbox": [ + 1278.707275390625, + 704.9971313476562, + 2293.896728515625, + 801.86767578125 + ] + } + ], + "timestamp": "2025-10-15T21:42:11.218001" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 4.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 4.json" new file mode 100644 index 0000000..8f95e31 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 4.json" @@ -0,0 +1,494 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 4.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7593793272972107, + "bbox": [ + 1347.364990234375, + 458.486328125, + 1456.197021484375, + 555.633056640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7393930554389954, + "bbox": [ + 254.23086547851562, + 1790.7158203125, + 370.2212829589844, + 1895.1822509765625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7369812726974487, + "bbox": [ + 274.3660888671875, + 570.5938110351562, + 389.0469970703125, + 674.4071655273438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7080551385879517, + "bbox": [ + 1799.5352783203125, + 2557.331298828125, + 1919.96630859375, + 2663.560791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254827976226807, + "bbox": [ + 936.06884765625, + 2071.2861328125, + 1065.16796875, + 2200.023681640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6220764517784119, + "bbox": [ + 1073.418701171875, + 1169.797119140625, + 1199.7271728515625, + 1290.4345703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5693151354789734, + "bbox": [ + 269.18743896484375, + 930.31689453125, + 357.8706970214844, + 1040.5709228515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.554220974445343, + "bbox": [ + 245.86785888671875, + 2032.929931640625, + 328.133056640625, + 2121.632080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5501797199249268, + "bbox": [ + 1320.8935546875, + 2633.862060546875, + 1436.4718017578125, + 2741.5361328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5383371710777283, + "bbox": [ + 2210.284423828125, + 3230.263427734375, + 2302.734375, + 3307.218017578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.29670441150665283, + "bbox": [ + 1059.0570068359375, + 1161.5684814453125, + 1215.7166748046875, + 1306.492919921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9127058386802673, + "bbox": [ + 1302.0462646484375, + 413.1278991699219, + 2370.060791015625, + 3094.311767578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9070683717727661, + "bbox": [ + 1315.893310546875, + 2617.87158203125, + 2293.95068359375, + 3042.982177734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8971260786056519, + "bbox": [ + 263.0885925292969, + 751.4413452148438, + 1202.0928955078125, + 1139.072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8688924908638, + "bbox": [ + 185.17428588867188, + 1737.710693359375, + 1256.1793212890625, + 2445.24169921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.851624608039856, + "bbox": [ + 222.6928253173828, + 517.2632446289062, + 1280.8424072265625, + 1273.4010009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8340811729431152, + "bbox": [ + 1347.1824951171875, + 664.0952758789062, + 2280.616943359375, + 2634.7421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8277298212051392, + "bbox": [ + 262.4835205078125, + 1978.341552734375, + 688.2744140625, + 2359.44091796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7881437540054321, + "bbox": [ + 1325.3629150390625, + 654.1343994140625, + 2250.82275390625, + 2619.892333984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7689452171325684, + "bbox": [ + 253.67236328125, + 1887.353515625, + 679.0177612304688, + 1981.14453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7652727961540222, + "bbox": [ + 1352.454345703125, + 552.654296875, + 1960.1392822265625, + 629.9302978515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7611307501792908, + "bbox": [ + 273.3910827636719, + 658.2020874023438, + 953.2110595703125, + 750.3832397460938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7593793272972107, + "bbox": [ + 1347.364990234375, + 458.486328125, + 1456.197021484375, + 555.633056640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7393930554389954, + "bbox": [ + 254.23086547851562, + 1790.7158203125, + 370.2212829589844, + 1895.1822509765625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7369812726974487, + "bbox": [ + 274.3660888671875, + 570.5938110351562, + 389.0469970703125, + 674.4071655273438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7080551385879517, + "bbox": [ + 1799.5352783203125, + 2557.331298828125, + 1919.96630859375, + 2663.560791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254827976226807, + "bbox": [ + 936.06884765625, + 2071.2861328125, + 1065.16796875, + 2200.023681640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6220764517784119, + "bbox": [ + 1073.418701171875, + 1169.797119140625, + 1199.7271728515625, + 1290.4345703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5693151354789734, + "bbox": [ + 269.18743896484375, + 930.31689453125, + 357.8706970214844, + 1040.5709228515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.554220974445343, + "bbox": [ + 245.86785888671875, + 2032.929931640625, + 328.133056640625, + 2121.632080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5501797199249268, + "bbox": [ + 1320.8935546875, + 2633.862060546875, + 1436.4718017578125, + 2741.5361328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5383371710777283, + "bbox": [ + 2210.284423828125, + 3230.263427734375, + 2302.734375, + 3307.218017578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.29670441150665283, + "bbox": [ + 1059.0570068359375, + 1161.5684814453125, + 1215.7166748046875, + 1306.492919921875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9127058386802673, + "bbox": [ + 1302.0462646484375, + 413.1278991699219, + 2370.060791015625, + 3094.311767578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9070683717727661, + "bbox": [ + 1315.893310546875, + 2617.87158203125, + 2293.95068359375, + 3042.982177734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8971260786056519, + "bbox": [ + 263.0885925292969, + 751.4413452148438, + 1202.0928955078125, + 1139.072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8688924908638, + "bbox": [ + 185.17428588867188, + 1737.710693359375, + 1256.1793212890625, + 2445.24169921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.851624608039856, + "bbox": [ + 222.6928253173828, + 517.2632446289062, + 1280.8424072265625, + 1273.4010009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8340811729431152, + "bbox": [ + 1347.1824951171875, + 664.0952758789062, + 2280.616943359375, + 2634.7421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8277298212051392, + "bbox": [ + 262.4835205078125, + 1978.341552734375, + 688.2744140625, + 2359.44091796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7881437540054321, + "bbox": [ + 1325.3629150390625, + 654.1343994140625, + 2250.82275390625, + 2619.892333984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7689452171325684, + "bbox": [ + 253.67236328125, + 1887.353515625, + 679.0177612304688, + 1981.14453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7652727961540222, + "bbox": [ + 1352.454345703125, + 552.654296875, + 1960.1392822265625, + 629.9302978515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7611307501792908, + "bbox": [ + 273.3910827636719, + 658.2020874023438, + 953.2110595703125, + 750.3832397460938 + ] + } + ], + "timestamp": "2025-10-15T21:42:11.651538" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 5.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 5.json" new file mode 100644 index 0000000..db7262b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 5.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 5.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7677583694458008, + "bbox": [ + 1309.1417236328125, + 476.5721130371094, + 1423.04638671875, + 574.1433715820312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7445803880691528, + "bbox": [ + 232.48446655273438, + 444.83660888671875, + 349.1918029785156, + 550.8106079101562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6803035140037537, + "bbox": [ + 1892.2884521484375, + 455.7478942871094, + 2017.25048828125, + 571.4432983398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6526297926902771, + "bbox": [ + 682.3638916015625, + 440.0401916503906, + 798.8223876953125, + 545.22265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6018808484077454, + "bbox": [ + 1296.0684814453125, + 2323.622314453125, + 1414.938232421875, + 2443.17236328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5414398908615112, + "bbox": [ + 217.0548553466797, + 1971.12548828125, + 322.3581848144531, + 2097.5634765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.47217127680778503, + "bbox": [ + 206.21902465820312, + 3252.438232421875, + 305.44732666015625, + 3335.3701171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2633710205554962, + "bbox": [ + 1321.580810546875, + 2326.974609375, + 1431.3680419921875, + 2434.635009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9423269033432007, + "bbox": [ + 159.95005798339844, + 392.461181640625, + 1246.1182861328125, + 2458.410888671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9345859289169312, + "bbox": [ + 220.5947723388672, + 634.6386108398438, + 1224.0379638671875, + 1941.019775390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9333347082138062, + "bbox": [ + 1249.7689208984375, + 385.37322998046875, + 2483.005615234375, + 2679.53857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9279950857162476, + "bbox": [ + 1302.260986328125, + 658.0155639648438, + 2312.850830078125, + 2057.89892578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9021546840667725, + "bbox": [ + 1297.522216796875, + 2138.218505859375, + 2185.178466796875, + 2581.94921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8916960954666138, + "bbox": [ + 189.1916046142578, + 1971.70849609375, + 927.3601684570312, + 2439.37841796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8025267124176025, + "bbox": [ + 248.9623260498047, + 544.7317504882812, + 1006.8497924804688, + 650.1686401367188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6537009477615356, + "bbox": [ + 1307.2677001953125, + 570.594482421875, + 2108.395263671875, + 649.5535278320312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7677583694458008, + "bbox": [ + 1309.1417236328125, + 476.5721130371094, + 1423.04638671875, + 574.1433715820312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7445803880691528, + "bbox": [ + 232.48446655273438, + 444.83660888671875, + 349.1918029785156, + 550.8106079101562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6803035140037537, + "bbox": [ + 1892.2884521484375, + 455.7478942871094, + 2017.25048828125, + 571.4432983398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6526297926902771, + "bbox": [ + 682.3638916015625, + 440.0401916503906, + 798.8223876953125, + 545.22265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6018808484077454, + "bbox": [ + 1296.0684814453125, + 2323.622314453125, + 1414.938232421875, + 2443.17236328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5414398908615112, + "bbox": [ + 217.0548553466797, + 1971.12548828125, + 322.3581848144531, + 2097.5634765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.47217127680778503, + "bbox": [ + 206.21902465820312, + 3252.438232421875, + 305.44732666015625, + 3335.3701171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2633710205554962, + "bbox": [ + 1321.580810546875, + 2326.974609375, + 1431.3680419921875, + 2434.635009765625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9423269033432007, + "bbox": [ + 159.95005798339844, + 392.461181640625, + 1246.1182861328125, + 2458.410888671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9345859289169312, + "bbox": [ + 220.5947723388672, + 634.6386108398438, + 1224.0379638671875, + 1941.019775390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9333347082138062, + "bbox": [ + 1249.7689208984375, + 385.37322998046875, + 2483.005615234375, + 2679.53857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9279950857162476, + "bbox": [ + 1302.260986328125, + 658.0155639648438, + 2312.850830078125, + 2057.89892578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9021546840667725, + "bbox": [ + 1297.522216796875, + 2138.218505859375, + 2185.178466796875, + 2581.94921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8916960954666138, + "bbox": [ + 189.1916046142578, + 1971.70849609375, + 927.3601684570312, + 2439.37841796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8025267124176025, + "bbox": [ + 248.9623260498047, + 544.7317504882812, + 1006.8497924804688, + 650.1686401367188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6537009477615356, + "bbox": [ + 1307.2677001953125, + 570.594482421875, + 2108.395263671875, + 649.5535278320312 + ] + } + ], + "timestamp": "2025-10-15T21:42:12.098268" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 6.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 6.json" new file mode 100644 index 0000000..a8b404b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 6.json" @@ -0,0 +1,406 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 6.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7571845054626465, + "bbox": [ + 1313.30126953125, + 464.71612548828125, + 1424.9083251953125, + 561.0454711914062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7350559234619141, + "bbox": [ + 262.83905029296875, + 437.4698791503906, + 379.729736328125, + 542.3573608398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6520333290100098, + "bbox": [ + 970.9507446289062, + 585.08740234375, + 1093.125244140625, + 702.7413330078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6486397981643677, + "bbox": [ + 1930.1192626953125, + 561.3494262695312, + 2053.650634765625, + 677.8642578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6299466490745544, + "bbox": [ + 1306.043212890625, + 2428.884033203125, + 1390.3916015625, + 2542.085205078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6112711429595947, + "bbox": [ + 237.3245849609375, + 2861.85693359375, + 321.7109069824219, + 2980.896240234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5517489314079285, + "bbox": [ + 2167.4609375, + 3164.13330078125, + 2255.414794921875, + 3237.143310546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2684604823589325, + "bbox": [ + 2159.164794921875, + 3155.559814453125, + 2260.237060546875, + 3246.5224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2544725239276886, + "bbox": [ + 245.3154754638672, + 2883.34228515625, + 316.9403991699219, + 2977.80029296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467024207115173, + "bbox": [ + 238.3568572998047, + 676.183837890625, + 1227.1839599609375, + 2350.79443359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.940246045589447, + "bbox": [ + 1308.952392578125, + 655.6648559570312, + 2273.24462890625, + 2025.9876708984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.936847448348999, + "bbox": [ + 1298.7720947265625, + 2059.05419921875, + 2299.991943359375, + 2633.1015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9263525009155273, + "bbox": [ + 240.2953643798828, + 2356.212890625, + 1219.1119384765625, + 3084.733642578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9171763062477112, + "bbox": [ + 1261.8824462890625, + 382.80078125, + 2432.9248046875, + 2838.482177734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8951767086982727, + "bbox": [ + 201.87583923339844, + 486.3996276855469, + 1247.02880859375, + 3127.574951171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6817691922187805, + "bbox": [ + 1317.1446533203125, + 561.309814453125, + 1874.561767578125, + 632.3062744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6320798993110657, + "bbox": [ + 260.888916015625, + 538.5783081054688, + 1213.7655029296875, + 628.1819458007812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5868484377861023, + "bbox": [ + 235.7426300048828, + 534.1860961914062, + 1230.2391357421875, + 665.4102172851562 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7571845054626465, + "bbox": [ + 1313.30126953125, + 464.71612548828125, + 1424.9083251953125, + 561.0454711914062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7350559234619141, + "bbox": [ + 262.83905029296875, + 437.4698791503906, + 379.729736328125, + 542.3573608398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6520333290100098, + "bbox": [ + 970.9507446289062, + 585.08740234375, + 1093.125244140625, + 702.7413330078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6486397981643677, + "bbox": [ + 1930.1192626953125, + 561.3494262695312, + 2053.650634765625, + 677.8642578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6299466490745544, + "bbox": [ + 1306.043212890625, + 2428.884033203125, + 1390.3916015625, + 2542.085205078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6112711429595947, + "bbox": [ + 237.3245849609375, + 2861.85693359375, + 321.7109069824219, + 2980.896240234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5517489314079285, + "bbox": [ + 2167.4609375, + 3164.13330078125, + 2255.414794921875, + 3237.143310546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2684604823589325, + "bbox": [ + 2159.164794921875, + 3155.559814453125, + 2260.237060546875, + 3246.5224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2544725239276886, + "bbox": [ + 245.3154754638672, + 2883.34228515625, + 316.9403991699219, + 2977.80029296875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467024207115173, + "bbox": [ + 238.3568572998047, + 676.183837890625, + 1227.1839599609375, + 2350.79443359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.940246045589447, + "bbox": [ + 1308.952392578125, + 655.6648559570312, + 2273.24462890625, + 2025.9876708984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.936847448348999, + "bbox": [ + 1298.7720947265625, + 2059.05419921875, + 2299.991943359375, + 2633.1015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9263525009155273, + "bbox": [ + 240.2953643798828, + 2356.212890625, + 1219.1119384765625, + 3084.733642578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9171763062477112, + "bbox": [ + 1261.8824462890625, + 382.80078125, + 2432.9248046875, + 2838.482177734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8951767086982727, + "bbox": [ + 201.87583923339844, + 486.3996276855469, + 1247.02880859375, + 3127.574951171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6817691922187805, + "bbox": [ + 1317.1446533203125, + 561.309814453125, + 1874.561767578125, + 632.3062744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6320798993110657, + "bbox": [ + 260.888916015625, + 538.5783081054688, + 1213.7655029296875, + 628.1819458007812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5868484377861023, + "bbox": [ + 235.7426300048828, + 534.1860961914062, + 1230.2391357421875, + 665.4102172851562 + ] + } + ], + "timestamp": "2025-10-15T21:42:12.495402" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 7.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 7.json" new file mode 100644 index 0000000..02e6e3f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 7.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 7.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.768508791923523, + "bbox": [ + 1247.5631103515625, + 462.2471008300781, + 1356.5361328125, + 559.650634765625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7568119168281555, + "bbox": [ + 223.93572998046875, + 437.9396667480469, + 335.3740539550781, + 533.7636108398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.664227306842804, + "bbox": [ + 1834.0775146484375, + 550.6853637695312, + 1959.118408203125, + 668.3765258789062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6493028402328491, + "bbox": [ + 792.1515502929688, + 525.58544921875, + 893.7704467773438, + 618.6138916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5095422863960266, + "bbox": [ + 1229.560302734375, + 2101.49853515625, + 1346.4901123046875, + 2222.722900390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4846366047859192, + "bbox": [ + 199.53390502929688, + 3131.569091796875, + 292.33056640625, + 3208.297607421875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.46805378794670105, + "bbox": [ + 210.54933166503906, + 1810.613037109375, + 323.7799987792969, + 1946.4163818359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9541044235229492, + "bbox": [ + 1238.14501953125, + 2048.781982421875, + 2219.730712890625, + 2676.8095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9409392476081848, + "bbox": [ + 191.54071044921875, + 1819.2218017578125, + 1153.790771484375, + 2522.009521484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9364492893218994, + "bbox": [ + 1232.597412109375, + 644.2908325195312, + 2185.266845703125, + 2001.259765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9210805892944336, + "bbox": [ + 213.07896423339844, + 617.7672729492188, + 1167.1640625, + 1815.6981201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9201038479804993, + "bbox": [ + 1206.663330078125, + 420.39990234375, + 2236.200439453125, + 2742.793701171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9175267815589905, + "bbox": [ + 172.26583862304688, + 394.28033447265625, + 1181.0562744140625, + 2594.19970703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7276173830032349, + "bbox": [ + 225.4040985107422, + 525.8201904296875, + 760.7993774414062, + 613.4086303710938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6856730580329895, + "bbox": [ + 1251.57080078125, + 556.6467895507812, + 1805.6676025390625, + 627.0037231445312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.768508791923523, + "bbox": [ + 1247.5631103515625, + 462.2471008300781, + 1356.5361328125, + 559.650634765625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7568119168281555, + "bbox": [ + 223.93572998046875, + 437.9396667480469, + 335.3740539550781, + 533.7636108398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.664227306842804, + "bbox": [ + 1834.0775146484375, + 550.6853637695312, + 1959.118408203125, + 668.3765258789062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6493028402328491, + "bbox": [ + 792.1515502929688, + 525.58544921875, + 893.7704467773438, + 618.6138916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5095422863960266, + "bbox": [ + 1229.560302734375, + 2101.49853515625, + 1346.4901123046875, + 2222.722900390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4846366047859192, + "bbox": [ + 199.53390502929688, + 3131.569091796875, + 292.33056640625, + 3208.297607421875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.46805378794670105, + "bbox": [ + 210.54933166503906, + 1810.613037109375, + 323.7799987792969, + 1946.4163818359375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9541044235229492, + "bbox": [ + 1238.14501953125, + 2048.781982421875, + 2219.730712890625, + 2676.8095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9409392476081848, + "bbox": [ + 191.54071044921875, + 1819.2218017578125, + 1153.790771484375, + 2522.009521484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9364492893218994, + "bbox": [ + 1232.597412109375, + 644.2908325195312, + 2185.266845703125, + 2001.259765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9210805892944336, + "bbox": [ + 213.07896423339844, + 617.7672729492188, + 1167.1640625, + 1815.6981201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9201038479804993, + "bbox": [ + 1206.663330078125, + 420.39990234375, + 2236.200439453125, + 2742.793701171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9175267815589905, + "bbox": [ + 172.26583862304688, + 394.28033447265625, + 1181.0562744140625, + 2594.19970703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7276173830032349, + "bbox": [ + 225.4040985107422, + 525.8201904296875, + 760.7993774414062, + 613.4086303710938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6856730580329895, + "bbox": [ + 1251.57080078125, + 556.6467895507812, + 1805.6676025390625, + 627.0037231445312 + ] + } + ], + "timestamp": "2025-10-15T21:42:12.889906" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 8.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 8.json" new file mode 100644 index 0000000..99a0500 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 8.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 8.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7626340985298157, + "bbox": [ + 1287.3861083984375, + 448.95611572265625, + 1399.5364990234375, + 547.1859130859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7594113349914551, + "bbox": [ + 259.8250427246094, + 430.52459716796875, + 372.1651611328125, + 524.6627197265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6873252987861633, + "bbox": [ + 1702.630859375, + 451.0979309082031, + 1819.9349365234375, + 559.7249145507812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6730852723121643, + "bbox": [ + 903.0289916992188, + 515.3897705078125, + 1025.6162109375, + 631.7552490234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5343709588050842, + "bbox": [ + 2146.871337890625, + 3132.63916015625, + 2231.72314453125, + 3203.087646484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5065203905105591, + "bbox": [ + 494.0369873046875, + 2468.900634765625, + 598.845703125, + 2592.79150390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47991713881492615, + "bbox": [ + 1275.1580810546875, + 2180.424072265625, + 1353.587646484375, + 2268.587646484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9354473352432251, + "bbox": [ + 1277.63916015625, + 680.4096069335938, + 2248.48828125, + 1977.952880859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9317852258682251, + "bbox": [ + 1249.241455078125, + 416.5291442871094, + 2371.324951171875, + 2593.223876953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9233621954917908, + "bbox": [ + 1285.1387939453125, + 1980.9615478515625, + 2258.741455078125, + 2454.271728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.921034574508667, + "bbox": [ + 237.45864868164062, + 604.6239013671875, + 1198.7724609375, + 2790.157958984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8704062104225159, + "bbox": [ + 188.7772979736328, + 403.77447509765625, + 1205.7091064453125, + 2973.708251953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8362190127372742, + "bbox": [ + 1291.685302734375, + 543.1148071289062, + 2253.18701171875, + 671.06103515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7847903966903687, + "bbox": [ + 257.5635986328125, + 523.8179321289062, + 867.9666137695312, + 606.8668212890625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7626340985298157, + "bbox": [ + 1287.3861083984375, + 448.95611572265625, + 1399.5364990234375, + 547.1859130859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7594113349914551, + "bbox": [ + 259.8250427246094, + 430.52459716796875, + 372.1651611328125, + 524.6627197265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6873252987861633, + "bbox": [ + 1702.630859375, + 451.0979309082031, + 1819.9349365234375, + 559.7249145507812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6730852723121643, + "bbox": [ + 903.0289916992188, + 515.3897705078125, + 1025.6162109375, + 631.7552490234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5343709588050842, + "bbox": [ + 2146.871337890625, + 3132.63916015625, + 2231.72314453125, + 3203.087646484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5065203905105591, + "bbox": [ + 494.0369873046875, + 2468.900634765625, + 598.845703125, + 2592.79150390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47991713881492615, + "bbox": [ + 1275.1580810546875, + 2180.424072265625, + 1353.587646484375, + 2268.587646484375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9354473352432251, + "bbox": [ + 1277.63916015625, + 680.4096069335938, + 2248.48828125, + 1977.952880859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9317852258682251, + "bbox": [ + 1249.241455078125, + 416.5291442871094, + 2371.324951171875, + 2593.223876953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9233621954917908, + "bbox": [ + 1285.1387939453125, + 1980.9615478515625, + 2258.741455078125, + 2454.271728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.921034574508667, + "bbox": [ + 237.45864868164062, + 604.6239013671875, + 1198.7724609375, + 2790.157958984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8704062104225159, + "bbox": [ + 188.7772979736328, + 403.77447509765625, + 1205.7091064453125, + 2973.708251953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8362190127372742, + "bbox": [ + 1291.685302734375, + 543.1148071289062, + 2253.18701171875, + 671.06103515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7847903966903687, + "bbox": [ + 257.5635986328125, + 523.8179321289062, + 867.9666137695312, + 606.8668212890625 + ] + } + ], + "timestamp": "2025-10-15T21:42:13.290779" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 9.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 9.json" new file mode 100644 index 0000000..e3acb45 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 5\341\204\222\341\205\254 - 9.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 9.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7508177757263184, + "bbox": [ + 1173.4302978515625, + 425.2012939453125, + 1279.53125, + 514.1151733398438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7502933740615845, + "bbox": [ + 210.20669555664062, + 403.5700378417969, + 319.5332336425781, + 495.5364074707031 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6541925668716431, + "bbox": [ + 430.15576171875, + 398.63671875, + 552.0100708007812, + 514.6303100585938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6131829023361206, + "bbox": [ + 1551.9039306640625, + 402.5128479003906, + 1686.8448486328125, + 528.0980224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6118751168251038, + "bbox": [ + 1151.0018310546875, + 2709.41552734375, + 1222.4666748046875, + 2790.322509765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49283769726753235, + "bbox": [ + 191.50885009765625, + 2584.095947265625, + 264.8513488769531, + 2669.792236328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.42905670404434204, + "bbox": [ + 191.80838012695312, + 2918.882568359375, + 278.0151062011719, + 2989.57421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9661281704902649, + "bbox": [ + 188.98069763183594, + 599.98193359375, + 1078.7130126953125, + 2446.7841796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9403825998306274, + "bbox": [ + 1159.5589599609375, + 624.0, + 2042.2353515625, + 2404.83056640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9308292269706726, + "bbox": [ + 1151.96142578125, + 2414.4365234375, + 2050.163330078125, + 2832.35546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9123905301094055, + "bbox": [ + 152.0648956298828, + 369.7189025878906, + 1102.7684326171875, + 2821.31396484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9080262780189514, + "bbox": [ + 185.9227294921875, + 2474.90283203125, + 986.0703735351562, + 2802.582763671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8346694111824036, + "bbox": [ + 1140.543701171875, + 450.7506408691406, + 2096.47900390625, + 2896.9814453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7973261475563049, + "bbox": [ + 1138.9320068359375, + 518.4557495117188, + 2072.438232421875, + 645.1550903320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7943465113639832, + "bbox": [ + 208.7053985595703, + 494.49334716796875, + 1100.00732421875, + 610.1264038085938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7508177757263184, + "bbox": [ + 1173.4302978515625, + 425.2012939453125, + 1279.53125, + 514.1151733398438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7502933740615845, + "bbox": [ + 210.20669555664062, + 403.5700378417969, + 319.5332336425781, + 495.5364074707031 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6541925668716431, + "bbox": [ + 430.15576171875, + 398.63671875, + 552.0100708007812, + 514.6303100585938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6131829023361206, + "bbox": [ + 1551.9039306640625, + 402.5128479003906, + 1686.8448486328125, + 528.0980224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6118751168251038, + "bbox": [ + 1151.0018310546875, + 2709.41552734375, + 1222.4666748046875, + 2790.322509765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49283769726753235, + "bbox": [ + 191.50885009765625, + 2584.095947265625, + 264.8513488769531, + 2669.792236328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.42905670404434204, + "bbox": [ + 191.80838012695312, + 2918.882568359375, + 278.0151062011719, + 2989.57421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9661281704902649, + "bbox": [ + 188.98069763183594, + 599.98193359375, + 1078.7130126953125, + 2446.7841796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9403825998306274, + "bbox": [ + 1159.5589599609375, + 624.0, + 2042.2353515625, + 2404.83056640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9308292269706726, + "bbox": [ + 1151.96142578125, + 2414.4365234375, + 2050.163330078125, + 2832.35546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9123905301094055, + "bbox": [ + 152.0648956298828, + 369.7189025878906, + 1102.7684326171875, + 2821.31396484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9080262780189514, + "bbox": [ + 185.9227294921875, + 2474.90283203125, + 986.0703735351562, + 2802.582763671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8346694111824036, + "bbox": [ + 1140.543701171875, + 450.7506408691406, + 2096.47900390625, + 2896.9814453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7973261475563049, + "bbox": [ + 1138.9320068359375, + 518.4557495117188, + 2072.438232421875, + 645.1550903320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7943465113639832, + "bbox": [ + 208.7053985595703, + 494.49334716796875, + 1100.00732421875, + 610.1264038085938 + ] + } + ], + "timestamp": "2025-10-15T21:42:13.661800" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 18.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 18.json" new file mode 100644 index 0000000..b2c26ff --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 18.json" @@ -0,0 +1,604 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 18.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7988360524177551, + "bbox": [ + 266.6395568847656, + 1754.8955078125, + 373.715087890625, + 1844.17041015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7963445782661438, + "bbox": [ + 1283.26123046875, + 2528.410888671875, + 1389.3795166015625, + 2619.096435546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7702808976173401, + "bbox": [ + 274.08935546875, + 990.58251953125, + 381.21746826171875, + 1085.0325927734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7555468082427979, + "bbox": [ + 1305.8837890625, + 511.416259765625, + 1408.949951171875, + 597.9923095703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7506996989250183, + "bbox": [ + 256.30889892578125, + 2575.3828125, + 360.0710144042969, + 2663.868408203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7245441675186157, + "bbox": [ + 1115.3079833984375, + 1888.2401123046875, + 1220.9700927734375, + 1994.5009765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.686287522315979, + "bbox": [ + 1006.14990234375, + 1182.5496826171875, + 1123.58154296875, + 1306.7569580078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6843833327293396, + "bbox": [ + 1915.1468505859375, + 2777.469970703125, + 2034.399658203125, + 2895.901611328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6344283223152161, + "bbox": [ + 1001.7526245117188, + 2786.904296875, + 1135.7393798828125, + 2915.542724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.615765392780304, + "bbox": [ + 1957.02587890625, + 1497.703369140625, + 2077.727783203125, + 1607.6060791015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5685915350914001, + "bbox": [ + 2138.949462890625, + 3133.7744140625, + 2230.209228515625, + 3208.52392578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9179354310035706, + "bbox": [ + 271.85992431640625, + 1938.2440185546875, + 1221.231689453125, + 2385.56201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9134776592254639, + "bbox": [ + 1244.6807861328125, + 469.7906188964844, + 2331.485595703125, + 1646.0828857421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9090062975883484, + "bbox": [ + 273.423828125, + 1222.642822265625, + 1067.2857666015625, + 1594.5966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9042997360229492, + "bbox": [ + 250.50770568847656, + 966.7921142578125, + 1254.7012939453125, + 1630.1319580078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8994130492210388, + "bbox": [ + 1286.73583984375, + 2752.8662109375, + 1684.2568359375, + 3114.019775390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8972051739692688, + "bbox": [ + 223.91647338867188, + 1711.00634765625, + 1255.7548828125, + 2426.257568359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8915121555328369, + "bbox": [ + 1244.8941650390625, + 2486.52978515625, + 2299.283935546875, + 3144.2822265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8828334808349609, + "bbox": [ + 207.23873901367188, + 2525.793212890625, + 1216.218505859375, + 3169.38037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8537259697914124, + "bbox": [ + 263.0040283203125, + 2737.02783203125, + 840.6228637695312, + 3097.193359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8298918008804321, + "bbox": [ + 1287.2052001953125, + 2616.00537109375, + 2243.275634765625, + 2747.1064453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8149411082267761, + "bbox": [ + 272.720947265625, + 1084.46875, + 1211.900146484375, + 1209.084228515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.801225483417511, + "bbox": [ + 1309.4150390625, + 606.8284301757812, + 2242.110595703125, + 679.174560546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7463299036026001, + "bbox": [ + 1327.240234375, + 690.3548583984375, + 2201.543701171875, + 1412.5960693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7393862009048462, + "bbox": [ + 260.7271423339844, + 2666.3134765625, + 1170.4888916015625, + 2746.1376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6692609786987305, + "bbox": [ + 254.0052490234375, + 1843.247802734375, + 1121.131103515625, + 1937.787841796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5282578468322754, + "bbox": [ + 258.3882751464844, + 1858.23583984375, + 1143.9510498046875, + 1921.92919921875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7988360524177551, + "bbox": [ + 266.6395568847656, + 1754.8955078125, + 373.715087890625, + 1844.17041015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7963445782661438, + "bbox": [ + 1283.26123046875, + 2528.410888671875, + 1389.3795166015625, + 2619.096435546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7702808976173401, + "bbox": [ + 274.08935546875, + 990.58251953125, + 381.21746826171875, + 1085.0325927734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7555468082427979, + "bbox": [ + 1305.8837890625, + 511.416259765625, + 1408.949951171875, + 597.9923095703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7506996989250183, + "bbox": [ + 256.30889892578125, + 2575.3828125, + 360.0710144042969, + 2663.868408203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7245441675186157, + "bbox": [ + 1115.3079833984375, + 1888.2401123046875, + 1220.9700927734375, + 1994.5009765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.686287522315979, + "bbox": [ + 1006.14990234375, + 1182.5496826171875, + 1123.58154296875, + 1306.7569580078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6843833327293396, + "bbox": [ + 1915.1468505859375, + 2777.469970703125, + 2034.399658203125, + 2895.901611328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6344283223152161, + "bbox": [ + 1001.7526245117188, + 2786.904296875, + 1135.7393798828125, + 2915.542724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.615765392780304, + "bbox": [ + 1957.02587890625, + 1497.703369140625, + 2077.727783203125, + 1607.6060791015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5685915350914001, + "bbox": [ + 2138.949462890625, + 3133.7744140625, + 2230.209228515625, + 3208.52392578125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9179354310035706, + "bbox": [ + 271.85992431640625, + 1938.2440185546875, + 1221.231689453125, + 2385.56201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9134776592254639, + "bbox": [ + 1244.6807861328125, + 469.7906188964844, + 2331.485595703125, + 1646.0828857421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9090062975883484, + "bbox": [ + 273.423828125, + 1222.642822265625, + 1067.2857666015625, + 1594.5966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9042997360229492, + "bbox": [ + 250.50770568847656, + 966.7921142578125, + 1254.7012939453125, + 1630.1319580078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8994130492210388, + "bbox": [ + 1286.73583984375, + 2752.8662109375, + 1684.2568359375, + 3114.019775390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8972051739692688, + "bbox": [ + 223.91647338867188, + 1711.00634765625, + 1255.7548828125, + 2426.257568359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8915121555328369, + "bbox": [ + 1244.8941650390625, + 2486.52978515625, + 2299.283935546875, + 3144.2822265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8828334808349609, + "bbox": [ + 207.23873901367188, + 2525.793212890625, + 1216.218505859375, + 3169.38037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8537259697914124, + "bbox": [ + 263.0040283203125, + 2737.02783203125, + 840.6228637695312, + 3097.193359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8298918008804321, + "bbox": [ + 1287.2052001953125, + 2616.00537109375, + 2243.275634765625, + 2747.1064453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8149411082267761, + "bbox": [ + 272.720947265625, + 1084.46875, + 1211.900146484375, + 1209.084228515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.801225483417511, + "bbox": [ + 1309.4150390625, + 606.8284301757812, + 2242.110595703125, + 679.174560546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7463299036026001, + "bbox": [ + 1327.240234375, + 690.3548583984375, + 2201.543701171875, + 1412.5960693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7393862009048462, + "bbox": [ + 260.7271423339844, + 2666.3134765625, + 1170.4888916015625, + 2746.1376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6692609786987305, + "bbox": [ + 254.0052490234375, + 1843.247802734375, + 1121.131103515625, + 1937.787841796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5282578468322754, + "bbox": [ + 258.3882751464844, + 1858.23583984375, + 1143.9510498046875, + 1921.92919921875 + ] + } + ], + "timestamp": "2025-10-15T21:42:14.012404" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 19.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 19.json" new file mode 100644 index 0000000..42bde12 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 19.json" @@ -0,0 +1,582 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 19.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7799789309501648, + "bbox": [ + 236.42135620117188, + 1491.102294921875, + 346.84930419921875, + 1585.6771240234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7617189288139343, + "bbox": [ + 219.2086181640625, + 2599.630126953125, + 330.7776184082031, + 2693.552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7551347613334656, + "bbox": [ + 251.35203552246094, + 440.0579833984375, + 364.3329772949219, + 534.511474609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7518501877784729, + "bbox": [ + 1274.0404052734375, + 2212.56005859375, + 1381.7314453125, + 2311.947021484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7396827340126038, + "bbox": [ + 1293.3111572265625, + 453.1151123046875, + 1408.1446533203125, + 547.0521240234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6511649489402771, + "bbox": [ + 998.819580078125, + 770.4944458007812, + 1127.314453125, + 898.8392333984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6420676708221436, + "bbox": [ + 901.3938598632812, + 2811.18603515625, + 1026.1092529296875, + 2942.670166015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6324604153633118, + "bbox": [ + 2007.9033203125, + 2409.888671875, + 2142.704833984375, + 2538.485107421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6264545321464539, + "bbox": [ + 940.5663452148438, + 1737.189208984375, + 1051.1849365234375, + 1845.5775146484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5935935974121094, + "bbox": [ + 1875.8968505859375, + 1064.6754150390625, + 2011.4327392578125, + 1199.8419189453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5061771273612976, + "bbox": [ + 218.67897033691406, + 3213.110595703125, + 309.2133483886719, + 3287.694091796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9349602460861206, + "bbox": [ + 195.1258087158203, + 2568.223388671875, + 1223.3797607421875, + 3204.415283203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9268251061439514, + "bbox": [ + 1274.4261474609375, + 2460.904296875, + 2240.489501953125, + 3223.320068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9231505393981934, + "bbox": [ + 1234.6695556640625, + 2191.095947265625, + 2284.1259765625, + 3254.711181640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898586630821228, + "bbox": [ + 241.22059631347656, + 1720.695068359375, + 768.417724609375, + 2097.063232421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8870161771774292, + "bbox": [ + 1294.296875, + 679.7814331054688, + 2282.68994140625, + 1039.0560302734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8789583444595337, + "bbox": [ + 195.89320373535156, + 1455.388427734375, + 1231.9229736328125, + 2160.877197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8771510720252991, + "bbox": [ + 218.3375244140625, + 421.7557067871094, + 1234.836181640625, + 1053.59765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8507099151611328, + "bbox": [ + 1278.712158203125, + 2307.6796875, + 2245.715087890625, + 2441.8017578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8405901193618774, + "bbox": [ + 220.95501708984375, + 2844.141357421875, + 488.1539001464844, + 3193.809814453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8051720261573792, + "bbox": [ + 1285.1673583984375, + 553.9171142578125, + 2265.085205078125, + 681.0060424804688 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7984182238578796, + "bbox": [ + 1257.0264892578125, + 406.44512939453125, + 2346.2001953125, + 1269.261474609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7960759401321411, + "bbox": [ + 233.32398986816406, + 2697.144287109375, + 1179.4000244140625, + 2818.571533203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7676852345466614, + "bbox": [ + 249.72409057617188, + 529.163330078125, + 1009.7285766601562, + 615.5933837890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7640076279640198, + "bbox": [ + 237.64263916015625, + 1589.1578369140625, + 1209.8028564453125, + 1719.4000244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7280345559120178, + "bbox": [ + 250.7264862060547, + 615.6535034179688, + 467.1109313964844, + 988.835205078125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7799789309501648, + "bbox": [ + 236.42135620117188, + 1491.102294921875, + 346.84930419921875, + 1585.6771240234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7617189288139343, + "bbox": [ + 219.2086181640625, + 2599.630126953125, + 330.7776184082031, + 2693.552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7551347613334656, + "bbox": [ + 251.35203552246094, + 440.0579833984375, + 364.3329772949219, + 534.511474609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7518501877784729, + "bbox": [ + 1274.0404052734375, + 2212.56005859375, + 1381.7314453125, + 2311.947021484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7396827340126038, + "bbox": [ + 1293.3111572265625, + 453.1151123046875, + 1408.1446533203125, + 547.0521240234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6511649489402771, + "bbox": [ + 998.819580078125, + 770.4944458007812, + 1127.314453125, + 898.8392333984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6420676708221436, + "bbox": [ + 901.3938598632812, + 2811.18603515625, + 1026.1092529296875, + 2942.670166015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6324604153633118, + "bbox": [ + 2007.9033203125, + 2409.888671875, + 2142.704833984375, + 2538.485107421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6264545321464539, + "bbox": [ + 940.5663452148438, + 1737.189208984375, + 1051.1849365234375, + 1845.5775146484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5935935974121094, + "bbox": [ + 1875.8968505859375, + 1064.6754150390625, + 2011.4327392578125, + 1199.8419189453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5061771273612976, + "bbox": [ + 218.67897033691406, + 3213.110595703125, + 309.2133483886719, + 3287.694091796875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9349602460861206, + "bbox": [ + 195.1258087158203, + 2568.223388671875, + 1223.3797607421875, + 3204.415283203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9268251061439514, + "bbox": [ + 1274.4261474609375, + 2460.904296875, + 2240.489501953125, + 3223.320068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9231505393981934, + "bbox": [ + 1234.6695556640625, + 2191.095947265625, + 2284.1259765625, + 3254.711181640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898586630821228, + "bbox": [ + 241.22059631347656, + 1720.695068359375, + 768.417724609375, + 2097.063232421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8870161771774292, + "bbox": [ + 1294.296875, + 679.7814331054688, + 2282.68994140625, + 1039.0560302734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8789583444595337, + "bbox": [ + 195.89320373535156, + 1455.388427734375, + 1231.9229736328125, + 2160.877197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8771510720252991, + "bbox": [ + 218.3375244140625, + 421.7557067871094, + 1234.836181640625, + 1053.59765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8507099151611328, + "bbox": [ + 1278.712158203125, + 2307.6796875, + 2245.715087890625, + 2441.8017578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8405901193618774, + "bbox": [ + 220.95501708984375, + 2844.141357421875, + 488.1539001464844, + 3193.809814453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8051720261573792, + "bbox": [ + 1285.1673583984375, + 553.9171142578125, + 2265.085205078125, + 681.0060424804688 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7984182238578796, + "bbox": [ + 1257.0264892578125, + 406.44512939453125, + 2346.2001953125, + 1269.261474609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7960759401321411, + "bbox": [ + 233.32398986816406, + 2697.144287109375, + 1179.4000244140625, + 2818.571533203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7676852345466614, + "bbox": [ + 249.72409057617188, + 529.163330078125, + 1009.7285766601562, + 615.5933837890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7640076279640198, + "bbox": [ + 237.64263916015625, + 1589.1578369140625, + 1209.8028564453125, + 1719.4000244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7280345559120178, + "bbox": [ + 250.7264862060547, + 615.6535034179688, + 467.1109313964844, + 988.835205078125 + ] + } + ], + "timestamp": "2025-10-15T21:42:14.360057" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 20.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 20.json" new file mode 100644 index 0000000..a2a4828 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 20.json" @@ -0,0 +1,670 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 20.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7617335915565491, + "bbox": [ + 235.94976806640625, + 1260.341552734375, + 342.07373046875, + 1358.637451171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.754991888999939, + "bbox": [ + 1227.7032470703125, + 439.0233459472656, + 1325.92724609375, + 534.3587646484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7475954294204712, + "bbox": [ + 228.6622772216797, + 2149.2431640625, + 331.0436096191406, + 2244.65673828125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.74605792760849, + "bbox": [ + 240.94383239746094, + 422.1424865722656, + 350.65338134765625, + 522.3436279296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.743106484413147, + "bbox": [ + 1008.3516845703125, + 1509.3255615234375, + 1097.95556640625, + 1610.0994873046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7280753254890442, + "bbox": [ + 1192.5535888671875, + 2321.738037109375, + 1303.6005859375, + 2422.66259765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7185413241386414, + "bbox": [ + 969.41455078125, + 2311.23828125, + 1072.1761474609375, + 2413.27392578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7015545964241028, + "bbox": [ + 1728.59228515625, + 2488.443603515625, + 1843.6575927734375, + 2602.124267578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6297272443771362, + "bbox": [ + 1671.8656005859375, + 1327.094970703125, + 1820.1619873046875, + 1466.4781494140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5902140140533447, + "bbox": [ + 864.98388671875, + 1070.56982421875, + 989.6040649414062, + 1198.7467041015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.581495463848114, + "bbox": [ + 2017.960693359375, + 3083.11376953125, + 2102.345947265625, + 3154.111572265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.44387584924697876, + "bbox": [ + 846.072021484375, + 1063.55517578125, + 1006.9411010742188, + 1216.497314453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9463142156600952, + "bbox": [ + 1212.622802734375, + 758.8275756835938, + 2160.294921875, + 1345.31591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9395202398300171, + "bbox": [ + 212.90879821777344, + 2471.366455078125, + 1130.6544189453125, + 3052.173095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.928021252155304, + "bbox": [ + 240.60340881347656, + 663.1104736328125, + 1084.81103515625, + 1016.5341186523438 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9256405234336853, + "bbox": [ + 1177.194091796875, + 2277.396484375, + 2199.388671875, + 3101.75537109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9166426062583923, + "bbox": [ + 1187.6693115234375, + 2654.62646484375, + 2140.08056640625, + 3071.5703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9090909957885742, + "bbox": [ + 154.2684326171875, + 2103.26220703125, + 1143.5704345703125, + 3115.939208984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9054855108261108, + "bbox": [ + 1205.798828125, + 386.1014404296875, + 2212.686279296875, + 1472.979248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898865818977356, + "bbox": [ + 248.88893127441406, + 1503.84423828125, + 1055.734619140625, + 1829.50634765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8959977030754089, + "bbox": [ + 1230.666748046875, + 535.18017578125, + 2149.8388671875, + 661.29052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8847728371620178, + "bbox": [ + 198.6621856689453, + 402.3240051269531, + 1187.515380859375, + 1058.36328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8811056017875671, + "bbox": [ + 213.63111877441406, + 1237.2928466796875, + 1146.5460205078125, + 1873.2451171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8396086096763611, + "bbox": [ + 228.85977172851562, + 525.4508666992188, + 1150.05810546875, + 647.6519165039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8098872303962708, + "bbox": [ + 1181.025390625, + 2419.885986328125, + 2140.873779296875, + 2545.842041015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8017297387123108, + "bbox": [ + 207.6827392578125, + 2246.136962890625, + 1117.052001953125, + 2369.760009765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7889149785041809, + "bbox": [ + 222.326416015625, + 1354.453125, + 1153.2178955078125, + 1478.2025146484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7090023756027222, + "bbox": [ + 1179.7125244140625, + 2553.3095703125, + 2135.983154296875, + 2639.6474609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6691240072250366, + "bbox": [ + 208.31613159179688, + 2379.58251953125, + 1103.410888671875, + 2471.18408203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6041886806488037, + "bbox": [ + 1207.4659423828125, + 652.74072265625, + 2144.13134765625, + 761.5387573242188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7617335915565491, + "bbox": [ + 235.94976806640625, + 1260.341552734375, + 342.07373046875, + 1358.637451171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.754991888999939, + "bbox": [ + 1227.7032470703125, + 439.0233459472656, + 1325.92724609375, + 534.3587646484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7475954294204712, + "bbox": [ + 228.6622772216797, + 2149.2431640625, + 331.0436096191406, + 2244.65673828125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.74605792760849, + "bbox": [ + 240.94383239746094, + 422.1424865722656, + 350.65338134765625, + 522.3436279296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.743106484413147, + "bbox": [ + 1008.3516845703125, + 1509.3255615234375, + 1097.95556640625, + 1610.0994873046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7280753254890442, + "bbox": [ + 1192.5535888671875, + 2321.738037109375, + 1303.6005859375, + 2422.66259765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7185413241386414, + "bbox": [ + 969.41455078125, + 2311.23828125, + 1072.1761474609375, + 2413.27392578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7015545964241028, + "bbox": [ + 1728.59228515625, + 2488.443603515625, + 1843.6575927734375, + 2602.124267578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6297272443771362, + "bbox": [ + 1671.8656005859375, + 1327.094970703125, + 1820.1619873046875, + 1466.4781494140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5902140140533447, + "bbox": [ + 864.98388671875, + 1070.56982421875, + 989.6040649414062, + 1198.7467041015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.581495463848114, + "bbox": [ + 2017.960693359375, + 3083.11376953125, + 2102.345947265625, + 3154.111572265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.44387584924697876, + "bbox": [ + 846.072021484375, + 1063.55517578125, + 1006.9411010742188, + 1216.497314453125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9463142156600952, + "bbox": [ + 1212.622802734375, + 758.8275756835938, + 2160.294921875, + 1345.31591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9395202398300171, + "bbox": [ + 212.90879821777344, + 2471.366455078125, + 1130.6544189453125, + 3052.173095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.928021252155304, + "bbox": [ + 240.60340881347656, + 663.1104736328125, + 1084.81103515625, + 1016.5341186523438 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9256405234336853, + "bbox": [ + 1177.194091796875, + 2277.396484375, + 2199.388671875, + 3101.75537109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9166426062583923, + "bbox": [ + 1187.6693115234375, + 2654.62646484375, + 2140.08056640625, + 3071.5703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9090909957885742, + "bbox": [ + 154.2684326171875, + 2103.26220703125, + 1143.5704345703125, + 3115.939208984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9054855108261108, + "bbox": [ + 1205.798828125, + 386.1014404296875, + 2212.686279296875, + 1472.979248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898865818977356, + "bbox": [ + 248.88893127441406, + 1503.84423828125, + 1055.734619140625, + 1829.50634765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8959977030754089, + "bbox": [ + 1230.666748046875, + 535.18017578125, + 2149.8388671875, + 661.29052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8847728371620178, + "bbox": [ + 198.6621856689453, + 402.3240051269531, + 1187.515380859375, + 1058.36328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8811056017875671, + "bbox": [ + 213.63111877441406, + 1237.2928466796875, + 1146.5460205078125, + 1873.2451171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8396086096763611, + "bbox": [ + 228.85977172851562, + 525.4508666992188, + 1150.05810546875, + 647.6519165039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8098872303962708, + "bbox": [ + 1181.025390625, + 2419.885986328125, + 2140.873779296875, + 2545.842041015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8017297387123108, + "bbox": [ + 207.6827392578125, + 2246.136962890625, + 1117.052001953125, + 2369.760009765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7889149785041809, + "bbox": [ + 222.326416015625, + 1354.453125, + 1153.2178955078125, + 1478.2025146484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7090023756027222, + "bbox": [ + 1179.7125244140625, + 2553.3095703125, + 2135.983154296875, + 2639.6474609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6691240072250366, + "bbox": [ + 208.31613159179688, + 2379.58251953125, + 1103.410888671875, + 2471.18408203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6041886806488037, + "bbox": [ + 1207.4659423828125, + 652.74072265625, + 2144.13134765625, + 761.5387573242188 + ] + } + ], + "timestamp": "2025-10-15T21:42:14.703251" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 21.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 21.json" new file mode 100644 index 0000000..ec1a163 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 21.json" @@ -0,0 +1,428 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 21.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7609845399856567, + "bbox": [ + 1265.4761962890625, + 460.44146728515625, + 1372.72998046875, + 553.6536865234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7520913481712341, + "bbox": [ + 232.48519897460938, + 578.6051635742188, + 338.0008544921875, + 676.820556640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7501529455184937, + "bbox": [ + 222.1729736328125, + 1845.4884033203125, + 335.4812316894531, + 1948.3370361328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.684562087059021, + "bbox": [ + 805.4273071289062, + 2136.070556640625, + 917.5810546875, + 2245.9453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6613016128540039, + "bbox": [ + 2072.452392578125, + 2524.58740234375, + 2202.64990234375, + 2655.87548828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6394456624984741, + "bbox": [ + 903.0519409179688, + 1262.8487548828125, + 1025.203369140625, + 1389.733154296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5251138806343079, + "bbox": [ + 226.74554443359375, + 3196.202392578125, + 315.4188537597656, + 3265.424072265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3338477909564972, + "bbox": [ + 217.36712646484375, + 3186.787841796875, + 318.413818359375, + 3276.339599609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9344406127929688, + "bbox": [ + 217.66490173339844, + 759.3243408203125, + 1202.80224609375, + 1231.4263916015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267095327377319, + "bbox": [ + 1224.459228515625, + 415.92987060546875, + 2270.26220703125, + 2983.034912109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8998392820358276, + "bbox": [ + 1260.04150390625, + 2516.952392578125, + 2157.68115234375, + 2867.141845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8952497243881226, + "bbox": [ + 213.6790008544922, + 2037.1563720703125, + 619.2114868164062, + 2406.072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8887794613838196, + "bbox": [ + 178.48138427734375, + 1810.49560546875, + 1199.16845703125, + 2447.0244140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8719655871391296, + "bbox": [ + 165.6348876953125, + 537.3223266601562, + 1238.2332763671875, + 1326.4775390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8273245692253113, + "bbox": [ + 1256.1771240234375, + 642.2066650390625, + 2189.99853515625, + 2532.552490234375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7313070893287659, + "bbox": [ + 1271.173095703125, + 550.31201171875, + 1850.9947509765625, + 629.716552734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6807247996330261, + "bbox": [ + 227.22056579589844, + 671.637939453125, + 879.6678466796875, + 747.79052734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5922560691833496, + "bbox": [ + 222.93804931640625, + 1951.6728515625, + 635.1351928710938, + 2017.148681640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.14023226499557495, + "bbox": [ + 1239.450439453125, + 572.3370971679688, + 2176.5283203125, + 2568.470458984375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7609845399856567, + "bbox": [ + 1265.4761962890625, + 460.44146728515625, + 1372.72998046875, + 553.6536865234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7520913481712341, + "bbox": [ + 232.48519897460938, + 578.6051635742188, + 338.0008544921875, + 676.820556640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7501529455184937, + "bbox": [ + 222.1729736328125, + 1845.4884033203125, + 335.4812316894531, + 1948.3370361328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.684562087059021, + "bbox": [ + 805.4273071289062, + 2136.070556640625, + 917.5810546875, + 2245.9453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6613016128540039, + "bbox": [ + 2072.452392578125, + 2524.58740234375, + 2202.64990234375, + 2655.87548828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6394456624984741, + "bbox": [ + 903.0519409179688, + 1262.8487548828125, + 1025.203369140625, + 1389.733154296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5251138806343079, + "bbox": [ + 226.74554443359375, + 3196.202392578125, + 315.4188537597656, + 3265.424072265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3338477909564972, + "bbox": [ + 217.36712646484375, + 3186.787841796875, + 318.413818359375, + 3276.339599609375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9344406127929688, + "bbox": [ + 217.66490173339844, + 759.3243408203125, + 1202.80224609375, + 1231.4263916015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267095327377319, + "bbox": [ + 1224.459228515625, + 415.92987060546875, + 2270.26220703125, + 2983.034912109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8998392820358276, + "bbox": [ + 1260.04150390625, + 2516.952392578125, + 2157.68115234375, + 2867.141845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8952497243881226, + "bbox": [ + 213.6790008544922, + 2037.1563720703125, + 619.2114868164062, + 2406.072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8887794613838196, + "bbox": [ + 178.48138427734375, + 1810.49560546875, + 1199.16845703125, + 2447.0244140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8719655871391296, + "bbox": [ + 165.6348876953125, + 537.3223266601562, + 1238.2332763671875, + 1326.4775390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8273245692253113, + "bbox": [ + 1256.1771240234375, + 642.2066650390625, + 2189.99853515625, + 2532.552490234375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7313070893287659, + "bbox": [ + 1271.173095703125, + 550.31201171875, + 1850.9947509765625, + 629.716552734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6807247996330261, + "bbox": [ + 227.22056579589844, + 671.637939453125, + 879.6678466796875, + 747.79052734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5922560691833496, + "bbox": [ + 222.93804931640625, + 1951.6728515625, + 635.1351928710938, + 2017.148681640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.14023226499557495, + "bbox": [ + 1239.450439453125, + 572.3370971679688, + 2176.5283203125, + 2568.470458984375 + ] + } + ], + "timestamp": "2025-10-15T21:42:15.075448" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 22.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 22.json" new file mode 100644 index 0000000..907c929 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 22.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 22.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7795184254646301, + "bbox": [ + 281.0706787109375, + 451.1649475097656, + 395.5906066894531, + 558.5849609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7511841058731079, + "bbox": [ + 1344.153076171875, + 467.2082824707031, + 1459.4049072265625, + 567.3482055664062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6356146335601807, + "bbox": [ + 2270.834228515625, + 2073.6806640625, + 2395.575927734375, + 2190.188232421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6329180598258972, + "bbox": [ + 1056.0555419921875, + 1869.0460205078125, + 1184.586669921875, + 1997.4613037109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5557655692100525, + "bbox": [ + 2216.745361328125, + 3285.78515625, + 2307.01416015625, + 3362.14306640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.26098957657814026, + "bbox": [ + 2261.696533203125, + 2067.105712890625, + 2410.91455078125, + 2208.152587890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9346016645431519, + "bbox": [ + 217.4479217529297, + 419.4060363769531, + 1283.344482421875, + 2361.360107421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9243698120117188, + "bbox": [ + 264.8602600097656, + 642.5381469726562, + 1254.9383544921875, + 1847.2689208984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9216163158416748, + "bbox": [ + 1314.1058349609375, + 442.07421875, + 2363.4912109375, + 2464.254638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198043346405029, + "bbox": [ + 1328.26171875, + 667.154541015625, + 2336.044677734375, + 1904.79345703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9161653518676758, + "bbox": [ + 1329.2763671875, + 1947.4105224609375, + 2324.307373046875, + 2338.989013671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8980361819267273, + "bbox": [ + 271.90753173828125, + 1893.48974609375, + 878.843994140625, + 2259.13916015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7084015607833862, + "bbox": [ + 1342.1243896484375, + 567.9030151367188, + 2152.659912109375, + 641.7802734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6854962110519409, + "bbox": [ + 291.1196594238281, + 567.5558471679688, + 1138.3717041015625, + 633.0941162109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.3021327257156372, + "bbox": [ + 296.24188232421875, + 557.2056884765625, + 1147.8460693359375, + 650.6898803710938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7795184254646301, + "bbox": [ + 281.0706787109375, + 451.1649475097656, + 395.5906066894531, + 558.5849609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7511841058731079, + "bbox": [ + 1344.153076171875, + 467.2082824707031, + 1459.4049072265625, + 567.3482055664062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6356146335601807, + "bbox": [ + 2270.834228515625, + 2073.6806640625, + 2395.575927734375, + 2190.188232421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6329180598258972, + "bbox": [ + 1056.0555419921875, + 1869.0460205078125, + 1184.586669921875, + 1997.4613037109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5557655692100525, + "bbox": [ + 2216.745361328125, + 3285.78515625, + 2307.01416015625, + 3362.14306640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.26098957657814026, + "bbox": [ + 2261.696533203125, + 2067.105712890625, + 2410.91455078125, + 2208.152587890625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9346016645431519, + "bbox": [ + 217.4479217529297, + 419.4060363769531, + 1283.344482421875, + 2361.360107421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9243698120117188, + "bbox": [ + 264.8602600097656, + 642.5381469726562, + 1254.9383544921875, + 1847.2689208984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9216163158416748, + "bbox": [ + 1314.1058349609375, + 442.07421875, + 2363.4912109375, + 2464.254638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198043346405029, + "bbox": [ + 1328.26171875, + 667.154541015625, + 2336.044677734375, + 1904.79345703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9161653518676758, + "bbox": [ + 1329.2763671875, + 1947.4105224609375, + 2324.307373046875, + 2338.989013671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8980361819267273, + "bbox": [ + 271.90753173828125, + 1893.48974609375, + 878.843994140625, + 2259.13916015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7084015607833862, + "bbox": [ + 1342.1243896484375, + 567.9030151367188, + 2152.659912109375, + 641.7802734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6854962110519409, + "bbox": [ + 291.1196594238281, + 567.5558471679688, + 1138.3717041015625, + 633.0941162109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.3021327257156372, + "bbox": [ + 296.24188232421875, + 557.2056884765625, + 1147.8460693359375, + 650.6898803710938 + ] + } + ], + "timestamp": "2025-10-15T21:42:15.456656" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 23.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 23.json" new file mode 100644 index 0000000..fb5673b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 23.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 23.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654995322227478, + "bbox": [ + 228.7303924560547, + 433.2192687988281, + 345.6019287109375, + 535.1857299804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7458115816116333, + "bbox": [ + 1273.211669921875, + 456.8508605957031, + 1386.8052978515625, + 554.6439819335938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6103271245956421, + "bbox": [ + 908.0278930664062, + 2835.655517578125, + 1056.2725830078125, + 2989.95703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6039152145385742, + "bbox": [ + 1666.9869384765625, + 2479.552734375, + 1797.5343017578125, + 2601.17041015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.47475534677505493, + "bbox": [ + 217.02630615234375, + 3150.31201171875, + 308.2370300292969, + 3221.366943359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.25467148423194885, + "bbox": [ + 202.75096130371094, + 3138.69677734375, + 313.9153137207031, + 3234.106689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9485726952552795, + "bbox": [ + 206.61221313476562, + 671.940185546875, + 1193.4862060546875, + 2212.44384765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9381181001663208, + "bbox": [ + 199.09536743164062, + 2257.632568359375, + 1177.6119384765625, + 2867.08984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9314593076705933, + "bbox": [ + 1267.08740234375, + 636.4830322265625, + 2236.609130859375, + 1944.1318359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9292885661125183, + "bbox": [ + 183.15655517578125, + 421.0118408203125, + 1215.676025390625, + 2940.68994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9245951771736145, + "bbox": [ + 1228.47607421875, + 421.11102294921875, + 2355.71826171875, + 2645.02685546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9102753400802612, + "bbox": [ + 1263.0137939453125, + 2008.4429931640625, + 2251.163330078125, + 2472.57666015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8342044949531555, + "bbox": [ + 234.9220733642578, + 537.8096923828125, + 1190.3470458984375, + 665.8623046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6448330283164978, + "bbox": [ + 1283.9390869140625, + 557.1524658203125, + 1821.07470703125, + 621.3471069335938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654995322227478, + "bbox": [ + 228.7303924560547, + 433.2192687988281, + 345.6019287109375, + 535.1857299804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7458115816116333, + "bbox": [ + 1273.211669921875, + 456.8508605957031, + 1386.8052978515625, + 554.6439819335938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6103271245956421, + "bbox": [ + 908.0278930664062, + 2835.655517578125, + 1056.2725830078125, + 2989.95703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6039152145385742, + "bbox": [ + 1666.9869384765625, + 2479.552734375, + 1797.5343017578125, + 2601.17041015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.47475534677505493, + "bbox": [ + 217.02630615234375, + 3150.31201171875, + 308.2370300292969, + 3221.366943359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.25467148423194885, + "bbox": [ + 202.75096130371094, + 3138.69677734375, + 313.9153137207031, + 3234.106689453125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9485726952552795, + "bbox": [ + 206.61221313476562, + 671.940185546875, + 1193.4862060546875, + 2212.44384765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9381181001663208, + "bbox": [ + 199.09536743164062, + 2257.632568359375, + 1177.6119384765625, + 2867.08984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9314593076705933, + "bbox": [ + 1267.08740234375, + 636.4830322265625, + 2236.609130859375, + 1944.1318359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9292885661125183, + "bbox": [ + 183.15655517578125, + 421.0118408203125, + 1215.676025390625, + 2940.68994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9245951771736145, + "bbox": [ + 1228.47607421875, + 421.11102294921875, + 2355.71826171875, + 2645.02685546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9102753400802612, + "bbox": [ + 1263.0137939453125, + 2008.4429931640625, + 2251.163330078125, + 2472.57666015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8342044949531555, + "bbox": [ + 234.9220733642578, + 537.8096923828125, + 1190.3470458984375, + 665.8623046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6448330283164978, + "bbox": [ + 1283.9390869140625, + 557.1524658203125, + 1821.07470703125, + 621.3471069335938 + ] + } + ], + "timestamp": "2025-10-15T21:42:15.850428" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 24.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 24.json" new file mode 100644 index 0000000..6cc15d5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 24.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 24.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7667497992515564, + "bbox": [ + 258.83489990234375, + 440.5694580078125, + 379.6180419921875, + 547.91552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7625042200088501, + "bbox": [ + 1327.470703125, + 462.8982849121094, + 1441.1715087890625, + 561.473876953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6474075317382812, + "bbox": [ + 1798.9244384765625, + 2369.840576171875, + 1961.3839111328125, + 2525.567626953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6122598648071289, + "bbox": [ + 1066.4884033203125, + 2331.44384765625, + 1198.9454345703125, + 2462.427001953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5640543699264526, + "bbox": [ + 2212.030517578125, + 3210.279296875, + 2301.90576171875, + 3284.257080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9440351128578186, + "bbox": [ + 230.3463134765625, + 411.798828125, + 1271.197021484375, + 2802.266845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.940769374370575, + "bbox": [ + 1333.4771728515625, + 1842.7164306640625, + 2322.935302734375, + 2382.621826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9402076601982117, + "bbox": [ + 252.21615600585938, + 629.1215209960938, + 1235.788330078125, + 2294.918212890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9322625994682312, + "bbox": [ + 1305.978759765625, + 654.1461181640625, + 2316.10107421875, + 1829.6925048828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8957377076148987, + "bbox": [ + 257.6315612792969, + 2323.16943359375, + 1185.0843505859375, + 2703.41748046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8766340017318726, + "bbox": [ + 1291.2962646484375, + 418.64752197265625, + 2390.367919921875, + 2574.923095703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7723098993301392, + "bbox": [ + 266.4828796386719, + 531.5541381835938, + 825.0005493164062, + 618.4894409179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7396525740623474, + "bbox": [ + 1328.3720703125, + 552.819580078125, + 1949.468994140625, + 637.3086547851562 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7667497992515564, + "bbox": [ + 258.83489990234375, + 440.5694580078125, + 379.6180419921875, + 547.91552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7625042200088501, + "bbox": [ + 1327.470703125, + 462.8982849121094, + 1441.1715087890625, + 561.473876953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6474075317382812, + "bbox": [ + 1798.9244384765625, + 2369.840576171875, + 1961.3839111328125, + 2525.567626953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6122598648071289, + "bbox": [ + 1066.4884033203125, + 2331.44384765625, + 1198.9454345703125, + 2462.427001953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5640543699264526, + "bbox": [ + 2212.030517578125, + 3210.279296875, + 2301.90576171875, + 3284.257080078125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9440351128578186, + "bbox": [ + 230.3463134765625, + 411.798828125, + 1271.197021484375, + 2802.266845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.940769374370575, + "bbox": [ + 1333.4771728515625, + 1842.7164306640625, + 2322.935302734375, + 2382.621826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9402076601982117, + "bbox": [ + 252.21615600585938, + 629.1215209960938, + 1235.788330078125, + 2294.918212890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9322625994682312, + "bbox": [ + 1305.978759765625, + 654.1461181640625, + 2316.10107421875, + 1829.6925048828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8957377076148987, + "bbox": [ + 257.6315612792969, + 2323.16943359375, + 1185.0843505859375, + 2703.41748046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8766340017318726, + "bbox": [ + 1291.2962646484375, + 418.64752197265625, + 2390.367919921875, + 2574.923095703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7723098993301392, + "bbox": [ + 266.4828796386719, + 531.5541381835938, + 825.0005493164062, + 618.4894409179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7396525740623474, + "bbox": [ + 1328.3720703125, + 552.819580078125, + 1949.468994140625, + 637.3086547851562 + ] + } + ], + "timestamp": "2025-10-15T21:42:16.256112" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 25.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 25.json" new file mode 100644 index 0000000..56c4f74 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 25.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 25.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7421303391456604, + "bbox": [ + 241.14080810546875, + 416.3816833496094, + 352.88690185546875, + 511.4723205566406 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7394232749938965, + "bbox": [ + 1258.4024658203125, + 429.98980712890625, + 1368.412841796875, + 526.475830078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7245084047317505, + "bbox": [ + 1801.9591064453125, + 419.2466125488281, + 1932.7330322265625, + 536.67822265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6493656635284424, + "bbox": [ + 866.092529296875, + 495.0104675292969, + 981.1055908203125, + 602.8601684570312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.42071205377578735, + "bbox": [ + 238.50132751464844, + 3077.484619140625, + 331.3274841308594, + 3155.2998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.26004695892333984, + "bbox": [ + 853.944580078125, + 485.6091003417969, + 990.0341796875, + 616.432373046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9469874501228333, + "bbox": [ + 1261.5064697265625, + 604.6077880859375, + 2195.870361328125, + 1890.533447265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9465720057487488, + "bbox": [ + 1230.3621826171875, + 385.51763916015625, + 2235.49072265625, + 2420.977294921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9135652184486389, + "bbox": [ + 211.06617736816406, + 597.3837890625, + 1168.9173583984375, + 2900.891845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8991339802742004, + "bbox": [ + 1254.18701171875, + 1947.0870361328125, + 2180.161865234375, + 2374.337646484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8678565621376038, + "bbox": [ + 167.61598205566406, + 405.13336181640625, + 1186.7459716796875, + 2929.685302734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7666568756103516, + "bbox": [ + 1270.4747314453125, + 525.1801147460938, + 2006.163818359375, + 618.0382080078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7213130593299866, + "bbox": [ + 246.58572387695312, + 508.7413635253906, + 834.2227783203125, + 587.8153076171875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7421303391456604, + "bbox": [ + 241.14080810546875, + 416.3816833496094, + 352.88690185546875, + 511.4723205566406 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7394232749938965, + "bbox": [ + 1258.4024658203125, + 429.98980712890625, + 1368.412841796875, + 526.475830078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7245084047317505, + "bbox": [ + 1801.9591064453125, + 419.2466125488281, + 1932.7330322265625, + 536.67822265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6493656635284424, + "bbox": [ + 866.092529296875, + 495.0104675292969, + 981.1055908203125, + 602.8601684570312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.42071205377578735, + "bbox": [ + 238.50132751464844, + 3077.484619140625, + 331.3274841308594, + 3155.2998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.26004695892333984, + "bbox": [ + 853.944580078125, + 485.6091003417969, + 990.0341796875, + 616.432373046875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9469874501228333, + "bbox": [ + 1261.5064697265625, + 604.6077880859375, + 2195.870361328125, + 1890.533447265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9465720057487488, + "bbox": [ + 1230.3621826171875, + 385.51763916015625, + 2235.49072265625, + 2420.977294921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9135652184486389, + "bbox": [ + 211.06617736816406, + 597.3837890625, + 1168.9173583984375, + 2900.891845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8991339802742004, + "bbox": [ + 1254.18701171875, + 1947.0870361328125, + 2180.161865234375, + 2374.337646484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8678565621376038, + "bbox": [ + 167.61598205566406, + 405.13336181640625, + 1186.7459716796875, + 2929.685302734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7666568756103516, + "bbox": [ + 1270.4747314453125, + 525.1801147460938, + 2006.163818359375, + 618.0382080078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7213130593299866, + "bbox": [ + 246.58572387695312, + 508.7413635253906, + 834.2227783203125, + 587.8153076171875 + ] + } + ], + "timestamp": "2025-10-15T21:42:16.652673" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 26.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 26.json" new file mode 100644 index 0000000..43dcd9e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 26.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 26.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7670165300369263, + "bbox": [ + 1345.222900390625, + 455.4881286621094, + 1459.423583984375, + 551.0560913085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7657334804534912, + "bbox": [ + 287.40631103515625, + 442.2474365234375, + 404.76336669921875, + 541.477783203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6469530463218689, + "bbox": [ + 790.02783203125, + 408.6924133300781, + 915.4380493164062, + 531.4673461914062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6160662174224854, + "bbox": [ + 1708.2203369140625, + 433.8625793457031, + 1852.505615234375, + 573.0357055664062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5654496550559998, + "bbox": [ + 2232.551513671875, + 3211.634765625, + 2323.775390625, + 3290.13330078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9186155796051025, + "bbox": [ + 286.39453125, + 632.7449340820312, + 1255.2913818359375, + 2753.25439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9177879095077515, + "bbox": [ + 1344.95361328125, + 2637.765625, + 2073.613525390625, + 3003.619873046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9041714668273926, + "bbox": [ + 290.95855712890625, + 2750.672607421875, + 912.4373779296875, + 3117.7109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9039917588233948, + "bbox": [ + 1342.7130126953125, + 684.3690795898438, + 2285.545166015625, + 2577.762451171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9029384851455688, + "bbox": [ + 237.6697235107422, + 409.00830078125, + 1272.479736328125, + 3103.65869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9007740616798401, + "bbox": [ + 1310.8316650390625, + 406.6678466796875, + 2488.408203125, + 3088.4248046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8320532441139221, + "bbox": [ + 270.7789001464844, + 538.1980590820312, + 1267.8721923828125, + 671.5665893554688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8263663649559021, + "bbox": [ + 1349.6661376953125, + 557.2345581054688, + 2324.2939453125, + 679.1968383789062 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7670165300369263, + "bbox": [ + 1345.222900390625, + 455.4881286621094, + 1459.423583984375, + 551.0560913085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7657334804534912, + "bbox": [ + 287.40631103515625, + 442.2474365234375, + 404.76336669921875, + 541.477783203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6469530463218689, + "bbox": [ + 790.02783203125, + 408.6924133300781, + 915.4380493164062, + 531.4673461914062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6160662174224854, + "bbox": [ + 1708.2203369140625, + 433.8625793457031, + 1852.505615234375, + 573.0357055664062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5654496550559998, + "bbox": [ + 2232.551513671875, + 3211.634765625, + 2323.775390625, + 3290.13330078125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9186155796051025, + "bbox": [ + 286.39453125, + 632.7449340820312, + 1255.2913818359375, + 2753.25439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9177879095077515, + "bbox": [ + 1344.95361328125, + 2637.765625, + 2073.613525390625, + 3003.619873046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9041714668273926, + "bbox": [ + 290.95855712890625, + 2750.672607421875, + 912.4373779296875, + 3117.7109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9039917588233948, + "bbox": [ + 1342.7130126953125, + 684.3690795898438, + 2285.545166015625, + 2577.762451171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9029384851455688, + "bbox": [ + 237.6697235107422, + 409.00830078125, + 1272.479736328125, + 3103.65869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9007740616798401, + "bbox": [ + 1310.8316650390625, + 406.6678466796875, + 2488.408203125, + 3088.4248046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8320532441139221, + "bbox": [ + 270.7789001464844, + 538.1980590820312, + 1267.8721923828125, + 671.5665893554688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8263663649559021, + "bbox": [ + 1349.6661376953125, + 557.2345581054688, + 2324.2939453125, + 679.1968383789062 + ] + } + ], + "timestamp": "2025-10-15T21:42:17.035272" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 27.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 27.json" new file mode 100644 index 0000000..6bf0f40 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 27.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 27.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7629451751708984, + "bbox": [ + 1226.6607666015625, + 431.4805908203125, + 1332.24755859375, + 527.6419067382812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7445833086967468, + "bbox": [ + 237.05784606933594, + 417.6116943359375, + 348.8619689941406, + 513.4798583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.65446937084198, + "bbox": [ + 813.6600341796875, + 2081.550537109375, + 945.07958984375, + 2225.9970703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.638734757900238, + "bbox": [ + 1589.9998779296875, + 1989.6064453125, + 1713.710693359375, + 2105.571044921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.48045268654823303, + "bbox": [ + 221.5921173095703, + 3024.630126953125, + 306.59747314453125, + 3091.858154296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3522263765335083, + "bbox": [ + 1577.0982666015625, + 1980.409423828125, + 1728.65478515625, + 2122.312255859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.25073206424713135, + "bbox": [ + 208.8902130126953, + 3014.2138671875, + 311.88079833984375, + 3105.6123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9425053000450134, + "bbox": [ + 1210.9202880859375, + 654.5132446289062, + 2160.998779296875, + 1989.579345703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9351682662963867, + "bbox": [ + 225.16668701171875, + 581.0144653320312, + 1145.6309814453125, + 2010.2855224609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9316285252571106, + "bbox": [ + 202.10169982910156, + 394.2331848144531, + 1154.2000732421875, + 2274.050048828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9142103791236877, + "bbox": [ + 1197.5684814453125, + 473.8812255859375, + 2158.3818359375, + 2160.2890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8653833270072937, + "bbox": [ + 1219.4805908203125, + 525.8115844726562, + 2147.09765625, + 648.558349609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7658183574676514, + "bbox": [ + 245.54653930664062, + 500.9640808105469, + 990.9666137695312, + 592.4256591796875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7629451751708984, + "bbox": [ + 1226.6607666015625, + 431.4805908203125, + 1332.24755859375, + 527.6419067382812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7445833086967468, + "bbox": [ + 237.05784606933594, + 417.6116943359375, + 348.8619689941406, + 513.4798583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.65446937084198, + "bbox": [ + 813.6600341796875, + 2081.550537109375, + 945.07958984375, + 2225.9970703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.638734757900238, + "bbox": [ + 1589.9998779296875, + 1989.6064453125, + 1713.710693359375, + 2105.571044921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.48045268654823303, + "bbox": [ + 221.5921173095703, + 3024.630126953125, + 306.59747314453125, + 3091.858154296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3522263765335083, + "bbox": [ + 1577.0982666015625, + 1980.409423828125, + 1728.65478515625, + 2122.312255859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.25073206424713135, + "bbox": [ + 208.8902130126953, + 3014.2138671875, + 311.88079833984375, + 3105.6123046875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9425053000450134, + "bbox": [ + 1210.9202880859375, + 654.5132446289062, + 2160.998779296875, + 1989.579345703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9351682662963867, + "bbox": [ + 225.16668701171875, + 581.0144653320312, + 1145.6309814453125, + 2010.2855224609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9316285252571106, + "bbox": [ + 202.10169982910156, + 394.2331848144531, + 1154.2000732421875, + 2274.050048828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9142103791236877, + "bbox": [ + 1197.5684814453125, + 473.8812255859375, + 2158.3818359375, + 2160.2890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8653833270072937, + "bbox": [ + 1219.4805908203125, + 525.8115844726562, + 2147.09765625, + 648.558349609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7658183574676514, + "bbox": [ + 245.54653930664062, + 500.9640808105469, + 990.9666137695312, + 592.4256591796875 + ] + } + ], + "timestamp": "2025-10-15T21:42:17.423270" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 28.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 28.json" new file mode 100644 index 0000000..f134cd4 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 28.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 28.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7724066376686096, + "bbox": [ + 1259.1282958984375, + 432.7243347167969, + 1366.846435546875, + 528.693603515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7565213441848755, + "bbox": [ + 270.1709899902344, + 525.3378295898438, + 379.07977294921875, + 625.3421630859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6693642139434814, + "bbox": [ + 1691.18408203125, + 2195.766357421875, + 1807.859375, + 2301.606201171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6524773836135864, + "bbox": [ + 861.5280151367188, + 2070.148681640625, + 986.4307861328125, + 2203.802978515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5644363760948181, + "bbox": [ + 2073.995849609375, + 3004.167236328125, + 2160.699951171875, + 3077.295654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.45235398411750793, + "bbox": [ + 835.8550415039062, + 2063.509521484375, + 1004.3845825195312, + 2220.439208984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2364511638879776, + "bbox": [ + 1680.267578125, + 2191.765380859375, + 1820.362060546875, + 2321.32177734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9347376823425293, + "bbox": [ + 1246.3223876953125, + 528.80517578125, + 2178.835693359375, + 1816.5362548828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9264846444129944, + "bbox": [ + 258.80523681640625, + 607.8046264648438, + 1182.5933837890625, + 1984.2490234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9128454923629761, + "bbox": [ + 1226.43896484375, + 475.4956359863281, + 2209.617431640625, + 2278.319580078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9066546559333801, + "bbox": [ + 210.298828125, + 390.4778747558594, + 1199.490478515625, + 2445.0556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898546576499939, + "bbox": [ + 1245.5506591796875, + 1840.7978515625, + 2124.052001953125, + 2214.091064453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7990778088569641, + "bbox": [ + 251.93734741210938, + 2006.59228515625, + 600.7636108398438, + 2361.75 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7903141975402832, + "bbox": [ + 246.685546875, + 406.2210998535156, + 1159.241455078125, + 498.7187805175781 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.1524120420217514, + "bbox": [ + 245.6783447265625, + 2005.6851806640625, + 902.2305908203125, + 2357.501953125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7724066376686096, + "bbox": [ + 1259.1282958984375, + 432.7243347167969, + 1366.846435546875, + 528.693603515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7565213441848755, + "bbox": [ + 270.1709899902344, + 525.3378295898438, + 379.07977294921875, + 625.3421630859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6693642139434814, + "bbox": [ + 1691.18408203125, + 2195.766357421875, + 1807.859375, + 2301.606201171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6524773836135864, + "bbox": [ + 861.5280151367188, + 2070.148681640625, + 986.4307861328125, + 2203.802978515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5644363760948181, + "bbox": [ + 2073.995849609375, + 3004.167236328125, + 2160.699951171875, + 3077.295654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.45235398411750793, + "bbox": [ + 835.8550415039062, + 2063.509521484375, + 1004.3845825195312, + 2220.439208984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2364511638879776, + "bbox": [ + 1680.267578125, + 2191.765380859375, + 1820.362060546875, + 2321.32177734375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9347376823425293, + "bbox": [ + 1246.3223876953125, + 528.80517578125, + 2178.835693359375, + 1816.5362548828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9264846444129944, + "bbox": [ + 258.80523681640625, + 607.8046264648438, + 1182.5933837890625, + 1984.2490234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9128454923629761, + "bbox": [ + 1226.43896484375, + 475.4956359863281, + 2209.617431640625, + 2278.319580078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9066546559333801, + "bbox": [ + 210.298828125, + 390.4778747558594, + 1199.490478515625, + 2445.0556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898546576499939, + "bbox": [ + 1245.5506591796875, + 1840.7978515625, + 2124.052001953125, + 2214.091064453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7990778088569641, + "bbox": [ + 251.93734741210938, + 2006.59228515625, + 600.7636108398438, + 2361.75 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7903141975402832, + "bbox": [ + 246.685546875, + 406.2210998535156, + 1159.241455078125, + 498.7187805175781 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.1524120420217514, + "bbox": [ + 245.6783447265625, + 2005.6851806640625, + 902.2305908203125, + 2357.501953125 + ] + } + ], + "timestamp": "2025-10-15T21:42:17.783723" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 29.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 29.json" new file mode 100644 index 0000000..5d850ad --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 29.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 29.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7478845119476318, + "bbox": [ + 239.27841186523438, + 447.50390625, + 357.9844970703125, + 554.5797729492188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7387045621871948, + "bbox": [ + 1273.8121337890625, + 457.00518798828125, + 1390.1126708984375, + 561.6438598632812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209024786949158, + "bbox": [ + 1746.133056640625, + 2365.487548828125, + 1900.2987060546875, + 2518.781982421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6102827191352844, + "bbox": [ + 630.2962646484375, + 2185.74658203125, + 779.4131469726562, + 2334.837158203125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.52583247423172, + "bbox": [ + 230.3710174560547, + 3191.055419921875, + 322.3893737792969, + 3268.047607421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9472480416297913, + "bbox": [ + 1263.2137451171875, + 571.4367065429688, + 2237.711181640625, + 1790.8809814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9438791275024414, + "bbox": [ + 218.17445373535156, + 568.1755981445312, + 1196.908203125, + 1750.872314453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9330787062644958, + "bbox": [ + 1265.666259765625, + 1814.294189453125, + 2230.926025390625, + 2363.1806640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.921006977558136, + "bbox": [ + 239.6374053955078, + 1752.021240234375, + 742.9075927734375, + 2120.180908203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8912978768348694, + "bbox": [ + 1238.6619873046875, + 422.170166015625, + 2265.972900390625, + 2486.128662109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8790758848190308, + "bbox": [ + 200.7998046875, + 396.44677734375, + 1217.9090576171875, + 2299.3212890625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7478845119476318, + "bbox": [ + 239.27841186523438, + 447.50390625, + 357.9844970703125, + 554.5797729492188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7387045621871948, + "bbox": [ + 1273.8121337890625, + 457.00518798828125, + 1390.1126708984375, + 561.6438598632812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209024786949158, + "bbox": [ + 1746.133056640625, + 2365.487548828125, + 1900.2987060546875, + 2518.781982421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6102827191352844, + "bbox": [ + 630.2962646484375, + 2185.74658203125, + 779.4131469726562, + 2334.837158203125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.52583247423172, + "bbox": [ + 230.3710174560547, + 3191.055419921875, + 322.3893737792969, + 3268.047607421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9472480416297913, + "bbox": [ + 1263.2137451171875, + 571.4367065429688, + 2237.711181640625, + 1790.8809814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9438791275024414, + "bbox": [ + 218.17445373535156, + 568.1755981445312, + 1196.908203125, + 1750.872314453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9330787062644958, + "bbox": [ + 1265.666259765625, + 1814.294189453125, + 2230.926025390625, + 2363.1806640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.921006977558136, + "bbox": [ + 239.6374053955078, + 1752.021240234375, + 742.9075927734375, + 2120.180908203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8912978768348694, + "bbox": [ + 1238.6619873046875, + 422.170166015625, + 2265.972900390625, + 2486.128662109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8790758848190308, + "bbox": [ + 200.7998046875, + 396.44677734375, + 1217.9090576171875, + 2299.3212890625 + ] + } + ], + "timestamp": "2025-10-15T21:42:18.147253" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 30.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 30.json" new file mode 100644 index 0000000..c976c18 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 30.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 30.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7611750960350037, + "bbox": [ + 266.7918395996094, + 423.0800476074219, + 372.1796875, + 513.7601318359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7512646913528442, + "bbox": [ + 1241.165771484375, + 594.25732421875, + 1344.6141357421875, + 688.2560424804688 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6790172457695007, + "bbox": [ + 524.0193481445312, + 1924.8118896484375, + 658.0245361328125, + 2057.033447265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6072844862937927, + "bbox": [ + 1315.171875, + 2378.080322265625, + 1451.56494140625, + 2510.37255859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5706136226654053, + "bbox": [ + 2060.8662109375, + 2995.408447265625, + 2147.43896484375, + 3068.205322265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9384544491767883, + "bbox": [ + 259.1288146972656, + 584.7393188476562, + 1172.3184814453125, + 1911.7039794921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9344468712806702, + "bbox": [ + 1222.38525390625, + 480.3403625488281, + 2227.930419921875, + 2866.1455078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9326108694076538, + "bbox": [ + 1219.9033203125, + 707.8358154296875, + 2143.001220703125, + 2479.75146484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9125939011573792, + "bbox": [ + 219.2490692138672, + 401.7417907714844, + 1193.0205078125, + 2118.626220703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8437103629112244, + "bbox": [ + 1228.490966796875, + 2501.2138671875, + 2040.79443359375, + 2727.453857421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8432681560516357, + "bbox": [ + 1245.2083740234375, + 417.77978515625, + 2168.982666015625, + 545.6913452148438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7915722727775574, + "bbox": [ + 261.16705322265625, + 510.0828552246094, + 900.70361328125, + 598.0518798828125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7611750960350037, + "bbox": [ + 266.7918395996094, + 423.0800476074219, + 372.1796875, + 513.7601318359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7512646913528442, + "bbox": [ + 1241.165771484375, + 594.25732421875, + 1344.6141357421875, + 688.2560424804688 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6790172457695007, + "bbox": [ + 524.0193481445312, + 1924.8118896484375, + 658.0245361328125, + 2057.033447265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6072844862937927, + "bbox": [ + 1315.171875, + 2378.080322265625, + 1451.56494140625, + 2510.37255859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5706136226654053, + "bbox": [ + 2060.8662109375, + 2995.408447265625, + 2147.43896484375, + 3068.205322265625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9384544491767883, + "bbox": [ + 259.1288146972656, + 584.7393188476562, + 1172.3184814453125, + 1911.7039794921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9344468712806702, + "bbox": [ + 1222.38525390625, + 480.3403625488281, + 2227.930419921875, + 2866.1455078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9326108694076538, + "bbox": [ + 1219.9033203125, + 707.8358154296875, + 2143.001220703125, + 2479.75146484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9125939011573792, + "bbox": [ + 219.2490692138672, + 401.7417907714844, + 1193.0205078125, + 2118.626220703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8437103629112244, + "bbox": [ + 1228.490966796875, + 2501.2138671875, + 2040.79443359375, + 2727.453857421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8432681560516357, + "bbox": [ + 1245.2083740234375, + 417.77978515625, + 2168.982666015625, + 545.6913452148438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7915722727775574, + "bbox": [ + 261.16705322265625, + 510.0828552246094, + 900.70361328125, + 598.0518798828125 + ] + } + ], + "timestamp": "2025-10-15T21:42:18.514371" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 31.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 31.json" new file mode 100644 index 0000000..9b62111 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 31.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 31.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7614631652832031, + "bbox": [ + 224.5087890625, + 398.6302795410156, + 331.80224609375, + 496.1607360839844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7323277592658997, + "bbox": [ + 1180.23095703125, + 575.7809448242188, + 1284.7669677734375, + 668.2564086914062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6479072570800781, + "bbox": [ + 601.4420166015625, + 402.2400207519531, + 711.2244262695312, + 508.0434265136719 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6271153092384338, + "bbox": [ + 1510.73876953125, + 552.88916015625, + 1634.616455078125, + 673.3267211914062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5133873224258423, + "bbox": [ + 186.88575744628906, + 2911.78466796875, + 274.33282470703125, + 2982.877685546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9613595604896545, + "bbox": [ + 154.57992553710938, + 364.99127197265625, + 1111.3770751953125, + 2621.02001953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9475172162055969, + "bbox": [ + 177.88113403320312, + 536.1973266601562, + 1092.2427978515625, + 2328.58056640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9266027808189392, + "bbox": [ + 1167.377197265625, + 672.6294555664062, + 2103.595458984375, + 2225.301025390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9130634665489197, + "bbox": [ + 1157.2149658203125, + 421.1015319824219, + 2137.074462890625, + 2405.45556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8513413071632385, + "bbox": [ + 184.75196838378906, + 2349.957763671875, + 931.402587890625, + 2562.699951171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.850841760635376, + "bbox": [ + 1176.6622314453125, + 409.95831298828125, + 2102.201171875, + 538.0986938476562 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7614631652832031, + "bbox": [ + 224.5087890625, + 398.6302795410156, + 331.80224609375, + 496.1607360839844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7323277592658997, + "bbox": [ + 1180.23095703125, + 575.7809448242188, + 1284.7669677734375, + 668.2564086914062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6479072570800781, + "bbox": [ + 601.4420166015625, + 402.2400207519531, + 711.2244262695312, + 508.0434265136719 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6271153092384338, + "bbox": [ + 1510.73876953125, + 552.88916015625, + 1634.616455078125, + 673.3267211914062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5133873224258423, + "bbox": [ + 186.88575744628906, + 2911.78466796875, + 274.33282470703125, + 2982.877685546875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9613595604896545, + "bbox": [ + 154.57992553710938, + 364.99127197265625, + 1111.3770751953125, + 2621.02001953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9475172162055969, + "bbox": [ + 177.88113403320312, + 536.1973266601562, + 1092.2427978515625, + 2328.58056640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9266027808189392, + "bbox": [ + 1167.377197265625, + 672.6294555664062, + 2103.595458984375, + 2225.301025390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9130634665489197, + "bbox": [ + 1157.2149658203125, + 421.1015319824219, + 2137.074462890625, + 2405.45556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8513413071632385, + "bbox": [ + 184.75196838378906, + 2349.957763671875, + 931.402587890625, + 2562.699951171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.850841760635376, + "bbox": [ + 1176.6622314453125, + 409.95831298828125, + 2102.201171875, + 538.0986938476562 + ] + } + ], + "timestamp": "2025-10-15T21:42:18.863868" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 32.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 32.json" new file mode 100644 index 0000000..ec99b59 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 32.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 32.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7473788857460022, + "bbox": [ + 256.6462707519531, + 414.59234619140625, + 377.5392150878906, + 524.4989013671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7459302544593811, + "bbox": [ + 1277.77197265625, + 433.1217041015625, + 1394.7154541015625, + 535.6997680664062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7229082584381104, + "bbox": [ + 1688.562744140625, + 416.6376647949219, + 1821.5228271484375, + 537.8909301757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6216470003128052, + "bbox": [ + 543.21337890625, + 414.53802490234375, + 678.0364990234375, + 542.1803588867188 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.580826461315155, + "bbox": [ + 2115.922119140625, + 3121.437255859375, + 2201.80908203125, + 3193.328857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9516152143478394, + "bbox": [ + 238.84461975097656, + 550.5658569335938, + 1198.468994140625, + 2048.26318359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9407613277435303, + "bbox": [ + 1259.935791015625, + 666.7273559570312, + 2258.46240234375, + 2101.78125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.938447117805481, + "bbox": [ + 199.93731689453125, + 367.5056457519531, + 1226.080810546875, + 2285.20556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9105662703514099, + "bbox": [ + 1267.262939453125, + 2121.923828125, + 1916.944580078125, + 2553.454345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9095644354820251, + "bbox": [ + 1237.24169921875, + 400.4144287109375, + 2317.078369140625, + 2610.015380859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8045415282249451, + "bbox": [ + 1265.9334716796875, + 538.101806640625, + 2224.9912109375, + 656.2567138671875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7473788857460022, + "bbox": [ + 256.6462707519531, + 414.59234619140625, + 377.5392150878906, + 524.4989013671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7459302544593811, + "bbox": [ + 1277.77197265625, + 433.1217041015625, + 1394.7154541015625, + 535.6997680664062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7229082584381104, + "bbox": [ + 1688.562744140625, + 416.6376647949219, + 1821.5228271484375, + 537.8909301757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6216470003128052, + "bbox": [ + 543.21337890625, + 414.53802490234375, + 678.0364990234375, + 542.1803588867188 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.580826461315155, + "bbox": [ + 2115.922119140625, + 3121.437255859375, + 2201.80908203125, + 3193.328857421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9516152143478394, + "bbox": [ + 238.84461975097656, + 550.5658569335938, + 1198.468994140625, + 2048.26318359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9407613277435303, + "bbox": [ + 1259.935791015625, + 666.7273559570312, + 2258.46240234375, + 2101.78125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.938447117805481, + "bbox": [ + 199.93731689453125, + 367.5056457519531, + 1226.080810546875, + 2285.20556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9105662703514099, + "bbox": [ + 1267.262939453125, + 2121.923828125, + 1916.944580078125, + 2553.454345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9095644354820251, + "bbox": [ + 1237.24169921875, + 400.4144287109375, + 2317.078369140625, + 2610.015380859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8045415282249451, + "bbox": [ + 1265.9334716796875, + 538.101806640625, + 2224.9912109375, + 656.2567138671875 + ] + } + ], + "timestamp": "2025-10-15T21:42:19.221550" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 33.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 33.json" new file mode 100644 index 0000000..dfb2dff --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 33.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 33.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7382001280784607, + "bbox": [ + 1159.257080078125, + 1779.679931640625, + 1266.6392822265625, + 1871.7481689453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7343220114707947, + "bbox": [ + 1176.4478759765625, + 411.1852722167969, + 1283.7557373046875, + 505.1670837402344 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6701210141181946, + "bbox": [ + 1453.3560791015625, + 371.0697021484375, + 1588.2186279296875, + 510.89605712890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6308708190917969, + "bbox": [ + 1368.5357666015625, + 1760.36962890625, + 1485.7447509765625, + 1876.999755859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4856923222541809, + "bbox": [ + 183.00831604003906, + 2886.1943359375, + 273.2265625, + 2959.83203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267694354057312, + "bbox": [ + 1125.4251708984375, + 1753.93798828125, + 2092.636962890625, + 2131.1220703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9180446267127991, + "bbox": [ + 199.50650024414062, + 527.6482543945312, + 1115.52880859375, + 2725.453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9033910036087036, + "bbox": [ + 1183.7301025390625, + 580.48046875, + 2099.0556640625, + 962.552490234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8924390077590942, + "bbox": [ + 1145.9691162109375, + 378.66009521484375, + 2142.837158203125, + 1028.6453857421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7847135066986084, + "bbox": [ + 1152.1920166015625, + 1872.78759765625, + 2045.9659423828125, + 1988.59130859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7793551683425903, + "bbox": [ + 1189.3531494140625, + 491.2174987792969, + 1700.331298828125, + 573.5440673828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6983219385147095, + "bbox": [ + 1152.140869140625, + 2010.901611328125, + 1964.4674072265625, + 2083.96435546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.225002259016037, + "bbox": [ + 1159.4427490234375, + 1859.1964111328125, + 2052.582275390625, + 1963.92236328125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7382001280784607, + "bbox": [ + 1159.257080078125, + 1779.679931640625, + 1266.6392822265625, + 1871.7481689453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7343220114707947, + "bbox": [ + 1176.4478759765625, + 411.1852722167969, + 1283.7557373046875, + 505.1670837402344 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6701210141181946, + "bbox": [ + 1453.3560791015625, + 371.0697021484375, + 1588.2186279296875, + 510.89605712890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6308708190917969, + "bbox": [ + 1368.5357666015625, + 1760.36962890625, + 1485.7447509765625, + 1876.999755859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4856923222541809, + "bbox": [ + 183.00831604003906, + 2886.1943359375, + 273.2265625, + 2959.83203125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267694354057312, + "bbox": [ + 1125.4251708984375, + 1753.93798828125, + 2092.636962890625, + 2131.1220703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9180446267127991, + "bbox": [ + 199.50650024414062, + 527.6482543945312, + 1115.52880859375, + 2725.453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9033910036087036, + "bbox": [ + 1183.7301025390625, + 580.48046875, + 2099.0556640625, + 962.552490234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8924390077590942, + "bbox": [ + 1145.9691162109375, + 378.66009521484375, + 2142.837158203125, + 1028.6453857421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7847135066986084, + "bbox": [ + 1152.1920166015625, + 1872.78759765625, + 2045.9659423828125, + 1988.59130859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7793551683425903, + "bbox": [ + 1189.3531494140625, + 491.2174987792969, + 1700.331298828125, + 573.5440673828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6983219385147095, + "bbox": [ + 1152.140869140625, + 2010.901611328125, + 1964.4674072265625, + 2083.96435546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.225002259016037, + "bbox": [ + 1159.4427490234375, + 1859.1964111328125, + 2052.582275390625, + 1963.92236328125 + ] + } + ], + "timestamp": "2025-10-15T21:42:19.595019" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 34.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 34.json" new file mode 100644 index 0000000..34f68ed --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 34.json" @@ -0,0 +1,472 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 34.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7631301879882812, + "bbox": [ + 1249.71240234375, + 2527.0068359375, + 1368.4134521484375, + 2629.692138671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7423908710479736, + "bbox": [ + 1259.1263427734375, + 1954.6392822265625, + 1369.4600830078125, + 2051.2158203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7371372580528259, + "bbox": [ + 1266.1046142578125, + 1191.31396484375, + 1382.3958740234375, + 1288.062255859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6443009972572327, + "bbox": [ + 1538.4713134765625, + 1176.868896484375, + 1659.90966796875, + 1292.151611328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6369273662567139, + "bbox": [ + 1479.8643798828125, + 1932.4456787109375, + 1606.90380859375, + 2058.20654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6345170140266418, + "bbox": [ + 1462.557373046875, + 2497.307373046875, + 1592.8426513671875, + 2630.5751953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5546056628227234, + "bbox": [ + 2104.216064453125, + 3072.8046875, + 2192.110595703125, + 3145.80517578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9187479615211487, + "bbox": [ + 1250.12841796875, + 2697.40576171875, + 2114.49560546875, + 3053.944580078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9182093143463135, + "bbox": [ + 1249.125732421875, + 409.1916198730469, + 2265.78955078125, + 1018.2421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8877222537994385, + "bbox": [ + 1223.094482421875, + 2473.58544921875, + 2236.861083984375, + 3072.441162109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8849437236785889, + "bbox": [ + 1251.2005615234375, + 1923.387939453125, + 2246.10205078125, + 2241.09033203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8652137517929077, + "bbox": [ + 1260.7471923828125, + 1424.1236572265625, + 2110.28955078125, + 1641.166748046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8641857504844666, + "bbox": [ + 227.31521606445312, + 488.87750244140625, + 1211.921630859375, + 3031.0078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8291875720024109, + "bbox": [ + 1241.6533203125, + 1144.5491943359375, + 2315.455078125, + 1725.8028564453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8220558166503906, + "bbox": [ + 1257.162841796875, + 1280.3243408203125, + 2217.109375, + 1413.4010009765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8107846975326538, + "bbox": [ + 1251.0623779296875, + 2118.6533203125, + 2146.95068359375, + 2227.070556640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.746609091758728, + "bbox": [ + 1248.7774658203125, + 2049.69677734375, + 2186.668212890625, + 2125.168212890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6305058598518372, + "bbox": [ + 1247.0965576171875, + 2624.22021484375, + 2026.6259765625, + 2689.923583984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6080125570297241, + "bbox": [ + 1250.698974609375, + 2610.531005859375, + 2031.059814453125, + 2704.65966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.5366713404655457, + "bbox": [ + 1230.085693359375, + 1911.0274658203125, + 2256.20703125, + 2366.303955078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.17180685698986053, + "bbox": [ + 210.44129943847656, + 1567.746826171875, + 1205.818359375, + 3082.11474609375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7631301879882812, + "bbox": [ + 1249.71240234375, + 2527.0068359375, + 1368.4134521484375, + 2629.692138671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7423908710479736, + "bbox": [ + 1259.1263427734375, + 1954.6392822265625, + 1369.4600830078125, + 2051.2158203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7371372580528259, + "bbox": [ + 1266.1046142578125, + 1191.31396484375, + 1382.3958740234375, + 1288.062255859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6443009972572327, + "bbox": [ + 1538.4713134765625, + 1176.868896484375, + 1659.90966796875, + 1292.151611328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6369273662567139, + "bbox": [ + 1479.8643798828125, + 1932.4456787109375, + 1606.90380859375, + 2058.20654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6345170140266418, + "bbox": [ + 1462.557373046875, + 2497.307373046875, + 1592.8426513671875, + 2630.5751953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5546056628227234, + "bbox": [ + 2104.216064453125, + 3072.8046875, + 2192.110595703125, + 3145.80517578125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9187479615211487, + "bbox": [ + 1250.12841796875, + 2697.40576171875, + 2114.49560546875, + 3053.944580078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9182093143463135, + "bbox": [ + 1249.125732421875, + 409.1916198730469, + 2265.78955078125, + 1018.2421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8877222537994385, + "bbox": [ + 1223.094482421875, + 2473.58544921875, + 2236.861083984375, + 3072.441162109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8849437236785889, + "bbox": [ + 1251.2005615234375, + 1923.387939453125, + 2246.10205078125, + 2241.09033203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8652137517929077, + "bbox": [ + 1260.7471923828125, + 1424.1236572265625, + 2110.28955078125, + 1641.166748046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8641857504844666, + "bbox": [ + 227.31521606445312, + 488.87750244140625, + 1211.921630859375, + 3031.0078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8291875720024109, + "bbox": [ + 1241.6533203125, + 1144.5491943359375, + 2315.455078125, + 1725.8028564453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8220558166503906, + "bbox": [ + 1257.162841796875, + 1280.3243408203125, + 2217.109375, + 1413.4010009765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8107846975326538, + "bbox": [ + 1251.0623779296875, + 2118.6533203125, + 2146.95068359375, + 2227.070556640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.746609091758728, + "bbox": [ + 1248.7774658203125, + 2049.69677734375, + 2186.668212890625, + 2125.168212890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6305058598518372, + "bbox": [ + 1247.0965576171875, + 2624.22021484375, + 2026.6259765625, + 2689.923583984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6080125570297241, + "bbox": [ + 1250.698974609375, + 2610.531005859375, + 2031.059814453125, + 2704.65966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.5366713404655457, + "bbox": [ + 1230.085693359375, + 1911.0274658203125, + 2256.20703125, + 2366.303955078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.17180685698986053, + "bbox": [ + 210.44129943847656, + 1567.746826171875, + 1205.818359375, + 3082.11474609375 + ] + } + ], + "timestamp": "2025-10-15T21:42:19.949438" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 18.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 18.json" new file mode 100644 index 0000000..5e384ca --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 18.json" @@ -0,0 +1,626 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 18.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7910915017127991, + "bbox": [ + 230.35317993164062, + 1696.62548828125, + 334.7241516113281, + 1784.8590087890625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7894256711006165, + "bbox": [ + 1218.0115966796875, + 499.1844482421875, + 1315.185546875, + 585.120361328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7800495028495789, + "bbox": [ + 219.83982849121094, + 2433.24365234375, + 324.06781005859375, + 2523.5966796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7800227999687195, + "bbox": [ + 239.15411376953125, + 962.5027465820312, + 340.45233154296875, + 1054.2579345703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7776979804039001, + "bbox": [ + 1196.5953369140625, + 2442.850341796875, + 1298.6729736328125, + 2528.152099609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6733511090278625, + "bbox": [ + 892.2962036132812, + 2695.182373046875, + 1007.4478149414062, + 2813.342529296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6496018171310425, + "bbox": [ + 1804.4677734375, + 2683.58984375, + 1921.677978515625, + 2796.089111328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6390625834465027, + "bbox": [ + 932.2650146484375, + 1918.0496826171875, + 1055.667724609375, + 2042.06884765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6274062991142273, + "bbox": [ + 978.3050537109375, + 1159.1876220703125, + 1103.3677978515625, + 1278.367431640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5472032427787781, + "bbox": [ + 217.8408203125, + 3010.2392578125, + 304.44696044921875, + 3082.525390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.511578381061554, + "bbox": [ + 1709.371337890625, + 1615.722412109375, + 1900.1365966796875, + 1773.5428466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4107294976711273, + "bbox": [ + 1377.29296875, + 875.92822265625, + 1439.489501953125, + 949.4154663085938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2509668171405792, + "bbox": [ + 204.6452178955078, + 3002.928466796875, + 307.5387268066406, + 3090.580322265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9257043600082397, + "bbox": [ + 1300.98583984375, + 724.2887573242188, + 2048.181396484375, + 1450.59765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9178515672683716, + "bbox": [ + 179.17300415039062, + 2406.8076171875, + 1148.363525390625, + 3016.5009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9130489230155945, + "bbox": [ + 205.57872009277344, + 921.8033447265625, + 1166.1492919921875, + 1615.3475341796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9111249446868896, + "bbox": [ + 242.34658813476562, + 1913.02587890625, + 822.146484375, + 2268.8994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9072135090827942, + "bbox": [ + 1169.2891845703125, + 467.41357421875, + 2180.331787109375, + 1808.6070556640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9000824093818665, + "bbox": [ + 199.4387664794922, + 1655.28759765625, + 1168.10986328125, + 2285.64404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8855061531066895, + "bbox": [ + 246.6758575439453, + 1181.281494140625, + 1045.549560546875, + 1539.4656982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8815263509750366, + "bbox": [ + 1183.1241455078125, + 2416.802734375, + 2178.5849609375, + 3055.8701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8798478245735168, + "bbox": [ + 1194.4471435546875, + 2670.7724609375, + 1709.8223876953125, + 3002.341552734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8509026765823364, + "bbox": [ + 225.53494262695312, + 2525.226318359375, + 1133.4140625, + 2648.425537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8382829427719116, + "bbox": [ + 1198.4517822265625, + 2535.956787109375, + 2102.91748046875, + 2654.66650390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8237183094024658, + "bbox": [ + 1206.3433837890625, + 584.2828979492188, + 2124.816162109375, + 708.138916015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8142625689506531, + "bbox": [ + 248.7885284423828, + 1053.3914794921875, + 1132.5595703125, + 1170.868896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8042677044868469, + "bbox": [ + 239.74069213867188, + 1792.6939697265625, + 1123.04052734375, + 1909.8460693359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7668336629867554, + "bbox": [ + 223.9656524658203, + 2652.184814453125, + 522.0737915039062, + 3002.47314453125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7910915017127991, + "bbox": [ + 230.35317993164062, + 1696.62548828125, + 334.7241516113281, + 1784.8590087890625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7894256711006165, + "bbox": [ + 1218.0115966796875, + 499.1844482421875, + 1315.185546875, + 585.120361328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7800495028495789, + "bbox": [ + 219.83982849121094, + 2433.24365234375, + 324.06781005859375, + 2523.5966796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7800227999687195, + "bbox": [ + 239.15411376953125, + 962.5027465820312, + 340.45233154296875, + 1054.2579345703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7776979804039001, + "bbox": [ + 1196.5953369140625, + 2442.850341796875, + 1298.6729736328125, + 2528.152099609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6733511090278625, + "bbox": [ + 892.2962036132812, + 2695.182373046875, + 1007.4478149414062, + 2813.342529296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6496018171310425, + "bbox": [ + 1804.4677734375, + 2683.58984375, + 1921.677978515625, + 2796.089111328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6390625834465027, + "bbox": [ + 932.2650146484375, + 1918.0496826171875, + 1055.667724609375, + 2042.06884765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6274062991142273, + "bbox": [ + 978.3050537109375, + 1159.1876220703125, + 1103.3677978515625, + 1278.367431640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5472032427787781, + "bbox": [ + 217.8408203125, + 3010.2392578125, + 304.44696044921875, + 3082.525390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.511578381061554, + "bbox": [ + 1709.371337890625, + 1615.722412109375, + 1900.1365966796875, + 1773.5428466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4107294976711273, + "bbox": [ + 1377.29296875, + 875.92822265625, + 1439.489501953125, + 949.4154663085938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2509668171405792, + "bbox": [ + 204.6452178955078, + 3002.928466796875, + 307.5387268066406, + 3090.580322265625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9257043600082397, + "bbox": [ + 1300.98583984375, + 724.2887573242188, + 2048.181396484375, + 1450.59765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9178515672683716, + "bbox": [ + 179.17300415039062, + 2406.8076171875, + 1148.363525390625, + 3016.5009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9130489230155945, + "bbox": [ + 205.57872009277344, + 921.8033447265625, + 1166.1492919921875, + 1615.3475341796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9111249446868896, + "bbox": [ + 242.34658813476562, + 1913.02587890625, + 822.146484375, + 2268.8994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9072135090827942, + "bbox": [ + 1169.2891845703125, + 467.41357421875, + 2180.331787109375, + 1808.6070556640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9000824093818665, + "bbox": [ + 199.4387664794922, + 1655.28759765625, + 1168.10986328125, + 2285.64404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8855061531066895, + "bbox": [ + 246.6758575439453, + 1181.281494140625, + 1045.549560546875, + 1539.4656982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8815263509750366, + "bbox": [ + 1183.1241455078125, + 2416.802734375, + 2178.5849609375, + 3055.8701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8798478245735168, + "bbox": [ + 1194.4471435546875, + 2670.7724609375, + 1709.8223876953125, + 3002.341552734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8509026765823364, + "bbox": [ + 225.53494262695312, + 2525.226318359375, + 1133.4140625, + 2648.425537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8382829427719116, + "bbox": [ + 1198.4517822265625, + 2535.956787109375, + 2102.91748046875, + 2654.66650390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8237183094024658, + "bbox": [ + 1206.3433837890625, + 584.2828979492188, + 2124.816162109375, + 708.138916015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8142625689506531, + "bbox": [ + 248.7885284423828, + 1053.3914794921875, + 1132.5595703125, + 1170.868896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8042677044868469, + "bbox": [ + 239.74069213867188, + 1792.6939697265625, + 1123.04052734375, + 1909.8460693359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7668336629867554, + "bbox": [ + 223.9656524658203, + 2652.184814453125, + 522.0737915039062, + 3002.47314453125 + ] + } + ], + "timestamp": "2025-10-15T21:42:20.321822" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 19.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 19.json" new file mode 100644 index 0000000..19a89d5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 19.json" @@ -0,0 +1,648 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 19.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7806082963943481, + "bbox": [ + 260.4742126464844, + 2552.689208984375, + 367.7405090332031, + 2644.792236328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7665067315101624, + "bbox": [ + 1281.30517578125, + 2187.93798828125, + 1388.53076171875, + 2285.638427734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7657893896102905, + "bbox": [ + 270.83685302734375, + 1464.469482421875, + 379.5198669433594, + 1557.2265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7619249820709229, + "bbox": [ + 275.1424255371094, + 433.4808044433594, + 388.0682067871094, + 525.6077270507812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7584542036056519, + "bbox": [ + 1290.5780029296875, + 441.8584289550781, + 1400.74658203125, + 534.2255249023438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6924356818199158, + "bbox": [ + 2001.152099609375, + 2359.5966796875, + 2114.89990234375, + 2471.18310546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6541412472724915, + "bbox": [ + 879.8652954101562, + 865.1585083007812, + 1005.1033935546875, + 994.0985717773438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6507939696311951, + "bbox": [ + 1800.3455810546875, + 1109.87158203125, + 1931.7371826171875, + 1240.5052490234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6496552228927612, + "bbox": [ + 908.044189453125, + 2073.95751953125, + 1030.516845703125, + 2202.4150390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6331442594528198, + "bbox": [ + 820.9244995117188, + 2823.184814453125, + 963.7505493164062, + 2962.852294921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5729832053184509, + "bbox": [ + 2134.70849609375, + 3167.5390625, + 2216.06640625, + 3236.526123046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.25601625442504883, + "bbox": [ + 889.1231079101562, + 2065.851318359375, + 1047.9351806640625, + 2213.17236328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.23071812093257904, + "bbox": [ + 1782.7469482421875, + 1102.794189453125, + 1946.5107421875, + 1255.462158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9307416677474976, + "bbox": [ + 1266.3680419921875, + 2402.033935546875, + 2219.42724609375, + 3127.4052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9289821982383728, + "bbox": [ + 1239.5794677734375, + 2138.07763671875, + 2238.72998046875, + 3161.428466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025497436523438, + "bbox": [ + 184.88475036621094, + 2505.998291015625, + 1225.9521484375, + 3198.6708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8965824246406555, + "bbox": [ + 222.63108825683594, + 390.1928405761719, + 1225.00830078125, + 1027.4793701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8800339102745056, + "bbox": [ + 1297.4991455078125, + 672.8602905273438, + 2058.8916015625, + 1009.163818359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8681506514549255, + "bbox": [ + 1287.49072265625, + 537.6287231445312, + 2234.968017578125, + 662.1790771484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8671602010726929, + "bbox": [ + 262.3607177734375, + 2643.1083984375, + 1194.009521484375, + 2770.321044921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8658437728881836, + "bbox": [ + 1258.4461669921875, + 399.8854675292969, + 2268.444580078125, + 1280.9931640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8502557873725891, + "bbox": [ + 267.3343200683594, + 2775.281982421875, + 573.3631591796875, + 3151.489501953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8367086052894592, + "bbox": [ + 1284.1024169921875, + 2285.1767578125, + 2232.129638671875, + 2409.434814453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8356109261512756, + "bbox": [ + 262.9279479980469, + 1692.6763916015625, + 828.67724609375, + 2061.722900390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8067290782928467, + "bbox": [ + 271.2767639160156, + 1562.9161376953125, + 1221.2308349609375, + 1686.8173828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7971253991127014, + "bbox": [ + 177.5136260986328, + 1399.8631591796875, + 1232.65673828125, + 2254.543701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7488017678260803, + "bbox": [ + 273.7868957519531, + 518.4130859375, + 1018.0195922851562, + 603.6983642578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5752869844436646, + "bbox": [ + 279.17352294921875, + 602.251220703125, + 579.3604125976562, + 960.1095581054688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.48882952332496643, + "bbox": [ + 278.0295104980469, + 604.2296752929688, + 909.8511352539062, + 973.5428466796875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7806082963943481, + "bbox": [ + 260.4742126464844, + 2552.689208984375, + 367.7405090332031, + 2644.792236328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7665067315101624, + "bbox": [ + 1281.30517578125, + 2187.93798828125, + 1388.53076171875, + 2285.638427734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7657893896102905, + "bbox": [ + 270.83685302734375, + 1464.469482421875, + 379.5198669433594, + 1557.2265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7619249820709229, + "bbox": [ + 275.1424255371094, + 433.4808044433594, + 388.0682067871094, + 525.6077270507812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7584542036056519, + "bbox": [ + 1290.5780029296875, + 441.8584289550781, + 1400.74658203125, + 534.2255249023438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6924356818199158, + "bbox": [ + 2001.152099609375, + 2359.5966796875, + 2114.89990234375, + 2471.18310546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6541412472724915, + "bbox": [ + 879.8652954101562, + 865.1585083007812, + 1005.1033935546875, + 994.0985717773438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6507939696311951, + "bbox": [ + 1800.3455810546875, + 1109.87158203125, + 1931.7371826171875, + 1240.5052490234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6496552228927612, + "bbox": [ + 908.044189453125, + 2073.95751953125, + 1030.516845703125, + 2202.4150390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6331442594528198, + "bbox": [ + 820.9244995117188, + 2823.184814453125, + 963.7505493164062, + 2962.852294921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5729832053184509, + "bbox": [ + 2134.70849609375, + 3167.5390625, + 2216.06640625, + 3236.526123046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.25601625442504883, + "bbox": [ + 889.1231079101562, + 2065.851318359375, + 1047.9351806640625, + 2213.17236328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.23071812093257904, + "bbox": [ + 1782.7469482421875, + 1102.794189453125, + 1946.5107421875, + 1255.462158203125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9307416677474976, + "bbox": [ + 1266.3680419921875, + 2402.033935546875, + 2219.42724609375, + 3127.4052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9289821982383728, + "bbox": [ + 1239.5794677734375, + 2138.07763671875, + 2238.72998046875, + 3161.428466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025497436523438, + "bbox": [ + 184.88475036621094, + 2505.998291015625, + 1225.9521484375, + 3198.6708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8965824246406555, + "bbox": [ + 222.63108825683594, + 390.1928405761719, + 1225.00830078125, + 1027.4793701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8800339102745056, + "bbox": [ + 1297.4991455078125, + 672.8602905273438, + 2058.8916015625, + 1009.163818359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8681506514549255, + "bbox": [ + 1287.49072265625, + 537.6287231445312, + 2234.968017578125, + 662.1790771484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8671602010726929, + "bbox": [ + 262.3607177734375, + 2643.1083984375, + 1194.009521484375, + 2770.321044921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8658437728881836, + "bbox": [ + 1258.4461669921875, + 399.8854675292969, + 2268.444580078125, + 1280.9931640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8502557873725891, + "bbox": [ + 267.3343200683594, + 2775.281982421875, + 573.3631591796875, + 3151.489501953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8367086052894592, + "bbox": [ + 1284.1024169921875, + 2285.1767578125, + 2232.129638671875, + 2409.434814453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8356109261512756, + "bbox": [ + 262.9279479980469, + 1692.6763916015625, + 828.67724609375, + 2061.722900390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8067290782928467, + "bbox": [ + 271.2767639160156, + 1562.9161376953125, + 1221.2308349609375, + 1686.8173828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7971253991127014, + "bbox": [ + 177.5136260986328, + 1399.8631591796875, + 1232.65673828125, + 2254.543701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7488017678260803, + "bbox": [ + 273.7868957519531, + 518.4130859375, + 1018.0195922851562, + 603.6983642578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5752869844436646, + "bbox": [ + 279.17352294921875, + 602.251220703125, + 579.3604125976562, + 960.1095581054688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.48882952332496643, + "bbox": [ + 278.0295104980469, + 604.2296752929688, + 909.8511352539062, + 973.5428466796875 + ] + } + ], + "timestamp": "2025-10-15T21:42:19.919632" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 20.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 20.json" new file mode 100644 index 0000000..15457fd --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 20.json" @@ -0,0 +1,670 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 20.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.770004391670227, + "bbox": [ + 227.8684844970703, + 1394.197509765625, + 337.5234069824219, + 1495.2420654296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.768976092338562, + "bbox": [ + 217.39999389648438, + 2215.935791015625, + 331.8891906738281, + 2320.3251953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7578659057617188, + "bbox": [ + 1280.75146484375, + 2218.473388671875, + 1387.6768798828125, + 2317.35400390625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7428791522979736, + "bbox": [ + 230.2537078857422, + 444.76806640625, + 342.75421142578125, + 551.8841552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.739993155002594, + "bbox": [ + 1291.6243896484375, + 457.6066589355469, + 1401.493896484375, + 560.59228515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7256499528884888, + "bbox": [ + 1888.666748046875, + 2395.322509765625, + 1995.644287109375, + 2497.0751953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7168436646461487, + "bbox": [ + 988.0191040039062, + 617.763671875, + 1097.1043701171875, + 717.18359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7033721804618835, + "bbox": [ + 969.8660278320312, + 2384.013671875, + 1093.8612060546875, + 2494.57080078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6732162237167358, + "bbox": [ + 958.989990234375, + 1541.8289794921875, + 1085.7752685546875, + 1663.0765380859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6503382921218872, + "bbox": [ + 1884.4066162109375, + 1448.2974853515625, + 2012.322265625, + 1577.9632568359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5782093405723572, + "bbox": [ + 218.05003356933594, + 3255.59326171875, + 308.6983947753906, + 3329.9345703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.22545643150806427, + "bbox": [ + 210.63072204589844, + 3244.712646484375, + 316.4281921386719, + 3338.673583984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9425860047340393, + "bbox": [ + 1283.8472900390625, + 789.8594970703125, + 2292.91015625, + 1424.7850341796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9388155341148376, + "bbox": [ + 196.3930206298828, + 2556.99072265625, + 1195.829833984375, + 3240.28125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.938155472278595, + "bbox": [ + 1276.2421875, + 2564.715576171875, + 2290.51220703125, + 3244.47802734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9302681088447571, + "bbox": [ + 226.6257781982422, + 685.9007568359375, + 1215.5958251953125, + 1297.10302734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9289887547492981, + "bbox": [ + 1247.750732421875, + 2183.6572265625, + 2317.90869140625, + 3290.12841796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9199828505516052, + "bbox": [ + 146.8144989013672, + 2176.79638671875, + 1212.3533935546875, + 3283.78271484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9105452299118042, + "bbox": [ + 222.23834228515625, + 1648.3890380859375, + 1200.869873046875, + 2109.9423828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9011641144752502, + "bbox": [ + 1242.2508544921875, + 384.0574035644531, + 2459.2666015625, + 1617.397216796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8988088369369507, + "bbox": [ + 180.63937377929688, + 1359.5283203125, + 1229.5303955078125, + 2150.76708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8803334832191467, + "bbox": [ + 190.84584045410156, + 421.8017883300781, + 1230.582763671875, + 1341.2467041015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8684792518615723, + "bbox": [ + 222.4640655517578, + 2309.5390625, + 1195.539306640625, + 2443.471435546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8513786792755127, + "bbox": [ + 1286.2598876953125, + 553.5436401367188, + 2295.742919921875, + 691.4363403320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8354985117912292, + "bbox": [ + 223.97247314453125, + 1489.9429931640625, + 1221.075439453125, + 1626.068603515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8143616914749146, + "bbox": [ + 198.7401580810547, + 2449.326416015625, + 1178.1917724609375, + 2555.345458984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.811147153377533, + "bbox": [ + 1282.1292724609375, + 2456.3984375, + 2263.775146484375, + 2565.2275390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8096005916595459, + "bbox": [ + 1283.961669921875, + 2313.198486328125, + 2263.112060546875, + 2448.741943359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7948641777038574, + "bbox": [ + 222.3987274169922, + 544.5414428710938, + 1204.582763671875, + 685.6777954101562 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5346129536628723, + "bbox": [ + 1286.0950927734375, + 688.2029418945312, + 2281.003173828125, + 798.1704711914062 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.770004391670227, + "bbox": [ + 227.8684844970703, + 1394.197509765625, + 337.5234069824219, + 1495.2420654296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.768976092338562, + "bbox": [ + 217.39999389648438, + 2215.935791015625, + 331.8891906738281, + 2320.3251953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7578659057617188, + "bbox": [ + 1280.75146484375, + 2218.473388671875, + 1387.6768798828125, + 2317.35400390625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7428791522979736, + "bbox": [ + 230.2537078857422, + 444.76806640625, + 342.75421142578125, + 551.8841552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.739993155002594, + "bbox": [ + 1291.6243896484375, + 457.6066589355469, + 1401.493896484375, + 560.59228515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7256499528884888, + "bbox": [ + 1888.666748046875, + 2395.322509765625, + 1995.644287109375, + 2497.0751953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7168436646461487, + "bbox": [ + 988.0191040039062, + 617.763671875, + 1097.1043701171875, + 717.18359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7033721804618835, + "bbox": [ + 969.8660278320312, + 2384.013671875, + 1093.8612060546875, + 2494.57080078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6732162237167358, + "bbox": [ + 958.989990234375, + 1541.8289794921875, + 1085.7752685546875, + 1663.0765380859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6503382921218872, + "bbox": [ + 1884.4066162109375, + 1448.2974853515625, + 2012.322265625, + 1577.9632568359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5782093405723572, + "bbox": [ + 218.05003356933594, + 3255.59326171875, + 308.6983947753906, + 3329.9345703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.22545643150806427, + "bbox": [ + 210.63072204589844, + 3244.712646484375, + 316.4281921386719, + 3338.673583984375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9425860047340393, + "bbox": [ + 1283.8472900390625, + 789.8594970703125, + 2292.91015625, + 1424.7850341796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9388155341148376, + "bbox": [ + 196.3930206298828, + 2556.99072265625, + 1195.829833984375, + 3240.28125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.938155472278595, + "bbox": [ + 1276.2421875, + 2564.715576171875, + 2290.51220703125, + 3244.47802734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9302681088447571, + "bbox": [ + 226.6257781982422, + 685.9007568359375, + 1215.5958251953125, + 1297.10302734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9289887547492981, + "bbox": [ + 1247.750732421875, + 2183.6572265625, + 2317.90869140625, + 3290.12841796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9199828505516052, + "bbox": [ + 146.8144989013672, + 2176.79638671875, + 1212.3533935546875, + 3283.78271484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9105452299118042, + "bbox": [ + 222.23834228515625, + 1648.3890380859375, + 1200.869873046875, + 2109.9423828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9011641144752502, + "bbox": [ + 1242.2508544921875, + 384.0574035644531, + 2459.2666015625, + 1617.397216796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8988088369369507, + "bbox": [ + 180.63937377929688, + 1359.5283203125, + 1229.5303955078125, + 2150.76708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8803334832191467, + "bbox": [ + 190.84584045410156, + 421.8017883300781, + 1230.582763671875, + 1341.2467041015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8684792518615723, + "bbox": [ + 222.4640655517578, + 2309.5390625, + 1195.539306640625, + 2443.471435546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8513786792755127, + "bbox": [ + 1286.2598876953125, + 553.5436401367188, + 2295.742919921875, + 691.4363403320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8354985117912292, + "bbox": [ + 223.97247314453125, + 1489.9429931640625, + 1221.075439453125, + 1626.068603515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8143616914749146, + "bbox": [ + 198.7401580810547, + 2449.326416015625, + 1178.1917724609375, + 2555.345458984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.811147153377533, + "bbox": [ + 1282.1292724609375, + 2456.3984375, + 2263.775146484375, + 2565.2275390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8096005916595459, + "bbox": [ + 1283.961669921875, + 2313.198486328125, + 2263.112060546875, + 2448.741943359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7948641777038574, + "bbox": [ + 222.3987274169922, + 544.5414428710938, + 1204.582763671875, + 685.6777954101562 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5346129536628723, + "bbox": [ + 1286.0950927734375, + 688.2029418945312, + 2281.003173828125, + 798.1704711914062 + ] + } + ], + "timestamp": "2025-10-15T21:42:20.285621" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 21.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 21.json" new file mode 100644 index 0000000..0894f5c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 21.json" @@ -0,0 +1,406 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 21.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7600154280662537, + "bbox": [ + 248.6562042236328, + 1725.99072265625, + 355.55767822265625, + 1828.3558349609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7479546070098877, + "bbox": [ + 1250.4852294921875, + 436.2503356933594, + 1355.2362060546875, + 533.615478515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.733197808265686, + "bbox": [ + 253.00140380859375, + 554.424072265625, + 357.7325134277344, + 653.5487670898438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7327031493186951, + "bbox": [ + 1043.0130615234375, + 681.7967529296875, + 1143.5816650390625, + 795.373046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6604880690574646, + "bbox": [ + 1955.669189453125, + 2711.767333984375, + 2072.642333984375, + 2829.921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6193154454231262, + "bbox": [ + 795.8218994140625, + 1958.0054931640625, + 928.4794311523438, + 2093.172119140625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6105974912643433, + "bbox": [ + 2074.02490234375, + 3095.677490234375, + 2155.341064453125, + 3166.094482421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2603116035461426, + "bbox": [ + 1938.94189453125, + 2704.4921875, + 2085.761474609375, + 2843.463134765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9225572943687439, + "bbox": [ + 248.07408142089844, + 735.6043090820312, + 1129.4544677734375, + 1107.1153564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9154878854751587, + "bbox": [ + 1216.0084228515625, + 411.1801452636719, + 2155.84326171875, + 2885.19921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9094707369804382, + "bbox": [ + 1260.2086181640625, + 661.39111328125, + 2104.07861328125, + 2299.278564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8934165835380554, + "bbox": [ + 194.86402893066406, + 1692.945068359375, + 1178.694580078125, + 2305.255126953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8931736350059509, + "bbox": [ + 233.5961151123047, + 525.005859375, + 1198.8087158203125, + 1167.3118896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8930615186691284, + "bbox": [ + 1231.3604736328125, + 2298.90087890625, + 2059.439453125, + 2670.651123046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.888836145401001, + "bbox": [ + 248.04222106933594, + 1906.90625, + 645.3184204101562, + 2270.5087890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7547680139541626, + "bbox": [ + 1246.5848388671875, + 537.1744995117188, + 1830.3382568359375, + 609.3684692382812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7489905953407288, + "bbox": [ + 245.0144500732422, + 1816.89306640625, + 646.7540893554688, + 1899.2235107421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7435820698738098, + "bbox": [ + 251.01722717285156, + 639.7962646484375, + 884.8085327148438, + 721.9888916015625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7600154280662537, + "bbox": [ + 248.6562042236328, + 1725.99072265625, + 355.55767822265625, + 1828.3558349609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7479546070098877, + "bbox": [ + 1250.4852294921875, + 436.2503356933594, + 1355.2362060546875, + 533.615478515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.733197808265686, + "bbox": [ + 253.00140380859375, + 554.424072265625, + 357.7325134277344, + 653.5487670898438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7327031493186951, + "bbox": [ + 1043.0130615234375, + 681.7967529296875, + 1143.5816650390625, + 795.373046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6604880690574646, + "bbox": [ + 1955.669189453125, + 2711.767333984375, + 2072.642333984375, + 2829.921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6193154454231262, + "bbox": [ + 795.8218994140625, + 1958.0054931640625, + 928.4794311523438, + 2093.172119140625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6105974912643433, + "bbox": [ + 2074.02490234375, + 3095.677490234375, + 2155.341064453125, + 3166.094482421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2603116035461426, + "bbox": [ + 1938.94189453125, + 2704.4921875, + 2085.761474609375, + 2843.463134765625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9225572943687439, + "bbox": [ + 248.07408142089844, + 735.6043090820312, + 1129.4544677734375, + 1107.1153564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9154878854751587, + "bbox": [ + 1216.0084228515625, + 411.1801452636719, + 2155.84326171875, + 2885.19921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9094707369804382, + "bbox": [ + 1260.2086181640625, + 661.39111328125, + 2104.07861328125, + 2299.278564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8934165835380554, + "bbox": [ + 194.86402893066406, + 1692.945068359375, + 1178.694580078125, + 2305.255126953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8931736350059509, + "bbox": [ + 233.5961151123047, + 525.005859375, + 1198.8087158203125, + 1167.3118896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8930615186691284, + "bbox": [ + 1231.3604736328125, + 2298.90087890625, + 2059.439453125, + 2670.651123046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.888836145401001, + "bbox": [ + 248.04222106933594, + 1906.90625, + 645.3184204101562, + 2270.5087890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7547680139541626, + "bbox": [ + 1246.5848388671875, + 537.1744995117188, + 1830.3382568359375, + 609.3684692382812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7489905953407288, + "bbox": [ + 245.0144500732422, + 1816.89306640625, + 646.7540893554688, + 1899.2235107421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7435820698738098, + "bbox": [ + 251.01722717285156, + 639.7962646484375, + 884.8085327148438, + 721.9888916015625 + ] + } + ], + "timestamp": "2025-10-15T21:42:20.738537" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 22.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 22.json" new file mode 100644 index 0000000..d24ac09 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 22.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 22.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.749894917011261, + "bbox": [ + 1292.4083251953125, + 466.3904113769531, + 1405.4862060546875, + 561.9081420898438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7435379028320312, + "bbox": [ + 234.83375549316406, + 447.31365966796875, + 348.72137451171875, + 547.6092529296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7019142508506775, + "bbox": [ + 1079.914794921875, + 555.5654296875, + 1189.1385498046875, + 659.0630493164062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6580477952957153, + "bbox": [ + 2200.89111328125, + 561.7781982421875, + 2296.7607421875, + 651.3455200195312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4683842957019806, + "bbox": [ + 231.07928466796875, + 3243.40673828125, + 324.36322021484375, + 3316.35546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9489567875862122, + "bbox": [ + 1289.3067626953125, + 2134.713623046875, + 2290.681396484375, + 2813.06689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9251753091812134, + "bbox": [ + 1288.3204345703125, + 660.3208618164062, + 2266.946533203125, + 2095.79248046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9172502160072327, + "bbox": [ + 224.95050048828125, + 643.0343017578125, + 1208.8421630859375, + 1602.077392578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9071513414382935, + "bbox": [ + 1244.216064453125, + 364.0979309082031, + 2436.4111328125, + 2889.01123046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.89444500207901, + "bbox": [ + 223.46446228027344, + 1652.935791015625, + 763.1084594726562, + 2026.03466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8889840245246887, + "bbox": [ + 159.27928161621094, + 460.1064147949219, + 1243.0948486328125, + 2116.891845703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7696119546890259, + "bbox": [ + 250.4680938720703, + 539.6641235351562, + 1028.5584716796875, + 640.7518920898438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7385724186897278, + "bbox": [ + 1301.8558349609375, + 565.8190307617188, + 2100.14404296875, + 632.9581298828125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.749894917011261, + "bbox": [ + 1292.4083251953125, + 466.3904113769531, + 1405.4862060546875, + 561.9081420898438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7435379028320312, + "bbox": [ + 234.83375549316406, + 447.31365966796875, + 348.72137451171875, + 547.6092529296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7019142508506775, + "bbox": [ + 1079.914794921875, + 555.5654296875, + 1189.1385498046875, + 659.0630493164062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6580477952957153, + "bbox": [ + 2200.89111328125, + 561.7781982421875, + 2296.7607421875, + 651.3455200195312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4683842957019806, + "bbox": [ + 231.07928466796875, + 3243.40673828125, + 324.36322021484375, + 3316.35546875 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9489567875862122, + "bbox": [ + 1289.3067626953125, + 2134.713623046875, + 2290.681396484375, + 2813.06689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9251753091812134, + "bbox": [ + 1288.3204345703125, + 660.3208618164062, + 2266.946533203125, + 2095.79248046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9172502160072327, + "bbox": [ + 224.95050048828125, + 643.0343017578125, + 1208.8421630859375, + 1602.077392578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9071513414382935, + "bbox": [ + 1244.216064453125, + 364.0979309082031, + 2436.4111328125, + 2889.01123046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.89444500207901, + "bbox": [ + 223.46446228027344, + 1652.935791015625, + 763.1084594726562, + 2026.03466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8889840245246887, + "bbox": [ + 159.27928161621094, + 460.1064147949219, + 1243.0948486328125, + 2116.891845703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7696119546890259, + "bbox": [ + 250.4680938720703, + 539.6641235351562, + 1028.5584716796875, + 640.7518920898438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7385724186897278, + "bbox": [ + 1301.8558349609375, + 565.8190307617188, + 2100.14404296875, + 632.9581298828125 + ] + } + ], + "timestamp": "2025-10-15T21:42:21.123823" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 23.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 23.json" new file mode 100644 index 0000000..e778e77 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 23.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 23.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7583073973655701, + "bbox": [ + 1315.4588623046875, + 458.1630859375, + 1427.9962158203125, + 557.2672119140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.749862015247345, + "bbox": [ + 258.67315673828125, + 438.832763671875, + 377.02880859375, + 543.326171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6795905828475952, + "bbox": [ + 977.0494995117188, + 2400.445068359375, + 1092.5443115234375, + 2517.457275390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6604072451591492, + "bbox": [ + 2010.1856689453125, + 2505.9365234375, + 2133.678466796875, + 2630.3076171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5867871642112732, + "bbox": [ + 2188.0361328125, + 3215.247314453125, + 2278.178466796875, + 3290.709716796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9407867789268494, + "bbox": [ + 196.7617950439453, + 470.0298156738281, + 1258.81298828125, + 2477.304443359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9302079677581787, + "bbox": [ + 247.22377014160156, + 684.0687866210938, + 1240.1390380859375, + 1915.2335205078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9238818883895874, + "bbox": [ + 1304.8209228515625, + 650.1387329101562, + 2271.716064453125, + 1859.27587890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9183475375175476, + "bbox": [ + 1305.7777099609375, + 1913.403564453125, + 2286.17041015625, + 2540.195068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.894358217716217, + "bbox": [ + 1270.8870849609375, + 463.6681823730469, + 2308.056396484375, + 2585.648193359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8862616419792175, + "bbox": [ + 256.6649169921875, + 1972.3564453125, + 1237.6002197265625, + 2403.973876953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8266939520835876, + "bbox": [ + 258.3373107910156, + 542.9675903320312, + 1237.476806640625, + 672.9326171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6949105858802795, + "bbox": [ + 1320.3643798828125, + 557.3768310546875, + 1859.4832763671875, + 637.4200439453125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7583073973655701, + "bbox": [ + 1315.4588623046875, + 458.1630859375, + 1427.9962158203125, + 557.2672119140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.749862015247345, + "bbox": [ + 258.67315673828125, + 438.832763671875, + 377.02880859375, + 543.326171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6795905828475952, + "bbox": [ + 977.0494995117188, + 2400.445068359375, + 1092.5443115234375, + 2517.457275390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6604072451591492, + "bbox": [ + 2010.1856689453125, + 2505.9365234375, + 2133.678466796875, + 2630.3076171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5867871642112732, + "bbox": [ + 2188.0361328125, + 3215.247314453125, + 2278.178466796875, + 3290.709716796875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9407867789268494, + "bbox": [ + 196.7617950439453, + 470.0298156738281, + 1258.81298828125, + 2477.304443359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9302079677581787, + "bbox": [ + 247.22377014160156, + 684.0687866210938, + 1240.1390380859375, + 1915.2335205078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9238818883895874, + "bbox": [ + 1304.8209228515625, + 650.1387329101562, + 2271.716064453125, + 1859.27587890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9183475375175476, + "bbox": [ + 1305.7777099609375, + 1913.403564453125, + 2286.17041015625, + 2540.195068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.894358217716217, + "bbox": [ + 1270.8870849609375, + 463.6681823730469, + 2308.056396484375, + 2585.648193359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8862616419792175, + "bbox": [ + 256.6649169921875, + 1972.3564453125, + 1237.6002197265625, + 2403.973876953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8266939520835876, + "bbox": [ + 258.3373107910156, + 542.9675903320312, + 1237.476806640625, + 672.9326171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6949105858802795, + "bbox": [ + 1320.3643798828125, + 557.3768310546875, + 1859.4832763671875, + 637.4200439453125 + ] + } + ], + "timestamp": "2025-10-15T21:42:21.529891" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 24.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 24.json" new file mode 100644 index 0000000..8de7583 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 24.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 24.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7603040337562561, + "bbox": [ + 1243.0264892578125, + 440.6341857910156, + 1355.69091796875, + 539.8180541992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7409763336181641, + "bbox": [ + 209.2268829345703, + 424.6160888671875, + 327.13189697265625, + 528.352783203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7084857821464539, + "bbox": [ + 1952.000244140625, + 2788.70263671875, + 2066.78076171875, + 2907.456298828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6180035471916199, + "bbox": [ + 932.4114990234375, + 2666.3642578125, + 1069.0654296875, + 2802.71728515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5591386556625366, + "bbox": [ + 207.4577178955078, + 3149.909423828125, + 296.1625671386719, + 3225.72705078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9445685148239136, + "bbox": [ + 1233.0321044921875, + 2203.9228515625, + 2217.4091796875, + 2813.353515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9393221735954285, + "bbox": [ + 207.30430603027344, + 633.2778930664062, + 1163.526611328125, + 2006.29248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9351040720939636, + "bbox": [ + 197.83212280273438, + 2020.2059326171875, + 1170.059814453125, + 2679.5615234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9278611540794373, + "bbox": [ + 1230.6417236328125, + 634.27099609375, + 2199.768798828125, + 2182.162353515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8942872881889343, + "bbox": [ + 131.9254150390625, + 369.9350280761719, + 1191.67431640625, + 2865.7119140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8931431770324707, + "bbox": [ + 1200.5067138671875, + 395.0010986328125, + 2260.846923828125, + 2937.7626953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7773128747940063, + "bbox": [ + 1248.9613037109375, + 530.0830688476562, + 1852.842041015625, + 618.823486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7031071186065674, + "bbox": [ + 217.8101806640625, + 525.7796020507812, + 766.0855712890625, + 614.9223022460938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7603040337562561, + "bbox": [ + 1243.0264892578125, + 440.6341857910156, + 1355.69091796875, + 539.8180541992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7409763336181641, + "bbox": [ + 209.2268829345703, + 424.6160888671875, + 327.13189697265625, + 528.352783203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7084857821464539, + "bbox": [ + 1952.000244140625, + 2788.70263671875, + 2066.78076171875, + 2907.456298828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6180035471916199, + "bbox": [ + 932.4114990234375, + 2666.3642578125, + 1069.0654296875, + 2802.71728515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5591386556625366, + "bbox": [ + 207.4577178955078, + 3149.909423828125, + 296.1625671386719, + 3225.72705078125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9445685148239136, + "bbox": [ + 1233.0321044921875, + 2203.9228515625, + 2217.4091796875, + 2813.353515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9393221735954285, + "bbox": [ + 207.30430603027344, + 633.2778930664062, + 1163.526611328125, + 2006.29248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9351040720939636, + "bbox": [ + 197.83212280273438, + 2020.2059326171875, + 1170.059814453125, + 2679.5615234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9278611540794373, + "bbox": [ + 1230.6417236328125, + 634.27099609375, + 2199.768798828125, + 2182.162353515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8942872881889343, + "bbox": [ + 131.9254150390625, + 369.9350280761719, + 1191.67431640625, + 2865.7119140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8931431770324707, + "bbox": [ + 1200.5067138671875, + 395.0010986328125, + 2260.846923828125, + 2937.7626953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7773128747940063, + "bbox": [ + 1248.9613037109375, + 530.0830688476562, + 1852.842041015625, + 618.823486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7031071186065674, + "bbox": [ + 217.8101806640625, + 525.7796020507812, + 766.0855712890625, + 614.9223022460938 + ] + } + ], + "timestamp": "2025-10-15T21:42:21.927331" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 25.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 25.json" new file mode 100644 index 0000000..842f243 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 25.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 25.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7470338940620422, + "bbox": [ + 1306.45263671875, + 444.80322265625, + 1428.02392578125, + 547.4015502929688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7452173233032227, + "bbox": [ + 257.1669616699219, + 439.913818359375, + 372.7599182128906, + 540.7339477539062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6380429863929749, + "bbox": [ + 1803.7135009765625, + 423.1590881347656, + 1928.1517333984375, + 535.1259155273438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5977344512939453, + "bbox": [ + 2205.128173828125, + 3191.2490234375, + 2298.59521484375, + 3269.12451171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5877411365509033, + "bbox": [ + 1056.515380859375, + 2646.32470703125, + 1188.398193359375, + 2776.163330078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5483492016792297, + "bbox": [ + 1049.000732421875, + 2641.85791015625, + 1208.7122802734375, + 2795.390869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9478623270988464, + "bbox": [ + 1269.507568359375, + 351.0958251953125, + 2454.247802734375, + 2677.606689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9334686994552612, + "bbox": [ + 1311.277099609375, + 625.7213134765625, + 2296.871826171875, + 2002.0159912109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9183816313743591, + "bbox": [ + 1304.6392822265625, + 2017.734130859375, + 2327.0908203125, + 2410.439697265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8889895081520081, + "bbox": [ + 210.6180419921875, + 408.8851318359375, + 1256.8125, + 2745.53125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7976266145706177, + "bbox": [ + 248.84210205078125, + 622.2708740234375, + 1245.0836181640625, + 2713.327392578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7661908268928528, + "bbox": [ + 255.46864318847656, + 529.7603149414062, + 923.6224975585938, + 621.5368041992188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.754187822341919, + "bbox": [ + 1312.457275390625, + 552.1898803710938, + 2230.454345703125, + 616.1677856445312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7470338940620422, + "bbox": [ + 1306.45263671875, + 444.80322265625, + 1428.02392578125, + 547.4015502929688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7452173233032227, + "bbox": [ + 257.1669616699219, + 439.913818359375, + 372.7599182128906, + 540.7339477539062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6380429863929749, + "bbox": [ + 1803.7135009765625, + 423.1590881347656, + 1928.1517333984375, + 535.1259155273438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5977344512939453, + "bbox": [ + 2205.128173828125, + 3191.2490234375, + 2298.59521484375, + 3269.12451171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5877411365509033, + "bbox": [ + 1056.515380859375, + 2646.32470703125, + 1188.398193359375, + 2776.163330078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5483492016792297, + "bbox": [ + 1049.000732421875, + 2641.85791015625, + 1208.7122802734375, + 2795.390869140625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9478623270988464, + "bbox": [ + 1269.507568359375, + 351.0958251953125, + 2454.247802734375, + 2677.606689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9334686994552612, + "bbox": [ + 1311.277099609375, + 625.7213134765625, + 2296.871826171875, + 2002.0159912109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9183816313743591, + "bbox": [ + 1304.6392822265625, + 2017.734130859375, + 2327.0908203125, + 2410.439697265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8889895081520081, + "bbox": [ + 210.6180419921875, + 408.8851318359375, + 1256.8125, + 2745.53125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7976266145706177, + "bbox": [ + 248.84210205078125, + 622.2708740234375, + 1245.0836181640625, + 2713.327392578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7661908268928528, + "bbox": [ + 255.46864318847656, + 529.7603149414062, + 923.6224975585938, + 621.5368041992188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.754187822341919, + "bbox": [ + 1312.457275390625, + 552.1898803710938, + 2230.454345703125, + 616.1677856445312 + ] + } + ], + "timestamp": "2025-10-15T21:42:22.332829" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 26.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 26.json" new file mode 100644 index 0000000..b27678a --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 26.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 26.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7639952301979065, + "bbox": [ + 1279.1861572265625, + 458.4612731933594, + 1395.311279296875, + 556.8256225585938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.748790979385376, + "bbox": [ + 218.9242706298828, + 445.974609375, + 337.1281433105469, + 550.1585083007812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7392202615737915, + "bbox": [ + 1083.750244140625, + 607.2634887695312, + 1192.764892578125, + 723.4690551757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6924455761909485, + "bbox": [ + 2156.49755859375, + 548.27001953125, + 2283.60400390625, + 676.18359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5407971739768982, + "bbox": [ + 233.24972534179688, + 3240.1552734375, + 331.2944030761719, + 3322.29638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443373084068298, + "bbox": [ + 224.71253967285156, + 619.0139770507812, + 1161.943359375, + 2465.961669921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9408209323883057, + "bbox": [ + 1287.1007080078125, + 651.6947021484375, + 2247.23779296875, + 2650.708740234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9366406798362732, + "bbox": [ + 204.81118774414062, + 400.9768981933594, + 1211.562744140625, + 2886.3173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9093062877655029, + "bbox": [ + 227.8299560546875, + 2447.629150390625, + 1153.9886474609375, + 2813.974853515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8991206884384155, + "bbox": [ + 1294.5072021484375, + 2643.141357421875, + 2100.5361328125, + 3015.75341796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8794580101966858, + "bbox": [ + 1249.0592041015625, + 381.87432861328125, + 2306.8974609375, + 3035.4580078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8281888365745544, + "bbox": [ + 227.48216247558594, + 549.6765747070312, + 1202.5408935546875, + 676.5394287109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7056913375854492, + "bbox": [ + 1292.6578369140625, + 548.9569702148438, + 2129.958984375, + 647.6627197265625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7639952301979065, + "bbox": [ + 1279.1861572265625, + 458.4612731933594, + 1395.311279296875, + 556.8256225585938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.748790979385376, + "bbox": [ + 218.9242706298828, + 445.974609375, + 337.1281433105469, + 550.1585083007812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7392202615737915, + "bbox": [ + 1083.750244140625, + 607.2634887695312, + 1192.764892578125, + 723.4690551757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6924455761909485, + "bbox": [ + 2156.49755859375, + 548.27001953125, + 2283.60400390625, + 676.18359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5407971739768982, + "bbox": [ + 233.24972534179688, + 3240.1552734375, + 331.2944030761719, + 3322.29638671875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443373084068298, + "bbox": [ + 224.71253967285156, + 619.0139770507812, + 1161.943359375, + 2465.961669921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9408209323883057, + "bbox": [ + 1287.1007080078125, + 651.6947021484375, + 2247.23779296875, + 2650.708740234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9366406798362732, + "bbox": [ + 204.81118774414062, + 400.9768981933594, + 1211.562744140625, + 2886.3173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9093062877655029, + "bbox": [ + 227.8299560546875, + 2447.629150390625, + 1153.9886474609375, + 2813.974853515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8991206884384155, + "bbox": [ + 1294.5072021484375, + 2643.141357421875, + 2100.5361328125, + 3015.75341796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8794580101966858, + "bbox": [ + 1249.0592041015625, + 381.87432861328125, + 2306.8974609375, + 3035.4580078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8281888365745544, + "bbox": [ + 227.48216247558594, + 549.6765747070312, + 1202.5408935546875, + 676.5394287109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7056913375854492, + "bbox": [ + 1292.6578369140625, + 548.9569702148438, + 2129.958984375, + 647.6627197265625 + ] + } + ], + "timestamp": "2025-10-15T21:42:22.725829" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 27.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 27.json" new file mode 100644 index 0000000..eee35bc --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 27.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 27.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7563045024871826, + "bbox": [ + 1265.173095703125, + 445.1062316894531, + 1371.8775634765625, + 538.3765869140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.744890570640564, + "bbox": [ + 245.68658447265625, + 430.6427307128906, + 362.5268859863281, + 533.1149291992188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6402556896209717, + "bbox": [ + 2003.559326171875, + 2111.378662109375, + 2122.32421875, + 2227.587158203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209704875946045, + "bbox": [ + 844.4823608398438, + 2039.5562744140625, + 976.6078491210938, + 2167.306396484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.566334068775177, + "bbox": [ + 2114.655029296875, + 3107.4013671875, + 2202.24853515625, + 3177.225830078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9525284767150879, + "bbox": [ + 247.88026428222656, + 618.3157348632812, + 1198.6685791015625, + 1942.540771484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9316564798355103, + "bbox": [ + 1242.405517578125, + 679.2432250976562, + 2217.74951171875, + 2047.7322998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9290622472763062, + "bbox": [ + 1227.5899658203125, + 344.68780517578125, + 2310.302001953125, + 2262.320068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.923385500907898, + "bbox": [ + 192.93392944335938, + 393.9797668457031, + 1226.361572265625, + 2281.7314453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8416505455970764, + "bbox": [ + 1241.6961669921875, + 537.61083984375, + 2195.19873046875, + 663.6416625976562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7822521328926086, + "bbox": [ + 263.68463134765625, + 524.5269165039062, + 930.4883422851562, + 618.067138671875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7563045024871826, + "bbox": [ + 1265.173095703125, + 445.1062316894531, + 1371.8775634765625, + 538.3765869140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.744890570640564, + "bbox": [ + 245.68658447265625, + 430.6427307128906, + 362.5268859863281, + 533.1149291992188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6402556896209717, + "bbox": [ + 2003.559326171875, + 2111.378662109375, + 2122.32421875, + 2227.587158203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209704875946045, + "bbox": [ + 844.4823608398438, + 2039.5562744140625, + 976.6078491210938, + 2167.306396484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.566334068775177, + "bbox": [ + 2114.655029296875, + 3107.4013671875, + 2202.24853515625, + 3177.225830078125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9525284767150879, + "bbox": [ + 247.88026428222656, + 618.3157348632812, + 1198.6685791015625, + 1942.540771484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9316564798355103, + "bbox": [ + 1242.405517578125, + 679.2432250976562, + 2217.74951171875, + 2047.7322998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9290622472763062, + "bbox": [ + 1227.5899658203125, + 344.68780517578125, + 2310.302001953125, + 2262.320068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.923385500907898, + "bbox": [ + 192.93392944335938, + 393.9797668457031, + 1226.361572265625, + 2281.7314453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8416505455970764, + "bbox": [ + 1241.6961669921875, + 537.61083984375, + 2195.19873046875, + 663.6416625976562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7822521328926086, + "bbox": [ + 263.68463134765625, + 524.5269165039062, + 930.4883422851562, + 618.067138671875 + ] + } + ], + "timestamp": "2025-10-15T21:42:23.100840" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 28.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 28.json" new file mode 100644 index 0000000..bbcf210 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 28.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 28.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7671974301338196, + "bbox": [ + 1208.6292724609375, + 427.62286376953125, + 1318.9957275390625, + 526.7385864257812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7321566343307495, + "bbox": [ + 202.8789520263672, + 540.8079223632812, + 313.92156982421875, + 644.37060546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254521608352661, + "bbox": [ + 866.705322265625, + 2150.987060546875, + 1014.4402465820312, + 2308.591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6054081320762634, + "bbox": [ + 880.777099609375, + 2158.013427734375, + 1018.0807495117188, + 2278.903564453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5955401062965393, + "bbox": [ + 1854.700439453125, + 2137.65478515625, + 1999.0965576171875, + 2275.367431640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5244964957237244, + "bbox": [ + 215.26780700683594, + 3034.26806640625, + 306.5033874511719, + 3107.3369140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9458028078079224, + "bbox": [ + 182.71018981933594, + 449.1365051269531, + 1153.0537109375, + 2508.34228515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9444642663002014, + "bbox": [ + 192.87725830078125, + 638.905029296875, + 1128.5235595703125, + 2079.979248046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9300796389579773, + "bbox": [ + 1186.2178955078125, + 417.3510437011719, + 2177.8935546875, + 2314.64697265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.928514838218689, + "bbox": [ + 1203.641357421875, + 527.40283203125, + 2157.0087890625, + 1736.680419921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9088085293769836, + "bbox": [ + 223.0669708251953, + 2115.339111328125, + 628.1900024414062, + 2468.33642578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8840155005455017, + "bbox": [ + 1212.266845703125, + 1744.49169921875, + 2010.3941650390625, + 2110.579833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6840057969093323, + "bbox": [ + 207.73658752441406, + 416.903076171875, + 1124.740966796875, + 491.5888977050781 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7671974301338196, + "bbox": [ + 1208.6292724609375, + 427.62286376953125, + 1318.9957275390625, + 526.7385864257812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7321566343307495, + "bbox": [ + 202.8789520263672, + 540.8079223632812, + 313.92156982421875, + 644.37060546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254521608352661, + "bbox": [ + 866.705322265625, + 2150.987060546875, + 1014.4402465820312, + 2308.591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6054081320762634, + "bbox": [ + 880.777099609375, + 2158.013427734375, + 1018.0807495117188, + 2278.903564453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5955401062965393, + "bbox": [ + 1854.700439453125, + 2137.65478515625, + 1999.0965576171875, + 2275.367431640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5244964957237244, + "bbox": [ + 215.26780700683594, + 3034.26806640625, + 306.5033874511719, + 3107.3369140625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9458028078079224, + "bbox": [ + 182.71018981933594, + 449.1365051269531, + 1153.0537109375, + 2508.34228515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9444642663002014, + "bbox": [ + 192.87725830078125, + 638.905029296875, + 1128.5235595703125, + 2079.979248046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9300796389579773, + "bbox": [ + 1186.2178955078125, + 417.3510437011719, + 2177.8935546875, + 2314.64697265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.928514838218689, + "bbox": [ + 1203.641357421875, + 527.40283203125, + 2157.0087890625, + 1736.680419921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9088085293769836, + "bbox": [ + 223.0669708251953, + 2115.339111328125, + 628.1900024414062, + 2468.33642578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8840155005455017, + "bbox": [ + 1212.266845703125, + 1744.49169921875, + 2010.3941650390625, + 2110.579833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6840057969093323, + "bbox": [ + 207.73658752441406, + 416.903076171875, + 1124.740966796875, + 491.5888977050781 + ] + } + ], + "timestamp": "2025-10-15T21:42:23.450963" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 29.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 29.json" new file mode 100644 index 0000000..84ccdbb --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 29.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 29.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7490072846412659, + "bbox": [ + 244.7371368408203, + 411.09942626953125, + 360.1676025390625, + 514.1549682617188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7359649538993835, + "bbox": [ + 1248.7650146484375, + 423.65740966796875, + 1360.45947265625, + 527.7479248046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6369026899337769, + "bbox": [ + 803.07666015625, + 363.80731201171875, + 919.5338134765625, + 476.9936828613281 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6240957975387573, + "bbox": [ + 1743.98291015625, + 392.9949951171875, + 1887.8016357421875, + 535.5162353515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5925480723381042, + "bbox": [ + 2095.988525390625, + 3039.96044921875, + 2179.296875, + 3109.859130859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9367966055870056, + "bbox": [ + 240.4109649658203, + 1794.9713134765625, + 1176.377197265625, + 2451.74853515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9272936582565308, + "bbox": [ + 1219.8980712890625, + 313.4834899902344, + 2307.443359375, + 2510.211669921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9262723922729492, + "bbox": [ + 1248.688232421875, + 531.0572509765625, + 2184.9443359375, + 1996.3455810546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9128106236457825, + "bbox": [ + 237.52662658691406, + 535.4241943359375, + 1183.2330322265625, + 1727.9837646484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9073975086212158, + "bbox": [ + 1248.099853515625, + 2049.310791015625, + 2173.978515625, + 2444.32470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.895458996295929, + "bbox": [ + 202.3297119140625, + 383.0038757324219, + 1199.4635009765625, + 2504.403076171875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7490072846412659, + "bbox": [ + 244.7371368408203, + 411.09942626953125, + 360.1676025390625, + 514.1549682617188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7359649538993835, + "bbox": [ + 1248.7650146484375, + 423.65740966796875, + 1360.45947265625, + 527.7479248046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6369026899337769, + "bbox": [ + 803.07666015625, + 363.80731201171875, + 919.5338134765625, + 476.9936828613281 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6240957975387573, + "bbox": [ + 1743.98291015625, + 392.9949951171875, + 1887.8016357421875, + 535.5162353515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5925480723381042, + "bbox": [ + 2095.988525390625, + 3039.96044921875, + 2179.296875, + 3109.859130859375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9367966055870056, + "bbox": [ + 240.4109649658203, + 1794.9713134765625, + 1176.377197265625, + 2451.74853515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9272936582565308, + "bbox": [ + 1219.8980712890625, + 313.4834899902344, + 2307.443359375, + 2510.211669921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9262723922729492, + "bbox": [ + 1248.688232421875, + 531.0572509765625, + 2184.9443359375, + 1996.3455810546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9128106236457825, + "bbox": [ + 237.52662658691406, + 535.4241943359375, + 1183.2330322265625, + 1727.9837646484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9073975086212158, + "bbox": [ + 1248.099853515625, + 2049.310791015625, + 2173.978515625, + 2444.32470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.895458996295929, + "bbox": [ + 202.3297119140625, + 383.0038757324219, + 1199.4635009765625, + 2504.403076171875 + ] + } + ], + "timestamp": "2025-10-15T21:42:23.797449" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 30.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 30.json" new file mode 100644 index 0000000..6cb885a --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 30.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 30.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7478122711181641, + "bbox": [ + 217.45802307128906, + 434.11572265625, + 329.8018798828125, + 534.5653686523438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7416979074478149, + "bbox": [ + 1252.624267578125, + 613.5382690429688, + 1365.750732421875, + 714.379150390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6869469881057739, + "bbox": [ + 856.775146484375, + 426.5235290527344, + 982.0392456054688, + 545.2455444335938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5516640543937683, + "bbox": [ + 1717.7908935546875, + 548.8966674804688, + 1872.585693359375, + 704.7841186523438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5431124567985535, + "bbox": [ + 226.42828369140625, + 3128.82470703125, + 319.4625549316406, + 3203.689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9370722770690918, + "bbox": [ + 222.5220489501953, + 619.6429443359375, + 1179.1151123046875, + 1887.2254638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9255450367927551, + "bbox": [ + 1251.167724609375, + 726.2056274414062, + 2220.2802734375, + 2536.865966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9112128019332886, + "bbox": [ + 1225.432373046875, + 421.2862854003906, + 2296.282958984375, + 2931.954345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8925390839576721, + "bbox": [ + 176.34066772460938, + 418.58099365234375, + 1195.7926025390625, + 2148.531494140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8900695443153381, + "bbox": [ + 1248.7115478515625, + 2554.833740234375, + 2065.1611328125, + 2785.1220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7875652313232422, + "bbox": [ + 224.31771850585938, + 533.2552490234375, + 866.4579467773438, + 615.2509155273438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7478898763656616, + "bbox": [ + 1237.149658203125, + 445.45220947265625, + 2243.2041015625, + 582.273681640625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7478122711181641, + "bbox": [ + 217.45802307128906, + 434.11572265625, + 329.8018798828125, + 534.5653686523438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7416979074478149, + "bbox": [ + 1252.624267578125, + 613.5382690429688, + 1365.750732421875, + 714.379150390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6869469881057739, + "bbox": [ + 856.775146484375, + 426.5235290527344, + 982.0392456054688, + 545.2455444335938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5516640543937683, + "bbox": [ + 1717.7908935546875, + 548.8966674804688, + 1872.585693359375, + 704.7841186523438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5431124567985535, + "bbox": [ + 226.42828369140625, + 3128.82470703125, + 319.4625549316406, + 3203.689453125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9370722770690918, + "bbox": [ + 222.5220489501953, + 619.6429443359375, + 1179.1151123046875, + 1887.2254638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9255450367927551, + "bbox": [ + 1251.167724609375, + 726.2056274414062, + 2220.2802734375, + 2536.865966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9112128019332886, + "bbox": [ + 1225.432373046875, + 421.2862854003906, + 2296.282958984375, + 2931.954345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8925390839576721, + "bbox": [ + 176.34066772460938, + 418.58099365234375, + 1195.7926025390625, + 2148.531494140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8900695443153381, + "bbox": [ + 1248.7115478515625, + 2554.833740234375, + 2065.1611328125, + 2785.1220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7875652313232422, + "bbox": [ + 224.31771850585938, + 533.2552490234375, + 866.4579467773438, + 615.2509155273438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7478898763656616, + "bbox": [ + 1237.149658203125, + 445.45220947265625, + 2243.2041015625, + 582.273681640625 + ] + } + ], + "timestamp": "2025-10-15T21:42:24.166790" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 31.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 31.json" new file mode 100644 index 0000000..3c9eb79 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 31.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 31.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7441417574882507, + "bbox": [ + 1305.3585205078125, + 619.4505615234375, + 1417.764892578125, + 716.9970703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7384775280952454, + "bbox": [ + 251.1217041015625, + 437.8577575683594, + 376.6976623535156, + 545.1366577148438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6475614309310913, + "bbox": [ + 1891.146484375, + 617.232666015625, + 2035.8447265625, + 749.7539672851562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209352612495422, + "bbox": [ + 828.2235107421875, + 416.9590148925781, + 962.45947265625, + 551.1586303710938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5551373362541199, + "bbox": [ + 1909.77294921875, + 622.6658935546875, + 2027.289794921875, + 734.7251586914062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5413956046104431, + "bbox": [ + 2182.302734375, + 3172.290771484375, + 2271.317138671875, + 3245.958740234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9492501616477966, + "bbox": [ + 240.32864379882812, + 570.3783569335938, + 1214.3411865234375, + 2140.682861328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9143268465995789, + "bbox": [ + 1274.05859375, + 461.7174377441406, + 2405.643310546875, + 2612.79052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9052168130874634, + "bbox": [ + 197.6411590576172, + 388.117431640625, + 1249.6856689453125, + 2462.703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9047935605049133, + "bbox": [ + 1281.997802734375, + 738.0966186523438, + 2272.8759765625, + 2533.966796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8775144219398499, + "bbox": [ + 241.9989471435547, + 2166.552734375, + 1097.3011474609375, + 2391.599853515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8400033116340637, + "bbox": [ + 1290.3184814453125, + 446.5696716308594, + 2311.39794921875, + 587.3668212890625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7441417574882507, + "bbox": [ + 1305.3585205078125, + 619.4505615234375, + 1417.764892578125, + 716.9970703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7384775280952454, + "bbox": [ + 251.1217041015625, + 437.8577575683594, + 376.6976623535156, + 545.1366577148438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6475614309310913, + "bbox": [ + 1891.146484375, + 617.232666015625, + 2035.8447265625, + 749.7539672851562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209352612495422, + "bbox": [ + 828.2235107421875, + 416.9590148925781, + 962.45947265625, + 551.1586303710938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5551373362541199, + "bbox": [ + 1909.77294921875, + 622.6658935546875, + 2027.289794921875, + 734.7251586914062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5413956046104431, + "bbox": [ + 2182.302734375, + 3172.290771484375, + 2271.317138671875, + 3245.958740234375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9492501616477966, + "bbox": [ + 240.32864379882812, + 570.3783569335938, + 1214.3411865234375, + 2140.682861328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9143268465995789, + "bbox": [ + 1274.05859375, + 461.7174377441406, + 2405.643310546875, + 2612.79052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9052168130874634, + "bbox": [ + 197.6411590576172, + 388.117431640625, + 1249.6856689453125, + 2462.703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9047935605049133, + "bbox": [ + 1281.997802734375, + 738.0966186523438, + 2272.8759765625, + 2533.966796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8775144219398499, + "bbox": [ + 241.9989471435547, + 2166.552734375, + 1097.3011474609375, + 2391.599853515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8400033116340637, + "bbox": [ + 1290.3184814453125, + 446.5696716308594, + 2311.39794921875, + 587.3668212890625 + ] + } + ], + "timestamp": "2025-10-15T21:42:24.554527" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 32.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 32.json" new file mode 100644 index 0000000..0f3e059 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 32.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 32.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7425358295440674, + "bbox": [ + 1218.9185791015625, + 437.5244445800781, + 1331.3175048828125, + 533.504638671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7329147458076477, + "bbox": [ + 202.97158813476562, + 421.9583740234375, + 320.283935546875, + 526.1498413085938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6677577495574951, + "bbox": [ + 1692.0718994140625, + 415.6666564941406, + 1818.622802734375, + 536.9111328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6237303614616394, + "bbox": [ + 784.9873046875, + 393.5762023925781, + 908.3550415039062, + 524.736572265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5060696005821228, + "bbox": [ + 219.06663513183594, + 3053.544921875, + 307.7846374511719, + 3124.40869140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.949751615524292, + "bbox": [ + 181.42724609375, + 551.2989501953125, + 1153.4652099609375, + 2190.4150390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9353466629981995, + "bbox": [ + 1206.99365234375, + 695.146240234375, + 2175.642578125, + 2246.903564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.922912061214447, + "bbox": [ + 173.48036193847656, + 387.88653564453125, + 1174.7154541015625, + 2288.66943359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9220249652862549, + "bbox": [ + 1206.2884521484375, + 397.27252197265625, + 2184.733642578125, + 2712.7158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9049123525619507, + "bbox": [ + 1216.1568603515625, + 2264.42138671875, + 1793.39453125, + 2695.1259765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8492533564567566, + "bbox": [ + 1201.4556884765625, + 533.108154296875, + 2151.549560546875, + 656.1810302734375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7425358295440674, + "bbox": [ + 1218.9185791015625, + 437.5244445800781, + 1331.3175048828125, + 533.504638671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7329147458076477, + "bbox": [ + 202.97158813476562, + 421.9583740234375, + 320.283935546875, + 526.1498413085938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6677577495574951, + "bbox": [ + 1692.0718994140625, + 415.6666564941406, + 1818.622802734375, + 536.9111328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6237303614616394, + "bbox": [ + 784.9873046875, + 393.5762023925781, + 908.3550415039062, + 524.736572265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5060696005821228, + "bbox": [ + 219.06663513183594, + 3053.544921875, + 307.7846374511719, + 3124.40869140625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.949751615524292, + "bbox": [ + 181.42724609375, + 551.2989501953125, + 1153.4652099609375, + 2190.4150390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9353466629981995, + "bbox": [ + 1206.99365234375, + 695.146240234375, + 2175.642578125, + 2246.903564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.922912061214447, + "bbox": [ + 173.48036193847656, + 387.88653564453125, + 1174.7154541015625, + 2288.66943359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9220249652862549, + "bbox": [ + 1206.2884521484375, + 397.27252197265625, + 2184.733642578125, + 2712.7158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9049123525619507, + "bbox": [ + 1216.1568603515625, + 2264.42138671875, + 1793.39453125, + 2695.1259765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8492533564567566, + "bbox": [ + 1201.4556884765625, + 533.108154296875, + 2151.549560546875, + 656.1810302734375 + ] + } + ], + "timestamp": "2025-10-15T21:42:24.956002" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 33.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 33.json" new file mode 100644 index 0000000..77debd7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 33.json" @@ -0,0 +1,384 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 33.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7465360164642334, + "bbox": [ + 1268.0550537109375, + 1946.707763671875, + 1382.6402587890625, + 2048.778564453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7267874479293823, + "bbox": [ + 1272.652099609375, + 443.0932922363281, + 1387.7669677734375, + 542.75537109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.651939332485199, + "bbox": [ + 1852.0780029296875, + 1141.5936279296875, + 1974.8770751953125, + 1256.622802734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6356967687606812, + "bbox": [ + 903.1343994140625, + 2354.328857421875, + 1027.98681640625, + 2482.572021484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6191906332969666, + "bbox": [ + 2123.530029296875, + 3110.798828125, + 2211.611083984375, + 3187.519287109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5796049237251282, + "bbox": [ + 1822.7315673828125, + 2390.33544921875, + 1959.0860595703125, + 2531.3896484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5343111157417297, + "bbox": [ + 1810.602294921875, + 2378.51806640625, + 1997.11279296875, + 2553.020751953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.48504820466041565, + "bbox": [ + 1842.450439453125, + 1137.1331787109375, + 1990.340087890625, + 1273.8870849609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.22974027693271637, + "bbox": [ + 885.6092529296875, + 2345.51220703125, + 1047.627685546875, + 2498.6982421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9189755320549011, + "bbox": [ + 216.62596130371094, + 514.4877319335938, + 1218.9073486328125, + 2331.495849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9152743220329285, + "bbox": [ + 1278.2694091796875, + 618.062255859375, + 2219.734619140625, + 1154.516357421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8925208449363708, + "bbox": [ + 1251.394775390625, + 410.710693359375, + 2291.44970703125, + 1327.9617919921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8547224998474121, + "bbox": [ + 1268.6759033203125, + 2034.6221923828125, + 2205.525390625, + 2157.5576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8407100439071655, + "bbox": [ + 1277.8563232421875, + 2162.852783203125, + 2155.653076171875, + 2278.419189453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8065725564956665, + "bbox": [ + 1235.706787109375, + 1906.808837890625, + 2250.329833984375, + 2590.80224609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7864087224006653, + "bbox": [ + 1283.74267578125, + 525.3441772460938, + 1844.7650146484375, + 613.0578002929688 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.735100507736206, + "bbox": [ + 221.11167907714844, + 290.04388427734375, + 1217.345703125, + 2520.044677734375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7465360164642334, + "bbox": [ + 1268.0550537109375, + 1946.707763671875, + 1382.6402587890625, + 2048.778564453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7267874479293823, + "bbox": [ + 1272.652099609375, + 443.0932922363281, + 1387.7669677734375, + 542.75537109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.651939332485199, + "bbox": [ + 1852.0780029296875, + 1141.5936279296875, + 1974.8770751953125, + 1256.622802734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6356967687606812, + "bbox": [ + 903.1343994140625, + 2354.328857421875, + 1027.98681640625, + 2482.572021484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6191906332969666, + "bbox": [ + 2123.530029296875, + 3110.798828125, + 2211.611083984375, + 3187.519287109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5796049237251282, + "bbox": [ + 1822.7315673828125, + 2390.33544921875, + 1959.0860595703125, + 2531.3896484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5343111157417297, + "bbox": [ + 1810.602294921875, + 2378.51806640625, + 1997.11279296875, + 2553.020751953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.48504820466041565, + "bbox": [ + 1842.450439453125, + 1137.1331787109375, + 1990.340087890625, + 1273.8870849609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.22974027693271637, + "bbox": [ + 885.6092529296875, + 2345.51220703125, + 1047.627685546875, + 2498.6982421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9189755320549011, + "bbox": [ + 216.62596130371094, + 514.4877319335938, + 1218.9073486328125, + 2331.495849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9152743220329285, + "bbox": [ + 1278.2694091796875, + 618.062255859375, + 2219.734619140625, + 1154.516357421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8925208449363708, + "bbox": [ + 1251.394775390625, + 410.710693359375, + 2291.44970703125, + 1327.9617919921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8547224998474121, + "bbox": [ + 1268.6759033203125, + 2034.6221923828125, + 2205.525390625, + 2157.5576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8407100439071655, + "bbox": [ + 1277.8563232421875, + 2162.852783203125, + 2155.653076171875, + 2278.419189453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8065725564956665, + "bbox": [ + 1235.706787109375, + 1906.808837890625, + 2250.329833984375, + 2590.80224609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7864087224006653, + "bbox": [ + 1283.74267578125, + 525.3441772460938, + 1844.7650146484375, + 613.0578002929688 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.735100507736206, + "bbox": [ + 221.11167907714844, + 290.04388427734375, + 1217.345703125, + 2520.044677734375 + ] + } + ], + "timestamp": "2025-10-15T21:42:25.371418" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 34.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 34.json" new file mode 100644 index 0000000..2c9e430 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\203\341\205\251\341\206\274\341\204\200\341\205\263\341\204\205\341\205\241\341\204\206\341\205\265 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 34.json" @@ -0,0 +1,428 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 34.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7781926393508911, + "bbox": [ + 1174.4473876953125, + 1686.5008544921875, + 1284.2032470703125, + 1783.850830078125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7510513067245483, + "bbox": [ + 1181.91552734375, + 939.6041870117188, + 1292.602294921875, + 1033.9320068359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7372850179672241, + "bbox": [ + 1174.50537109375, + 2255.149658203125, + 1283.459716796875, + 2348.498291015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7137385606765747, + "bbox": [ + 1606.68115234375, + 898.678466796875, + 1711.3818359375, + 1001.8609619140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.671506941318512, + "bbox": [ + 1615.319580078125, + 1671.7012939453125, + 1728.802734375, + 1781.5047607421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6139318943023682, + "bbox": [ + 1613.926025390625, + 2223.26904296875, + 1749.8485107421875, + 2356.7177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5193522572517395, + "bbox": [ + 202.40505981445312, + 2935.1513671875, + 287.6956787109375, + 3007.1943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9420422315597534, + "bbox": [ + 1174.9542236328125, + 2420.994140625, + 2085.4755859375, + 2926.9267578125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9323466420173645, + "bbox": [ + 1148.2633056640625, + 383.50079345703125, + 2117.773681640625, + 735.6179809570312 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9067971110343933, + "bbox": [ + 180.83953857421875, + 771.261474609375, + 1113.4952392578125, + 2942.336181640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8982246518135071, + "bbox": [ + 1134.5289306640625, + 2207.236572265625, + 2111.487548828125, + 2978.97802734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8889222145080566, + "bbox": [ + 1169.5894775390625, + 1157.7430419921875, + 1977.7525634765625, + 1388.2022705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8770790696144104, + "bbox": [ + 1159.0941162109375, + 877.7720947265625, + 2132.783203125, + 1449.4947509765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8737181425094604, + "bbox": [ + 1153.5150146484375, + 1640.8978271484375, + 2132.93359375, + 1984.821044921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8346871137619019, + "bbox": [ + 1171.3275146484375, + 1032.1533203125, + 2074.8056640625, + 1147.1588134765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8261359930038452, + "bbox": [ + 1159.975341796875, + 1847.9400634765625, + 2031.1605224609375, + 1942.773681640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7757102251052856, + "bbox": [ + 1172.5452880859375, + 1775.2913818359375, + 2091.083251953125, + 1846.134521484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6931411623954773, + "bbox": [ + 1169.341552734375, + 2350.129638671875, + 1977.834228515625, + 2414.37255859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.33718404173851013, + "bbox": [ + 174.7861785888672, + 789.3289184570312, + 1128.7498779296875, + 3119.5009765625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7781926393508911, + "bbox": [ + 1174.4473876953125, + 1686.5008544921875, + 1284.2032470703125, + 1783.850830078125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7510513067245483, + "bbox": [ + 1181.91552734375, + 939.6041870117188, + 1292.602294921875, + 1033.9320068359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7372850179672241, + "bbox": [ + 1174.50537109375, + 2255.149658203125, + 1283.459716796875, + 2348.498291015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7137385606765747, + "bbox": [ + 1606.68115234375, + 898.678466796875, + 1711.3818359375, + 1001.8609619140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.671506941318512, + "bbox": [ + 1615.319580078125, + 1671.7012939453125, + 1728.802734375, + 1781.5047607421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6139318943023682, + "bbox": [ + 1613.926025390625, + 2223.26904296875, + 1749.8485107421875, + 2356.7177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5193522572517395, + "bbox": [ + 202.40505981445312, + 2935.1513671875, + 287.6956787109375, + 3007.1943359375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9420422315597534, + "bbox": [ + 1174.9542236328125, + 2420.994140625, + 2085.4755859375, + 2926.9267578125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9323466420173645, + "bbox": [ + 1148.2633056640625, + 383.50079345703125, + 2117.773681640625, + 735.6179809570312 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9067971110343933, + "bbox": [ + 180.83953857421875, + 771.261474609375, + 1113.4952392578125, + 2942.336181640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8982246518135071, + "bbox": [ + 1134.5289306640625, + 2207.236572265625, + 2111.487548828125, + 2978.97802734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8889222145080566, + "bbox": [ + 1169.5894775390625, + 1157.7430419921875, + 1977.7525634765625, + 1388.2022705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8770790696144104, + "bbox": [ + 1159.0941162109375, + 877.7720947265625, + 2132.783203125, + 1449.4947509765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8737181425094604, + "bbox": [ + 1153.5150146484375, + 1640.8978271484375, + 2132.93359375, + 1984.821044921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8346871137619019, + "bbox": [ + 1171.3275146484375, + 1032.1533203125, + 2074.8056640625, + 1147.1588134765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8261359930038452, + "bbox": [ + 1159.975341796875, + 1847.9400634765625, + 2031.1605224609375, + 1942.773681640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7757102251052856, + "bbox": [ + 1172.5452880859375, + 1775.2913818359375, + 2091.083251953125, + 1846.134521484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6931411623954773, + "bbox": [ + 1169.341552734375, + 2350.129638671875, + 1977.834228515625, + 2414.37255859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.33718404173851013, + "bbox": [ + 174.7861785888672, + 789.3289184570312, + 1128.7498779296875, + 3119.5009765625 + ] + } + ], + "timestamp": "2025-10-15T21:42:25.797255" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 1.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 1.json" new file mode 100644 index 0000000..2facf2e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 1.json" @@ -0,0 +1,604 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 1.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7983983755111694, + "bbox": [ + 1283.0810546875, + 1325.125732421875, + 1384.5260009765625, + 1416.30517578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7833477854728699, + "bbox": [ + 1270.5338134765625, + 517.6687622070312, + 1370.0843505859375, + 604.6702270507812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7758641242980957, + "bbox": [ + 299.525634765625, + 2626.5654296875, + 403.6762390136719, + 2715.09521484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7672030329704285, + "bbox": [ + 1295.678955078125, + 2624.228515625, + 1397.1365966796875, + 2711.986572265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7534511089324951, + "bbox": [ + 252.71568298339844, + 1017.978759765625, + 359.1546325683594, + 1113.8841552734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5481052398681641, + "bbox": [ + 2150.65478515625, + 3157.123779296875, + 2214.282958984375, + 3223.521240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5346898436546326, + "bbox": [ + 299.5550537109375, + 2967.251708984375, + 380.8943176269531, + 3063.773193359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5339068174362183, + "bbox": [ + 263.4315490722656, + 1373.9403076171875, + 340.1243896484375, + 1462.311767578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4563981890678406, + "bbox": [ + 1281.653564453125, + 896.8413696289062, + 1335.547119140625, + 968.05224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.44000840187072754, + "bbox": [ + 1297.4481201171875, + 2913.19091796875, + 1367.2335205078125, + 2994.41650390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.33058685064315796, + "bbox": [ + 1282.7811279296875, + 867.6663818359375, + 1362.669921875, + 981.5889282226562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.31872302293777466, + "bbox": [ + 1282.557861328125, + 877.6746215820312, + 1345.3052978515625, + 972.828369140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9117227792739868, + "bbox": [ + 1311.9637451171875, + 2798.298583984375, + 1734.390869140625, + 3133.28125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.910882830619812, + "bbox": [ + 263.6938781738281, + 2601.31787109375, + 1244.248291015625, + 3169.282470703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9080847501754761, + "bbox": [ + 273.4270324707031, + 1251.4666748046875, + 1193.434814453125, + 1611.5238037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8978163599967957, + "bbox": [ + 309.0304260253906, + 2800.632568359375, + 1195.1446533203125, + 3142.251953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8972594738006592, + "bbox": [ + 1255.6527099609375, + 1290.3077392578125, + 2243.359130859375, + 2541.968994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8952165842056274, + "bbox": [ + 237.6722869873047, + 986.0549926757812, + 1225.9930419921875, + 1638.569580078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8858779072761536, + "bbox": [ + 1287.703369140625, + 2612.586669921875, + 2259.971435546875, + 3154.13134765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8842043876647949, + "bbox": [ + 1231.833740234375, + 497.8525085449219, + 2235.005615234375, + 1078.83203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8692703247070312, + "bbox": [ + 1296.16259765625, + 1421.6787109375, + 2222.47216796875, + 1539.3712158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8480411171913147, + "bbox": [ + 1261.0084228515625, + 684.3721313476562, + 1693.477294921875, + 1047.2835693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8372505903244019, + "bbox": [ + 255.3374786376953, + 1111.43408203125, + 1194.5457763671875, + 1241.8060302734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7672603130340576, + "bbox": [ + 1275.9937744140625, + 598.87646484375, + 2159.73095703125, + 691.5820922851562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6891952753067017, + "bbox": [ + 296.5080261230469, + 2720.46337890625, + 1117.2606201171875, + 2783.51220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6798402070999146, + "bbox": [ + 1286.1678466796875, + 2722.088623046875, + 2128.16064453125, + 2783.493408203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5077571272850037, + "bbox": [ + 1267.4857177734375, + 619.4249267578125, + 2184.38818359375, + 681.4090576171875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7983983755111694, + "bbox": [ + 1283.0810546875, + 1325.125732421875, + 1384.5260009765625, + 1416.30517578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7833477854728699, + "bbox": [ + 1270.5338134765625, + 517.6687622070312, + 1370.0843505859375, + 604.6702270507812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7758641242980957, + "bbox": [ + 299.525634765625, + 2626.5654296875, + 403.6762390136719, + 2715.09521484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7672030329704285, + "bbox": [ + 1295.678955078125, + 2624.228515625, + 1397.1365966796875, + 2711.986572265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7534511089324951, + "bbox": [ + 252.71568298339844, + 1017.978759765625, + 359.1546325683594, + 1113.8841552734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5481052398681641, + "bbox": [ + 2150.65478515625, + 3157.123779296875, + 2214.282958984375, + 3223.521240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5346898436546326, + "bbox": [ + 299.5550537109375, + 2967.251708984375, + 380.8943176269531, + 3063.773193359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5339068174362183, + "bbox": [ + 263.4315490722656, + 1373.9403076171875, + 340.1243896484375, + 1462.311767578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4563981890678406, + "bbox": [ + 1281.653564453125, + 896.8413696289062, + 1335.547119140625, + 968.05224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.44000840187072754, + "bbox": [ + 1297.4481201171875, + 2913.19091796875, + 1367.2335205078125, + 2994.41650390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.33058685064315796, + "bbox": [ + 1282.7811279296875, + 867.6663818359375, + 1362.669921875, + 981.5889282226562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.31872302293777466, + "bbox": [ + 1282.557861328125, + 877.6746215820312, + 1345.3052978515625, + 972.828369140625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9117227792739868, + "bbox": [ + 1311.9637451171875, + 2798.298583984375, + 1734.390869140625, + 3133.28125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.910882830619812, + "bbox": [ + 263.6938781738281, + 2601.31787109375, + 1244.248291015625, + 3169.282470703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9080847501754761, + "bbox": [ + 273.4270324707031, + 1251.4666748046875, + 1193.434814453125, + 1611.5238037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8978163599967957, + "bbox": [ + 309.0304260253906, + 2800.632568359375, + 1195.1446533203125, + 3142.251953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8972594738006592, + "bbox": [ + 1255.6527099609375, + 1290.3077392578125, + 2243.359130859375, + 2541.968994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8952165842056274, + "bbox": [ + 237.6722869873047, + 986.0549926757812, + 1225.9930419921875, + 1638.569580078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8858779072761536, + "bbox": [ + 1287.703369140625, + 2612.586669921875, + 2259.971435546875, + 3154.13134765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8842043876647949, + "bbox": [ + 1231.833740234375, + 497.8525085449219, + 2235.005615234375, + 1078.83203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8692703247070312, + "bbox": [ + 1296.16259765625, + 1421.6787109375, + 2222.47216796875, + 1539.3712158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8480411171913147, + "bbox": [ + 1261.0084228515625, + 684.3721313476562, + 1693.477294921875, + 1047.2835693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8372505903244019, + "bbox": [ + 255.3374786376953, + 1111.43408203125, + 1194.5457763671875, + 1241.8060302734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7672603130340576, + "bbox": [ + 1275.9937744140625, + 598.87646484375, + 2159.73095703125, + 691.5820922851562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6891952753067017, + "bbox": [ + 296.5080261230469, + 2720.46337890625, + 1117.2606201171875, + 2783.51220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6798402070999146, + "bbox": [ + 1286.1678466796875, + 2722.088623046875, + 2128.16064453125, + 2783.493408203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5077571272850037, + "bbox": [ + 1267.4857177734375, + 619.4249267578125, + 2184.38818359375, + 681.4090576171875 + ] + } + ], + "timestamp": "2025-10-15T21:42:26.250360" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 10.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 10.json" new file mode 100644 index 0000000..8093a19 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 10.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 10.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7498956322669983, + "bbox": [ + 1253.09423828125, + 437.26129150390625, + 1363.0908203125, + 535.4747314453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7466577887535095, + "bbox": [ + 219.9500274658203, + 420.7716064453125, + 334.8387145996094, + 521.4635009765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4943804442882538, + "bbox": [ + 1236.9693603515625, + 2108.3427734375, + 1322.0042724609375, + 2210.2109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4773181080818176, + "bbox": [ + 205.4591827392578, + 3102.048828125, + 301.423095703125, + 3179.406494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4750249981880188, + "bbox": [ + 212.13185119628906, + 2420.391845703125, + 289.6446228027344, + 2508.38916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3371717929840088, + "bbox": [ + 1240.31298828125, + 2094.489990234375, + 1353.9873046875, + 2211.92529296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9598448276519775, + "bbox": [ + 198.72532653808594, + 416.22711181640625, + 1188.51025390625, + 2551.113525390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9463230967521667, + "bbox": [ + 220.7576446533203, + 652.781494140625, + 1173.3251953125, + 2095.71826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357991814613342, + "bbox": [ + 1227.901123046875, + 646.3494262695312, + 2223.19091796875, + 2263.518798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9165553450584412, + "bbox": [ + 1222.325439453125, + 399.36920166015625, + 2270.02099609375, + 2440.1201171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9154998660087585, + "bbox": [ + 210.45138549804688, + 2084.444091796875, + 1149.6212158203125, + 2539.61328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8472641110420227, + "bbox": [ + 1243.5191650390625, + 526.148681640625, + 2203.15625, + 658.5746459960938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8187816739082336, + "bbox": [ + 226.65904235839844, + 517.9035034179688, + 1171.0238037109375, + 643.3629760742188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7498956322669983, + "bbox": [ + 1253.09423828125, + 437.26129150390625, + 1363.0908203125, + 535.4747314453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7466577887535095, + "bbox": [ + 219.9500274658203, + 420.7716064453125, + 334.8387145996094, + 521.4635009765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4943804442882538, + "bbox": [ + 1236.9693603515625, + 2108.3427734375, + 1322.0042724609375, + 2210.2109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4773181080818176, + "bbox": [ + 205.4591827392578, + 3102.048828125, + 301.423095703125, + 3179.406494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4750249981880188, + "bbox": [ + 212.13185119628906, + 2420.391845703125, + 289.6446228027344, + 2508.38916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3371717929840088, + "bbox": [ + 1240.31298828125, + 2094.489990234375, + 1353.9873046875, + 2211.92529296875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9598448276519775, + "bbox": [ + 198.72532653808594, + 416.22711181640625, + 1188.51025390625, + 2551.113525390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9463230967521667, + "bbox": [ + 220.7576446533203, + 652.781494140625, + 1173.3251953125, + 2095.71826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357991814613342, + "bbox": [ + 1227.901123046875, + 646.3494262695312, + 2223.19091796875, + 2263.518798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9165553450584412, + "bbox": [ + 1222.325439453125, + 399.36920166015625, + 2270.02099609375, + 2440.1201171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9154998660087585, + "bbox": [ + 210.45138549804688, + 2084.444091796875, + 1149.6212158203125, + 2539.61328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8472641110420227, + "bbox": [ + 1243.5191650390625, + 526.148681640625, + 2203.15625, + 658.5746459960938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8187816739082336, + "bbox": [ + 226.65904235839844, + 517.9035034179688, + 1171.0238037109375, + 643.3629760742188 + ] + } + ], + "timestamp": "2025-10-15T21:42:26.690416" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 11.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 11.json" new file mode 100644 index 0000000..3f1f8a9 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 11.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 11.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.769625186920166, + "bbox": [ + 1193.9013671875, + 411.6297912597656, + 1294.7420654296875, + 504.9017028808594 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7410354614257812, + "bbox": [ + 239.9515838623047, + 510.9247741699219, + 348.0657958984375, + 612.8770141601562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6081646084785461, + "bbox": [ + 1181.966552734375, + 1769.7359619140625, + 1272.2777099609375, + 1870.7689208984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5379481911659241, + "bbox": [ + 1975.5869140625, + 2919.9306640625, + 2056.822021484375, + 2988.044921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5209168791770935, + "bbox": [ + 239.58367919921875, + 1824.7596435546875, + 292.6419372558594, + 1897.9163818359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267647862434387, + "bbox": [ + 193.06170654296875, + 451.1763916015625, + 1133.93701171875, + 2170.513427734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9236084222793579, + "bbox": [ + 235.49276733398438, + 606.1898803710938, + 1123.8157958984375, + 1818.8232421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9209499359130859, + "bbox": [ + 1186.902099609375, + 505.4231872558594, + 2087.885498046875, + 1746.8739013671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9179527163505554, + "bbox": [ + 1165.9041748046875, + 374.26458740234375, + 2118.08154296875, + 2219.896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9094914793968201, + "bbox": [ + 1170.4171142578125, + 1762.361328125, + 1886.2886962890625, + 2140.8681640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8502747416496277, + "bbox": [ + 230.94947814941406, + 1819.18017578125, + 515.2252197265625, + 2171.938720703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.16945244371891022, + "bbox": [ + 245.3971405029297, + 392.58917236328125, + 1108.775634765625, + 477.5325927734375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.769625186920166, + "bbox": [ + 1193.9013671875, + 411.6297912597656, + 1294.7420654296875, + 504.9017028808594 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7410354614257812, + "bbox": [ + 239.9515838623047, + 510.9247741699219, + 348.0657958984375, + 612.8770141601562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6081646084785461, + "bbox": [ + 1181.966552734375, + 1769.7359619140625, + 1272.2777099609375, + 1870.7689208984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5379481911659241, + "bbox": [ + 1975.5869140625, + 2919.9306640625, + 2056.822021484375, + 2988.044921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5209168791770935, + "bbox": [ + 239.58367919921875, + 1824.7596435546875, + 292.6419372558594, + 1897.9163818359375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267647862434387, + "bbox": [ + 193.06170654296875, + 451.1763916015625, + 1133.93701171875, + 2170.513427734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9236084222793579, + "bbox": [ + 235.49276733398438, + 606.1898803710938, + 1123.8157958984375, + 1818.8232421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9209499359130859, + "bbox": [ + 1186.902099609375, + 505.4231872558594, + 2087.885498046875, + 1746.8739013671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9179527163505554, + "bbox": [ + 1165.9041748046875, + 374.26458740234375, + 2118.08154296875, + 2219.896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9094914793968201, + "bbox": [ + 1170.4171142578125, + 1762.361328125, + 1886.2886962890625, + 2140.8681640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8502747416496277, + "bbox": [ + 230.94947814941406, + 1819.18017578125, + 515.2252197265625, + 2171.938720703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.16945244371891022, + "bbox": [ + 245.3971405029297, + 392.58917236328125, + 1108.775634765625, + 477.5325927734375 + ] + } + ], + "timestamp": "2025-10-15T21:42:27.120048" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 12.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 12.json" new file mode 100644 index 0000000..abd7d47 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 12.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 12.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7562362551689148, + "bbox": [ + 1160.1668701171875, + 408.057373046875, + 1263.46435546875, + 504.8369140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7475709319114685, + "bbox": [ + 200.54055786132812, + 394.1004943847656, + 308.0591735839844, + 492.9911804199219 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5514852404594421, + "bbox": [ + 1153.5855712890625, + 2008.839111328125, + 1242.3758544921875, + 2121.357177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5247412323951721, + "bbox": [ + 188.00927734375, + 2913.408447265625, + 270.85369873046875, + 2981.86181640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.45308178663253784, + "bbox": [ + 184.98451232910156, + 1756.4378662109375, + 266.897216796875, + 1865.091064453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9482830762863159, + "bbox": [ + 1152.7852783203125, + 509.9342956542969, + 2051.6015625, + 1937.4033203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9468105435371399, + "bbox": [ + 185.42393493652344, + 501.5539855957031, + 1088.8555908203125, + 1771.2637939453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9409053921699524, + "bbox": [ + 68.03823852539062, + 324.8498229980469, + 1131.4425048828125, + 2235.022216796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9293498396873474, + "bbox": [ + 1139.730224609375, + 1965.3916015625, + 2068.163330078125, + 2555.632080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.914040744304657, + "bbox": [ + 1129.5128173828125, + 309.1934814453125, + 2129.876953125, + 2587.1640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8962591886520386, + "bbox": [ + 166.27484130859375, + 1776.977783203125, + 1066.45751953125, + 2153.0712890625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7562362551689148, + "bbox": [ + 1160.1668701171875, + 408.057373046875, + 1263.46435546875, + 504.8369140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7475709319114685, + "bbox": [ + 200.54055786132812, + 394.1004943847656, + 308.0591735839844, + 492.9911804199219 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5514852404594421, + "bbox": [ + 1153.5855712890625, + 2008.839111328125, + 1242.3758544921875, + 2121.357177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5247412323951721, + "bbox": [ + 188.00927734375, + 2913.408447265625, + 270.85369873046875, + 2981.86181640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.45308178663253784, + "bbox": [ + 184.98451232910156, + 1756.4378662109375, + 266.897216796875, + 1865.091064453125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9482830762863159, + "bbox": [ + 1152.7852783203125, + 509.9342956542969, + 2051.6015625, + 1937.4033203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9468105435371399, + "bbox": [ + 185.42393493652344, + 501.5539855957031, + 1088.8555908203125, + 1771.2637939453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9409053921699524, + "bbox": [ + 68.03823852539062, + 324.8498229980469, + 1131.4425048828125, + 2235.022216796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9293498396873474, + "bbox": [ + 1139.730224609375, + 1965.3916015625, + 2068.163330078125, + 2555.632080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.914040744304657, + "bbox": [ + 1129.5128173828125, + 309.1934814453125, + 2129.876953125, + 2587.1640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8962591886520386, + "bbox": [ + 166.27484130859375, + 1776.977783203125, + 1066.45751953125, + 2153.0712890625 + ] + } + ], + "timestamp": "2025-10-15T21:42:27.508385" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 13.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 13.json" new file mode 100644 index 0000000..0ac64e5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 13.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 13.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7680276036262512, + "bbox": [ + 278.3542785644531, + 457.345947265625, + 395.1463928222656, + 558.2904052734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7644332051277161, + "bbox": [ + 1357.119140625, + 654.5264282226562, + 1472.816650390625, + 760.7462768554688 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5698052048683167, + "bbox": [ + 2257.1025390625, + 3295.5244140625, + 2349.038818359375, + 3371.6279296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5080156326293945, + "bbox": [ + 1832.9876708984375, + 2895.34326171875, + 1917.37451171875, + 2993.5810546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47311776876449585, + "bbox": [ + 1828.94580078125, + 2892.5390625, + 1942.0557861328125, + 3001.663818359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4436294138431549, + "bbox": [ + 344.9924621582031, + 1654.6114501953125, + 435.7452087402344, + 1774.8326416015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.25038841366767883, + "bbox": [ + 351.0723876953125, + 1667.418212890625, + 425.6062316894531, + 1769.4010009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9496482014656067, + "bbox": [ + 262.9560241699219, + 651.1697387695312, + 1285.721923828125, + 2209.787353515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9147956967353821, + "bbox": [ + 206.30442810058594, + 422.3699645996094, + 1310.095947265625, + 2428.255615234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.907930314540863, + "bbox": [ + 1311.4210205078125, + 508.7779235839844, + 2433.566162109375, + 3251.7216796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9047802090644836, + "bbox": [ + 1337.1585693359375, + 785.3707275390625, + 2373.08154296875, + 2874.9697265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8832629323005676, + "bbox": [ + 1360.2425537109375, + 463.0682678222656, + 2380.642578125, + 606.2174682617188 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8688421845436096, + "bbox": [ + 1329.946533203125, + 2905.05078125, + 2234.341796875, + 3161.738525390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8258352279663086, + "bbox": [ + 276.62689208984375, + 555.5448608398438, + 955.1264038085938, + 650.677978515625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7680276036262512, + "bbox": [ + 278.3542785644531, + 457.345947265625, + 395.1463928222656, + 558.2904052734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7644332051277161, + "bbox": [ + 1357.119140625, + 654.5264282226562, + 1472.816650390625, + 760.7462768554688 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5698052048683167, + "bbox": [ + 2257.1025390625, + 3295.5244140625, + 2349.038818359375, + 3371.6279296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5080156326293945, + "bbox": [ + 1832.9876708984375, + 2895.34326171875, + 1917.37451171875, + 2993.5810546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47311776876449585, + "bbox": [ + 1828.94580078125, + 2892.5390625, + 1942.0557861328125, + 3001.663818359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4436294138431549, + "bbox": [ + 344.9924621582031, + 1654.6114501953125, + 435.7452087402344, + 1774.8326416015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.25038841366767883, + "bbox": [ + 351.0723876953125, + 1667.418212890625, + 425.6062316894531, + 1769.4010009765625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9496482014656067, + "bbox": [ + 262.9560241699219, + 651.1697387695312, + 1285.721923828125, + 2209.787353515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9147956967353821, + "bbox": [ + 206.30442810058594, + 422.3699645996094, + 1310.095947265625, + 2428.255615234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.907930314540863, + "bbox": [ + 1311.4210205078125, + 508.7779235839844, + 2433.566162109375, + 3251.7216796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9047802090644836, + "bbox": [ + 1337.1585693359375, + 785.3707275390625, + 2373.08154296875, + 2874.9697265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8832629323005676, + "bbox": [ + 1360.2425537109375, + 463.0682678222656, + 2380.642578125, + 606.2174682617188 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8688421845436096, + "bbox": [ + 1329.946533203125, + 2905.05078125, + 2234.341796875, + 3161.738525390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8258352279663086, + "bbox": [ + 276.62689208984375, + 555.5448608398438, + 955.1264038085938, + 650.677978515625 + ] + } + ], + "timestamp": "2025-10-15T21:42:27.923826" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 14.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 14.json" new file mode 100644 index 0000000..b443c2c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 14.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 14.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7571019530296326, + "bbox": [ + 1319.928466796875, + 643.2127075195312, + 1440.204345703125, + 750.6448974609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7395848631858826, + "bbox": [ + 225.2307586669922, + 444.5059509277344, + 354.924560546875, + 558.2901611328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5535116791725159, + "bbox": [ + 214.28953552246094, + 3301.438720703125, + 306.5604248046875, + 3377.03466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.545263946056366, + "bbox": [ + 1978.4940185546875, + 2234.808349609375, + 2083.9951171875, + 2356.7978515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5419098138809204, + "bbox": [ + 205.3944854736328, + 2366.942626953125, + 292.9066162109375, + 2467.761474609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.29056352376937866, + "bbox": [ + 218.72137451171875, + 2375.827392578125, + 287.6325378417969, + 2459.669677734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9417833089828491, + "bbox": [ + 201.4429473876953, + 596.1659545898438, + 1235.79541015625, + 2282.4345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9353044629096985, + "bbox": [ + 165.16282653808594, + 419.957275390625, + 1270.2552490234375, + 2599.68994140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198238849639893, + "bbox": [ + 1300.49609375, + 750.6350708007812, + 2356.668212890625, + 2524.529541015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9177219271659851, + "bbox": [ + 1299.2945556640625, + 441.6905517578125, + 2422.601806640625, + 2665.2197265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8577864766120911, + "bbox": [ + 204.6634521484375, + 2300.43896484375, + 1129.145263671875, + 2550.255126953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5652002096176147, + "bbox": [ + 1317.556884765625, + 450.5865478515625, + 2337.7607421875, + 591.3380126953125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7571019530296326, + "bbox": [ + 1319.928466796875, + 643.2127075195312, + 1440.204345703125, + 750.6448974609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7395848631858826, + "bbox": [ + 225.2307586669922, + 444.5059509277344, + 354.924560546875, + 558.2901611328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5535116791725159, + "bbox": [ + 214.28953552246094, + 3301.438720703125, + 306.5604248046875, + 3377.03466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.545263946056366, + "bbox": [ + 1978.4940185546875, + 2234.808349609375, + 2083.9951171875, + 2356.7978515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5419098138809204, + "bbox": [ + 205.3944854736328, + 2366.942626953125, + 292.9066162109375, + 2467.761474609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.29056352376937866, + "bbox": [ + 218.72137451171875, + 2375.827392578125, + 287.6325378417969, + 2459.669677734375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9417833089828491, + "bbox": [ + 201.4429473876953, + 596.1659545898438, + 1235.79541015625, + 2282.4345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9353044629096985, + "bbox": [ + 165.16282653808594, + 419.957275390625, + 1270.2552490234375, + 2599.68994140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198238849639893, + "bbox": [ + 1300.49609375, + 750.6350708007812, + 2356.668212890625, + 2524.529541015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9177219271659851, + "bbox": [ + 1299.2945556640625, + 441.6905517578125, + 2422.601806640625, + 2665.2197265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8577864766120911, + "bbox": [ + 204.6634521484375, + 2300.43896484375, + 1129.145263671875, + 2550.255126953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5652002096176147, + "bbox": [ + 1317.556884765625, + 450.5865478515625, + 2337.7607421875, + 591.3380126953125 + ] + } + ], + "timestamp": "2025-10-15T21:42:28.365365" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 15.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 15.json" new file mode 100644 index 0000000..07b77f7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 15.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 15.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7386469841003418, + "bbox": [ + 1308.0301513671875, + 438.7203369140625, + 1429.345703125, + 543.7706909179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.738272488117218, + "bbox": [ + 267.5554504394531, + 424.9104309082031, + 387.3697204589844, + 534.2511596679688 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5815479159355164, + "bbox": [ + 2180.595458984375, + 3174.380615234375, + 2270.413330078125, + 3247.901611328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5765143036842346, + "bbox": [ + 1312.6749267578125, + 2663.98388671875, + 1398.4183349609375, + 2774.806396484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.473430871963501, + "bbox": [ + 295.23846435546875, + 1291.9967041015625, + 372.9425354003906, + 1392.6434326171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.959924042224884, + "bbox": [ + 1308.38037109375, + 676.193115234375, + 2288.805908203125, + 2516.53369140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9263380765914917, + "bbox": [ + 243.09495544433594, + 546.7361450195312, + 1230.0963134765625, + 2322.612548828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.913431704044342, + "bbox": [ + 232.9462127685547, + 321.7449645996094, + 1244.2493896484375, + 2416.34326171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9119288325309753, + "bbox": [ + 1274.6981201171875, + 436.9805603027344, + 2373.663330078125, + 3026.113037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8863656520843506, + "bbox": [ + 1309.9918212890625, + 2484.562255859375, + 1955.0662841796875, + 2939.748046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8755819797515869, + "bbox": [ + 1309.408935546875, + 542.5592041015625, + 2286.833984375, + 671.601806640625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7386469841003418, + "bbox": [ + 1308.0301513671875, + 438.7203369140625, + 1429.345703125, + 543.7706909179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.738272488117218, + "bbox": [ + 267.5554504394531, + 424.9104309082031, + 387.3697204589844, + 534.2511596679688 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5815479159355164, + "bbox": [ + 2180.595458984375, + 3174.380615234375, + 2270.413330078125, + 3247.901611328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5765143036842346, + "bbox": [ + 1312.6749267578125, + 2663.98388671875, + 1398.4183349609375, + 2774.806396484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.473430871963501, + "bbox": [ + 295.23846435546875, + 1291.9967041015625, + 372.9425354003906, + 1392.6434326171875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.959924042224884, + "bbox": [ + 1308.38037109375, + 676.193115234375, + 2288.805908203125, + 2516.53369140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9263380765914917, + "bbox": [ + 243.09495544433594, + 546.7361450195312, + 1230.0963134765625, + 2322.612548828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.913431704044342, + "bbox": [ + 232.9462127685547, + 321.7449645996094, + 1244.2493896484375, + 2416.34326171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9119288325309753, + "bbox": [ + 1274.6981201171875, + 436.9805603027344, + 2373.663330078125, + 3026.113037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8863656520843506, + "bbox": [ + 1309.9918212890625, + 2484.562255859375, + 1955.0662841796875, + 2939.748046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8755819797515869, + "bbox": [ + 1309.408935546875, + 542.5592041015625, + 2286.833984375, + 671.601806640625 + ] + } + ], + "timestamp": "2025-10-15T21:42:28.785872" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 16.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 16.json" new file mode 100644 index 0000000..5ea842b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 16.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 16.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7566924095153809, + "bbox": [ + 1303.558837890625, + 463.9815368652344, + 1428.698974609375, + 574.919189453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7408478260040283, + "bbox": [ + 1299.2528076171875, + 2036.307861328125, + 1423.756103515625, + 2141.32373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6828992962837219, + "bbox": [ + 1313.28662109375, + 1025.3017578125, + 1415.196044921875, + 1129.6080322265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5258637070655823, + "bbox": [ + 216.9156494140625, + 3269.890625, + 311.3939514160156, + 3347.684814453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.42604172229766846, + "bbox": [ + 1891.65625, + 2270.4970703125, + 1953.131103515625, + 2355.619384765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9320166110992432, + "bbox": [ + 1274.0712890625, + 2034.815185546875, + 2329.8359375, + 2405.299560546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9268423318862915, + "bbox": [ + 1322.0179443359375, + 647.7603759765625, + 2351.85693359375, + 1205.0968017578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9122989773750305, + "bbox": [ + 1282.268310546875, + 432.29107666015625, + 2418.70556640625, + 1345.0736083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8509558439254761, + "bbox": [ + 196.17742919921875, + 569.5825805664062, + 1249.0784912109375, + 2550.984130859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8253114819526672, + "bbox": [ + 1290.557373046875, + 2133.1572265625, + 2298.28369140625, + 2260.04541015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7797009944915771, + "bbox": [ + 1315.5189208984375, + 565.0599365234375, + 1881.8953857421875, + 645.9404907226562 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6387441754341125, + "bbox": [ + 1291.7265625, + 2259.445556640625, + 2258.3974609375, + 2376.928955078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.3375714123249054, + "bbox": [ + 1305.10009765625, + 2278.071044921875, + 2218.874755859375, + 2362.13134765625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7566924095153809, + "bbox": [ + 1303.558837890625, + 463.9815368652344, + 1428.698974609375, + 574.919189453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7408478260040283, + "bbox": [ + 1299.2528076171875, + 2036.307861328125, + 1423.756103515625, + 2141.32373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6828992962837219, + "bbox": [ + 1313.28662109375, + 1025.3017578125, + 1415.196044921875, + 1129.6080322265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5258637070655823, + "bbox": [ + 216.9156494140625, + 3269.890625, + 311.3939514160156, + 3347.684814453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.42604172229766846, + "bbox": [ + 1891.65625, + 2270.4970703125, + 1953.131103515625, + 2355.619384765625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9320166110992432, + "bbox": [ + 1274.0712890625, + 2034.815185546875, + 2329.8359375, + 2405.299560546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9268423318862915, + "bbox": [ + 1322.0179443359375, + 647.7603759765625, + 2351.85693359375, + 1205.0968017578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9122989773750305, + "bbox": [ + 1282.268310546875, + 432.29107666015625, + 2418.70556640625, + 1345.0736083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8509558439254761, + "bbox": [ + 196.17742919921875, + 569.5825805664062, + 1249.0784912109375, + 2550.984130859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8253114819526672, + "bbox": [ + 1290.557373046875, + 2133.1572265625, + 2298.28369140625, + 2260.04541015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7797009944915771, + "bbox": [ + 1315.5189208984375, + 565.0599365234375, + 1881.8953857421875, + 645.9404907226562 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6387441754341125, + "bbox": [ + 1291.7265625, + 2259.445556640625, + 2258.3974609375, + 2376.928955078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.3375714123249054, + "bbox": [ + 1305.10009765625, + 2278.071044921875, + 2218.874755859375, + 2362.13134765625 + ] + } + ], + "timestamp": "2025-10-15T21:42:29.201271" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 17.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 17.json" new file mode 100644 index 0000000..0c0d8c3 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 17.json" @@ -0,0 +1,406 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 17.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7485170960426331, + "bbox": [ + 1228.128662109375, + 1429.826904296875, + 1336.8826904296875, + 1521.368408203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7410387396812439, + "bbox": [ + 1219.1810302734375, + 2010.50048828125, + 1331.3731689453125, + 2108.992431640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7382306456565857, + "bbox": [ + 1218.4896240234375, + 2418.4912109375, + 1332.4351806640625, + 2519.4248046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6166597008705139, + "bbox": [ + 1228.687255859375, + 2907.854248046875, + 1285.19189453125, + 2979.4755859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.564454197883606, + "bbox": [ + 2053.67041015625, + 3009.162841796875, + 2136.96875, + 3076.246337890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5624663829803467, + "bbox": [ + 1666.3101806640625, + 1693.443115234375, + 1751.0045166015625, + 1790.0400390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5183578729629517, + "bbox": [ + 1566.604736328125, + 2163.695556640625, + 1660.8863525390625, + 2264.471923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9359051585197449, + "bbox": [ + 223.7063751220703, + 546.440185546875, + 1180.1690673828125, + 2950.478515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9159271717071533, + "bbox": [ + 1195.490966796875, + 1949.8662109375, + 2196.252685546875, + 2333.4384765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9141084551811218, + "bbox": [ + 1199.5240478515625, + 395.34307861328125, + 2173.250732421875, + 1297.2220458984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9124875068664551, + "bbox": [ + 1216.6912841796875, + 2583.717041015625, + 2127.26318359375, + 2980.590576171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8947314023971558, + "bbox": [ + 1187.8404541015625, + 2390.708740234375, + 2175.625244140625, + 2998.51220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8858322501182556, + "bbox": [ + 1216.5596923828125, + 1520.9996337890625, + 2167.90576171875, + 1640.150634765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.858069658279419, + "bbox": [ + 1197.7967529296875, + 1401.124267578125, + 2234.5712890625, + 1876.79541015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8350728154182434, + "bbox": [ + 1214.2359619140625, + 1655.3553466796875, + 2000.2890625, + 1856.89013671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8085700869560242, + "bbox": [ + 1224.291259765625, + 2508.45849609375, + 1859.20947265625, + 2596.18408203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7542762160301208, + "bbox": [ + 1220.1319580078125, + 2098.65234375, + 2135.69287109375, + 2196.173095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6814409494400024, + "bbox": [ + 1206.3046875, + 2164.535400390625, + 2086.9326171875, + 2286.73828125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7485170960426331, + "bbox": [ + 1228.128662109375, + 1429.826904296875, + 1336.8826904296875, + 1521.368408203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7410387396812439, + "bbox": [ + 1219.1810302734375, + 2010.50048828125, + 1331.3731689453125, + 2108.992431640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7382306456565857, + "bbox": [ + 1218.4896240234375, + 2418.4912109375, + 1332.4351806640625, + 2519.4248046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6166597008705139, + "bbox": [ + 1228.687255859375, + 2907.854248046875, + 1285.19189453125, + 2979.4755859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.564454197883606, + "bbox": [ + 2053.67041015625, + 3009.162841796875, + 2136.96875, + 3076.246337890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5624663829803467, + "bbox": [ + 1666.3101806640625, + 1693.443115234375, + 1751.0045166015625, + 1790.0400390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5183578729629517, + "bbox": [ + 1566.604736328125, + 2163.695556640625, + 1660.8863525390625, + 2264.471923828125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9359051585197449, + "bbox": [ + 223.7063751220703, + 546.440185546875, + 1180.1690673828125, + 2950.478515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9159271717071533, + "bbox": [ + 1195.490966796875, + 1949.8662109375, + 2196.252685546875, + 2333.4384765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9141084551811218, + "bbox": [ + 1199.5240478515625, + 395.34307861328125, + 2173.250732421875, + 1297.2220458984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9124875068664551, + "bbox": [ + 1216.6912841796875, + 2583.717041015625, + 2127.26318359375, + 2980.590576171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8947314023971558, + "bbox": [ + 1187.8404541015625, + 2390.708740234375, + 2175.625244140625, + 2998.51220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8858322501182556, + "bbox": [ + 1216.5596923828125, + 1520.9996337890625, + 2167.90576171875, + 1640.150634765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.858069658279419, + "bbox": [ + 1197.7967529296875, + 1401.124267578125, + 2234.5712890625, + 1876.79541015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8350728154182434, + "bbox": [ + 1214.2359619140625, + 1655.3553466796875, + 2000.2890625, + 1856.89013671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8085700869560242, + "bbox": [ + 1224.291259765625, + 2508.45849609375, + 1859.20947265625, + 2596.18408203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7542762160301208, + "bbox": [ + 1220.1319580078125, + 2098.65234375, + 2135.69287109375, + 2196.173095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6814409494400024, + "bbox": [ + 1206.3046875, + 2164.535400390625, + 2086.9326171875, + 2286.73828125 + ] + } + ], + "timestamp": "2025-10-15T21:42:29.607835" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 2.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 2.json" new file mode 100644 index 0000000..6d30c65 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 2.json" @@ -0,0 +1,604 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 2.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.773139476776123, + "bbox": [ + 192.2500762939453, + 2584.900146484375, + 301.58831787109375, + 2677.50341796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7676541209220886, + "bbox": [ + 1215.4931640625, + 2238.238037109375, + 1320.641357421875, + 2333.06787109375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7633708715438843, + "bbox": [ + 206.25807189941406, + 1510.27099609375, + 314.306640625, + 1601.9495849609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7526618838310242, + "bbox": [ + 1228.820068359375, + 449.1214599609375, + 1338.8291015625, + 541.99658203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7422521114349365, + "bbox": [ + 211.4695587158203, + 436.35723876953125, + 324.2906188964844, + 529.6375122070312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7195858955383301, + "bbox": [ + 1232.6488037109375, + 955.6524658203125, + 1290.787109375, + 1031.388671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6265618205070496, + "bbox": [ + 192.98904418945312, + 3015.14794921875, + 254.03233337402344, + 3094.64501953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5657617449760437, + "bbox": [ + 208.47308349609375, + 1718.9996337890625, + 296.2408142089844, + 1834.0938720703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.500086784362793, + "bbox": [ + 1210.1043701171875, + 2697.981689453125, + 1316.89990234375, + 2825.78271484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4743703007698059, + "bbox": [ + 211.9891357421875, + 866.4877319335938, + 287.8264465332031, + 957.8651733398438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3897053301334381, + "bbox": [ + 190.72596740722656, + 3190.45654296875, + 283.2001647949219, + 3268.12841796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9433939456939697, + "bbox": [ + 1206.7149658203125, + 2435.04345703125, + 2162.81982421875, + 3187.415283203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9314338564872742, + "bbox": [ + 179.29930114746094, + 407.8069763183594, + 1171.303955078125, + 1019.8289794921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9252327680587769, + "bbox": [ + 152.95619201660156, + 2565.73388671875, + 1161.3707275390625, + 3191.96875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9056389927864075, + "bbox": [ + 1169.372314453125, + 2183.521484375, + 2209.51171875, + 3185.657958984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9019029140472412, + "bbox": [ + 1223.5853271484375, + 684.700927734375, + 2057.514404296875, + 1057.96826171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8933302760124207, + "bbox": [ + 205.90478515625, + 1685.59423828125, + 793.9609985351562, + 2062.454345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.89143967628479, + "bbox": [ + 161.6622314453125, + 1473.24609375, + 1177.6116943359375, + 2111.179443359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8466437458992004, + "bbox": [ + 1211.3382568359375, + 544.82373046875, + 2171.995361328125, + 674.3635864257812 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8367560505867004, + "bbox": [ + 1180.5792236328125, + 400.8259582519531, + 2270.049560546875, + 1222.7286376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8104263544082642, + "bbox": [ + 211.9488525390625, + 518.5576782226562, + 946.94580078125, + 615.2498779296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8092429041862488, + "bbox": [ + 199.29608154296875, + 2832.9716796875, + 442.92041015625, + 3173.62744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8091081380844116, + "bbox": [ + 188.92068481445312, + 2686.10888671875, + 1140.5042724609375, + 2805.667724609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7639308571815491, + "bbox": [ + 205.1981964111328, + 1596.6451416015625, + 1013.4995727539062, + 1683.8123779296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5721950531005859, + "bbox": [ + 1207.5059814453125, + 2335.354248046875, + 2131.326171875, + 2416.983154296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.3128732144832611, + "bbox": [ + 222.141357421875, + 605.5153198242188, + 556.7269897460938, + 965.7357788085938 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.27527865767478943, + "bbox": [ + 219.0604705810547, + 604.6409301757812, + 761.763671875, + 972.642333984375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.773139476776123, + "bbox": [ + 192.2500762939453, + 2584.900146484375, + 301.58831787109375, + 2677.50341796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7676541209220886, + "bbox": [ + 1215.4931640625, + 2238.238037109375, + 1320.641357421875, + 2333.06787109375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7633708715438843, + "bbox": [ + 206.25807189941406, + 1510.27099609375, + 314.306640625, + 1601.9495849609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7526618838310242, + "bbox": [ + 1228.820068359375, + 449.1214599609375, + 1338.8291015625, + 541.99658203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7422521114349365, + "bbox": [ + 211.4695587158203, + 436.35723876953125, + 324.2906188964844, + 529.6375122070312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7195858955383301, + "bbox": [ + 1232.6488037109375, + 955.6524658203125, + 1290.787109375, + 1031.388671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6265618205070496, + "bbox": [ + 192.98904418945312, + 3015.14794921875, + 254.03233337402344, + 3094.64501953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5657617449760437, + "bbox": [ + 208.47308349609375, + 1718.9996337890625, + 296.2408142089844, + 1834.0938720703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.500086784362793, + "bbox": [ + 1210.1043701171875, + 2697.981689453125, + 1316.89990234375, + 2825.78271484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4743703007698059, + "bbox": [ + 211.9891357421875, + 866.4877319335938, + 287.8264465332031, + 957.8651733398438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3897053301334381, + "bbox": [ + 190.72596740722656, + 3190.45654296875, + 283.2001647949219, + 3268.12841796875 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9433939456939697, + "bbox": [ + 1206.7149658203125, + 2435.04345703125, + 2162.81982421875, + 3187.415283203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9314338564872742, + "bbox": [ + 179.29930114746094, + 407.8069763183594, + 1171.303955078125, + 1019.8289794921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9252327680587769, + "bbox": [ + 152.95619201660156, + 2565.73388671875, + 1161.3707275390625, + 3191.96875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9056389927864075, + "bbox": [ + 1169.372314453125, + 2183.521484375, + 2209.51171875, + 3185.657958984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9019029140472412, + "bbox": [ + 1223.5853271484375, + 684.700927734375, + 2057.514404296875, + 1057.96826171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8933302760124207, + "bbox": [ + 205.90478515625, + 1685.59423828125, + 793.9609985351562, + 2062.454345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.89143967628479, + "bbox": [ + 161.6622314453125, + 1473.24609375, + 1177.6116943359375, + 2111.179443359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8466437458992004, + "bbox": [ + 1211.3382568359375, + 544.82373046875, + 2171.995361328125, + 674.3635864257812 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8367560505867004, + "bbox": [ + 1180.5792236328125, + 400.8259582519531, + 2270.049560546875, + 1222.7286376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8104263544082642, + "bbox": [ + 211.9488525390625, + 518.5576782226562, + 946.94580078125, + 615.2498779296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8092429041862488, + "bbox": [ + 199.29608154296875, + 2832.9716796875, + 442.92041015625, + 3173.62744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8091081380844116, + "bbox": [ + 188.92068481445312, + 2686.10888671875, + 1140.5042724609375, + 2805.667724609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7639308571815491, + "bbox": [ + 205.1981964111328, + 1596.6451416015625, + 1013.4995727539062, + 1683.8123779296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5721950531005859, + "bbox": [ + 1207.5059814453125, + 2335.354248046875, + 2131.326171875, + 2416.983154296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.3128732144832611, + "bbox": [ + 222.141357421875, + 605.5153198242188, + 556.7269897460938, + 965.7357788085938 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.27527865767478943, + "bbox": [ + 219.0604705810547, + 604.6409301757812, + 761.763671875, + 972.642333984375 + ] + } + ], + "timestamp": "2025-10-15T21:42:30.072016" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 3.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 3.json" new file mode 100644 index 0000000..309fd3e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 3.json" @@ -0,0 +1,692 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 3.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.763209342956543, + "bbox": [ + 1314.411865234375, + 449.1679992675781, + 1423.410400390625, + 551.4131469726562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7545271515846252, + "bbox": [ + 257.5189208984375, + 1282.41845703125, + 370.71868896484375, + 1386.22021484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7480810284614563, + "bbox": [ + 1295.855224609375, + 2191.54638671875, + 1405.607421875, + 2287.02392578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7448151707649231, + "bbox": [ + 266.94952392578125, + 441.7080383300781, + 379.1337585449219, + 544.2326049804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7343556880950928, + "bbox": [ + 249.61859130859375, + 2308.408447265625, + 362.1669006347656, + 2410.77294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6138310432434082, + "bbox": [ + 235.81959533691406, + 3015.343017578125, + 308.1266174316406, + 3117.077880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5855740308761597, + "bbox": [ + 1303.1883544921875, + 1280.341796875, + 1396.1474609375, + 1385.2835693359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5771365165710449, + "bbox": [ + 2172.08837890625, + 3216.8466796875, + 2267.779541015625, + 3299.461669921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.554063081741333, + "bbox": [ + 265.5001525878906, + 653.8616943359375, + 357.20526123046875, + 758.0416259765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5282912850379944, + "bbox": [ + 268.5801696777344, + 1494.091064453125, + 356.52252197265625, + 1587.99609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4771351218223572, + "bbox": [ + 258.55584716796875, + 1483.3260498046875, + 376.03424072265625, + 1602.6806640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4733010530471802, + "bbox": [ + 1288.043212890625, + 3010.6591796875, + 1381.97509765625, + 3124.916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3831689655780792, + "bbox": [ + 245.97938537597656, + 3033.33349609375, + 309.8055725097656, + 3116.13330078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9388336539268494, + "bbox": [ + 1281.742431640625, + 2518.37158203125, + 2271.1201171875, + 3199.3701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9373374581336975, + "bbox": [ + 241.59617614746094, + 2645.763427734375, + 1216.6578369140625, + 3193.408935546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9359375238418579, + "bbox": [ + 1300.2862548828125, + 783.489013671875, + 2307.87548828125, + 1465.9833984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9321898818016052, + "bbox": [ + 247.10382080078125, + 1512.0419921875, + 1228.8599853515625, + 2191.217041015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.928565502166748, + "bbox": [ + 214.58412170410156, + 1255.245849609375, + 1241.388916015625, + 2219.69287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9172302484512329, + "bbox": [ + 200.93795776367188, + 402.0989074707031, + 1252.154052734375, + 1219.3779296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.912268877029419, + "bbox": [ + 1260.694580078125, + 2125.35205078125, + 2291.84033203125, + 3219.77197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9112990498542786, + "bbox": [ + 180.5989227294922, + 2265.222900390625, + 1249.9031982421875, + 3237.217529296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9095674753189087, + "bbox": [ + 252.14273071289062, + 672.3754272460938, + 1230.1636962890625, + 1175.6072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9001824855804443, + "bbox": [ + 1260.8485107421875, + 394.76519775390625, + 2400.4462890625, + 1522.1595458984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8762091398239136, + "bbox": [ + 1278.30078125, + 2421.822509765625, + 2266.958740234375, + 2530.472900390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8707284331321716, + "bbox": [ + 240.9610595703125, + 537.4722290039062, + 1230.8153076171875, + 677.4971923828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.862907886505127, + "bbox": [ + 249.6811981201172, + 1374.184326171875, + 1226.9427490234375, + 1501.307861328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8625087141990662, + "bbox": [ + 225.2228240966797, + 2404.477783203125, + 1220.9378662109375, + 2536.891845703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8577516674995422, + "bbox": [ + 1316.193359375, + 683.9502563476562, + 2294.273681640625, + 778.3448486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8393417596817017, + "bbox": [ + 1289.963623046875, + 2280.35595703125, + 2277.13427734375, + 2411.633056640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8281707167625427, + "bbox": [ + 1313.4229736328125, + 542.356689453125, + 2290.7119140625, + 671.3619995117188 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5733320116996765, + "bbox": [ + 241.21707153320312, + 2533.07763671875, + 1205.958740234375, + 2650.150146484375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.763209342956543, + "bbox": [ + 1314.411865234375, + 449.1679992675781, + 1423.410400390625, + 551.4131469726562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7545271515846252, + "bbox": [ + 257.5189208984375, + 1282.41845703125, + 370.71868896484375, + 1386.22021484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7480810284614563, + "bbox": [ + 1295.855224609375, + 2191.54638671875, + 1405.607421875, + 2287.02392578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7448151707649231, + "bbox": [ + 266.94952392578125, + 441.7080383300781, + 379.1337585449219, + 544.2326049804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7343556880950928, + "bbox": [ + 249.61859130859375, + 2308.408447265625, + 362.1669006347656, + 2410.77294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6138310432434082, + "bbox": [ + 235.81959533691406, + 3015.343017578125, + 308.1266174316406, + 3117.077880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5855740308761597, + "bbox": [ + 1303.1883544921875, + 1280.341796875, + 1396.1474609375, + 1385.2835693359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5771365165710449, + "bbox": [ + 2172.08837890625, + 3216.8466796875, + 2267.779541015625, + 3299.461669921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.554063081741333, + "bbox": [ + 265.5001525878906, + 653.8616943359375, + 357.20526123046875, + 758.0416259765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5282912850379944, + "bbox": [ + 268.5801696777344, + 1494.091064453125, + 356.52252197265625, + 1587.99609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4771351218223572, + "bbox": [ + 258.55584716796875, + 1483.3260498046875, + 376.03424072265625, + 1602.6806640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4733010530471802, + "bbox": [ + 1288.043212890625, + 3010.6591796875, + 1381.97509765625, + 3124.916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3831689655780792, + "bbox": [ + 245.97938537597656, + 3033.33349609375, + 309.8055725097656, + 3116.13330078125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9388336539268494, + "bbox": [ + 1281.742431640625, + 2518.37158203125, + 2271.1201171875, + 3199.3701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9373374581336975, + "bbox": [ + 241.59617614746094, + 2645.763427734375, + 1216.6578369140625, + 3193.408935546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9359375238418579, + "bbox": [ + 1300.2862548828125, + 783.489013671875, + 2307.87548828125, + 1465.9833984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9321898818016052, + "bbox": [ + 247.10382080078125, + 1512.0419921875, + 1228.8599853515625, + 2191.217041015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.928565502166748, + "bbox": [ + 214.58412170410156, + 1255.245849609375, + 1241.388916015625, + 2219.69287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9172302484512329, + "bbox": [ + 200.93795776367188, + 402.0989074707031, + 1252.154052734375, + 1219.3779296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.912268877029419, + "bbox": [ + 1260.694580078125, + 2125.35205078125, + 2291.84033203125, + 3219.77197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9112990498542786, + "bbox": [ + 180.5989227294922, + 2265.222900390625, + 1249.9031982421875, + 3237.217529296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9095674753189087, + "bbox": [ + 252.14273071289062, + 672.3754272460938, + 1230.1636962890625, + 1175.6072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9001824855804443, + "bbox": [ + 1260.8485107421875, + 394.76519775390625, + 2400.4462890625, + 1522.1595458984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8762091398239136, + "bbox": [ + 1278.30078125, + 2421.822509765625, + 2266.958740234375, + 2530.472900390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8707284331321716, + "bbox": [ + 240.9610595703125, + 537.4722290039062, + 1230.8153076171875, + 677.4971923828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.862907886505127, + "bbox": [ + 249.6811981201172, + 1374.184326171875, + 1226.9427490234375, + 1501.307861328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8625087141990662, + "bbox": [ + 225.2228240966797, + 2404.477783203125, + 1220.9378662109375, + 2536.891845703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8577516674995422, + "bbox": [ + 1316.193359375, + 683.9502563476562, + 2294.273681640625, + 778.3448486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8393417596817017, + "bbox": [ + 1289.963623046875, + 2280.35595703125, + 2277.13427734375, + 2411.633056640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8281707167625427, + "bbox": [ + 1313.4229736328125, + 542.356689453125, + 2290.7119140625, + 671.3619995117188 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5733320116996765, + "bbox": [ + 241.21707153320312, + 2533.07763671875, + 1205.958740234375, + 2650.150146484375 + ] + } + ], + "timestamp": "2025-10-15T21:42:30.462871" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 4.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 4.json" new file mode 100644 index 0000000..bc633cd --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 4.json" @@ -0,0 +1,384 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 4.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.778863251209259, + "bbox": [ + 1191.870361328125, + 415.920654296875, + 1295.2523193359375, + 511.8294982910156 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7557286620140076, + "bbox": [ + 205.35946655273438, + 525.6177978515625, + 309.5257263183594, + 624.0623168945312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7311107516288757, + "bbox": [ + 191.5093536376953, + 1722.0103759765625, + 302.2926025390625, + 1822.052490234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.656991720199585, + "bbox": [ + 1179.72705078125, + 2347.092041015625, + 1269.48974609375, + 2454.12109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5569954514503479, + "bbox": [ + 207.88653564453125, + 667.4052124023438, + 305.1193542480469, + 774.6541137695312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5301179885864258, + "bbox": [ + 193.0784912109375, + 3003.834716796875, + 277.7440185546875, + 3074.09326171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4741879105567932, + "bbox": [ + 192.82325744628906, + 2013.6138916015625, + 263.5181884765625, + 2098.947021484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9225581288337708, + "bbox": [ + 195.69033813476562, + 677.9916381835938, + 1114.3905029296875, + 1050.36376953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9136741757392883, + "bbox": [ + 1188.46435546875, + 595.431396484375, + 2074.439697265625, + 2184.782470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9106642007827759, + "bbox": [ + 1155.7833251953125, + 365.0885925292969, + 2194.62548828125, + 2737.09619140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9093073010444641, + "bbox": [ + 1181.6075439453125, + 2230.82275390625, + 1947.29541015625, + 2602.575927734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9043163061141968, + "bbox": [ + 171.7726593017578, + 496.01177978515625, + 1160.2034912109375, + 1133.364990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8974544405937195, + "bbox": [ + 187.04861450195312, + 1895.8814697265625, + 604.8574829101562, + 2249.16015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8833035230636597, + "bbox": [ + 123.42131042480469, + 1684.7811279296875, + 1139.8331298828125, + 2313.213623046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7732571959495544, + "bbox": [ + 1197.5740966796875, + 499.45263671875, + 1779.0638427734375, + 579.8079223632812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6505650281906128, + "bbox": [ + 200.16371154785156, + 613.4199829101562, + 825.3067016601562, + 688.7120971679688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6393455862998962, + "bbox": [ + 193.83375549316406, + 1818.899658203125, + 593.0745849609375, + 1897.2552490234375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.778863251209259, + "bbox": [ + 1191.870361328125, + 415.920654296875, + 1295.2523193359375, + 511.8294982910156 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7557286620140076, + "bbox": [ + 205.35946655273438, + 525.6177978515625, + 309.5257263183594, + 624.0623168945312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7311107516288757, + "bbox": [ + 191.5093536376953, + 1722.0103759765625, + 302.2926025390625, + 1822.052490234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.656991720199585, + "bbox": [ + 1179.72705078125, + 2347.092041015625, + 1269.48974609375, + 2454.12109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5569954514503479, + "bbox": [ + 207.88653564453125, + 667.4052124023438, + 305.1193542480469, + 774.6541137695312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5301179885864258, + "bbox": [ + 193.0784912109375, + 3003.834716796875, + 277.7440185546875, + 3074.09326171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4741879105567932, + "bbox": [ + 192.82325744628906, + 2013.6138916015625, + 263.5181884765625, + 2098.947021484375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9225581288337708, + "bbox": [ + 195.69033813476562, + 677.9916381835938, + 1114.3905029296875, + 1050.36376953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9136741757392883, + "bbox": [ + 1188.46435546875, + 595.431396484375, + 2074.439697265625, + 2184.782470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9106642007827759, + "bbox": [ + 1155.7833251953125, + 365.0885925292969, + 2194.62548828125, + 2737.09619140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9093073010444641, + "bbox": [ + 1181.6075439453125, + 2230.82275390625, + 1947.29541015625, + 2602.575927734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9043163061141968, + "bbox": [ + 171.7726593017578, + 496.01177978515625, + 1160.2034912109375, + 1133.364990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8974544405937195, + "bbox": [ + 187.04861450195312, + 1895.8814697265625, + 604.8574829101562, + 2249.16015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8833035230636597, + "bbox": [ + 123.42131042480469, + 1684.7811279296875, + 1139.8331298828125, + 2313.213623046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7732571959495544, + "bbox": [ + 1197.5740966796875, + 499.45263671875, + 1779.0638427734375, + 579.8079223632812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6505650281906128, + "bbox": [ + 200.16371154785156, + 613.4199829101562, + 825.3067016601562, + 688.7120971679688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6393455862998962, + "bbox": [ + 193.83375549316406, + 1818.899658203125, + 593.0745849609375, + 1897.2552490234375 + ] + } + ], + "timestamp": "2025-10-15T21:42:30.848169" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 5.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 5.json" new file mode 100644 index 0000000..2804b8d --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 5.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 5.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7590410709381104, + "bbox": [ + 1244.9266357421875, + 424.6640319824219, + 1355.979248046875, + 520.8428344726562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7537903785705566, + "bbox": [ + 253.0414581298828, + 411.5349426269531, + 358.78839111328125, + 509.7574462890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6539319157600403, + "bbox": [ + 1243.7724609375, + 2317.952880859375, + 1325.805419921875, + 2428.751220703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.549699604511261, + "bbox": [ + 2068.84375, + 3059.930908203125, + 2155.918212890625, + 3130.73388671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5082973837852478, + "bbox": [ + 236.89224243164062, + 2123.05078125, + 305.14068603515625, + 2199.552978515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9484599828720093, + "bbox": [ + 246.9534454345703, + 595.8448486328125, + 1161.034423828125, + 1878.875732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9476075768470764, + "bbox": [ + 201.04127502441406, + 389.6425476074219, + 1180.9970703125, + 2343.943359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9343069791793823, + "bbox": [ + 1232.7979736328125, + 594.7357177734375, + 2174.822998046875, + 1935.1080322265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.927017092704773, + "bbox": [ + 1211.080078125, + 383.5271301269531, + 2214.51806640625, + 2570.34619140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9178480505943298, + "bbox": [ + 1237.7528076171875, + 2024.776123046875, + 2168.660400390625, + 2481.8115234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9051907062530518, + "bbox": [ + 239.8685760498047, + 1937.699462890625, + 768.4166870117188, + 2281.149169921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7685898542404175, + "bbox": [ + 1260.042236328125, + 518.130615234375, + 2010.4139404296875, + 608.478271484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.691926896572113, + "bbox": [ + 249.53062438964844, + 496.96636962890625, + 972.8667602539062, + 575.5149536132812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6241666674613953, + "bbox": [ + 1247.048583984375, + 528.7554321289062, + 2026.0137939453125, + 592.5413818359375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7590410709381104, + "bbox": [ + 1244.9266357421875, + 424.6640319824219, + 1355.979248046875, + 520.8428344726562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7537903785705566, + "bbox": [ + 253.0414581298828, + 411.5349426269531, + 358.78839111328125, + 509.7574462890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6539319157600403, + "bbox": [ + 1243.7724609375, + 2317.952880859375, + 1325.805419921875, + 2428.751220703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.549699604511261, + "bbox": [ + 2068.84375, + 3059.930908203125, + 2155.918212890625, + 3130.73388671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5082973837852478, + "bbox": [ + 236.89224243164062, + 2123.05078125, + 305.14068603515625, + 2199.552978515625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9484599828720093, + "bbox": [ + 246.9534454345703, + 595.8448486328125, + 1161.034423828125, + 1878.875732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9476075768470764, + "bbox": [ + 201.04127502441406, + 389.6425476074219, + 1180.9970703125, + 2343.943359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9343069791793823, + "bbox": [ + 1232.7979736328125, + 594.7357177734375, + 2174.822998046875, + 1935.1080322265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.927017092704773, + "bbox": [ + 1211.080078125, + 383.5271301269531, + 2214.51806640625, + 2570.34619140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9178480505943298, + "bbox": [ + 1237.7528076171875, + 2024.776123046875, + 2168.660400390625, + 2481.8115234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9051907062530518, + "bbox": [ + 239.8685760498047, + 1937.699462890625, + 768.4166870117188, + 2281.149169921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7685898542404175, + "bbox": [ + 1260.042236328125, + 518.130615234375, + 2010.4139404296875, + 608.478271484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.691926896572113, + "bbox": [ + 249.53062438964844, + 496.96636962890625, + 972.8667602539062, + 575.5149536132812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6241666674613953, + "bbox": [ + 1247.048583984375, + 528.7554321289062, + 2026.0137939453125, + 592.5413818359375 + ] + } + ], + "timestamp": "2025-10-15T21:42:31.204328" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 6.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 6.json" new file mode 100644 index 0000000..d057489 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 6.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 6.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491795420646667, + "bbox": [ + 1223.7366943359375, + 428.72467041015625, + 1333.751953125, + 525.1738891601562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7411307692527771, + "bbox": [ + 214.4866943359375, + 413.9234313964844, + 327.1632385253906, + 512.0313110351562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5187163949012756, + "bbox": [ + 196.06837463378906, + 3050.721435546875, + 284.88629150390625, + 3125.38623046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5107085704803467, + "bbox": [ + 196.14381408691406, + 2442.447998046875, + 279.31195068359375, + 2561.37939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49005451798439026, + "bbox": [ + 1210.2567138671875, + 2374.678955078125, + 1300.98779296875, + 2484.461669921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9435957670211792, + "bbox": [ + 164.20184326171875, + 377.003173828125, + 1158.844970703125, + 2636.35546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9418251514434814, + "bbox": [ + 197.4623565673828, + 644.52685546875, + 1149.731689453125, + 1956.58447265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9379463791847229, + "bbox": [ + 180.2716827392578, + 2041.52490234375, + 1140.852783203125, + 2646.2470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9261289238929749, + "bbox": [ + 1216.048828125, + 580.7479858398438, + 2171.823486328125, + 2260.050048828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9239684343338013, + "bbox": [ + 1205.02490234375, + 2325.142578125, + 2121.4384765625, + 2695.517333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9028078317642212, + "bbox": [ + 1184.0750732421875, + 381.66583251953125, + 2195.732421875, + 2805.02392578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8230200409889221, + "bbox": [ + 201.6152801513672, + 507.9662780761719, + 1148.1668701171875, + 634.564453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7481492757797241, + "bbox": [ + 1232.4373779296875, + 508.6654357910156, + 1765.220947265625, + 595.0596313476562 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491795420646667, + "bbox": [ + 1223.7366943359375, + 428.72467041015625, + 1333.751953125, + 525.1738891601562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7411307692527771, + "bbox": [ + 214.4866943359375, + 413.9234313964844, + 327.1632385253906, + 512.0313110351562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5187163949012756, + "bbox": [ + 196.06837463378906, + 3050.721435546875, + 284.88629150390625, + 3125.38623046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5107085704803467, + "bbox": [ + 196.14381408691406, + 2442.447998046875, + 279.31195068359375, + 2561.37939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49005451798439026, + "bbox": [ + 1210.2567138671875, + 2374.678955078125, + 1300.98779296875, + 2484.461669921875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9435957670211792, + "bbox": [ + 164.20184326171875, + 377.003173828125, + 1158.844970703125, + 2636.35546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9418251514434814, + "bbox": [ + 197.4623565673828, + 644.52685546875, + 1149.731689453125, + 1956.58447265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9379463791847229, + "bbox": [ + 180.2716827392578, + 2041.52490234375, + 1140.852783203125, + 2646.2470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9261289238929749, + "bbox": [ + 1216.048828125, + 580.7479858398438, + 2171.823486328125, + 2260.050048828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9239684343338013, + "bbox": [ + 1205.02490234375, + 2325.142578125, + 2121.4384765625, + 2695.517333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9028078317642212, + "bbox": [ + 1184.0750732421875, + 381.66583251953125, + 2195.732421875, + 2805.02392578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8230200409889221, + "bbox": [ + 201.6152801513672, + 507.9662780761719, + 1148.1668701171875, + 634.564453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7481492757797241, + "bbox": [ + 1232.4373779296875, + 508.6654357910156, + 1765.220947265625, + 595.0596313476562 + ] + } + ], + "timestamp": "2025-10-15T21:42:31.572107" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 7.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 7.json" new file mode 100644 index 0000000..0098eb0 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 7.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 7.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7612056732177734, + "bbox": [ + 1325.2484130859375, + 448.3669738769531, + 1441.96484375, + 550.7628784179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7573733329772949, + "bbox": [ + 263.52923583984375, + 439.2020568847656, + 381.2477111816406, + 540.640869140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6630344986915588, + "bbox": [ + 1323.3297119140625, + 2406.1513671875, + 1412.327392578125, + 2526.4814453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5677933692932129, + "bbox": [ + 2203.697265625, + 3219.5830078125, + 2302.647216796875, + 3301.492431640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.529183566570282, + "bbox": [ + 255.1278533935547, + 1998.453125, + 356.11474609375, + 2127.900390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4180631637573242, + "bbox": [ + 1309.0074462890625, + 2403.96240234375, + 1428.2066650390625, + 2535.266357421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9539963006973267, + "bbox": [ + 1326.5028076171875, + 638.5123291015625, + 2320.687255859375, + 2125.1123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9492160081863403, + "bbox": [ + 243.94677734375, + 629.4617919921875, + 1244.364013671875, + 1888.191650390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9468057155609131, + "bbox": [ + 1325.242919921875, + 2178.634033203125, + 2327.711669921875, + 2737.770263671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9402197599411011, + "bbox": [ + 1282.40234375, + 356.3473205566406, + 2475.557861328125, + 2846.28564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.937237560749054, + "bbox": [ + 217.1188507080078, + 389.8701171875, + 1259.607666015625, + 2691.2763671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9347747564315796, + "bbox": [ + 240.94369506835938, + 1957.65087890625, + 1248.9676513671875, + 2597.036376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7310627102851868, + "bbox": [ + 1336.3514404296875, + 543.7594604492188, + 1944.1654052734375, + 627.0003662109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6655001640319824, + "bbox": [ + 259.629638671875, + 531.927001953125, + 823.11572265625, + 618.2756958007812 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7612056732177734, + "bbox": [ + 1325.2484130859375, + 448.3669738769531, + 1441.96484375, + 550.7628784179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7573733329772949, + "bbox": [ + 263.52923583984375, + 439.2020568847656, + 381.2477111816406, + 540.640869140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6630344986915588, + "bbox": [ + 1323.3297119140625, + 2406.1513671875, + 1412.327392578125, + 2526.4814453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5677933692932129, + "bbox": [ + 2203.697265625, + 3219.5830078125, + 2302.647216796875, + 3301.492431640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.529183566570282, + "bbox": [ + 255.1278533935547, + 1998.453125, + 356.11474609375, + 2127.900390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4180631637573242, + "bbox": [ + 1309.0074462890625, + 2403.96240234375, + 1428.2066650390625, + 2535.266357421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9539963006973267, + "bbox": [ + 1326.5028076171875, + 638.5123291015625, + 2320.687255859375, + 2125.1123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9492160081863403, + "bbox": [ + 243.94677734375, + 629.4617919921875, + 1244.364013671875, + 1888.191650390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9468057155609131, + "bbox": [ + 1325.242919921875, + 2178.634033203125, + 2327.711669921875, + 2737.770263671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9402197599411011, + "bbox": [ + 1282.40234375, + 356.3473205566406, + 2475.557861328125, + 2846.28564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.937237560749054, + "bbox": [ + 217.1188507080078, + 389.8701171875, + 1259.607666015625, + 2691.2763671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9347747564315796, + "bbox": [ + 240.94369506835938, + 1957.65087890625, + 1248.9676513671875, + 2597.036376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7310627102851868, + "bbox": [ + 1336.3514404296875, + 543.7594604492188, + 1944.1654052734375, + 627.0003662109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6655001640319824, + "bbox": [ + 259.629638671875, + 531.927001953125, + 823.11572265625, + 618.2756958007812 + ] + } + ], + "timestamp": "2025-10-15T21:42:31.979155" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 8.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 8.json" new file mode 100644 index 0000000..18f7eb1 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 8.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 8.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7588344812393188, + "bbox": [ + 1191.49951171875, + 403.5597839355469, + 1300.09814453125, + 500.7749938964844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7518787980079651, + "bbox": [ + 211.57595825195312, + 401.6043701171875, + 317.3182067871094, + 489.6629638671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6756214499473572, + "bbox": [ + 749.4872436523438, + 2684.63330078125, + 805.3353881835938, + 2754.498291015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5186352133750916, + "bbox": [ + 1176.7537841796875, + 2172.101806640625, + 1268.2066650390625, + 2281.197998046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.49068084359169006, + "bbox": [ + 197.5060577392578, + 2962.158447265625, + 286.7390441894531, + 3036.118896484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9395431876182556, + "bbox": [ + 1144.3035888671875, + 331.2355651855469, + 2226.7216796875, + 2531.980712890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9320506453514099, + "bbox": [ + 1174.18115234375, + 580.43115234375, + 2109.4140625, + 1887.785888671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9272489547729492, + "bbox": [ + 1176.2601318359375, + 1942.9906005859375, + 2106.0146484375, + 2358.02197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9073701500892639, + "bbox": [ + 138.0968017578125, + 457.8233947753906, + 1128.2633056640625, + 2944.27490234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9056805372238159, + "bbox": [ + 168.82777404785156, + 799.6654052734375, + 1123.5394287109375, + 3011.501708984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7156044840812683, + "bbox": [ + 207.78250122070312, + 488.5344543457031, + 777.79736328125, + 563.3496704101562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5013728141784668, + "bbox": [ + 1190.416748046875, + 496.51605224609375, + 2013.04248046875, + 570.550048828125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7588344812393188, + "bbox": [ + 1191.49951171875, + 403.5597839355469, + 1300.09814453125, + 500.7749938964844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7518787980079651, + "bbox": [ + 211.57595825195312, + 401.6043701171875, + 317.3182067871094, + 489.6629638671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6756214499473572, + "bbox": [ + 749.4872436523438, + 2684.63330078125, + 805.3353881835938, + 2754.498291015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5186352133750916, + "bbox": [ + 1176.7537841796875, + 2172.101806640625, + 1268.2066650390625, + 2281.197998046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.49068084359169006, + "bbox": [ + 197.5060577392578, + 2962.158447265625, + 286.7390441894531, + 3036.118896484375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9395431876182556, + "bbox": [ + 1144.3035888671875, + 331.2355651855469, + 2226.7216796875, + 2531.980712890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9320506453514099, + "bbox": [ + 1174.18115234375, + 580.43115234375, + 2109.4140625, + 1887.785888671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9272489547729492, + "bbox": [ + 1176.2601318359375, + 1942.9906005859375, + 2106.0146484375, + 2358.02197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9073701500892639, + "bbox": [ + 138.0968017578125, + 457.8233947753906, + 1128.2633056640625, + 2944.27490234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9056805372238159, + "bbox": [ + 168.82777404785156, + 799.6654052734375, + 1123.5394287109375, + 3011.501708984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7156044840812683, + "bbox": [ + 207.78250122070312, + 488.5344543457031, + 777.79736328125, + 563.3496704101562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5013728141784668, + "bbox": [ + 1190.416748046875, + 496.51605224609375, + 2013.04248046875, + 570.550048828125 + ] + } + ], + "timestamp": "2025-10-15T21:42:32.396102" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 9.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 9.json" new file mode 100644 index 0000000..699a0d8 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\206\341\205\241\341\206\275\341\204\213\341\205\263\341\206\267) - 9.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 9.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7407278418540955, + "bbox": [ + 255.2974853515625, + 418.0464172363281, + 371.5840148925781, + 517.6305541992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.73762446641922, + "bbox": [ + 1266.562255859375, + 430.7855529785156, + 1379.7364501953125, + 528.1295776367188 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6129497289657593, + "bbox": [ + 256.64495849609375, + 2696.13232421875, + 339.9280700683594, + 2795.55810546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5788566470146179, + "bbox": [ + 1268.5531005859375, + 2682.50732421875, + 1360.7955322265625, + 2796.12939453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.560023307800293, + "bbox": [ + 2111.072509765625, + 3090.164794921875, + 2196.01416015625, + 3163.5751953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9463841319084167, + "bbox": [ + 234.2601318359375, + 635.1507568359375, + 1182.9820556640625, + 2453.857177734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9330389499664307, + "bbox": [ + 193.59645080566406, + 370.2449035644531, + 1223.2989501953125, + 2869.853271484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9254768490791321, + "bbox": [ + 1255.192626953125, + 2508.532958984375, + 2160.4423828125, + 2887.697509765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9240542650222778, + "bbox": [ + 1249.451904296875, + 662.1696166992188, + 2177.839599609375, + 2505.013671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9159631729125977, + "bbox": [ + 1218.432373046875, + 391.7794189453125, + 2360.726318359375, + 2950.974365234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.904816210269928, + "bbox": [ + 236.9214630126953, + 2465.253662109375, + 1179.156494140625, + 2821.782470703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8692476153373718, + "bbox": [ + 255.6144256591797, + 517.9653930664062, + 1190.3916015625, + 637.4789428710938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8335717916488647, + "bbox": [ + 1271.274658203125, + 527.8038330078125, + 2215.580322265625, + 647.83203125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7407278418540955, + "bbox": [ + 255.2974853515625, + 418.0464172363281, + 371.5840148925781, + 517.6305541992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.73762446641922, + "bbox": [ + 1266.562255859375, + 430.7855529785156, + 1379.7364501953125, + 528.1295776367188 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6129497289657593, + "bbox": [ + 256.64495849609375, + 2696.13232421875, + 339.9280700683594, + 2795.55810546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5788566470146179, + "bbox": [ + 1268.5531005859375, + 2682.50732421875, + 1360.7955322265625, + 2796.12939453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.560023307800293, + "bbox": [ + 2111.072509765625, + 3090.164794921875, + 2196.01416015625, + 3163.5751953125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9463841319084167, + "bbox": [ + 234.2601318359375, + 635.1507568359375, + 1182.9820556640625, + 2453.857177734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9330389499664307, + "bbox": [ + 193.59645080566406, + 370.2449035644531, + 1223.2989501953125, + 2869.853271484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9254768490791321, + "bbox": [ + 1255.192626953125, + 2508.532958984375, + 2160.4423828125, + 2887.697509765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9240542650222778, + "bbox": [ + 1249.451904296875, + 662.1696166992188, + 2177.839599609375, + 2505.013671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9159631729125977, + "bbox": [ + 1218.432373046875, + 391.7794189453125, + 2360.726318359375, + 2950.974365234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.904816210269928, + "bbox": [ + 236.9214630126953, + 2465.253662109375, + 1179.156494140625, + 2821.782470703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8692476153373718, + "bbox": [ + 255.6144256591797, + 517.9653930664062, + 1190.3916015625, + 637.4789428710938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8335717916488647, + "bbox": [ + 1271.274658203125, + 527.8038330078125, + 2215.580322265625, + 647.83203125 + ] + } + ], + "timestamp": "2025-10-15T21:42:32.815033" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 18.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 18.json" new file mode 100644 index 0000000..6b275f6 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 18.json" @@ -0,0 +1,692 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 18.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7846184968948364, + "bbox": [ + 1299.5025634765625, + 2579.77587890625, + 1403.5953369140625, + 2668.6572265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7759642601013184, + "bbox": [ + 1311.9716796875, + 499.1026916503906, + 1415.04541015625, + 586.4191284179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7688509821891785, + "bbox": [ + 277.18115234375, + 983.3073120117188, + 385.6111145019531, + 1079.220703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7686595916748047, + "bbox": [ + 281.42486572265625, + 1812.1678466796875, + 389.3860168457031, + 1902.4697265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7683885097503662, + "bbox": [ + 275.0069274902344, + 2575.080322265625, + 378.5321044921875, + 2662.817626953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6927738785743713, + "bbox": [ + 284.9305725097656, + 1272.8846435546875, + 346.3131408691406, + 1350.852294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6015613079071045, + "bbox": [ + 281.03338623046875, + 2236.856689453125, + 344.9021911621094, + 2316.61376953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5922463536262512, + "bbox": [ + 1652.839111328125, + 1372.059326171875, + 1732.7091064453125, + 1467.650634765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5721011757850647, + "bbox": [ + 1644.0538330078125, + 1366.1192626953125, + 1747.117919921875, + 1488.8909912109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5473920106887817, + "bbox": [ + 274.6693115234375, + 2840.498291015625, + 363.9375, + 2959.8251953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47175300121307373, + "bbox": [ + 1300.7203369140625, + 2852.48876953125, + 1369.9244384765625, + 2956.456298828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2746185064315796, + "bbox": [ + 274.9037780761719, + 3113.80322265625, + 339.4065856933594, + 3182.939697265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2637054920196533, + "bbox": [ + 1301.8348388671875, + 2873.325927734375, + 1362.2965087890625, + 2953.63671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9293239712715149, + "bbox": [ + 1266.37890625, + 476.09173583984375, + 2383.884765625, + 1645.0438232421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9134370684623718, + "bbox": [ + 218.10020446777344, + 940.7481689453125, + 1272.26220703125, + 1695.993408203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9127632975578308, + "bbox": [ + 242.83966064453125, + 2518.5888671875, + 1235.6380615234375, + 3124.789306640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9111214876174927, + "bbox": [ + 1303.947021484375, + 790.7500610351562, + 2278.843017578125, + 1575.8875732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9110651016235352, + "bbox": [ + 246.1043701171875, + 1774.0943603515625, + 1276.2115478515625, + 2395.957275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9026702642440796, + "bbox": [ + 279.34564208984375, + 1205.5506591796875, + 1070.8385009765625, + 1589.974365234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9004862308502197, + "bbox": [ + 288.5530700683594, + 1988.044677734375, + 1097.0166015625, + 2346.018798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8881144523620605, + "bbox": [ + 1285.2596435546875, + 2520.07275390625, + 2363.521728515625, + 3152.701416015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8513363599777222, + "bbox": [ + 1303.148193359375, + 2755.71630859375, + 1679.3857421875, + 3103.17333984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8495510220527649, + "bbox": [ + 277.11761474609375, + 2754.44677734375, + 887.9896240234375, + 3090.192626953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8236514329910278, + "bbox": [ + 1299.0938720703125, + 591.206298828125, + 2275.47607421875, + 726.4122314453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7922306060791016, + "bbox": [ + 269.9949645996094, + 1078.7987060546875, + 1232.0540771484375, + 1208.58837890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7671198844909668, + "bbox": [ + 1307.8310546875, + 2763.368896484375, + 1836.4410400390625, + 3105.093994140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7585636973381042, + "bbox": [ + 1307.326416015625, + 2657.321533203125, + 2123.777099609375, + 2754.283203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7545921206474304, + "bbox": [ + 291.4330749511719, + 2657.18310546875, + 1180.22998046875, + 2765.054931640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6911676526069641, + "bbox": [ + 271.2880554199219, + 1901.6171875, + 1129.6876220703125, + 1982.912841796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.18145117163658142, + "bbox": [ + 1306.4901123046875, + 2765.097900390625, + 2052.065673828125, + 3111.32470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.1613447517156601, + "bbox": [ + 787.3344116210938, + 0.0, + 2318.010986328125, + 1246.785400390625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7846184968948364, + "bbox": [ + 1299.5025634765625, + 2579.77587890625, + 1403.5953369140625, + 2668.6572265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7759642601013184, + "bbox": [ + 1311.9716796875, + 499.1026916503906, + 1415.04541015625, + 586.4191284179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7688509821891785, + "bbox": [ + 277.18115234375, + 983.3073120117188, + 385.6111145019531, + 1079.220703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7686595916748047, + "bbox": [ + 281.42486572265625, + 1812.1678466796875, + 389.3860168457031, + 1902.4697265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7683885097503662, + "bbox": [ + 275.0069274902344, + 2575.080322265625, + 378.5321044921875, + 2662.817626953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6927738785743713, + "bbox": [ + 284.9305725097656, + 1272.8846435546875, + 346.3131408691406, + 1350.852294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6015613079071045, + "bbox": [ + 281.03338623046875, + 2236.856689453125, + 344.9021911621094, + 2316.61376953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5922463536262512, + "bbox": [ + 1652.839111328125, + 1372.059326171875, + 1732.7091064453125, + 1467.650634765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5721011757850647, + "bbox": [ + 1644.0538330078125, + 1366.1192626953125, + 1747.117919921875, + 1488.8909912109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5473920106887817, + "bbox": [ + 274.6693115234375, + 2840.498291015625, + 363.9375, + 2959.8251953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47175300121307373, + "bbox": [ + 1300.7203369140625, + 2852.48876953125, + 1369.9244384765625, + 2956.456298828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2746185064315796, + "bbox": [ + 274.9037780761719, + 3113.80322265625, + 339.4065856933594, + 3182.939697265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2637054920196533, + "bbox": [ + 1301.8348388671875, + 2873.325927734375, + 1362.2965087890625, + 2953.63671875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9293239712715149, + "bbox": [ + 1266.37890625, + 476.09173583984375, + 2383.884765625, + 1645.0438232421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9134370684623718, + "bbox": [ + 218.10020446777344, + 940.7481689453125, + 1272.26220703125, + 1695.993408203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9127632975578308, + "bbox": [ + 242.83966064453125, + 2518.5888671875, + 1235.6380615234375, + 3124.789306640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9111214876174927, + "bbox": [ + 1303.947021484375, + 790.7500610351562, + 2278.843017578125, + 1575.8875732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9110651016235352, + "bbox": [ + 246.1043701171875, + 1774.0943603515625, + 1276.2115478515625, + 2395.957275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9026702642440796, + "bbox": [ + 279.34564208984375, + 1205.5506591796875, + 1070.8385009765625, + 1589.974365234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9004862308502197, + "bbox": [ + 288.5530700683594, + 1988.044677734375, + 1097.0166015625, + 2346.018798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8881144523620605, + "bbox": [ + 1285.2596435546875, + 2520.07275390625, + 2363.521728515625, + 3152.701416015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8513363599777222, + "bbox": [ + 1303.148193359375, + 2755.71630859375, + 1679.3857421875, + 3103.17333984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8495510220527649, + "bbox": [ + 277.11761474609375, + 2754.44677734375, + 887.9896240234375, + 3090.192626953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8236514329910278, + "bbox": [ + 1299.0938720703125, + 591.206298828125, + 2275.47607421875, + 726.4122314453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7922306060791016, + "bbox": [ + 269.9949645996094, + 1078.7987060546875, + 1232.0540771484375, + 1208.58837890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7671198844909668, + "bbox": [ + 1307.8310546875, + 2763.368896484375, + 1836.4410400390625, + 3105.093994140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7585636973381042, + "bbox": [ + 1307.326416015625, + 2657.321533203125, + 2123.777099609375, + 2754.283203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7545921206474304, + "bbox": [ + 291.4330749511719, + 2657.18310546875, + 1180.22998046875, + 2765.054931640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6911676526069641, + "bbox": [ + 271.2880554199219, + 1901.6171875, + 1129.6876220703125, + 1982.912841796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.18145117163658142, + "bbox": [ + 1306.4901123046875, + 2765.097900390625, + 2052.065673828125, + 3111.32470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.1613447517156601, + "bbox": [ + 787.3344116210938, + 0.0, + 2318.010986328125, + 1246.785400390625 + ] + } + ], + "timestamp": "2025-10-15T21:42:33.236275" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 19.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 19.json" new file mode 100644 index 0000000..366dbc0 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 19.json" @@ -0,0 +1,648 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 19.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.776886522769928, + "bbox": [ + 283.5733642578125, + 2426.473876953125, + 387.6286926269531, + 2512.195068359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7768315076828003, + "bbox": [ + 1266.2724609375, + 413.9976501464844, + 1366.1689453125, + 501.0334167480469 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7644055485725403, + "bbox": [ + 1249.869384765625, + 2046.2265625, + 1352.7569580078125, + 2140.320556640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7643024921417236, + "bbox": [ + 295.2785949707031, + 407.83740234375, + 399.2215576171875, + 494.1003723144531 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7611289620399475, + "bbox": [ + 289.8592224121094, + 1422.781005859375, + 394.20849609375, + 1510.9014892578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5970655679702759, + "bbox": [ + 287.11077880859375, + 2700.139404296875, + 345.15118408203125, + 2774.53515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5823915004730225, + "bbox": [ + 2077.378173828125, + 3010.5712890625, + 2142.211669921875, + 3077.97265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5772170424461365, + "bbox": [ + 291.4651184082031, + 1834.798583984375, + 359.6415100097656, + 1916.8997802734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5558503866195679, + "bbox": [ + 296.27001953125, + 745.8803100585938, + 370.512451171875, + 836.5371704101562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4381183385848999, + "bbox": [ + 1263.4603271484375, + 734.3966674804688, + 1341.9556884765625, + 844.0040283203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3939880430698395, + "bbox": [ + 1244.367431640625, + 2406.23046875, + 1320.1290283203125, + 2528.68603515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3665919601917267, + "bbox": [ + 1245.845458984375, + 2434.719970703125, + 1306.94970703125, + 2514.757568359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2390291690826416, + "bbox": [ + 1263.19189453125, + 747.9443359375, + 1330.3409423828125, + 835.8890380859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9369932413101196, + "bbox": [ + 1242.16064453125, + 2264.775390625, + 2156.21435546875, + 2980.147705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9147666692733765, + "bbox": [ + 1213.319091796875, + 2002.53759765625, + 2254.7412109375, + 3020.351806640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025638699531555, + "bbox": [ + 1224.840087890625, + 369.44952392578125, + 2228.216552734375, + 1138.3333740234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9012763500213623, + "bbox": [ + 1256.3372802734375, + 630.2367553710938, + 2183.962158203125, + 1048.2635498046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.879751443862915, + "bbox": [ + 1250.16064453125, + 2137.86962890625, + 2157.86328125, + 2254.598388671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8764828443527222, + "bbox": [ + 219.86053466796875, + 341.5624694824219, + 1197.3204345703125, + 982.4178466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8693755269050598, + "bbox": [ + 194.22976684570312, + 2379.40380859375, + 1211.2135009765625, + 3035.416015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.841931939125061, + "bbox": [ + 281.1965637207031, + 1585.2760009765625, + 796.1295166015625, + 1933.79052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8362790942192078, + "bbox": [ + 195.65646362304688, + 1355.9951171875, + 1216.2904052734375, + 2024.539794921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8332664370536804, + "bbox": [ + 300.0977478027344, + 485.620361328125, + 1005.7455444335938, + 575.8887329101562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8241668343544006, + "bbox": [ + 276.8126220703125, + 2512.34716796875, + 1193.011962890625, + 2636.438720703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8082225918769836, + "bbox": [ + 1238.1475830078125, + 499.14422607421875, + 2168.482666015625, + 623.4498291015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7346722483634949, + "bbox": [ + 272.5602111816406, + 2625.090576171875, + 843.850830078125, + 2981.4912109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7311903834342957, + "bbox": [ + 295.2333068847656, + 1503.4769287109375, + 1181.2420654296875, + 1591.7735595703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6637079119682312, + "bbox": [ + 292.0624084472656, + 574.4183959960938, + 801.4624633789062, + 921.5722045898438 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5581426024436951, + "bbox": [ + 285.98358154296875, + 570.8383178710938, + 1041.527099609375, + 930.4381103515625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.776886522769928, + "bbox": [ + 283.5733642578125, + 2426.473876953125, + 387.6286926269531, + 2512.195068359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7768315076828003, + "bbox": [ + 1266.2724609375, + 413.9976501464844, + 1366.1689453125, + 501.0334167480469 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7644055485725403, + "bbox": [ + 1249.869384765625, + 2046.2265625, + 1352.7569580078125, + 2140.320556640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7643024921417236, + "bbox": [ + 295.2785949707031, + 407.83740234375, + 399.2215576171875, + 494.1003723144531 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7611289620399475, + "bbox": [ + 289.8592224121094, + 1422.781005859375, + 394.20849609375, + 1510.9014892578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5970655679702759, + "bbox": [ + 287.11077880859375, + 2700.139404296875, + 345.15118408203125, + 2774.53515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5823915004730225, + "bbox": [ + 2077.378173828125, + 3010.5712890625, + 2142.211669921875, + 3077.97265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5772170424461365, + "bbox": [ + 291.4651184082031, + 1834.798583984375, + 359.6415100097656, + 1916.8997802734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5558503866195679, + "bbox": [ + 296.27001953125, + 745.8803100585938, + 370.512451171875, + 836.5371704101562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4381183385848999, + "bbox": [ + 1263.4603271484375, + 734.3966674804688, + 1341.9556884765625, + 844.0040283203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3939880430698395, + "bbox": [ + 1244.367431640625, + 2406.23046875, + 1320.1290283203125, + 2528.68603515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3665919601917267, + "bbox": [ + 1245.845458984375, + 2434.719970703125, + 1306.94970703125, + 2514.757568359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2390291690826416, + "bbox": [ + 1263.19189453125, + 747.9443359375, + 1330.3409423828125, + 835.8890380859375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9369932413101196, + "bbox": [ + 1242.16064453125, + 2264.775390625, + 2156.21435546875, + 2980.147705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9147666692733765, + "bbox": [ + 1213.319091796875, + 2002.53759765625, + 2254.7412109375, + 3020.351806640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025638699531555, + "bbox": [ + 1224.840087890625, + 369.44952392578125, + 2228.216552734375, + 1138.3333740234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9012763500213623, + "bbox": [ + 1256.3372802734375, + 630.2367553710938, + 2183.962158203125, + 1048.2635498046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.879751443862915, + "bbox": [ + 1250.16064453125, + 2137.86962890625, + 2157.86328125, + 2254.598388671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8764828443527222, + "bbox": [ + 219.86053466796875, + 341.5624694824219, + 1197.3204345703125, + 982.4178466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8693755269050598, + "bbox": [ + 194.22976684570312, + 2379.40380859375, + 1211.2135009765625, + 3035.416015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.841931939125061, + "bbox": [ + 281.1965637207031, + 1585.2760009765625, + 796.1295166015625, + 1933.79052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8362790942192078, + "bbox": [ + 195.65646362304688, + 1355.9951171875, + 1216.2904052734375, + 2024.539794921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8332664370536804, + "bbox": [ + 300.0977478027344, + 485.620361328125, + 1005.7455444335938, + 575.8887329101562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8241668343544006, + "bbox": [ + 276.8126220703125, + 2512.34716796875, + 1193.011962890625, + 2636.438720703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8082225918769836, + "bbox": [ + 1238.1475830078125, + 499.14422607421875, + 2168.482666015625, + 623.4498291015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7346722483634949, + "bbox": [ + 272.5602111816406, + 2625.090576171875, + 843.850830078125, + 2981.4912109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7311903834342957, + "bbox": [ + 295.2333068847656, + 1503.4769287109375, + 1181.2420654296875, + 1591.7735595703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6637079119682312, + "bbox": [ + 292.0624084472656, + 574.4183959960938, + 801.4624633789062, + 921.5722045898438 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5581426024436951, + "bbox": [ + 285.98358154296875, + 570.8383178710938, + 1041.527099609375, + 930.4381103515625 + ] + } + ], + "timestamp": "2025-10-15T21:42:33.660183" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 20.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 20.json" new file mode 100644 index 0000000..aa4bea3 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 20.json" @@ -0,0 +1,692 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 20.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7683119177818298, + "bbox": [ + 1294.6053466796875, + 2186.27197265625, + 1405.178955078125, + 2287.918701171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7465526461601257, + "bbox": [ + 1301.8123779296875, + 450.5603942871094, + 1409.76416015625, + 550.3806762695312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7413792014122009, + "bbox": [ + 259.5576477050781, + 1291.7227783203125, + 371.1444091796875, + 1393.9207763671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7396041750907898, + "bbox": [ + 266.5613708496094, + 2373.946533203125, + 377.9087829589844, + 2472.917724609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7320401668548584, + "bbox": [ + 254.419921875, + 450.9359130859375, + 367.9903869628906, + 554.7522583007812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6151673197746277, + "bbox": [ + 267.76898193359375, + 2670.884521484375, + 335.87518310546875, + 2772.5595703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5330805778503418, + "bbox": [ + 264.5439453125, + 1882.8548583984375, + 345.8608703613281, + 1997.4920654296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.517382800579071, + "bbox": [ + 1291.6021728515625, + 2740.08203125, + 1384.17333984375, + 2858.27734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47035977244377136, + "bbox": [ + 259.740966796875, + 805.1583251953125, + 344.5245056152344, + 908.6259155273438 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4395650327205658, + "bbox": [ + 1305.577880859375, + 1286.509765625, + 1379.93017578125, + 1394.7322998046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2608482539653778, + "bbox": [ + 260.96734619140625, + 814.7350463867188, + 329.8089599609375, + 903.3792114257812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23759527504444122, + "bbox": [ + 1306.128173828125, + 1300.0406494140625, + 1368.4461669921875, + 1388.9654541015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23563717305660248, + "bbox": [ + 261.4866638183594, + 2656.289794921875, + 357.9808044433594, + 2783.037353515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9357314705848694, + "bbox": [ + 263.1419677734375, + 1534.25341796875, + 1229.466064453125, + 2205.520751953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9351439476013184, + "bbox": [ + 1288.099853515625, + 785.0848388671875, + 2283.196533203125, + 1479.415771484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9332083463668823, + "bbox": [ + 1287.0062255859375, + 2522.52734375, + 2307.506591796875, + 3211.444580078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9296055436134338, + "bbox": [ + 253.7504425048828, + 2669.001953125, + 1225.1944580078125, + 3185.684814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9240237474441528, + "bbox": [ + 1242.92919921875, + 2138.17919921875, + 2508.63916015625, + 3288.89599609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9096837043762207, + "bbox": [ + 179.63861083984375, + 416.0799560546875, + 1265.3074951171875, + 1215.5218505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9057604670524597, + "bbox": [ + 249.77549743652344, + 693.5044555664062, + 1229.744384765625, + 1131.046630859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9057407975196838, + "bbox": [ + 180.18362426757812, + 1231.96044921875, + 1233.4793701171875, + 2291.24267578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8987570405006409, + "bbox": [ + 95.62633514404297, + 2318.595947265625, + 1257.8924560546875, + 3234.850341796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8982102274894714, + "bbox": [ + 1243.2581787109375, + 381.5397033691406, + 2506.340576171875, + 1607.3770751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8445404171943665, + "bbox": [ + 1292.8731689453125, + 549.1233520507812, + 2278.39013671875, + 686.5225830078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8079210519790649, + "bbox": [ + 1290.36083984375, + 2417.9638671875, + 2293.914794921875, + 2526.770751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8078394532203674, + "bbox": [ + 256.3052062988281, + 2459.707763671875, + 1217.355224609375, + 2586.982666015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8025450110435486, + "bbox": [ + 243.53396606445312, + 550.616943359375, + 1228.8731689453125, + 680.1709594726562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7976649403572083, + "bbox": [ + 255.0074920654297, + 1390.3236083984375, + 1221.2130126953125, + 1517.3192138671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7810220718383789, + "bbox": [ + 1295.839111328125, + 2278.012939453125, + 2276.5224609375, + 2417.0380859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7180396318435669, + "bbox": [ + 234.9778289794922, + 2600.342041015625, + 1204.498779296875, + 2697.6337890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5510781407356262, + "bbox": [ + 1290.2784423828125, + 682.504638671875, + 2280.008544921875, + 789.3525390625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7683119177818298, + "bbox": [ + 1294.6053466796875, + 2186.27197265625, + 1405.178955078125, + 2287.918701171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7465526461601257, + "bbox": [ + 1301.8123779296875, + 450.5603942871094, + 1409.76416015625, + 550.3806762695312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7413792014122009, + "bbox": [ + 259.5576477050781, + 1291.7227783203125, + 371.1444091796875, + 1393.9207763671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7396041750907898, + "bbox": [ + 266.5613708496094, + 2373.946533203125, + 377.9087829589844, + 2472.917724609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7320401668548584, + "bbox": [ + 254.419921875, + 450.9359130859375, + 367.9903869628906, + 554.7522583007812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6151673197746277, + "bbox": [ + 267.76898193359375, + 2670.884521484375, + 335.87518310546875, + 2772.5595703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5330805778503418, + "bbox": [ + 264.5439453125, + 1882.8548583984375, + 345.8608703613281, + 1997.4920654296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.517382800579071, + "bbox": [ + 1291.6021728515625, + 2740.08203125, + 1384.17333984375, + 2858.27734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47035977244377136, + "bbox": [ + 259.740966796875, + 805.1583251953125, + 344.5245056152344, + 908.6259155273438 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4395650327205658, + "bbox": [ + 1305.577880859375, + 1286.509765625, + 1379.93017578125, + 1394.7322998046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2608482539653778, + "bbox": [ + 260.96734619140625, + 814.7350463867188, + 329.8089599609375, + 903.3792114257812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23759527504444122, + "bbox": [ + 1306.128173828125, + 1300.0406494140625, + 1368.4461669921875, + 1388.9654541015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23563717305660248, + "bbox": [ + 261.4866638183594, + 2656.289794921875, + 357.9808044433594, + 2783.037353515625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9357314705848694, + "bbox": [ + 263.1419677734375, + 1534.25341796875, + 1229.466064453125, + 2205.520751953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9351439476013184, + "bbox": [ + 1288.099853515625, + 785.0848388671875, + 2283.196533203125, + 1479.415771484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9332083463668823, + "bbox": [ + 1287.0062255859375, + 2522.52734375, + 2307.506591796875, + 3211.444580078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9296055436134338, + "bbox": [ + 253.7504425048828, + 2669.001953125, + 1225.1944580078125, + 3185.684814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9240237474441528, + "bbox": [ + 1242.92919921875, + 2138.17919921875, + 2508.63916015625, + 3288.89599609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9096837043762207, + "bbox": [ + 179.63861083984375, + 416.0799560546875, + 1265.3074951171875, + 1215.5218505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9057604670524597, + "bbox": [ + 249.77549743652344, + 693.5044555664062, + 1229.744384765625, + 1131.046630859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9057407975196838, + "bbox": [ + 180.18362426757812, + 1231.96044921875, + 1233.4793701171875, + 2291.24267578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8987570405006409, + "bbox": [ + 95.62633514404297, + 2318.595947265625, + 1257.8924560546875, + 3234.850341796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8982102274894714, + "bbox": [ + 1243.2581787109375, + 381.5397033691406, + 2506.340576171875, + 1607.3770751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8445404171943665, + "bbox": [ + 1292.8731689453125, + 549.1233520507812, + 2278.39013671875, + 686.5225830078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8079210519790649, + "bbox": [ + 1290.36083984375, + 2417.9638671875, + 2293.914794921875, + 2526.770751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8078394532203674, + "bbox": [ + 256.3052062988281, + 2459.707763671875, + 1217.355224609375, + 2586.982666015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8025450110435486, + "bbox": [ + 243.53396606445312, + 550.616943359375, + 1228.8731689453125, + 680.1709594726562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7976649403572083, + "bbox": [ + 255.0074920654297, + 1390.3236083984375, + 1221.2130126953125, + 1517.3192138671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7810220718383789, + "bbox": [ + 1295.839111328125, + 2278.012939453125, + 2276.5224609375, + 2417.0380859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7180396318435669, + "bbox": [ + 234.9778289794922, + 2600.342041015625, + 1204.498779296875, + 2697.6337890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5510781407356262, + "bbox": [ + 1290.2784423828125, + 682.504638671875, + 2280.008544921875, + 789.3525390625 + ] + } + ], + "timestamp": "2025-10-15T21:42:34.043990" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 21.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 21.json" new file mode 100644 index 0000000..71a9d37 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 21.json" @@ -0,0 +1,428 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 21.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7755255103111267, + "bbox": [ + 278.7999267578125, + 577.7952270507812, + 389.59356689453125, + 679.859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7565394043922424, + "bbox": [ + 296.09716796875, + 1798.5341796875, + 409.3768005371094, + 1900.365478515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7444714903831482, + "bbox": [ + 1322.7049560546875, + 448.2289733886719, + 1433.8587646484375, + 544.5680541992188 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.629237711429596, + "bbox": [ + 282.9502868652344, + 821.1759033203125, + 347.4347839355469, + 899.3653564453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5262008309364319, + "bbox": [ + 2222.088134765625, + 3173.7548828125, + 2288.16455078125, + 3244.7802734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49576127529144287, + "bbox": [ + 1334.5206298828125, + 2519.017822265625, + 1412.8782958984375, + 2613.996826171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4206846356391907, + "bbox": [ + 299.3791198730469, + 2170.7138671875, + 365.9861145019531, + 2253.27294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22485481202602386, + "bbox": [ + 1337.4964599609375, + 2530.310546875, + 1402.6473388671875, + 2607.80517578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9287400841712952, + "bbox": [ + 1306.3515625, + 431.64556884765625, + 2378.428466796875, + 2747.514404296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9176496267318726, + "bbox": [ + 1340.85595703125, + 659.8131713867188, + 2278.302734375, + 2171.390869140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.911493718624115, + "bbox": [ + 1332.449951171875, + 2255.69873046875, + 2300.87841796875, + 2629.593505859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9001783132553101, + "bbox": [ + 215.18112182617188, + 1728.2930908203125, + 1254.460693359375, + 2491.9404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8969367146492004, + "bbox": [ + 278.4331970214844, + 765.9695434570312, + 1163.850341796875, + 1149.8345947265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8511821627616882, + "bbox": [ + 296.6651611328125, + 1977.7093505859375, + 669.780029296875, + 2368.931884765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8454031348228455, + "bbox": [ + 221.4619140625, + 554.1069946289062, + 1264.8031005859375, + 1322.068359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7742727994918823, + "bbox": [ + 281.0895690917969, + 673.0726318359375, + 944.4588012695312, + 743.7951049804688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7531977891921997, + "bbox": [ + 1326.954833984375, + 541.9246215820312, + 1915.188232421875, + 619.284912109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6431077718734741, + "bbox": [ + 296.1228942871094, + 1894.5391845703125, + 694.1431884765625, + 1966.3424072265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.14548256993293762, + "bbox": [ + 309.6708984375, + 1889.41357421875, + 1176.5767822265625, + 1962.09326171875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7755255103111267, + "bbox": [ + 278.7999267578125, + 577.7952270507812, + 389.59356689453125, + 679.859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7565394043922424, + "bbox": [ + 296.09716796875, + 1798.5341796875, + 409.3768005371094, + 1900.365478515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7444714903831482, + "bbox": [ + 1322.7049560546875, + 448.2289733886719, + 1433.8587646484375, + 544.5680541992188 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.629237711429596, + "bbox": [ + 282.9502868652344, + 821.1759033203125, + 347.4347839355469, + 899.3653564453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5262008309364319, + "bbox": [ + 2222.088134765625, + 3173.7548828125, + 2288.16455078125, + 3244.7802734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49576127529144287, + "bbox": [ + 1334.5206298828125, + 2519.017822265625, + 1412.8782958984375, + 2613.996826171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4206846356391907, + "bbox": [ + 299.3791198730469, + 2170.7138671875, + 365.9861145019531, + 2253.27294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22485481202602386, + "bbox": [ + 1337.4964599609375, + 2530.310546875, + 1402.6473388671875, + 2607.80517578125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9287400841712952, + "bbox": [ + 1306.3515625, + 431.64556884765625, + 2378.428466796875, + 2747.514404296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9176496267318726, + "bbox": [ + 1340.85595703125, + 659.8131713867188, + 2278.302734375, + 2171.390869140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.911493718624115, + "bbox": [ + 1332.449951171875, + 2255.69873046875, + 2300.87841796875, + 2629.593505859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9001783132553101, + "bbox": [ + 215.18112182617188, + 1728.2930908203125, + 1254.460693359375, + 2491.9404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8969367146492004, + "bbox": [ + 278.4331970214844, + 765.9695434570312, + 1163.850341796875, + 1149.8345947265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8511821627616882, + "bbox": [ + 296.6651611328125, + 1977.7093505859375, + 669.780029296875, + 2368.931884765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8454031348228455, + "bbox": [ + 221.4619140625, + 554.1069946289062, + 1264.8031005859375, + 1322.068359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7742727994918823, + "bbox": [ + 281.0895690917969, + 673.0726318359375, + 944.4588012695312, + 743.7951049804688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7531977891921997, + "bbox": [ + 1326.954833984375, + 541.9246215820312, + 1915.188232421875, + 619.284912109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6431077718734741, + "bbox": [ + 296.1228942871094, + 1894.5391845703125, + 694.1431884765625, + 1966.3424072265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.14548256993293762, + "bbox": [ + 309.6708984375, + 1889.41357421875, + 1176.5767822265625, + 1962.09326171875 + ] + } + ], + "timestamp": "2025-10-15T21:42:34.458263" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 22.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 22.json" new file mode 100644 index 0000000..59e0a7e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 22.json" @@ -0,0 +1,164 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 22.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7464569807052612, + "bbox": [ + 239.90000915527344, + 436.77703857421875, + 355.4010009765625, + 542.0134887695312 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9374851584434509, + "bbox": [ + 217.72842407226562, + 557.4828491210938, + 1207.46875, + 1882.2918701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9336852431297302, + "bbox": [ + 1268.0975341796875, + 1816.1700439453125, + 2234.017822265625, + 2323.7080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9251554012298584, + "bbox": [ + 1257.7198486328125, + 335.0719299316406, + 2276.373291015625, + 2427.7158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9245746731758118, + "bbox": [ + 1269.748291015625, + 620.04296875, + 2251.647705078125, + 1839.697021484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9057725667953491, + "bbox": [ + 187.8255615234375, + 315.9036560058594, + 1218.9857177734375, + 2285.388671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.48269322514533997, + "bbox": [ + 1280.476318359375, + 534.2542114257812, + 2159.66943359375, + 620.7685546875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7464569807052612, + "bbox": [ + 239.90000915527344, + 436.77703857421875, + 355.4010009765625, + 542.0134887695312 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9374851584434509, + "bbox": [ + 217.72842407226562, + 557.4828491210938, + 1207.46875, + 1882.2918701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9336852431297302, + "bbox": [ + 1268.0975341796875, + 1816.1700439453125, + 2234.017822265625, + 2323.7080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9251554012298584, + "bbox": [ + 1257.7198486328125, + 335.0719299316406, + 2276.373291015625, + 2427.7158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9245746731758118, + "bbox": [ + 1269.748291015625, + 620.04296875, + 2251.647705078125, + 1839.697021484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9057725667953491, + "bbox": [ + 187.8255615234375, + 315.9036560058594, + 1218.9857177734375, + 2285.388671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.48269322514533997, + "bbox": [ + 1280.476318359375, + 534.2542114257812, + 2159.66943359375, + 620.7685546875 + ] + } + ], + "timestamp": "2025-10-15T21:42:34.833494" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 23.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 23.json" new file mode 100644 index 0000000..95896f9 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 23.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 23.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7408531308174133, + "bbox": [ + 287.06646728515625, + 449.28607177734375, + 410.17767333984375, + 557.0758666992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7263175845146179, + "bbox": [ + 1360.0926513671875, + 458.1968688964844, + 1482.261474609375, + 564.0873413085938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5333561301231384, + "bbox": [ + 1349.552001953125, + 2101.04052734375, + 1418.1453857421875, + 2195.279296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.22785744071006775, + "bbox": [ + 2264.17626953125, + 3246.12060546875, + 2333.58837890625, + 3319.25390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9693681001663208, + "bbox": [ + 231.01339721679688, + 391.47076416015625, + 1288.99462890625, + 2860.60546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9644021391868591, + "bbox": [ + 273.0490417480469, + 678.5719604492188, + 1275.4842529296875, + 2203.12109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9547895193099976, + "bbox": [ + 1352.018798828125, + 646.2605590820312, + 2353.725830078125, + 2035.519775390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.925831139087677, + "bbox": [ + 293.6109619140625, + 2205.3525390625, + 1274.806640625, + 2737.760986328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9235560894012451, + "bbox": [ + 1345.933837890625, + 2062.98583984375, + 2352.359130859375, + 2724.531982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9206604957580566, + "bbox": [ + 1337.7620849609375, + 410.28399658203125, + 2390.07470703125, + 2833.5146484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7335054874420166, + "bbox": [ + 285.7752380371094, + 560.9447021484375, + 1292.3006591796875, + 675.047607421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6728856563568115, + "bbox": [ + 1367.9661865234375, + 547.0529174804688, + 1979.1614990234375, + 629.7887573242188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7408531308174133, + "bbox": [ + 287.06646728515625, + 449.28607177734375, + 410.17767333984375, + 557.0758666992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7263175845146179, + "bbox": [ + 1360.0926513671875, + 458.1968688964844, + 1482.261474609375, + 564.0873413085938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5333561301231384, + "bbox": [ + 1349.552001953125, + 2101.04052734375, + 1418.1453857421875, + 2195.279296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.22785744071006775, + "bbox": [ + 2264.17626953125, + 3246.12060546875, + 2333.58837890625, + 3319.25390625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9693681001663208, + "bbox": [ + 231.01339721679688, + 391.47076416015625, + 1288.99462890625, + 2860.60546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9644021391868591, + "bbox": [ + 273.0490417480469, + 678.5719604492188, + 1275.4842529296875, + 2203.12109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9547895193099976, + "bbox": [ + 1352.018798828125, + 646.2605590820312, + 2353.725830078125, + 2035.519775390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.925831139087677, + "bbox": [ + 293.6109619140625, + 2205.3525390625, + 1274.806640625, + 2737.760986328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9235560894012451, + "bbox": [ + 1345.933837890625, + 2062.98583984375, + 2352.359130859375, + 2724.531982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9206604957580566, + "bbox": [ + 1337.7620849609375, + 410.28399658203125, + 2390.07470703125, + 2833.5146484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7335054874420166, + "bbox": [ + 285.7752380371094, + 560.9447021484375, + 1292.3006591796875, + 675.047607421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6728856563568115, + "bbox": [ + 1367.9661865234375, + 547.0529174804688, + 1979.1614990234375, + 629.7887573242188 + ] + } + ], + "timestamp": "2025-10-15T21:42:35.249293" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 24.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 24.json" new file mode 100644 index 0000000..4931cfb --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 24.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 24.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7499555945396423, + "bbox": [ + 1291.2161865234375, + 438.009033203125, + 1405.6112060546875, + 538.0480346679688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7326586842536926, + "bbox": [ + 227.97157287597656, + 428.57269287109375, + 343.1900634765625, + 528.3182373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5441185235977173, + "bbox": [ + 1281.55322265625, + 2111.874755859375, + 1383.5269775390625, + 2240.95361328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49203798174858093, + "bbox": [ + 1293.846923828125, + 2114.91943359375, + 1375.3638916015625, + 2225.69873046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.413155734539032, + "bbox": [ + 210.71299743652344, + 2712.188720703125, + 288.1453552246094, + 2827.98828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3804877698421478, + "bbox": [ + 209.66197204589844, + 3172.32421875, + 281.32183837890625, + 3241.4794921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3566216826438904, + "bbox": [ + 213.76446533203125, + 2725.703125, + 277.2315368652344, + 2820.79638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9519443511962891, + "bbox": [ + 1290.3035888671875, + 614.5211791992188, + 2283.529541015625, + 2095.49169921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9456939697265625, + "bbox": [ + 193.9445037841797, + 607.7117919921875, + 1208.30419921875, + 2376.8505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9412693977355957, + "bbox": [ + 1268.4588623046875, + 2126.5390625, + 2307.359375, + 2783.716552734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9335028529167175, + "bbox": [ + 201.33453369140625, + 2403.188232421875, + 1200.840087890625, + 3049.89306640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9077781438827515, + "bbox": [ + 1246.1876220703125, + 378.7965393066406, + 2389.033447265625, + 2864.5546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9028221368789673, + "bbox": [ + 174.9167938232422, + 402.5443115234375, + 1220.2403564453125, + 3064.48291015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.791551947593689, + "bbox": [ + 1293.18701171875, + 532.70458984375, + 1906.813232421875, + 619.83203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6859422326087952, + "bbox": [ + 222.75241088867188, + 528.7889404296875, + 798.6803588867188, + 604.3812255859375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7499555945396423, + "bbox": [ + 1291.2161865234375, + 438.009033203125, + 1405.6112060546875, + 538.0480346679688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7326586842536926, + "bbox": [ + 227.97157287597656, + 428.57269287109375, + 343.1900634765625, + 528.3182373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5441185235977173, + "bbox": [ + 1281.55322265625, + 2111.874755859375, + 1383.5269775390625, + 2240.95361328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49203798174858093, + "bbox": [ + 1293.846923828125, + 2114.91943359375, + 1375.3638916015625, + 2225.69873046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.413155734539032, + "bbox": [ + 210.71299743652344, + 2712.188720703125, + 288.1453552246094, + 2827.98828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3804877698421478, + "bbox": [ + 209.66197204589844, + 3172.32421875, + 281.32183837890625, + 3241.4794921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3566216826438904, + "bbox": [ + 213.76446533203125, + 2725.703125, + 277.2315368652344, + 2820.79638671875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9519443511962891, + "bbox": [ + 1290.3035888671875, + 614.5211791992188, + 2283.529541015625, + 2095.49169921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9456939697265625, + "bbox": [ + 193.9445037841797, + 607.7117919921875, + 1208.30419921875, + 2376.8505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9412693977355957, + "bbox": [ + 1268.4588623046875, + 2126.5390625, + 2307.359375, + 2783.716552734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9335028529167175, + "bbox": [ + 201.33453369140625, + 2403.188232421875, + 1200.840087890625, + 3049.89306640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9077781438827515, + "bbox": [ + 1246.1876220703125, + 378.7965393066406, + 2389.033447265625, + 2864.5546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9028221368789673, + "bbox": [ + 174.9167938232422, + 402.5443115234375, + 1220.2403564453125, + 3064.48291015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.791551947593689, + "bbox": [ + 1293.18701171875, + 532.70458984375, + 1906.813232421875, + 619.83203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6859422326087952, + "bbox": [ + 222.75241088867188, + 528.7889404296875, + 798.6803588867188, + 604.3812255859375 + ] + } + ], + "timestamp": "2025-10-15T21:42:35.665625" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 25.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 25.json" new file mode 100644 index 0000000..a5eec3f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 25.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 25.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7588517665863037, + "bbox": [ + 253.2764892578125, + 421.21722412109375, + 362.099365234375, + 511.5015563964844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.744519054889679, + "bbox": [ + 1281.52734375, + 426.3513488769531, + 1394.95166015625, + 525.2432250976562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5451107025146484, + "bbox": [ + 2151.921142578125, + 3101.869873046875, + 2222.90576171875, + 3173.123291015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5401171445846558, + "bbox": [ + 577.0313110351562, + 2279.5029296875, + 647.5426025390625, + 2382.59375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5006833076477051, + "bbox": [ + 572.7830810546875, + 2262.6181640625, + 669.4131469726562, + 2384.542724609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4181232750415802, + "bbox": [ + 1276.4649658203125, + 2208.54296875, + 1349.0118408203125, + 2294.375244140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9257944822311401, + "bbox": [ + 223.26390075683594, + 588.3057861328125, + 1191.5623779296875, + 2844.76806640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9230045676231384, + "bbox": [ + 1238.033447265625, + 349.1878662109375, + 2369.723388671875, + 2524.9853515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9217695593833923, + "bbox": [ + 1265.813720703125, + 612.49658203125, + 2246.471435546875, + 1843.5926513671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8942376375198364, + "bbox": [ + 181.24403381347656, + 365.82989501953125, + 1205.1279296875, + 2894.113037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.886620819568634, + "bbox": [ + 1281.673828125, + 1952.19580078125, + 2204.450439453125, + 2329.89794921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7905508875846863, + "bbox": [ + 1284.2349853515625, + 523.783203125, + 2242.9775390625, + 595.498046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7832826375961304, + "bbox": [ + 251.33091735839844, + 499.77655029296875, + 885.39453125, + 589.5597534179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6460133194923401, + "bbox": [ + 1276.4615478515625, + 515.9039916992188, + 2240.80078125, + 618.1329345703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7588517665863037, + "bbox": [ + 253.2764892578125, + 421.21722412109375, + 362.099365234375, + 511.5015563964844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.744519054889679, + "bbox": [ + 1281.52734375, + 426.3513488769531, + 1394.95166015625, + 525.2432250976562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5451107025146484, + "bbox": [ + 2151.921142578125, + 3101.869873046875, + 2222.90576171875, + 3173.123291015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5401171445846558, + "bbox": [ + 577.0313110351562, + 2279.5029296875, + 647.5426025390625, + 2382.59375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5006833076477051, + "bbox": [ + 572.7830810546875, + 2262.6181640625, + 669.4131469726562, + 2384.542724609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4181232750415802, + "bbox": [ + 1276.4649658203125, + 2208.54296875, + 1349.0118408203125, + 2294.375244140625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9257944822311401, + "bbox": [ + 223.26390075683594, + 588.3057861328125, + 1191.5623779296875, + 2844.76806640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9230045676231384, + "bbox": [ + 1238.033447265625, + 349.1878662109375, + 2369.723388671875, + 2524.9853515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9217695593833923, + "bbox": [ + 1265.813720703125, + 612.49658203125, + 2246.471435546875, + 1843.5926513671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8942376375198364, + "bbox": [ + 181.24403381347656, + 365.82989501953125, + 1205.1279296875, + 2894.113037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.886620819568634, + "bbox": [ + 1281.673828125, + 1952.19580078125, + 2204.450439453125, + 2329.89794921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7905508875846863, + "bbox": [ + 1284.2349853515625, + 523.783203125, + 2242.9775390625, + 595.498046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7832826375961304, + "bbox": [ + 251.33091735839844, + 499.77655029296875, + 885.39453125, + 589.5597534179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6460133194923401, + "bbox": [ + 1276.4615478515625, + 515.9039916992188, + 2240.80078125, + 618.1329345703125 + ] + } + ], + "timestamp": "2025-10-15T21:42:36.126571" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 26.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 26.json" new file mode 100644 index 0000000..eda0a45 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 26.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 26.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7596745491027832, + "bbox": [ + 1288.18359375, + 449.7130126953125, + 1403.3021240234375, + 546.7435913085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7418139576911926, + "bbox": [ + 215.77146911621094, + 435.322998046875, + 334.2380676269531, + 538.6536865234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5511476993560791, + "bbox": [ + 209.92529296875, + 3225.406494140625, + 279.00347900390625, + 3298.470947265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4902820885181427, + "bbox": [ + 204.9746856689453, + 2785.687255859375, + 293.31475830078125, + 2901.49853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3675852417945862, + "bbox": [ + 1280.572509765625, + 2682.492431640625, + 1362.28466796875, + 2775.82275390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.24419505894184113, + "bbox": [ + 207.1783905029297, + 2798.9833984375, + 281.4012756347656, + 2894.383056640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9641221761703491, + "bbox": [ + 222.19129943847656, + 690.30078125, + 1191.4837646484375, + 2709.96435546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9178310632705688, + "bbox": [ + 1289.8916015625, + 737.4950561523438, + 2264.526123046875, + 2532.69775390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.910405695438385, + "bbox": [ + 1275.86328125, + 2561.068115234375, + 2248.11083984375, + 2929.56591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9098260402679443, + "bbox": [ + 205.25616455078125, + 2758.667236328125, + 965.216796875, + 3104.0439453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.893539547920227, + "bbox": [ + 1256.6043701171875, + 408.494140625, + 2377.472412109375, + 3074.17919921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8921395540237427, + "bbox": [ + 180.58187866210938, + 497.1212158203125, + 1220.1986083984375, + 3193.210693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8459108471870422, + "bbox": [ + 1290.4840087890625, + 552.0759887695312, + 2277.9189453125, + 681.0967407226562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.84539794921875, + "bbox": [ + 212.72360229492188, + 539.130126953125, + 1205.5245361328125, + 662.7799682617188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7596745491027832, + "bbox": [ + 1288.18359375, + 449.7130126953125, + 1403.3021240234375, + 546.7435913085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7418139576911926, + "bbox": [ + 215.77146911621094, + 435.322998046875, + 334.2380676269531, + 538.6536865234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5511476993560791, + "bbox": [ + 209.92529296875, + 3225.406494140625, + 279.00347900390625, + 3298.470947265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4902820885181427, + "bbox": [ + 204.9746856689453, + 2785.687255859375, + 293.31475830078125, + 2901.49853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3675852417945862, + "bbox": [ + 1280.572509765625, + 2682.492431640625, + 1362.28466796875, + 2775.82275390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.24419505894184113, + "bbox": [ + 207.1783905029297, + 2798.9833984375, + 281.4012756347656, + 2894.383056640625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9641221761703491, + "bbox": [ + 222.19129943847656, + 690.30078125, + 1191.4837646484375, + 2709.96435546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9178310632705688, + "bbox": [ + 1289.8916015625, + 737.4950561523438, + 2264.526123046875, + 2532.69775390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.910405695438385, + "bbox": [ + 1275.86328125, + 2561.068115234375, + 2248.11083984375, + 2929.56591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9098260402679443, + "bbox": [ + 205.25616455078125, + 2758.667236328125, + 965.216796875, + 3104.0439453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.893539547920227, + "bbox": [ + 1256.6043701171875, + 408.494140625, + 2377.472412109375, + 3074.17919921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8921395540237427, + "bbox": [ + 180.58187866210938, + 497.1212158203125, + 1220.1986083984375, + 3193.210693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8459108471870422, + "bbox": [ + 1290.4840087890625, + 552.0759887695312, + 2277.9189453125, + 681.0967407226562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.84539794921875, + "bbox": [ + 212.72360229492188, + 539.130126953125, + 1205.5245361328125, + 662.7799682617188 + ] + } + ], + "timestamp": "2025-10-15T21:42:36.539561" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 27.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 27.json" new file mode 100644 index 0000000..9b802ff --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 27.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 27.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7638723850250244, + "bbox": [ + 1330.3487548828125, + 449.0606689453125, + 1443.7520751953125, + 548.515869140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7412780523300171, + "bbox": [ + 256.0634460449219, + 436.2818908691406, + 374.9673767089844, + 540.9154663085938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5307528972625732, + "bbox": [ + 2229.40625, + 3239.025634765625, + 2306.802734375, + 3315.8076171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48615193367004395, + "bbox": [ + 829.5568237304688, + 1822.3836669921875, + 917.01708984375, + 1947.096435546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.34501194953918457, + "bbox": [ + 1663.9466552734375, + 1079.282958984375, + 1767.3944091796875, + 1186.89599609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.34173306822776794, + "bbox": [ + 832.4179077148438, + 1850.501708984375, + 905.244140625, + 1942.8924560546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.32376375794410706, + "bbox": [ + 1675.54638671875, + 1102.3599853515625, + 1734.1160888671875, + 1174.1597900390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22445310652256012, + "bbox": [ + 1671.8634033203125, + 1089.52587890625, + 1749.6319580078125, + 1179.9449462890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.951564371585846, + "bbox": [ + 240.27755737304688, + 613.5882568359375, + 1250.046142578125, + 2042.783203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9317596554756165, + "bbox": [ + 181.37548828125, + 390.0022888183594, + 1270.5513916015625, + 2413.478515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9204766154289246, + "bbox": [ + 1312.3494873046875, + 677.1195678710938, + 2370.054931640625, + 2456.36083984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9020445942878723, + "bbox": [ + 1301.4417724609375, + 393.9384460449219, + 2398.073974609375, + 2544.815673828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8693385720252991, + "bbox": [ + 1321.2469482421875, + 540.7301635742188, + 2330.0556640625, + 681.1175537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7307010293006897, + "bbox": [ + 258.93499755859375, + 527.5663452148438, + 996.69677734375, + 610.9852905273438 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7638723850250244, + "bbox": [ + 1330.3487548828125, + 449.0606689453125, + 1443.7520751953125, + 548.515869140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7412780523300171, + "bbox": [ + 256.0634460449219, + 436.2818908691406, + 374.9673767089844, + 540.9154663085938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5307528972625732, + "bbox": [ + 2229.40625, + 3239.025634765625, + 2306.802734375, + 3315.8076171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48615193367004395, + "bbox": [ + 829.5568237304688, + 1822.3836669921875, + 917.01708984375, + 1947.096435546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.34501194953918457, + "bbox": [ + 1663.9466552734375, + 1079.282958984375, + 1767.3944091796875, + 1186.89599609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.34173306822776794, + "bbox": [ + 832.4179077148438, + 1850.501708984375, + 905.244140625, + 1942.8924560546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.32376375794410706, + "bbox": [ + 1675.54638671875, + 1102.3599853515625, + 1734.1160888671875, + 1174.1597900390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22445310652256012, + "bbox": [ + 1671.8634033203125, + 1089.52587890625, + 1749.6319580078125, + 1179.9449462890625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.951564371585846, + "bbox": [ + 240.27755737304688, + 613.5882568359375, + 1250.046142578125, + 2042.783203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9317596554756165, + "bbox": [ + 181.37548828125, + 390.0022888183594, + 1270.5513916015625, + 2413.478515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9204766154289246, + "bbox": [ + 1312.3494873046875, + 677.1195678710938, + 2370.054931640625, + 2456.36083984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9020445942878723, + "bbox": [ + 1301.4417724609375, + 393.9384460449219, + 2398.073974609375, + 2544.815673828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8693385720252991, + "bbox": [ + 1321.2469482421875, + 540.7301635742188, + 2330.0556640625, + 681.1175537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7307010293006897, + "bbox": [ + 258.93499755859375, + 527.5663452148438, + 996.69677734375, + 610.9852905273438 + ] + } + ], + "timestamp": "2025-10-15T21:42:36.948460" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 28.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 28.json" new file mode 100644 index 0000000..749259c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 28.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 28.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7706470489501953, + "bbox": [ + 1270.4822998046875, + 445.1375732421875, + 1387.30029296875, + 548.8352661132812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7398648262023926, + "bbox": [ + 208.3574676513672, + 558.369873046875, + 326.0821838378906, + 671.6571044921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.673129141330719, + "bbox": [ + 210.5732879638672, + 2352.39111328125, + 270.662841796875, + 2427.5390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5725505352020264, + "bbox": [ + 204.86293029785156, + 3192.977294921875, + 271.15777587890625, + 3263.29052734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47195759415626526, + "bbox": [ + 1260.0882568359375, + 2394.65478515625, + 1357.42333984375, + 2518.730712890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.946494460105896, + "bbox": [ + 1252.6865234375, + 584.6635131835938, + 2282.361083984375, + 2264.861083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9423710107803345, + "bbox": [ + 189.21725463867188, + 671.4733276367188, + 1187.787841796875, + 2095.35693359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9383378624916077, + "bbox": [ + 159.18954467773438, + 424.1270446777344, + 1211.526611328125, + 2757.468505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.924258291721344, + "bbox": [ + 1260.0135498046875, + 2356.609130859375, + 2272.234375, + 2848.530029296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025425910949707, + "bbox": [ + 1242.078857421875, + 357.2750549316406, + 2318.62890625, + 2940.401611328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7688406109809875, + "bbox": [ + 198.8504180908203, + 2142.577880859375, + 534.9755859375, + 2509.209716796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.524790346622467, + "bbox": [ + 196.96731567382812, + 430.1003112792969, + 1168.8123779296875, + 509.7503356933594 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7706470489501953, + "bbox": [ + 1270.4822998046875, + 445.1375732421875, + 1387.30029296875, + 548.8352661132812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7398648262023926, + "bbox": [ + 208.3574676513672, + 558.369873046875, + 326.0821838378906, + 671.6571044921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.673129141330719, + "bbox": [ + 210.5732879638672, + 2352.39111328125, + 270.662841796875, + 2427.5390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5725505352020264, + "bbox": [ + 204.86293029785156, + 3192.977294921875, + 271.15777587890625, + 3263.29052734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47195759415626526, + "bbox": [ + 1260.0882568359375, + 2394.65478515625, + 1357.42333984375, + 2518.730712890625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.946494460105896, + "bbox": [ + 1252.6865234375, + 584.6635131835938, + 2282.361083984375, + 2264.861083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9423710107803345, + "bbox": [ + 189.21725463867188, + 671.4733276367188, + 1187.787841796875, + 2095.35693359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9383378624916077, + "bbox": [ + 159.18954467773438, + 424.1270446777344, + 1211.526611328125, + 2757.468505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.924258291721344, + "bbox": [ + 1260.0135498046875, + 2356.609130859375, + 2272.234375, + 2848.530029296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025425910949707, + "bbox": [ + 1242.078857421875, + 357.2750549316406, + 2318.62890625, + 2940.401611328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7688406109809875, + "bbox": [ + 198.8504180908203, + 2142.577880859375, + 534.9755859375, + 2509.209716796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.524790346622467, + "bbox": [ + 196.96731567382812, + 430.1003112792969, + 1168.8123779296875, + 509.7503356933594 + ] + } + ], + "timestamp": "2025-10-15T21:42:37.341034" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 29.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 29.json" new file mode 100644 index 0000000..7f1d1f4 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 29.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 29.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7501577734947205, + "bbox": [ + 1325.4620361328125, + 448.038330078125, + 1439.882568359375, + 551.6939697265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7451260089874268, + "bbox": [ + 255.96917724609375, + 434.606689453125, + 379.2396240234375, + 544.2586059570312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5935863256454468, + "bbox": [ + 1317.526123046875, + 2395.2587890625, + 1410.2218017578125, + 2508.357177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5673851370811462, + "bbox": [ + 2232.501953125, + 3219.645751953125, + 2298.851318359375, + 3290.481689453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5436837077140808, + "bbox": [ + 236.4222412109375, + 2440.740966796875, + 317.3433532714844, + 2560.536376953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3088797628879547, + "bbox": [ + 2225.019775390625, + 3211.59619140625, + 2305.6044921875, + 3297.51806640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9517142176628113, + "bbox": [ + 243.9226837158203, + 563.9421997070312, + 1249.5345458984375, + 1963.65625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9423195719718933, + "bbox": [ + 238.99754333496094, + 1966.3900146484375, + 1248.7452392578125, + 2645.022705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9315354228019714, + "bbox": [ + 201.7589111328125, + 331.1204833984375, + 1267.9127197265625, + 2793.51953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9239529967308044, + "bbox": [ + 1313.292724609375, + 586.2428588867188, + 2333.1875, + 2290.515869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.90784752368927, + "bbox": [ + 1281.184326171875, + 357.16607666015625, + 2436.878173828125, + 2839.7822265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9017939567565918, + "bbox": [ + 1308.8287353515625, + 2346.03076171875, + 2255.67236328125, + 2751.169921875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7501577734947205, + "bbox": [ + 1325.4620361328125, + 448.038330078125, + 1439.882568359375, + 551.6939697265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7451260089874268, + "bbox": [ + 255.96917724609375, + 434.606689453125, + 379.2396240234375, + 544.2586059570312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5935863256454468, + "bbox": [ + 1317.526123046875, + 2395.2587890625, + 1410.2218017578125, + 2508.357177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5673851370811462, + "bbox": [ + 2232.501953125, + 3219.645751953125, + 2298.851318359375, + 3290.481689453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5436837077140808, + "bbox": [ + 236.4222412109375, + 2440.740966796875, + 317.3433532714844, + 2560.536376953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3088797628879547, + "bbox": [ + 2225.019775390625, + 3211.59619140625, + 2305.6044921875, + 3297.51806640625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9517142176628113, + "bbox": [ + 243.9226837158203, + 563.9421997070312, + 1249.5345458984375, + 1963.65625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9423195719718933, + "bbox": [ + 238.99754333496094, + 1966.3900146484375, + 1248.7452392578125, + 2645.022705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9315354228019714, + "bbox": [ + 201.7589111328125, + 331.1204833984375, + 1267.9127197265625, + 2793.51953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9239529967308044, + "bbox": [ + 1313.292724609375, + 586.2428588867188, + 2333.1875, + 2290.515869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.90784752368927, + "bbox": [ + 1281.184326171875, + 357.16607666015625, + 2436.878173828125, + 2839.7822265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9017939567565918, + "bbox": [ + 1308.8287353515625, + 2346.03076171875, + 2255.67236328125, + 2751.169921875 + ] + } + ], + "timestamp": "2025-10-15T21:42:37.739906" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 30.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 30.json" new file mode 100644 index 0000000..5a1633e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 30.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 30.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7524389624595642, + "bbox": [ + 218.1105194091797, + 432.3792419433594, + 331.2661437988281, + 529.723876953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7431447505950928, + "bbox": [ + 1268.9561767578125, + 620.7142944335938, + 1380.503173828125, + 719.0180053710938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5657069683074951, + "bbox": [ + 203.51329040527344, + 3163.104736328125, + 270.4930725097656, + 3233.476318359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5415539741516113, + "bbox": [ + 210.21817016601562, + 1502.0819091796875, + 302.5581359863281, + 1635.3358154296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.497967004776001, + "bbox": [ + 1263.3370361328125, + 2694.544677734375, + 1360.75927734375, + 2815.271240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.27456340193748474, + "bbox": [ + 1259.626220703125, + 2730.238037109375, + 1317.905517578125, + 2812.861328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9465410113334656, + "bbox": [ + 203.84593200683594, + 606.2454833984375, + 1176.6834716796875, + 1973.0828857421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.915999174118042, + "bbox": [ + 155.33132934570312, + 399.47796630859375, + 1211.4317626953125, + 2130.087158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9147048592567444, + "bbox": [ + 1251.8206787109375, + 705.6549682617188, + 2268.6123046875, + 2709.52783203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8729478716850281, + "bbox": [ + 1249.799560546875, + 2707.37744140625, + 2087.024658203125, + 2977.895751953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8509178161621094, + "bbox": [ + 1226.6080322265625, + 405.0224304199219, + 2359.810791015625, + 3058.579833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8282656073570251, + "bbox": [ + 1253.253173828125, + 436.8195495605469, + 2259.229248046875, + 574.5007934570312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7515450716018677, + "bbox": [ + 223.15435791015625, + 521.2745361328125, + 923.1041870117188, + 614.8323974609375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7524389624595642, + "bbox": [ + 218.1105194091797, + 432.3792419433594, + 331.2661437988281, + 529.723876953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7431447505950928, + "bbox": [ + 1268.9561767578125, + 620.7142944335938, + 1380.503173828125, + 719.0180053710938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5657069683074951, + "bbox": [ + 203.51329040527344, + 3163.104736328125, + 270.4930725097656, + 3233.476318359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5415539741516113, + "bbox": [ + 210.21817016601562, + 1502.0819091796875, + 302.5581359863281, + 1635.3358154296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.497967004776001, + "bbox": [ + 1263.3370361328125, + 2694.544677734375, + 1360.75927734375, + 2815.271240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.27456340193748474, + "bbox": [ + 1259.626220703125, + 2730.238037109375, + 1317.905517578125, + 2812.861328125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9465410113334656, + "bbox": [ + 203.84593200683594, + 606.2454833984375, + 1176.6834716796875, + 1973.0828857421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.915999174118042, + "bbox": [ + 155.33132934570312, + 399.47796630859375, + 1211.4317626953125, + 2130.087158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9147048592567444, + "bbox": [ + 1251.8206787109375, + 705.6549682617188, + 2268.6123046875, + 2709.52783203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8729478716850281, + "bbox": [ + 1249.799560546875, + 2707.37744140625, + 2087.024658203125, + 2977.895751953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8509178161621094, + "bbox": [ + 1226.6080322265625, + 405.0224304199219, + 2359.810791015625, + 3058.579833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8282656073570251, + "bbox": [ + 1253.253173828125, + 436.8195495605469, + 2259.229248046875, + 574.5007934570312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7515450716018677, + "bbox": [ + 223.15435791015625, + 521.2745361328125, + 923.1041870117188, + 614.8323974609375 + ] + } + ], + "timestamp": "2025-10-15T21:42:38.131287" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 31.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 31.json" new file mode 100644 index 0000000..a4a13ee --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 31.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 31.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.757439374923706, + "bbox": [ + 251.25486755371094, + 443.82220458984375, + 377.39044189453125, + 555.3685302734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7536944150924683, + "bbox": [ + 1320.012451171875, + 631.9494018554688, + 1439.536865234375, + 735.8262939453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5715716481208801, + "bbox": [ + 2220.909912109375, + 3227.278564453125, + 2297.780029296875, + 3301.607177734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5012226104736328, + "bbox": [ + 1343.55908203125, + 1359.9927978515625, + 1457.388427734375, + 1484.091552734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4293169677257538, + "bbox": [ + 249.9940643310547, + 2473.937744140625, + 323.93194580078125, + 2561.1884765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22854651510715485, + "bbox": [ + 1344.647705078125, + 1378.2685546875, + 1439.79345703125, + 1479.3126220703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9552593231201172, + "bbox": [ + 185.90904235839844, + 406.054443359375, + 1261.943115234375, + 2722.56396484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9472499489784241, + "bbox": [ + 216.91537475585938, + 587.9608154296875, + 1221.4420166015625, + 2392.9052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9072291254997253, + "bbox": [ + 1296.498046875, + 430.9252014160156, + 2412.779541015625, + 2568.98779296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8981093168258667, + "bbox": [ + 1300.797607421875, + 732.6492309570312, + 2319.101318359375, + 2452.923095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8867239356040955, + "bbox": [ + 239.82240295410156, + 2410.149658203125, + 1120.15966796875, + 2645.758544921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6936172842979431, + "bbox": [ + 1314.6751708984375, + 442.8094787597656, + 2340.904541015625, + 583.9773559570312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.757439374923706, + "bbox": [ + 251.25486755371094, + 443.82220458984375, + 377.39044189453125, + 555.3685302734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7536944150924683, + "bbox": [ + 1320.012451171875, + 631.9494018554688, + 1439.536865234375, + 735.8262939453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5715716481208801, + "bbox": [ + 2220.909912109375, + 3227.278564453125, + 2297.780029296875, + 3301.607177734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5012226104736328, + "bbox": [ + 1343.55908203125, + 1359.9927978515625, + 1457.388427734375, + 1484.091552734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4293169677257538, + "bbox": [ + 249.9940643310547, + 2473.937744140625, + 323.93194580078125, + 2561.1884765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22854651510715485, + "bbox": [ + 1344.647705078125, + 1378.2685546875, + 1439.79345703125, + 1479.3126220703125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9552593231201172, + "bbox": [ + 185.90904235839844, + 406.054443359375, + 1261.943115234375, + 2722.56396484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9472499489784241, + "bbox": [ + 216.91537475585938, + 587.9608154296875, + 1221.4420166015625, + 2392.9052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9072291254997253, + "bbox": [ + 1296.498046875, + 430.9252014160156, + 2412.779541015625, + 2568.98779296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8981093168258667, + "bbox": [ + 1300.797607421875, + 732.6492309570312, + 2319.101318359375, + 2452.923095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8867239356040955, + "bbox": [ + 239.82240295410156, + 2410.149658203125, + 1120.15966796875, + 2645.758544921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6936172842979431, + "bbox": [ + 1314.6751708984375, + 442.8094787597656, + 2340.904541015625, + 583.9773559570312 + ] + } + ], + "timestamp": "2025-10-15T21:42:38.531081" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 32.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 32.json" new file mode 100644 index 0000000..7baa3b5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 32.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 32.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7537367343902588, + "bbox": [ + 215.76312255859375, + 431.362060546875, + 339.2625427246094, + 540.633544921875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7403443455696106, + "bbox": [ + 1288.9766845703125, + 438.431640625, + 1410.3887939453125, + 543.279052734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6039438843727112, + "bbox": [ + 449.89678955078125, + 1637.0438232421875, + 543.3538208007812, + 1755.72119140625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.545609176158905, + "bbox": [ + 200.62168884277344, + 3214.473388671875, + 271.7879333496094, + 3286.687744140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5373581647872925, + "bbox": [ + 1275.1387939453125, + 2615.8154296875, + 1366.220947265625, + 2740.909912109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3767046332359314, + "bbox": [ + 1267.4312744140625, + 2612.901611328125, + 1385.57958984375, + 2753.568359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9467175602912903, + "bbox": [ + 178.8080596923828, + 369.65167236328125, + 1239.1895751953125, + 2232.146240234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9442576169967651, + "bbox": [ + 205.36691284179688, + 570.5679321289062, + 1213.5880126953125, + 2127.832763671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9394538402557373, + "bbox": [ + 1274.2745361328125, + 676.3482666015625, + 2299.51318359375, + 2592.802001953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8979507088661194, + "bbox": [ + 1265.6138916015625, + 2590.404296875, + 1988.0531005859375, + 3063.463134765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.879187285900116, + "bbox": [ + 1247.9554443359375, + 417.18487548828125, + 2382.702880859375, + 3104.080322265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.795914888381958, + "bbox": [ + 1281.336181640625, + 538.7757568359375, + 2282.024658203125, + 676.7781982421875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7537367343902588, + "bbox": [ + 215.76312255859375, + 431.362060546875, + 339.2625427246094, + 540.633544921875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7403443455696106, + "bbox": [ + 1288.9766845703125, + 438.431640625, + 1410.3887939453125, + 543.279052734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6039438843727112, + "bbox": [ + 449.89678955078125, + 1637.0438232421875, + 543.3538208007812, + 1755.72119140625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.545609176158905, + "bbox": [ + 200.62168884277344, + 3214.473388671875, + 271.7879333496094, + 3286.687744140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5373581647872925, + "bbox": [ + 1275.1387939453125, + 2615.8154296875, + 1366.220947265625, + 2740.909912109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3767046332359314, + "bbox": [ + 1267.4312744140625, + 2612.901611328125, + 1385.57958984375, + 2753.568359375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9467175602912903, + "bbox": [ + 178.8080596923828, + 369.65167236328125, + 1239.1895751953125, + 2232.146240234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9442576169967651, + "bbox": [ + 205.36691284179688, + 570.5679321289062, + 1213.5880126953125, + 2127.832763671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9394538402557373, + "bbox": [ + 1274.2745361328125, + 676.3482666015625, + 2299.51318359375, + 2592.802001953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8979507088661194, + "bbox": [ + 1265.6138916015625, + 2590.404296875, + 1988.0531005859375, + 3063.463134765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.879187285900116, + "bbox": [ + 1247.9554443359375, + 417.18487548828125, + 2382.702880859375, + 3104.080322265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.795914888381958, + "bbox": [ + 1281.336181640625, + 538.7757568359375, + 2282.024658203125, + 676.7781982421875 + ] + } + ], + "timestamp": "2025-10-15T21:42:38.971866" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 33.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 33.json" new file mode 100644 index 0000000..8637aaa --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 33.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 33.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7411893010139465, + "bbox": [ + 1300.99951171875, + 1884.986328125, + 1414.5931396484375, + 1984.8748779296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7399178743362427, + "bbox": [ + 1303.1260986328125, + 441.34423828125, + 1426.8656005859375, + 547.0007934570312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5413951277732849, + "bbox": [ + 2199.412841796875, + 3162.26513671875, + 2270.846923828125, + 3232.426513671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5286170244216919, + "bbox": [ + 1670.9439697265625, + 2077.5595703125, + 1775.7470703125, + 2204.891845703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47840628027915955, + "bbox": [ + 1309.3226318359375, + 677.20849609375, + 1383.680908203125, + 760.7073364257812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2938893139362335, + "bbox": [ + 1303.7100830078125, + 666.0673217773438, + 1395.251220703125, + 772.9533081054688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.912496030330658, + "bbox": [ + 1300.3553466796875, + 618.7408447265625, + 2320.264404296875, + 1013.4635620117188 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.907829225063324, + "bbox": [ + 233.6698760986328, + 500.5492858886719, + 1214.142578125, + 2870.9140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8595885634422302, + "bbox": [ + 1268.8282470703125, + 406.6799621582031, + 2359.125244140625, + 1070.231689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8345154523849487, + "bbox": [ + 1308.2244873046875, + 1970.0843505859375, + 2278.702392578125, + 2102.19873046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8244978189468384, + "bbox": [ + 1281.503662109375, + 1879.2235107421875, + 2317.342041015625, + 2247.312744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.801175057888031, + "bbox": [ + 1313.3333740234375, + 539.0196533203125, + 1917.875732421875, + 620.1353759765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7592750787734985, + "bbox": [ + 1302.6474609375, + 2099.78076171875, + 2209.174072265625, + 2216.144287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7527307868003845, + "bbox": [ + 1259.6568603515625, + 1818.8466796875, + 2363.342041015625, + 2542.586669921875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7411893010139465, + "bbox": [ + 1300.99951171875, + 1884.986328125, + 1414.5931396484375, + 1984.8748779296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7399178743362427, + "bbox": [ + 1303.1260986328125, + 441.34423828125, + 1426.8656005859375, + 547.0007934570312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5413951277732849, + "bbox": [ + 2199.412841796875, + 3162.26513671875, + 2270.846923828125, + 3232.426513671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5286170244216919, + "bbox": [ + 1670.9439697265625, + 2077.5595703125, + 1775.7470703125, + 2204.891845703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47840628027915955, + "bbox": [ + 1309.3226318359375, + 677.20849609375, + 1383.680908203125, + 760.7073364257812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2938893139362335, + "bbox": [ + 1303.7100830078125, + 666.0673217773438, + 1395.251220703125, + 772.9533081054688 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.912496030330658, + "bbox": [ + 1300.3553466796875, + 618.7408447265625, + 2320.264404296875, + 1013.4635620117188 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.907829225063324, + "bbox": [ + 233.6698760986328, + 500.5492858886719, + 1214.142578125, + 2870.9140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8595885634422302, + "bbox": [ + 1268.8282470703125, + 406.6799621582031, + 2359.125244140625, + 1070.231689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8345154523849487, + "bbox": [ + 1308.2244873046875, + 1970.0843505859375, + 2278.702392578125, + 2102.19873046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8244978189468384, + "bbox": [ + 1281.503662109375, + 1879.2235107421875, + 2317.342041015625, + 2247.312744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.801175057888031, + "bbox": [ + 1313.3333740234375, + 539.0196533203125, + 1917.875732421875, + 620.1353759765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7592750787734985, + "bbox": [ + 1302.6474609375, + 2099.78076171875, + 2209.174072265625, + 2216.144287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7527307868003845, + "bbox": [ + 1259.6568603515625, + 1818.8466796875, + 2363.342041015625, + 2542.586669921875 + ] + } + ], + "timestamp": "2025-10-15T21:42:39.396952" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 34.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 34.json" new file mode 100644 index 0000000..2f3fc07 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253\341\204\221\341\205\247\341\206\253 \341\204\216\341\205\246\341\204\217\341\205\263 (\341\204\220\341\205\263\341\206\257\341\204\205\341\205\265\341\206\267) - 34.json" @@ -0,0 +1,494 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 34.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491088509559631, + "bbox": [ + 1160.76953125, + 2333.6337890625, + 1273.255126953125, + 2430.89013671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7468457221984863, + "bbox": [ + 1172.97900390625, + 1334.2735595703125, + 1285.610595703125, + 1430.9822998046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7360896468162537, + "bbox": [ + 1166.3289794921875, + 1921.4727783203125, + 1274.552001953125, + 2017.7860107421875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5627599358558655, + "bbox": [ + 188.8057098388672, + 2960.930908203125, + 251.6896514892578, + 3027.109619140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5433753728866577, + "bbox": [ + 1176.138427734375, + 2457.60009765625, + 1257.6358642578125, + 2565.6689453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5327596068382263, + "bbox": [ + 1165.512939453125, + 2455.51220703125, + 1268.2003173828125, + 2580.243408203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48111236095428467, + "bbox": [ + 1171.7445068359375, + 1667.20751953125, + 1252.659423828125, + 1760.013671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3576454818248749, + "bbox": [ + 1522.5712890625, + 2090.10888671875, + 1577.92724609375, + 2159.05224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3199736475944519, + "bbox": [ + 1516.66455078125, + 2065.78369140625, + 1619.7232666015625, + 2176.07080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22252248227596283, + "bbox": [ + 1519.90087890625, + 2074.296142578125, + 1589.55224609375, + 2164.406005859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9160225987434387, + "bbox": [ + 164.7313232421875, + 553.2631225585938, + 1113.3837890625, + 2936.509521484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9152095913887024, + "bbox": [ + 1158.708251953125, + 396.1984558105469, + 2105.56591796875, + 1295.8599853515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9100043773651123, + "bbox": [ + 1169.5513916015625, + 2488.27978515625, + 2103.4541015625, + 2962.3154296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9066509008407593, + "bbox": [ + 1136.8170166015625, + 1853.5128173828125, + 2144.7626953125, + 2266.220703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9039163589477539, + "bbox": [ + 1143.0206298828125, + 2310.55322265625, + 2167.1904296875, + 3061.783203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8926684260368347, + "bbox": [ + 1178.4119873046875, + 2075.851318359375, + 2026.3492431640625, + 2201.259765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8925706148147583, + "bbox": [ + 1164.1436767578125, + 1562.869873046875, + 2048.20947265625, + 1784.335205078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8855495452880859, + "bbox": [ + 1171.2210693359375, + 1432.71826171875, + 2088.3916015625, + 1549.0565185546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8439065217971802, + "bbox": [ + 1159.432861328125, + 1303.171142578125, + 2137.692138671875, + 1878.1734619140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7733128666877747, + "bbox": [ + 1176.855224609375, + 2012.6065673828125, + 2074.808837890625, + 2086.485595703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7340794801712036, + "bbox": [ + 1165.768310546875, + 2420.44482421875, + 1776.43359375, + 2503.021484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.3301795423030853, + "bbox": [ + 115.9123306274414, + 1127.7506103515625, + 1101.5943603515625, + 3083.561279296875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491088509559631, + "bbox": [ + 1160.76953125, + 2333.6337890625, + 1273.255126953125, + 2430.89013671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7468457221984863, + "bbox": [ + 1172.97900390625, + 1334.2735595703125, + 1285.610595703125, + 1430.9822998046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7360896468162537, + "bbox": [ + 1166.3289794921875, + 1921.4727783203125, + 1274.552001953125, + 2017.7860107421875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5627599358558655, + "bbox": [ + 188.8057098388672, + 2960.930908203125, + 251.6896514892578, + 3027.109619140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5433753728866577, + "bbox": [ + 1176.138427734375, + 2457.60009765625, + 1257.6358642578125, + 2565.6689453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5327596068382263, + "bbox": [ + 1165.512939453125, + 2455.51220703125, + 1268.2003173828125, + 2580.243408203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48111236095428467, + "bbox": [ + 1171.7445068359375, + 1667.20751953125, + 1252.659423828125, + 1760.013671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3576454818248749, + "bbox": [ + 1522.5712890625, + 2090.10888671875, + 1577.92724609375, + 2159.05224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3199736475944519, + "bbox": [ + 1516.66455078125, + 2065.78369140625, + 1619.7232666015625, + 2176.07080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22252248227596283, + "bbox": [ + 1519.90087890625, + 2074.296142578125, + 1589.55224609375, + 2164.406005859375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9160225987434387, + "bbox": [ + 164.7313232421875, + 553.2631225585938, + 1113.3837890625, + 2936.509521484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9152095913887024, + "bbox": [ + 1158.708251953125, + 396.1984558105469, + 2105.56591796875, + 1295.8599853515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9100043773651123, + "bbox": [ + 1169.5513916015625, + 2488.27978515625, + 2103.4541015625, + 2962.3154296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9066509008407593, + "bbox": [ + 1136.8170166015625, + 1853.5128173828125, + 2144.7626953125, + 2266.220703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9039163589477539, + "bbox": [ + 1143.0206298828125, + 2310.55322265625, + 2167.1904296875, + 3061.783203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8926684260368347, + "bbox": [ + 1178.4119873046875, + 2075.851318359375, + 2026.3492431640625, + 2201.259765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8925706148147583, + "bbox": [ + 1164.1436767578125, + 1562.869873046875, + 2048.20947265625, + 1784.335205078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8855495452880859, + "bbox": [ + 1171.2210693359375, + 1432.71826171875, + 2088.3916015625, + 1549.0565185546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8439065217971802, + "bbox": [ + 1159.432861328125, + 1303.171142578125, + 2137.692138671875, + 1878.1734619140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7733128666877747, + "bbox": [ + 1176.855224609375, + 2012.6065673828125, + 2074.808837890625, + 2086.485595703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7340794801712036, + "bbox": [ + 1165.768310546875, + 2420.44482421875, + 1776.43359375, + 2503.021484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.3301795423030853, + "bbox": [ + 115.9123306274414, + 1127.7506103515625, + 1101.5943603515625, + 3083.561279296875 + ] + } + ], + "timestamp": "2025-10-15T21:42:39.785599" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 1.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 1.json" new file mode 100644 index 0000000..83b83bb --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 1.json" @@ -0,0 +1,736 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 1.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7842864394187927, + "bbox": [ + 209.82127380371094, + 983.5015869140625, + 315.1547546386719, + 1077.3642578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7796093821525574, + "bbox": [ + 194.84866333007812, + 2530.756103515625, + 299.7784423828125, + 2619.1904296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7758496999740601, + "bbox": [ + 1201.541259765625, + 2547.717529296875, + 1306.71240234375, + 2636.89111328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7748382687568665, + "bbox": [ + 204.1857452392578, + 1762.2987060546875, + 311.1451416015625, + 1853.1903076171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.760775625705719, + "bbox": [ + 1229.2142333984375, + 506.0862121582031, + 1330.3555908203125, + 593.1375732421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6700394749641418, + "bbox": [ + 982.4317016601562, + 1175.0797119140625, + 1097.6727294921875, + 1290.3974609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6694291830062866, + "bbox": [ + 1984.017333984375, + 1458.207275390625, + 2108.075927734375, + 1578.694091796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6627236008644104, + "bbox": [ + 205.47837829589844, + 2216.375732421875, + 293.70159912109375, + 2319.92724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6498438119888306, + "bbox": [ + 1793.1846923828125, + 2874.021728515625, + 1916.0955810546875, + 2990.895263671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6435327529907227, + "bbox": [ + 934.218994140625, + 1955.9635009765625, + 1058.0439453125, + 2096.315673828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6288009881973267, + "bbox": [ + 868.28271484375, + 2731.48095703125, + 993.3394165039062, + 2859.762939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6076654195785522, + "bbox": [ + 187.42324829101562, + 2808.025390625, + 264.7101135253906, + 2894.24853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5182301998138428, + "bbox": [ + 212.46214294433594, + 1307.2203369140625, + 298.7174072265625, + 1418.5716552734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48577332496643066, + "bbox": [ + 1198.943359375, + 2959.239501953125, + 1282.6090087890625, + 3065.4677734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.29050731658935547, + "bbox": [ + 192.86740112304688, + 3054.283935546875, + 278.1156921386719, + 3124.05908203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9364607930183411, + "bbox": [ + 1183.287353515625, + 473.7222595214844, + 2210.54150390625, + 1497.5501708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9210142493247986, + "bbox": [ + 152.06390380859375, + 1719.4591064453125, + 1157.144287109375, + 2398.49658203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9079030156135559, + "bbox": [ + 212.20230102539062, + 1212.751220703125, + 1055.266357421875, + 1566.6224365234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9016505479812622, + "bbox": [ + 199.58111572265625, + 949.6400146484375, + 1167.95068359375, + 1607.5753173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8950299024581909, + "bbox": [ + 200.73915100097656, + 1986.2904052734375, + 877.3661499023438, + 2338.2509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8821834325790405, + "bbox": [ + 1191.2994384765625, + 2730.24365234375, + 1996.87744140625, + 3072.180419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8723593950271606, + "bbox": [ + 1163.6500244140625, + 2516.7265625, + 2219.306884765625, + 3105.668701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8393189907073975, + "bbox": [ + 1262.1522216796875, + 681.9396362304688, + 2138.0703125, + 1407.77294921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8269436955451965, + "bbox": [ + 120.31210327148438, + 2468.3427734375, + 1172.5150146484375, + 3188.714599609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8134581446647644, + "bbox": [ + 192.9573974609375, + 2688.423828125, + 677.4232788085938, + 3070.353515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8019182682037354, + "bbox": [ + 208.113525390625, + 1077.8402099609375, + 1138.860595703125, + 1198.867919921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7849441766738892, + "bbox": [ + 1230.732421875, + 597.2572021484375, + 2136.079833984375, + 677.7405395507812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7762291431427002, + "bbox": [ + 196.7760772705078, + 1854.8236083984375, + 1123.649169921875, + 1981.5537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6008186936378479, + "bbox": [ + 195.57530212402344, + 2625.833740234375, + 1057.8720703125, + 2689.551513671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5075584650039673, + "bbox": [ + 195.4400634765625, + 2614.5849609375, + 1060.255615234375, + 2710.299560546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.47797083854675293, + "bbox": [ + 1204.70361328125, + 2647.417724609375, + 2055.885009765625, + 2710.023193359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.3939492106437683, + "bbox": [ + 1125.26025390625, + 2515.19677734375, + 2429.0, + 3146.61279296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.32467153668403625, + "bbox": [ + 1236.76025390625, + 611.8999633789062, + 2103.35107421875, + 663.91162109375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7842864394187927, + "bbox": [ + 209.82127380371094, + 983.5015869140625, + 315.1547546386719, + 1077.3642578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7796093821525574, + "bbox": [ + 194.84866333007812, + 2530.756103515625, + 299.7784423828125, + 2619.1904296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7758496999740601, + "bbox": [ + 1201.541259765625, + 2547.717529296875, + 1306.71240234375, + 2636.89111328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7748382687568665, + "bbox": [ + 204.1857452392578, + 1762.2987060546875, + 311.1451416015625, + 1853.1903076171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.760775625705719, + "bbox": [ + 1229.2142333984375, + 506.0862121582031, + 1330.3555908203125, + 593.1375732421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6700394749641418, + "bbox": [ + 982.4317016601562, + 1175.0797119140625, + 1097.6727294921875, + 1290.3974609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6694291830062866, + "bbox": [ + 1984.017333984375, + 1458.207275390625, + 2108.075927734375, + 1578.694091796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6627236008644104, + "bbox": [ + 205.47837829589844, + 2216.375732421875, + 293.70159912109375, + 2319.92724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6498438119888306, + "bbox": [ + 1793.1846923828125, + 2874.021728515625, + 1916.0955810546875, + 2990.895263671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6435327529907227, + "bbox": [ + 934.218994140625, + 1955.9635009765625, + 1058.0439453125, + 2096.315673828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6288009881973267, + "bbox": [ + 868.28271484375, + 2731.48095703125, + 993.3394165039062, + 2859.762939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6076654195785522, + "bbox": [ + 187.42324829101562, + 2808.025390625, + 264.7101135253906, + 2894.24853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5182301998138428, + "bbox": [ + 212.46214294433594, + 1307.2203369140625, + 298.7174072265625, + 1418.5716552734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48577332496643066, + "bbox": [ + 1198.943359375, + 2959.239501953125, + 1282.6090087890625, + 3065.4677734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.29050731658935547, + "bbox": [ + 192.86740112304688, + 3054.283935546875, + 278.1156921386719, + 3124.05908203125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9364607930183411, + "bbox": [ + 1183.287353515625, + 473.7222595214844, + 2210.54150390625, + 1497.5501708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9210142493247986, + "bbox": [ + 152.06390380859375, + 1719.4591064453125, + 1157.144287109375, + 2398.49658203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9079030156135559, + "bbox": [ + 212.20230102539062, + 1212.751220703125, + 1055.266357421875, + 1566.6224365234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9016505479812622, + "bbox": [ + 199.58111572265625, + 949.6400146484375, + 1167.95068359375, + 1607.5753173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8950299024581909, + "bbox": [ + 200.73915100097656, + 1986.2904052734375, + 877.3661499023438, + 2338.2509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8821834325790405, + "bbox": [ + 1191.2994384765625, + 2730.24365234375, + 1996.87744140625, + 3072.180419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8723593950271606, + "bbox": [ + 1163.6500244140625, + 2516.7265625, + 2219.306884765625, + 3105.668701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8393189907073975, + "bbox": [ + 1262.1522216796875, + 681.9396362304688, + 2138.0703125, + 1407.77294921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8269436955451965, + "bbox": [ + 120.31210327148438, + 2468.3427734375, + 1172.5150146484375, + 3188.714599609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8134581446647644, + "bbox": [ + 192.9573974609375, + 2688.423828125, + 677.4232788085938, + 3070.353515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8019182682037354, + "bbox": [ + 208.113525390625, + 1077.8402099609375, + 1138.860595703125, + 1198.867919921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7849441766738892, + "bbox": [ + 1230.732421875, + 597.2572021484375, + 2136.079833984375, + 677.7405395507812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7762291431427002, + "bbox": [ + 196.7760772705078, + 1854.8236083984375, + 1123.649169921875, + 1981.5537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6008186936378479, + "bbox": [ + 195.57530212402344, + 2625.833740234375, + 1057.8720703125, + 2689.551513671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5075584650039673, + "bbox": [ + 195.4400634765625, + 2614.5849609375, + 1060.255615234375, + 2710.299560546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.47797083854675293, + "bbox": [ + 1204.70361328125, + 2647.417724609375, + 2055.885009765625, + 2710.023193359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.3939492106437683, + "bbox": [ + 1125.26025390625, + 2515.19677734375, + 2429.0, + 3146.61279296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.32467153668403625, + "bbox": [ + 1236.76025390625, + 611.8999633789062, + 2103.35107421875, + 663.91162109375 + ] + } + ], + "timestamp": "2025-10-15T21:42:07.425684" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 10.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 10.json" new file mode 100644 index 0000000..3de221b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 10.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 10.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7653053998947144, + "bbox": [ + 1335.1885986328125, + 473.2847595214844, + 1444.0208740234375, + 571.9437866210938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7515062689781189, + "bbox": [ + 264.93951416015625, + 449.0201721191406, + 387.2547302246094, + 556.3081665039062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6523391604423523, + "bbox": [ + 1627.788330078125, + 1220.8560791015625, + 1734.173583984375, + 1341.718505859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6165726780891418, + "bbox": [ + 1801.0130615234375, + 2369.959228515625, + 1947.3907470703125, + 2514.678955078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5832147002220154, + "bbox": [ + 883.0390625, + 1590.44140625, + 960.6878662109375, + 1682.2232666015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5786518454551697, + "bbox": [ + 726.6168823242188, + 1861.361083984375, + 897.37548828125, + 2025.74951171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.527641236782074, + "bbox": [ + 2213.706787109375, + 3238.08837890625, + 2304.36962890625, + 3313.344482421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9310768842697144, + "bbox": [ + 255.3965301513672, + 621.7555541992188, + 1254.7518310546875, + 1828.46630859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9298466444015503, + "bbox": [ + 1324.8475341796875, + 718.0027465820312, + 2315.462158203125, + 2326.831298828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9169687628746033, + "bbox": [ + 206.598388671875, + 400.14007568359375, + 1279.3929443359375, + 2265.59814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9040104150772095, + "bbox": [ + 1304.7769775390625, + 410.1015625, + 2412.81103515625, + 2588.61083984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8365683555603027, + "bbox": [ + 1328.4508056640625, + 571.41845703125, + 2317.35205078125, + 704.6746826171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6994885802268982, + "bbox": [ + 288.2322692871094, + 548.0073852539062, + 1055.132568359375, + 650.0685424804688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7653053998947144, + "bbox": [ + 1335.1885986328125, + 473.2847595214844, + 1444.0208740234375, + 571.9437866210938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7515062689781189, + "bbox": [ + 264.93951416015625, + 449.0201721191406, + 387.2547302246094, + 556.3081665039062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6523391604423523, + "bbox": [ + 1627.788330078125, + 1220.8560791015625, + 1734.173583984375, + 1341.718505859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6165726780891418, + "bbox": [ + 1801.0130615234375, + 2369.959228515625, + 1947.3907470703125, + 2514.678955078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5832147002220154, + "bbox": [ + 883.0390625, + 1590.44140625, + 960.6878662109375, + 1682.2232666015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5786518454551697, + "bbox": [ + 726.6168823242188, + 1861.361083984375, + 897.37548828125, + 2025.74951171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.527641236782074, + "bbox": [ + 2213.706787109375, + 3238.08837890625, + 2304.36962890625, + 3313.344482421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9310768842697144, + "bbox": [ + 255.3965301513672, + 621.7555541992188, + 1254.7518310546875, + 1828.46630859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9298466444015503, + "bbox": [ + 1324.8475341796875, + 718.0027465820312, + 2315.462158203125, + 2326.831298828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9169687628746033, + "bbox": [ + 206.598388671875, + 400.14007568359375, + 1279.3929443359375, + 2265.59814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9040104150772095, + "bbox": [ + 1304.7769775390625, + 410.1015625, + 2412.81103515625, + 2588.61083984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8365683555603027, + "bbox": [ + 1328.4508056640625, + 571.41845703125, + 2317.35205078125, + 704.6746826171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6994885802268982, + "bbox": [ + 288.2322692871094, + 548.0073852539062, + 1055.132568359375, + 650.0685424804688 + ] + } + ], + "timestamp": "2025-10-15T21:42:07.823214" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 11.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 11.json" new file mode 100644 index 0000000..dcd974e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 11.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 11.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7643402814865112, + "bbox": [ + 1359.9254150390625, + 494.22344970703125, + 1481.3714599609375, + 603.9540405273438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7294407486915588, + "bbox": [ + 238.2257537841797, + 602.3335571289062, + 363.9731140136719, + 718.8900756835938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6631203889846802, + "bbox": [ + 2164.05615234375, + 2165.859375, + 2300.899169921875, + 2298.61328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6480240821838379, + "bbox": [ + 733.7203979492188, + 2151.0556640625, + 885.5621948242188, + 2300.496337890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5725988149642944, + "bbox": [ + 1355.4454345703125, + 2125.122314453125, + 1464.3118896484375, + 2233.203857421875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5007991790771484, + "bbox": [ + 237.26341247558594, + 2271.555419921875, + 321.5048522949219, + 2374.010009765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4629310965538025, + "bbox": [ + 220.8455047607422, + 3383.128173828125, + 322.3902282714844, + 3464.67529296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2334883213043213, + "bbox": [ + 209.8589630126953, + 3373.67724609375, + 325.4581298828125, + 3481.084716796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.933046817779541, + "bbox": [ + 209.1478271484375, + 709.8484497070312, + 1278.4327392578125, + 2061.591796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9282971024513245, + "bbox": [ + 1292.234130859375, + 390.7762145996094, + 2578.676513671875, + 2752.066162109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9254588484764099, + "bbox": [ + 1343.6204833984375, + 611.84423828125, + 2404.65185546875, + 2082.94189453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9247848987579346, + "bbox": [ + 149.21279907226562, + 445.5929260253906, + 1316.418212890625, + 2585.745849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8934788107872009, + "bbox": [ + 1344.14990234375, + 2109.83642578125, + 2224.857666015625, + 2574.1376953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8265691995620728, + "bbox": [ + 213.9228973388672, + 2069.004150390625, + 607.4859619140625, + 2479.982421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7405682802200317, + "bbox": [ + 222.30398559570312, + 459.6543273925781, + 1230.0869140625, + 570.4458618164062 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7643402814865112, + "bbox": [ + 1359.9254150390625, + 494.22344970703125, + 1481.3714599609375, + 603.9540405273438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7294407486915588, + "bbox": [ + 238.2257537841797, + 602.3335571289062, + 363.9731140136719, + 718.8900756835938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6631203889846802, + "bbox": [ + 2164.05615234375, + 2165.859375, + 2300.899169921875, + 2298.61328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6480240821838379, + "bbox": [ + 733.7203979492188, + 2151.0556640625, + 885.5621948242188, + 2300.496337890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5725988149642944, + "bbox": [ + 1355.4454345703125, + 2125.122314453125, + 1464.3118896484375, + 2233.203857421875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5007991790771484, + "bbox": [ + 237.26341247558594, + 2271.555419921875, + 321.5048522949219, + 2374.010009765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4629310965538025, + "bbox": [ + 220.8455047607422, + 3383.128173828125, + 322.3902282714844, + 3464.67529296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2334883213043213, + "bbox": [ + 209.8589630126953, + 3373.67724609375, + 325.4581298828125, + 3481.084716796875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.933046817779541, + "bbox": [ + 209.1478271484375, + 709.8484497070312, + 1278.4327392578125, + 2061.591796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9282971024513245, + "bbox": [ + 1292.234130859375, + 390.7762145996094, + 2578.676513671875, + 2752.066162109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9254588484764099, + "bbox": [ + 1343.6204833984375, + 611.84423828125, + 2404.65185546875, + 2082.94189453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9247848987579346, + "bbox": [ + 149.21279907226562, + 445.5929260253906, + 1316.418212890625, + 2585.745849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8934788107872009, + "bbox": [ + 1344.14990234375, + 2109.83642578125, + 2224.857666015625, + 2574.1376953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8265691995620728, + "bbox": [ + 213.9228973388672, + 2069.004150390625, + 607.4859619140625, + 2479.982421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7405682802200317, + "bbox": [ + 222.30398559570312, + 459.6543273925781, + 1230.0869140625, + 570.4458618164062 + ] + } + ], + "timestamp": "2025-10-15T21:42:08.180740" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 12.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 12.json" new file mode 100644 index 0000000..1dc6633 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 12.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 12.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7468553185462952, + "bbox": [ + 1303.35693359375, + 474.560302734375, + 1413.9576416015625, + 573.5556030273438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.743333637714386, + "bbox": [ + 266.29180908203125, + 444.13360595703125, + 384.87127685546875, + 554.2145385742188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6878947615623474, + "bbox": [ + 858.9346313476562, + 2338.166259765625, + 972.7527465820312, + 2456.422119140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.609759509563446, + "bbox": [ + 1840.326416015625, + 2247.04296875, + 1974.393310546875, + 2374.877197265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.574940025806427, + "bbox": [ + 2148.958251953125, + 3183.304931640625, + 2236.269287109375, + 3255.7392578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5190994739532471, + "bbox": [ + 1288.8978271484375, + 2063.99169921875, + 1374.2425537109375, + 2163.8310546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5038196444511414, + "bbox": [ + 258.90240478515625, + 1718.33837890625, + 366.2701110839844, + 1838.8165283203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3262196481227875, + "bbox": [ + 1823.564453125, + 2234.002197265625, + 1990.3455810546875, + 2390.14208984375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.24487733840942383, + "bbox": [ + 1291.2572021484375, + 2076.20361328125, + 1358.3148193359375, + 2159.2080078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9450184106826782, + "bbox": [ + 254.3839111328125, + 1724.6357421875, + 1218.76953125, + 2361.24462890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9308471083641052, + "bbox": [ + 1299.9635009765625, + 587.5728759765625, + 2258.749755859375, + 1657.2542724609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9247321486473083, + "bbox": [ + 267.0700378417969, + 576.1969604492188, + 1226.2620849609375, + 1714.6993408203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9033681750297546, + "bbox": [ + 1253.46484375, + 416.5853576660156, + 2287.47119140625, + 2378.7509765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9000604152679443, + "bbox": [ + 198.62510681152344, + 415.2583312988281, + 1238.20849609375, + 2536.2900390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8977319002151489, + "bbox": [ + 1291.826171875, + 1750.477294921875, + 2260.676513671875, + 2211.61572265625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7468553185462952, + "bbox": [ + 1303.35693359375, + 474.560302734375, + 1413.9576416015625, + 573.5556030273438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.743333637714386, + "bbox": [ + 266.29180908203125, + 444.13360595703125, + 384.87127685546875, + 554.2145385742188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6878947615623474, + "bbox": [ + 858.9346313476562, + 2338.166259765625, + 972.7527465820312, + 2456.422119140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.609759509563446, + "bbox": [ + 1840.326416015625, + 2247.04296875, + 1974.393310546875, + 2374.877197265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.574940025806427, + "bbox": [ + 2148.958251953125, + 3183.304931640625, + 2236.269287109375, + 3255.7392578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5190994739532471, + "bbox": [ + 1288.8978271484375, + 2063.99169921875, + 1374.2425537109375, + 2163.8310546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5038196444511414, + "bbox": [ + 258.90240478515625, + 1718.33837890625, + 366.2701110839844, + 1838.8165283203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3262196481227875, + "bbox": [ + 1823.564453125, + 2234.002197265625, + 1990.3455810546875, + 2390.14208984375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.24487733840942383, + "bbox": [ + 1291.2572021484375, + 2076.20361328125, + 1358.3148193359375, + 2159.2080078125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9450184106826782, + "bbox": [ + 254.3839111328125, + 1724.6357421875, + 1218.76953125, + 2361.24462890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9308471083641052, + "bbox": [ + 1299.9635009765625, + 587.5728759765625, + 2258.749755859375, + 1657.2542724609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9247321486473083, + "bbox": [ + 267.0700378417969, + 576.1969604492188, + 1226.2620849609375, + 1714.6993408203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9033681750297546, + "bbox": [ + 1253.46484375, + 416.5853576660156, + 2287.47119140625, + 2378.7509765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9000604152679443, + "bbox": [ + 198.62510681152344, + 415.2583312988281, + 1238.20849609375, + 2536.2900390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8977319002151489, + "bbox": [ + 1291.826171875, + 1750.477294921875, + 2260.676513671875, + 2211.61572265625 + ] + } + ], + "timestamp": "2025-10-15T21:42:08.548719" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 13.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 13.json" new file mode 100644 index 0000000..b6b7a58 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 13.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 13.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7539030909538269, + "bbox": [ + 226.65045166015625, + 436.5482177734375, + 336.9461364746094, + 533.13232421875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7358774542808533, + "bbox": [ + 1261.66943359375, + 618.375244140625, + 1377.0872802734375, + 723.4207153320312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6378952264785767, + "bbox": [ + 1781.2056884765625, + 2619.267333984375, + 1906.25927734375, + 2743.0087890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6156203746795654, + "bbox": [ + 811.2224731445312, + 2233.1611328125, + 943.4743041992188, + 2363.2109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5854724049568176, + "bbox": [ + 1787.4603271484375, + 2429.828857421875, + 1890.47119140625, + 2532.645751953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.49399974942207336, + "bbox": [ + 206.4445037841797, + 3156.03857421875, + 298.3339538574219, + 3228.31640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4745909571647644, + "bbox": [ + 609.5523681640625, + 1265.285400390625, + 696.9658813476562, + 1379.5419921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.23185904324054718, + "bbox": [ + 796.2357788085938, + 2223.01611328125, + 958.38818359375, + 2377.260009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9576107859611511, + "bbox": [ + 223.9379119873047, + 597.4452514648438, + 1190.8133544921875, + 2160.656982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9423897862434387, + "bbox": [ + 1246.1944580078125, + 552.9278564453125, + 2264.4462890625, + 2786.99755859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9403762221336365, + "bbox": [ + 188.3887176513672, + 422.1142883300781, + 1205.0401611328125, + 2193.403564453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9352357983589172, + "bbox": [ + 1260.1524658203125, + 738.2506103515625, + 2235.455078125, + 2452.466552734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9004422426223755, + "bbox": [ + 1254.08935546875, + 2443.832275390625, + 2141.1533203125, + 2691.5478515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8053814768791199, + "bbox": [ + 237.9296417236328, + 533.0311889648438, + 880.7869873046875, + 617.3201293945312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7539030909538269, + "bbox": [ + 226.65045166015625, + 436.5482177734375, + 336.9461364746094, + 533.13232421875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7358774542808533, + "bbox": [ + 1261.66943359375, + 618.375244140625, + 1377.0872802734375, + 723.4207153320312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6378952264785767, + "bbox": [ + 1781.2056884765625, + 2619.267333984375, + 1906.25927734375, + 2743.0087890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6156203746795654, + "bbox": [ + 811.2224731445312, + 2233.1611328125, + 943.4743041992188, + 2363.2109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5854724049568176, + "bbox": [ + 1787.4603271484375, + 2429.828857421875, + 1890.47119140625, + 2532.645751953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.49399974942207336, + "bbox": [ + 206.4445037841797, + 3156.03857421875, + 298.3339538574219, + 3228.31640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4745909571647644, + "bbox": [ + 609.5523681640625, + 1265.285400390625, + 696.9658813476562, + 1379.5419921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.23185904324054718, + "bbox": [ + 796.2357788085938, + 2223.01611328125, + 958.38818359375, + 2377.260009765625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9576107859611511, + "bbox": [ + 223.9379119873047, + 597.4452514648438, + 1190.8133544921875, + 2160.656982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9423897862434387, + "bbox": [ + 1246.1944580078125, + 552.9278564453125, + 2264.4462890625, + 2786.99755859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9403762221336365, + "bbox": [ + 188.3887176513672, + 422.1142883300781, + 1205.0401611328125, + 2193.403564453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9352357983589172, + "bbox": [ + 1260.1524658203125, + 738.2506103515625, + 2235.455078125, + 2452.466552734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9004422426223755, + "bbox": [ + 1254.08935546875, + 2443.832275390625, + 2141.1533203125, + 2691.5478515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8053814768791199, + "bbox": [ + 237.9296417236328, + 533.0311889648438, + 880.7869873046875, + 617.3201293945312 + ] + } + ], + "timestamp": "2025-10-15T21:42:08.936856" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 14.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 14.json" new file mode 100644 index 0000000..18daace --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 14.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 14.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7595505714416504, + "bbox": [ + 1346.3468017578125, + 647.7832641601562, + 1462.1785888671875, + 748.4773559570312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7329692244529724, + "bbox": [ + 270.8448791503906, + 452.4239807128906, + 395.484619140625, + 565.8150024414062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6492832899093628, + "bbox": [ + 1840.446044921875, + 616.318359375, + 1975.78955078125, + 741.5443115234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5978890657424927, + "bbox": [ + 2122.638671875, + 1821.96435546875, + 2198.71923828125, + 1905.0386962890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5505934357643127, + "bbox": [ + 805.83935546875, + 416.22467041015625, + 944.9745483398438, + 560.6581420898438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5403531193733215, + "bbox": [ + 788.4834594726562, + 413.8154296875, + 962.0928955078125, + 579.7442016601562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5387457609176636, + "bbox": [ + 2236.574951171875, + 3281.37548828125, + 2328.183837890625, + 3355.042236328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5325353145599365, + "bbox": [ + 807.6753540039062, + 2689.809326171875, + 906.0247802734375, + 2795.542236328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2643180191516876, + "bbox": [ + 2231.086669921875, + 3271.66064453125, + 2334.06201171875, + 3366.62548828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9354086518287659, + "bbox": [ + 273.001220703125, + 594.9843139648438, + 1261.5015869140625, + 2714.177001953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9212610721588135, + "bbox": [ + 1321.295166015625, + 502.48590087890625, + 2384.5517578125, + 2614.390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9196062684059143, + "bbox": [ + 208.19671630859375, + 360.1167907714844, + 1280.9722900390625, + 3056.80322265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9168121218681335, + "bbox": [ + 1327.8677978515625, + 789.0895385742188, + 2357.0478515625, + 2530.500244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8972429633140564, + "bbox": [ + 243.51612854003906, + 2712.170654296875, + 1179.3507080078125, + 2952.126953125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7595505714416504, + "bbox": [ + 1346.3468017578125, + 647.7832641601562, + 1462.1785888671875, + 748.4773559570312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7329692244529724, + "bbox": [ + 270.8448791503906, + 452.4239807128906, + 395.484619140625, + 565.8150024414062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6492832899093628, + "bbox": [ + 1840.446044921875, + 616.318359375, + 1975.78955078125, + 741.5443115234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5978890657424927, + "bbox": [ + 2122.638671875, + 1821.96435546875, + 2198.71923828125, + 1905.0386962890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5505934357643127, + "bbox": [ + 805.83935546875, + 416.22467041015625, + 944.9745483398438, + 560.6581420898438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5403531193733215, + "bbox": [ + 788.4834594726562, + 413.8154296875, + 962.0928955078125, + 579.7442016601562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5387457609176636, + "bbox": [ + 2236.574951171875, + 3281.37548828125, + 2328.183837890625, + 3355.042236328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5325353145599365, + "bbox": [ + 807.6753540039062, + 2689.809326171875, + 906.0247802734375, + 2795.542236328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2643180191516876, + "bbox": [ + 2231.086669921875, + 3271.66064453125, + 2334.06201171875, + 3366.62548828125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9354086518287659, + "bbox": [ + 273.001220703125, + 594.9843139648438, + 1261.5015869140625, + 2714.177001953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9212610721588135, + "bbox": [ + 1321.295166015625, + 502.48590087890625, + 2384.5517578125, + 2614.390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9196062684059143, + "bbox": [ + 208.19671630859375, + 360.1167907714844, + 1280.9722900390625, + 3056.80322265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9168121218681335, + "bbox": [ + 1327.8677978515625, + 789.0895385742188, + 2357.0478515625, + 2530.500244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8972429633140564, + "bbox": [ + 243.51612854003906, + 2712.170654296875, + 1179.3507080078125, + 2952.126953125 + ] + } + ], + "timestamp": "2025-10-15T21:42:09.300964" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 15.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 15.json" new file mode 100644 index 0000000..a6f6b60 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 15.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 15.jpg", + "detections": [ + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7709265947341919, + "bbox": [ + 757.7011108398438, + 1642.23828125, + 831.4276123046875, + 1723.648681640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7512796521186829, + "bbox": [ + 1250.7691650390625, + 449.2054443359375, + 1369.477783203125, + 552.7395629882812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.746095597743988, + "bbox": [ + 1727.1451416015625, + 451.3596496582031, + 1837.5162353515625, + 555.0620727539062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7332658767700195, + "bbox": [ + 217.3208465576172, + 430.0409240722656, + 337.3678283691406, + 538.7100219726562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7135115265846252, + "bbox": [ + 1239.494873046875, + 2946.19091796875, + 1300.6754150390625, + 3019.131591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5977818965911865, + "bbox": [ + 642.9950561523438, + 409.12738037109375, + 806.7240600585938, + 566.059814453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5201202034950256, + "bbox": [ + 177.28924560546875, + 3136.826171875, + 272.313232421875, + 3215.5986328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4174672067165375, + "bbox": [ + 658.50048828125, + 412.24029541015625, + 787.9365234375, + 549.4918212890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467200636863708, + "bbox": [ + 193.93765258789062, + 556.6621704101562, + 1172.0560302734375, + 2345.81298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9338167905807495, + "bbox": [ + 1227.8487548828125, + 2673.30615234375, + 1939.58251953125, + 3123.354736328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9334197640419006, + "bbox": [ + 181.73133850097656, + 377.7413024902344, + 1195.246826171875, + 2412.146728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9282165169715881, + "bbox": [ + 1240.0458984375, + 692.778076171875, + 2242.693115234375, + 2681.3818359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8594691753387451, + "bbox": [ + 1253.1800537109375, + 550.5917358398438, + 2215.42626953125, + 672.3336181640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7580432891845703, + "bbox": [ + 1218.0592041015625, + 485.32421875, + 2242.52490234375, + 3119.447021484375 + ] + } + ], + "small_detections": [ + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7709265947341919, + "bbox": [ + 757.7011108398438, + 1642.23828125, + 831.4276123046875, + 1723.648681640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7512796521186829, + "bbox": [ + 1250.7691650390625, + 449.2054443359375, + 1369.477783203125, + 552.7395629882812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.746095597743988, + "bbox": [ + 1727.1451416015625, + 451.3596496582031, + 1837.5162353515625, + 555.0620727539062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7332658767700195, + "bbox": [ + 217.3208465576172, + 430.0409240722656, + 337.3678283691406, + 538.7100219726562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7135115265846252, + "bbox": [ + 1239.494873046875, + 2946.19091796875, + 1300.6754150390625, + 3019.131591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5977818965911865, + "bbox": [ + 642.9950561523438, + 409.12738037109375, + 806.7240600585938, + 566.059814453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5201202034950256, + "bbox": [ + 177.28924560546875, + 3136.826171875, + 272.313232421875, + 3215.5986328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4174672067165375, + "bbox": [ + 658.50048828125, + 412.24029541015625, + 787.9365234375, + 549.4918212890625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467200636863708, + "bbox": [ + 193.93765258789062, + 556.6621704101562, + 1172.0560302734375, + 2345.81298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9338167905807495, + "bbox": [ + 1227.8487548828125, + 2673.30615234375, + 1939.58251953125, + 3123.354736328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9334197640419006, + "bbox": [ + 181.73133850097656, + 377.7413024902344, + 1195.246826171875, + 2412.146728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9282165169715881, + "bbox": [ + 1240.0458984375, + 692.778076171875, + 2242.693115234375, + 2681.3818359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8594691753387451, + "bbox": [ + 1253.1800537109375, + 550.5917358398438, + 2215.42626953125, + 672.3336181640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7580432891845703, + "bbox": [ + 1218.0592041015625, + 485.32421875, + 2242.52490234375, + 3119.447021484375 + ] + } + ], + "timestamp": "2025-10-15T21:42:09.696829" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 16.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 16.json" new file mode 100644 index 0000000..0309333 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 16.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 16.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7394245862960815, + "bbox": [ + 1319.5382080078125, + 441.8236389160156, + 1444.5771484375, + 549.0018310546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7383383512496948, + "bbox": [ + 1317.24462890625, + 1973.5938720703125, + 1438.3150634765625, + 2076.056640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6485133171081543, + "bbox": [ + 1845.4642333984375, + 1959.1015625, + 1977.4010009765625, + 2080.37109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6381608247756958, + "bbox": [ + 1961.736328125, + 517.8731689453125, + 2087.7841796875, + 633.8662109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6209801435470581, + "bbox": [ + 2208.62939453125, + 3186.538818359375, + 2294.36376953125, + 3261.06298828125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5827338099479675, + "bbox": [ + 1327.644775390625, + 1066.6015625, + 1408.052734375, + 1156.60888671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5392507314682007, + "bbox": [ + 1694.02587890625, + 2178.87451171875, + 1808.8529052734375, + 2306.447509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9416528344154358, + "bbox": [ + 1324.2122802734375, + 624.6874389648438, + 2321.627685546875, + 1243.6190185546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9395679235458374, + "bbox": [ + 242.77822875976562, + 467.1435546875, + 1253.210205078125, + 2805.60107421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9366462826728821, + "bbox": [ + 1292.594970703125, + 403.25653076171875, + 2358.701416015625, + 1350.2135009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9223382472991943, + "bbox": [ + 1297.19384765625, + 1973.437255859375, + 2315.1337890625, + 2339.700439453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8365064263343811, + "bbox": [ + 1320.27294921875, + 2069.30224609375, + 2289.273193359375, + 2194.34326171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7927699685096741, + "bbox": [ + 1328.95849609375, + 530.7588500976562, + 1901.698486328125, + 622.0433349609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6997930407524109, + "bbox": [ + 1311.615234375, + 2202.505859375, + 2236.17529296875, + 2310.228271484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.12609320878982544, + "bbox": [ + 1277.857666015625, + 1952.2440185546875, + 2360.20654296875, + 2681.72265625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7394245862960815, + "bbox": [ + 1319.5382080078125, + 441.8236389160156, + 1444.5771484375, + 549.0018310546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7383383512496948, + "bbox": [ + 1317.24462890625, + 1973.5938720703125, + 1438.3150634765625, + 2076.056640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6485133171081543, + "bbox": [ + 1845.4642333984375, + 1959.1015625, + 1977.4010009765625, + 2080.37109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6381608247756958, + "bbox": [ + 1961.736328125, + 517.8731689453125, + 2087.7841796875, + 633.8662109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6209801435470581, + "bbox": [ + 2208.62939453125, + 3186.538818359375, + 2294.36376953125, + 3261.06298828125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5827338099479675, + "bbox": [ + 1327.644775390625, + 1066.6015625, + 1408.052734375, + 1156.60888671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5392507314682007, + "bbox": [ + 1694.02587890625, + 2178.87451171875, + 1808.8529052734375, + 2306.447509765625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9416528344154358, + "bbox": [ + 1324.2122802734375, + 624.6874389648438, + 2321.627685546875, + 1243.6190185546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9395679235458374, + "bbox": [ + 242.77822875976562, + 467.1435546875, + 1253.210205078125, + 2805.60107421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9366462826728821, + "bbox": [ + 1292.594970703125, + 403.25653076171875, + 2358.701416015625, + 1350.2135009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9223382472991943, + "bbox": [ + 1297.19384765625, + 1973.437255859375, + 2315.1337890625, + 2339.700439453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8365064263343811, + "bbox": [ + 1320.27294921875, + 2069.30224609375, + 2289.273193359375, + 2194.34326171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7927699685096741, + "bbox": [ + 1328.95849609375, + 530.7588500976562, + 1901.698486328125, + 622.0433349609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6997930407524109, + "bbox": [ + 1311.615234375, + 2202.505859375, + 2236.17529296875, + 2310.228271484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.12609320878982544, + "bbox": [ + 1277.857666015625, + 1952.2440185546875, + 2360.20654296875, + 2681.72265625 + ] + } + ], + "timestamp": "2025-10-15T21:42:10.082442" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 17.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 17.json" new file mode 100644 index 0000000..051682e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 17.json" @@ -0,0 +1,538 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 17.jpg", + "detections": [ + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7553172707557678, + "bbox": [ + 1904.0810546875, + 2652.21484375, + 1999.6212158203125, + 2752.388427734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7405208349227905, + "bbox": [ + 1228.488525390625, + 2560.163330078125, + 1348.9630126953125, + 2663.23291015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7378954887390137, + "bbox": [ + 1232.9552001953125, + 2060.12255859375, + 1348.1224365234375, + 2161.304443359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7348079085350037, + "bbox": [ + 1234.5758056640625, + 1367.315185546875, + 1352.947021484375, + 1472.8436279296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6704397797584534, + "bbox": [ + 1818.5050048828125, + 2040.3316650390625, + 1943.7882080078125, + 2161.420654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6310093998908997, + "bbox": [ + 1671.664306640625, + 1329.9208984375, + 1801.4307861328125, + 1450.3365478515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.514884352684021, + "bbox": [ + 200.9347381591797, + 3168.342529296875, + 289.3312683105469, + 3238.86572265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5119954347610474, + "bbox": [ + 1241.677734375, + 1665.2855224609375, + 1310.2342529296875, + 1748.99951171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4803646504878998, + "bbox": [ + 1233.292724609375, + 2798.07470703125, + 1306.5723876953125, + 2883.75537109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.41963425278663635, + "bbox": [ + 1787.5924072265625, + 2210.290771484375, + 1894.63037109375, + 2324.00146484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3070087134838104, + "bbox": [ + 1792.1875, + 2219.70947265625, + 1867.9805908203125, + 2315.359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.24295583367347717, + "bbox": [ + 187.42868041992188, + 3156.55322265625, + 294.78070068359375, + 3252.2138671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9328781366348267, + "bbox": [ + 169.57785034179688, + 548.7540893554688, + 1177.3165283203125, + 3100.60791015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9176549911499023, + "bbox": [ + 1228.684326171875, + 422.03265380859375, + 2255.84326171875, + 1284.239501953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.909488320350647, + "bbox": [ + 1180.44873046875, + 1977.3375244140625, + 2291.776611328125, + 2435.398193359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9030292630195618, + "bbox": [ + 1225.3302001953125, + 2740.937255859375, + 2235.19970703125, + 3171.450439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9014828205108643, + "bbox": [ + 1224.3828125, + 1596.2593994140625, + 2165.94921875, + 1845.5018310546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8685874342918396, + "bbox": [ + 1211.3822021484375, + 1262.552001953125, + 2268.720947265625, + 1932.6785888671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8626507520675659, + "bbox": [ + 1182.16064453125, + 2516.91748046875, + 2261.010986328125, + 3244.611083984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8117498755455017, + "bbox": [ + 1216.327880859375, + 1476.62060546875, + 2189.8271484375, + 1599.65576171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7215481996536255, + "bbox": [ + 1234.3970947265625, + 2650.897216796875, + 1907.3302001953125, + 2741.4833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7190080285072327, + "bbox": [ + 1236.6243896484375, + 2154.9111328125, + 2196.468994140625, + 2251.61474609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6263931393623352, + "bbox": [ + 1216.1605224609375, + 2229.458251953125, + 2154.37890625, + 2369.947509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.2010408490896225, + "bbox": [ + 1220.49951171875, + 2231.757080078125, + 2180.56982421875, + 2323.49658203125 + ] + } + ], + "small_detections": [ + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7553172707557678, + "bbox": [ + 1904.0810546875, + 2652.21484375, + 1999.6212158203125, + 2752.388427734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7405208349227905, + "bbox": [ + 1228.488525390625, + 2560.163330078125, + 1348.9630126953125, + 2663.23291015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7378954887390137, + "bbox": [ + 1232.9552001953125, + 2060.12255859375, + 1348.1224365234375, + 2161.304443359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7348079085350037, + "bbox": [ + 1234.5758056640625, + 1367.315185546875, + 1352.947021484375, + 1472.8436279296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6704397797584534, + "bbox": [ + 1818.5050048828125, + 2040.3316650390625, + 1943.7882080078125, + 2161.420654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6310093998908997, + "bbox": [ + 1671.664306640625, + 1329.9208984375, + 1801.4307861328125, + 1450.3365478515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.514884352684021, + "bbox": [ + 200.9347381591797, + 3168.342529296875, + 289.3312683105469, + 3238.86572265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5119954347610474, + "bbox": [ + 1241.677734375, + 1665.2855224609375, + 1310.2342529296875, + 1748.99951171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4803646504878998, + "bbox": [ + 1233.292724609375, + 2798.07470703125, + 1306.5723876953125, + 2883.75537109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.41963425278663635, + "bbox": [ + 1787.5924072265625, + 2210.290771484375, + 1894.63037109375, + 2324.00146484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3070087134838104, + "bbox": [ + 1792.1875, + 2219.70947265625, + 1867.9805908203125, + 2315.359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.24295583367347717, + "bbox": [ + 187.42868041992188, + 3156.55322265625, + 294.78070068359375, + 3252.2138671875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9328781366348267, + "bbox": [ + 169.57785034179688, + 548.7540893554688, + 1177.3165283203125, + 3100.60791015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9176549911499023, + "bbox": [ + 1228.684326171875, + 422.03265380859375, + 2255.84326171875, + 1284.239501953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.909488320350647, + "bbox": [ + 1180.44873046875, + 1977.3375244140625, + 2291.776611328125, + 2435.398193359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9030292630195618, + "bbox": [ + 1225.3302001953125, + 2740.937255859375, + 2235.19970703125, + 3171.450439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9014828205108643, + "bbox": [ + 1224.3828125, + 1596.2593994140625, + 2165.94921875, + 1845.5018310546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8685874342918396, + "bbox": [ + 1211.3822021484375, + 1262.552001953125, + 2268.720947265625, + 1932.6785888671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8626507520675659, + "bbox": [ + 1182.16064453125, + 2516.91748046875, + 2261.010986328125, + 3244.611083984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8117498755455017, + "bbox": [ + 1216.327880859375, + 1476.62060546875, + 2189.8271484375, + 1599.65576171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7215481996536255, + "bbox": [ + 1234.3970947265625, + 2650.897216796875, + 1907.3302001953125, + 2741.4833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7190080285072327, + "bbox": [ + 1236.6243896484375, + 2154.9111328125, + 2196.468994140625, + 2251.61474609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6263931393623352, + "bbox": [ + 1216.1605224609375, + 2229.458251953125, + 2154.37890625, + 2369.947509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.2010408490896225, + "bbox": [ + 1220.49951171875, + 2231.757080078125, + 2180.56982421875, + 2323.49658203125 + ] + } + ], + "timestamp": "2025-10-15T21:42:10.440306" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 2.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 2.json" new file mode 100644 index 0000000..8cd7645 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 2.json" @@ -0,0 +1,802 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 2.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7761788964271545, + "bbox": [ + 266.99273681640625, + 1558.7828369140625, + 383.18426513671875, + 1656.45751953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7647627592086792, + "bbox": [ + 248.6532745361328, + 2730.1572265625, + 362.35321044921875, + 2825.101806640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.759023129940033, + "bbox": [ + 289.3776550292969, + 450.9398193359375, + 405.08209228515625, + 545.6597900390625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7449226379394531, + "bbox": [ + 1333.320556640625, + 2388.941162109375, + 1448.6380615234375, + 2494.62744140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7373238801956177, + "bbox": [ + 1364.1485595703125, + 465.3263244628906, + 1480.4686279296875, + 566.6741333007812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7221008539199829, + "bbox": [ + 2084.166259765625, + 2581.75927734375, + 2209.69580078125, + 2700.759521484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.643187940120697, + "bbox": [ + 1361.0081787109375, + 881.2794799804688, + 1458.28076171875, + 1000.9185791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254684925079346, + "bbox": [ + 867.2763671875, + 739.5374755859375, + 994.551513671875, + 858.9783935546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6105570793151855, + "bbox": [ + 838.1183471679688, + 3006.087890625, + 982.9075317382812, + 3151.343505859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.605405867099762, + "bbox": [ + 279.5609436035156, + 810.837158203125, + 382.6033935546875, + 927.8025512695312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6026655435562134, + "bbox": [ + 1798.0853271484375, + 1257.5687255859375, + 1942.20849609375, + 1399.855712890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5937169790267944, + "bbox": [ + 955.8529052734375, + 1969.0958251953125, + 1076.17431640625, + 2084.57373046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5857372283935547, + "bbox": [ + 2237.54296875, + 3322.159423828125, + 2328.824951171875, + 3397.091064453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5852604508399963, + "bbox": [ + 1326.194580078125, + 3076.443115234375, + 1413.85595703125, + 3207.711669921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5764795541763306, + "bbox": [ + 267.99298095703125, + 1752.395263671875, + 365.58203125, + 1882.5455322265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5486968755722046, + "bbox": [ + 243.95086669921875, + 2965.39697265625, + 320.57720947265625, + 3057.10791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4284059703350067, + "bbox": [ + 940.7259521484375, + 1959.599365234375, + 1101.253173828125, + 2112.238525390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3805253505706787, + "bbox": [ + 1331.4544677734375, + 3071.6142578125, + 1400.8343505859375, + 3188.0625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3261685073375702, + "bbox": [ + 858.0497436523438, + 733.5635986328125, + 1012.0326538085938, + 878.7215576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9215754270553589, + "bbox": [ + 1314.7261962890625, + 2627.35546875, + 2341.076904296875, + 3300.589599609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9131869077682495, + "bbox": [ + 1289.9248046875, + 2345.0859375, + 2386.544921875, + 3362.467041015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.877517819404602, + "bbox": [ + 1309.8182373046875, + 424.8322448730469, + 2466.941162109375, + 1356.65625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8768096566200256, + "bbox": [ + 1349.5880126953125, + 705.5388793945312, + 2371.05224609375, + 1102.4268798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8741651773452759, + "bbox": [ + 181.15310668945312, + 395.4048156738281, + 1300.0750732421875, + 1241.311767578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8677266836166382, + "bbox": [ + 161.9854278564453, + 2660.0302734375, + 1284.8515625, + 3384.88525390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8651233315467834, + "bbox": [ + 229.70944213867188, + 1786.194091796875, + 958.8402709960938, + 2194.424072265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8435643315315247, + "bbox": [ + 162.44256591796875, + 1491.2109375, + 1303.119140625, + 2295.40087890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.842098593711853, + "bbox": [ + 216.950927734375, + 2894.42236328125, + 815.963134765625, + 3296.249267578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8274424076080322, + "bbox": [ + 1360.77197265625, + 570.7152099609375, + 2366.440185546875, + 702.28173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8246386647224426, + "bbox": [ + 239.35411071777344, + 1660.4132080078125, + 1292.6300048828125, + 1802.973388671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8238803744316101, + "bbox": [ + 1329.432861328125, + 2488.91064453125, + 2375.02880859375, + 2627.652099609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7948890328407288, + "bbox": [ + 295.4638366699219, + 538.1303100585938, + 1063.72265625, + 638.1751708984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7100364565849304, + "bbox": [ + 253.65850830078125, + 2817.990966796875, + 1219.7672119140625, + 2923.89404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.47947999835014343, + "bbox": [ + 269.66802978515625, + 633.0128173828125, + 704.3484497070312, + 1049.5858154296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.28664639592170715, + "bbox": [ + 265.0177001953125, + 629.5206298828125, + 574.70654296875, + 1055.244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.1540307253599167, + "bbox": [ + 169.15061950683594, + 1783.506103515625, + 1328.599365234375, + 2202.476806640625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7761788964271545, + "bbox": [ + 266.99273681640625, + 1558.7828369140625, + 383.18426513671875, + 1656.45751953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7647627592086792, + "bbox": [ + 248.6532745361328, + 2730.1572265625, + 362.35321044921875, + 2825.101806640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.759023129940033, + "bbox": [ + 289.3776550292969, + 450.9398193359375, + 405.08209228515625, + 545.6597900390625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7449226379394531, + "bbox": [ + 1333.320556640625, + 2388.941162109375, + 1448.6380615234375, + 2494.62744140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7373238801956177, + "bbox": [ + 1364.1485595703125, + 465.3263244628906, + 1480.4686279296875, + 566.6741333007812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7221008539199829, + "bbox": [ + 2084.166259765625, + 2581.75927734375, + 2209.69580078125, + 2700.759521484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.643187940120697, + "bbox": [ + 1361.0081787109375, + 881.2794799804688, + 1458.28076171875, + 1000.9185791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254684925079346, + "bbox": [ + 867.2763671875, + 739.5374755859375, + 994.551513671875, + 858.9783935546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6105570793151855, + "bbox": [ + 838.1183471679688, + 3006.087890625, + 982.9075317382812, + 3151.343505859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.605405867099762, + "bbox": [ + 279.5609436035156, + 810.837158203125, + 382.6033935546875, + 927.8025512695312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6026655435562134, + "bbox": [ + 1798.0853271484375, + 1257.5687255859375, + 1942.20849609375, + 1399.855712890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5937169790267944, + "bbox": [ + 955.8529052734375, + 1969.0958251953125, + 1076.17431640625, + 2084.57373046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5857372283935547, + "bbox": [ + 2237.54296875, + 3322.159423828125, + 2328.824951171875, + 3397.091064453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5852604508399963, + "bbox": [ + 1326.194580078125, + 3076.443115234375, + 1413.85595703125, + 3207.711669921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5764795541763306, + "bbox": [ + 267.99298095703125, + 1752.395263671875, + 365.58203125, + 1882.5455322265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5486968755722046, + "bbox": [ + 243.95086669921875, + 2965.39697265625, + 320.57720947265625, + 3057.10791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4284059703350067, + "bbox": [ + 940.7259521484375, + 1959.599365234375, + 1101.253173828125, + 2112.238525390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3805253505706787, + "bbox": [ + 1331.4544677734375, + 3071.6142578125, + 1400.8343505859375, + 3188.0625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3261685073375702, + "bbox": [ + 858.0497436523438, + 733.5635986328125, + 1012.0326538085938, + 878.7215576171875 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9215754270553589, + "bbox": [ + 1314.7261962890625, + 2627.35546875, + 2341.076904296875, + 3300.589599609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9131869077682495, + "bbox": [ + 1289.9248046875, + 2345.0859375, + 2386.544921875, + 3362.467041015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.877517819404602, + "bbox": [ + 1309.8182373046875, + 424.8322448730469, + 2466.941162109375, + 1356.65625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8768096566200256, + "bbox": [ + 1349.5880126953125, + 705.5388793945312, + 2371.05224609375, + 1102.4268798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8741651773452759, + "bbox": [ + 181.15310668945312, + 395.4048156738281, + 1300.0750732421875, + 1241.311767578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8677266836166382, + "bbox": [ + 161.9854278564453, + 2660.0302734375, + 1284.8515625, + 3384.88525390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8651233315467834, + "bbox": [ + 229.70944213867188, + 1786.194091796875, + 958.8402709960938, + 2194.424072265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8435643315315247, + "bbox": [ + 162.44256591796875, + 1491.2109375, + 1303.119140625, + 2295.40087890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.842098593711853, + "bbox": [ + 216.950927734375, + 2894.42236328125, + 815.963134765625, + 3296.249267578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8274424076080322, + "bbox": [ + 1360.77197265625, + 570.7152099609375, + 2366.440185546875, + 702.28173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8246386647224426, + "bbox": [ + 239.35411071777344, + 1660.4132080078125, + 1292.6300048828125, + 1802.973388671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8238803744316101, + "bbox": [ + 1329.432861328125, + 2488.91064453125, + 2375.02880859375, + 2627.652099609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7948890328407288, + "bbox": [ + 295.4638366699219, + 538.1303100585938, + 1063.72265625, + 638.1751708984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7100364565849304, + "bbox": [ + 253.65850830078125, + 2817.990966796875, + 1219.7672119140625, + 2923.89404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.47947999835014343, + "bbox": [ + 269.66802978515625, + 633.0128173828125, + 704.3484497070312, + 1049.5858154296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.28664639592170715, + "bbox": [ + 265.0177001953125, + 629.5206298828125, + 574.70654296875, + 1055.244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.1540307253599167, + "bbox": [ + 169.15061950683594, + 1783.506103515625, + 1328.599365234375, + 2202.476806640625 + ] + } + ], + "timestamp": "2025-10-15T21:42:10.827434" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 3.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 3.json" new file mode 100644 index 0000000..7bca90f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 3.json" @@ -0,0 +1,758 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 3.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7696303725242615, + "bbox": [ + 223.0105743408203, + 1340.7686767578125, + 333.165771484375, + 1439.1741943359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7662075161933899, + "bbox": [ + 227.72108459472656, + 453.09716796875, + 341.2016296386719, + 557.6080932617188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491800785064697, + "bbox": [ + 1271.42578125, + 2272.972900390625, + 1384.8057861328125, + 2376.00341796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7473263144493103, + "bbox": [ + 213.26458740234375, + 2228.923828125, + 326.3470458984375, + 2332.885986328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7375100255012512, + "bbox": [ + 1284.90478515625, + 465.6437683105469, + 1391.51513671875, + 564.97607421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6880739331245422, + "bbox": [ + 1078.7891845703125, + 628.5864868164062, + 1185.00830078125, + 731.3709106445312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6850149631500244, + "bbox": [ + 1282.54833984375, + 2669.095458984375, + 1391.5721435546875, + 2772.88916015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6587640047073364, + "bbox": [ + 922.0879516601562, + 3183.639892578125, + 1056.18994140625, + 3320.46484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6501002907752991, + "bbox": [ + 1286.0626220703125, + 1248.363037109375, + 1391.0321044921875, + 1355.641845703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6441842317581177, + "bbox": [ + 1690.89990234375, + 1374.8173828125, + 1839.9354248046875, + 1525.0179443359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6410592794418335, + "bbox": [ + 873.2308959960938, + 2128.321533203125, + 1018.5245361328125, + 2266.60546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5732426047325134, + "bbox": [ + 1773.8692626953125, + 3221.498291015625, + 1907.4022216796875, + 3347.53515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.56553053855896, + "bbox": [ + 219.10939025878906, + 3265.025146484375, + 305.9117431640625, + 3339.4951171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5392040610313416, + "bbox": [ + 214.8755340576172, + 2011.581298828125, + 306.24462890625, + 2126.156494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5277695655822754, + "bbox": [ + 216.8645477294922, + 2937.44677734375, + 296.99237060546875, + 3037.490966796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5114830732345581, + "bbox": [ + 231.13966369628906, + 837.8092651367188, + 340.0629577636719, + 971.8974609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.944679856300354, + "bbox": [ + 1276.1063232421875, + 2602.904541015625, + 2303.22314453125, + 3250.145751953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9415110945701599, + "bbox": [ + 1283.3656005859375, + 799.0108642578125, + 2308.63525390625, + 1438.8958740234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9394901394844055, + "bbox": [ + 197.43211364746094, + 2558.8935546875, + 1190.1873779296875, + 3229.662109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9179395437240601, + "bbox": [ + 147.7063751220703, + 1289.9468994140625, + 1215.0191650390625, + 2329.81494140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9115380048751831, + "bbox": [ + 145.92544555664062, + 2201.862060546875, + 1218.2733154296875, + 3327.82568359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9063612222671509, + "bbox": [ + 210.1962432861328, + 680.5601196289062, + 1203.97314453125, + 1300.6231689453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8994267582893372, + "bbox": [ + 1246.04931640625, + 406.2789611816406, + 2393.520263671875, + 1609.38232421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8859707117080688, + "bbox": [ + 1220.1680908203125, + 2209.14404296875, + 2388.92529296875, + 3449.989990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8798978924751282, + "bbox": [ + 204.82620239257812, + 1565.3433837890625, + 1189.9580078125, + 2188.39892578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8601134419441223, + "bbox": [ + 1281.376708984375, + 565.7146606445312, + 2298.846435546875, + 702.8644409179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.825463593006134, + "bbox": [ + 213.14068603515625, + 546.3707885742188, + 1201.7559814453125, + 685.4963989257812 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8183915019035339, + "bbox": [ + 174.32371520996094, + 424.7967224121094, + 1209.0806884765625, + 1374.72216796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.807461678981781, + "bbox": [ + 192.3368377685547, + 1439.521728515625, + 1190.0751953125, + 1575.1380615234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7986094951629639, + "bbox": [ + 199.4864959716797, + 2458.625244140625, + 1223.9398193359375, + 2571.09912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7752985954284668, + "bbox": [ + 1243.1365966796875, + 2500.671142578125, + 2285.529052734375, + 2612.31689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7662193775177002, + "bbox": [ + 186.5366668701172, + 2328.260009765625, + 1199.236083984375, + 2468.15283203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7596904039382935, + "bbox": [ + 1243.0107421875, + 2366.3681640625, + 2287.01513671875, + 2507.69677734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6811506152153015, + "bbox": [ + 1278.707275390625, + 704.9971313476562, + 2293.896728515625, + 801.86767578125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7696303725242615, + "bbox": [ + 223.0105743408203, + 1340.7686767578125, + 333.165771484375, + 1439.1741943359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7662075161933899, + "bbox": [ + 227.72108459472656, + 453.09716796875, + 341.2016296386719, + 557.6080932617188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491800785064697, + "bbox": [ + 1271.42578125, + 2272.972900390625, + 1384.8057861328125, + 2376.00341796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7473263144493103, + "bbox": [ + 213.26458740234375, + 2228.923828125, + 326.3470458984375, + 2332.885986328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7375100255012512, + "bbox": [ + 1284.90478515625, + 465.6437683105469, + 1391.51513671875, + 564.97607421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6880739331245422, + "bbox": [ + 1078.7891845703125, + 628.5864868164062, + 1185.00830078125, + 731.3709106445312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6850149631500244, + "bbox": [ + 1282.54833984375, + 2669.095458984375, + 1391.5721435546875, + 2772.88916015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6587640047073364, + "bbox": [ + 922.0879516601562, + 3183.639892578125, + 1056.18994140625, + 3320.46484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6501002907752991, + "bbox": [ + 1286.0626220703125, + 1248.363037109375, + 1391.0321044921875, + 1355.641845703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6441842317581177, + "bbox": [ + 1690.89990234375, + 1374.8173828125, + 1839.9354248046875, + 1525.0179443359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6410592794418335, + "bbox": [ + 873.2308959960938, + 2128.321533203125, + 1018.5245361328125, + 2266.60546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5732426047325134, + "bbox": [ + 1773.8692626953125, + 3221.498291015625, + 1907.4022216796875, + 3347.53515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.56553053855896, + "bbox": [ + 219.10939025878906, + 3265.025146484375, + 305.9117431640625, + 3339.4951171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5392040610313416, + "bbox": [ + 214.8755340576172, + 2011.581298828125, + 306.24462890625, + 2126.156494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5277695655822754, + "bbox": [ + 216.8645477294922, + 2937.44677734375, + 296.99237060546875, + 3037.490966796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5114830732345581, + "bbox": [ + 231.13966369628906, + 837.8092651367188, + 340.0629577636719, + 971.8974609375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.944679856300354, + "bbox": [ + 1276.1063232421875, + 2602.904541015625, + 2303.22314453125, + 3250.145751953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9415110945701599, + "bbox": [ + 1283.3656005859375, + 799.0108642578125, + 2308.63525390625, + 1438.8958740234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9394901394844055, + "bbox": [ + 197.43211364746094, + 2558.8935546875, + 1190.1873779296875, + 3229.662109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9179395437240601, + "bbox": [ + 147.7063751220703, + 1289.9468994140625, + 1215.0191650390625, + 2329.81494140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9115380048751831, + "bbox": [ + 145.92544555664062, + 2201.862060546875, + 1218.2733154296875, + 3327.82568359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9063612222671509, + "bbox": [ + 210.1962432861328, + 680.5601196289062, + 1203.97314453125, + 1300.6231689453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8994267582893372, + "bbox": [ + 1246.04931640625, + 406.2789611816406, + 2393.520263671875, + 1609.38232421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8859707117080688, + "bbox": [ + 1220.1680908203125, + 2209.14404296875, + 2388.92529296875, + 3449.989990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8798978924751282, + "bbox": [ + 204.82620239257812, + 1565.3433837890625, + 1189.9580078125, + 2188.39892578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8601134419441223, + "bbox": [ + 1281.376708984375, + 565.7146606445312, + 2298.846435546875, + 702.8644409179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.825463593006134, + "bbox": [ + 213.14068603515625, + 546.3707885742188, + 1201.7559814453125, + 685.4963989257812 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8183915019035339, + "bbox": [ + 174.32371520996094, + 424.7967224121094, + 1209.0806884765625, + 1374.72216796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.807461678981781, + "bbox": [ + 192.3368377685547, + 1439.521728515625, + 1190.0751953125, + 1575.1380615234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7986094951629639, + "bbox": [ + 199.4864959716797, + 2458.625244140625, + 1223.9398193359375, + 2571.09912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7752985954284668, + "bbox": [ + 1243.1365966796875, + 2500.671142578125, + 2285.529052734375, + 2612.31689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7662193775177002, + "bbox": [ + 186.5366668701172, + 2328.260009765625, + 1199.236083984375, + 2468.15283203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7596904039382935, + "bbox": [ + 1243.0107421875, + 2366.3681640625, + 2287.01513671875, + 2507.69677734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6811506152153015, + "bbox": [ + 1278.707275390625, + 704.9971313476562, + 2293.896728515625, + 801.86767578125 + ] + } + ], + "timestamp": "2025-10-15T21:42:11.218001" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 4.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 4.json" new file mode 100644 index 0000000..8f95e31 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 4.json" @@ -0,0 +1,494 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 4.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7593793272972107, + "bbox": [ + 1347.364990234375, + 458.486328125, + 1456.197021484375, + 555.633056640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7393930554389954, + "bbox": [ + 254.23086547851562, + 1790.7158203125, + 370.2212829589844, + 1895.1822509765625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7369812726974487, + "bbox": [ + 274.3660888671875, + 570.5938110351562, + 389.0469970703125, + 674.4071655273438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7080551385879517, + "bbox": [ + 1799.5352783203125, + 2557.331298828125, + 1919.96630859375, + 2663.560791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254827976226807, + "bbox": [ + 936.06884765625, + 2071.2861328125, + 1065.16796875, + 2200.023681640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6220764517784119, + "bbox": [ + 1073.418701171875, + 1169.797119140625, + 1199.7271728515625, + 1290.4345703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5693151354789734, + "bbox": [ + 269.18743896484375, + 930.31689453125, + 357.8706970214844, + 1040.5709228515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.554220974445343, + "bbox": [ + 245.86785888671875, + 2032.929931640625, + 328.133056640625, + 2121.632080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5501797199249268, + "bbox": [ + 1320.8935546875, + 2633.862060546875, + 1436.4718017578125, + 2741.5361328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5383371710777283, + "bbox": [ + 2210.284423828125, + 3230.263427734375, + 2302.734375, + 3307.218017578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.29670441150665283, + "bbox": [ + 1059.0570068359375, + 1161.5684814453125, + 1215.7166748046875, + 1306.492919921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9127058386802673, + "bbox": [ + 1302.0462646484375, + 413.1278991699219, + 2370.060791015625, + 3094.311767578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9070683717727661, + "bbox": [ + 1315.893310546875, + 2617.87158203125, + 2293.95068359375, + 3042.982177734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8971260786056519, + "bbox": [ + 263.0885925292969, + 751.4413452148438, + 1202.0928955078125, + 1139.072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8688924908638, + "bbox": [ + 185.17428588867188, + 1737.710693359375, + 1256.1793212890625, + 2445.24169921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.851624608039856, + "bbox": [ + 222.6928253173828, + 517.2632446289062, + 1280.8424072265625, + 1273.4010009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8340811729431152, + "bbox": [ + 1347.1824951171875, + 664.0952758789062, + 2280.616943359375, + 2634.7421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8277298212051392, + "bbox": [ + 262.4835205078125, + 1978.341552734375, + 688.2744140625, + 2359.44091796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7881437540054321, + "bbox": [ + 1325.3629150390625, + 654.1343994140625, + 2250.82275390625, + 2619.892333984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7689452171325684, + "bbox": [ + 253.67236328125, + 1887.353515625, + 679.0177612304688, + 1981.14453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7652727961540222, + "bbox": [ + 1352.454345703125, + 552.654296875, + 1960.1392822265625, + 629.9302978515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7611307501792908, + "bbox": [ + 273.3910827636719, + 658.2020874023438, + 953.2110595703125, + 750.3832397460938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7593793272972107, + "bbox": [ + 1347.364990234375, + 458.486328125, + 1456.197021484375, + 555.633056640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7393930554389954, + "bbox": [ + 254.23086547851562, + 1790.7158203125, + 370.2212829589844, + 1895.1822509765625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7369812726974487, + "bbox": [ + 274.3660888671875, + 570.5938110351562, + 389.0469970703125, + 674.4071655273438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7080551385879517, + "bbox": [ + 1799.5352783203125, + 2557.331298828125, + 1919.96630859375, + 2663.560791015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254827976226807, + "bbox": [ + 936.06884765625, + 2071.2861328125, + 1065.16796875, + 2200.023681640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6220764517784119, + "bbox": [ + 1073.418701171875, + 1169.797119140625, + 1199.7271728515625, + 1290.4345703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5693151354789734, + "bbox": [ + 269.18743896484375, + 930.31689453125, + 357.8706970214844, + 1040.5709228515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.554220974445343, + "bbox": [ + 245.86785888671875, + 2032.929931640625, + 328.133056640625, + 2121.632080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5501797199249268, + "bbox": [ + 1320.8935546875, + 2633.862060546875, + 1436.4718017578125, + 2741.5361328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5383371710777283, + "bbox": [ + 2210.284423828125, + 3230.263427734375, + 2302.734375, + 3307.218017578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.29670441150665283, + "bbox": [ + 1059.0570068359375, + 1161.5684814453125, + 1215.7166748046875, + 1306.492919921875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9127058386802673, + "bbox": [ + 1302.0462646484375, + 413.1278991699219, + 2370.060791015625, + 3094.311767578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9070683717727661, + "bbox": [ + 1315.893310546875, + 2617.87158203125, + 2293.95068359375, + 3042.982177734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8971260786056519, + "bbox": [ + 263.0885925292969, + 751.4413452148438, + 1202.0928955078125, + 1139.072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8688924908638, + "bbox": [ + 185.17428588867188, + 1737.710693359375, + 1256.1793212890625, + 2445.24169921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.851624608039856, + "bbox": [ + 222.6928253173828, + 517.2632446289062, + 1280.8424072265625, + 1273.4010009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8340811729431152, + "bbox": [ + 1347.1824951171875, + 664.0952758789062, + 2280.616943359375, + 2634.7421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8277298212051392, + "bbox": [ + 262.4835205078125, + 1978.341552734375, + 688.2744140625, + 2359.44091796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7881437540054321, + "bbox": [ + 1325.3629150390625, + 654.1343994140625, + 2250.82275390625, + 2619.892333984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7689452171325684, + "bbox": [ + 253.67236328125, + 1887.353515625, + 679.0177612304688, + 1981.14453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7652727961540222, + "bbox": [ + 1352.454345703125, + 552.654296875, + 1960.1392822265625, + 629.9302978515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7611307501792908, + "bbox": [ + 273.3910827636719, + 658.2020874023438, + 953.2110595703125, + 750.3832397460938 + ] + } + ], + "timestamp": "2025-10-15T21:42:11.651538" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 5.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 5.json" new file mode 100644 index 0000000..db7262b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 5.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 5.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7677583694458008, + "bbox": [ + 1309.1417236328125, + 476.5721130371094, + 1423.04638671875, + 574.1433715820312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7445803880691528, + "bbox": [ + 232.48446655273438, + 444.83660888671875, + 349.1918029785156, + 550.8106079101562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6803035140037537, + "bbox": [ + 1892.2884521484375, + 455.7478942871094, + 2017.25048828125, + 571.4432983398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6526297926902771, + "bbox": [ + 682.3638916015625, + 440.0401916503906, + 798.8223876953125, + 545.22265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6018808484077454, + "bbox": [ + 1296.0684814453125, + 2323.622314453125, + 1414.938232421875, + 2443.17236328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5414398908615112, + "bbox": [ + 217.0548553466797, + 1971.12548828125, + 322.3581848144531, + 2097.5634765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.47217127680778503, + "bbox": [ + 206.21902465820312, + 3252.438232421875, + 305.44732666015625, + 3335.3701171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2633710205554962, + "bbox": [ + 1321.580810546875, + 2326.974609375, + 1431.3680419921875, + 2434.635009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9423269033432007, + "bbox": [ + 159.95005798339844, + 392.461181640625, + 1246.1182861328125, + 2458.410888671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9345859289169312, + "bbox": [ + 220.5947723388672, + 634.6386108398438, + 1224.0379638671875, + 1941.019775390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9333347082138062, + "bbox": [ + 1249.7689208984375, + 385.37322998046875, + 2483.005615234375, + 2679.53857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9279950857162476, + "bbox": [ + 1302.260986328125, + 658.0155639648438, + 2312.850830078125, + 2057.89892578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9021546840667725, + "bbox": [ + 1297.522216796875, + 2138.218505859375, + 2185.178466796875, + 2581.94921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8916960954666138, + "bbox": [ + 189.1916046142578, + 1971.70849609375, + 927.3601684570312, + 2439.37841796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8025267124176025, + "bbox": [ + 248.9623260498047, + 544.7317504882812, + 1006.8497924804688, + 650.1686401367188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6537009477615356, + "bbox": [ + 1307.2677001953125, + 570.594482421875, + 2108.395263671875, + 649.5535278320312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7677583694458008, + "bbox": [ + 1309.1417236328125, + 476.5721130371094, + 1423.04638671875, + 574.1433715820312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7445803880691528, + "bbox": [ + 232.48446655273438, + 444.83660888671875, + 349.1918029785156, + 550.8106079101562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6803035140037537, + "bbox": [ + 1892.2884521484375, + 455.7478942871094, + 2017.25048828125, + 571.4432983398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6526297926902771, + "bbox": [ + 682.3638916015625, + 440.0401916503906, + 798.8223876953125, + 545.22265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6018808484077454, + "bbox": [ + 1296.0684814453125, + 2323.622314453125, + 1414.938232421875, + 2443.17236328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5414398908615112, + "bbox": [ + 217.0548553466797, + 1971.12548828125, + 322.3581848144531, + 2097.5634765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.47217127680778503, + "bbox": [ + 206.21902465820312, + 3252.438232421875, + 305.44732666015625, + 3335.3701171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2633710205554962, + "bbox": [ + 1321.580810546875, + 2326.974609375, + 1431.3680419921875, + 2434.635009765625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9423269033432007, + "bbox": [ + 159.95005798339844, + 392.461181640625, + 1246.1182861328125, + 2458.410888671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9345859289169312, + "bbox": [ + 220.5947723388672, + 634.6386108398438, + 1224.0379638671875, + 1941.019775390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9333347082138062, + "bbox": [ + 1249.7689208984375, + 385.37322998046875, + 2483.005615234375, + 2679.53857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9279950857162476, + "bbox": [ + 1302.260986328125, + 658.0155639648438, + 2312.850830078125, + 2057.89892578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9021546840667725, + "bbox": [ + 1297.522216796875, + 2138.218505859375, + 2185.178466796875, + 2581.94921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8916960954666138, + "bbox": [ + 189.1916046142578, + 1971.70849609375, + 927.3601684570312, + 2439.37841796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8025267124176025, + "bbox": [ + 248.9623260498047, + 544.7317504882812, + 1006.8497924804688, + 650.1686401367188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6537009477615356, + "bbox": [ + 1307.2677001953125, + 570.594482421875, + 2108.395263671875, + 649.5535278320312 + ] + } + ], + "timestamp": "2025-10-15T21:42:12.098268" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 6.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 6.json" new file mode 100644 index 0000000..a8b404b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 6.json" @@ -0,0 +1,406 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 6.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7571845054626465, + "bbox": [ + 1313.30126953125, + 464.71612548828125, + 1424.9083251953125, + 561.0454711914062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7350559234619141, + "bbox": [ + 262.83905029296875, + 437.4698791503906, + 379.729736328125, + 542.3573608398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6520333290100098, + "bbox": [ + 970.9507446289062, + 585.08740234375, + 1093.125244140625, + 702.7413330078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6486397981643677, + "bbox": [ + 1930.1192626953125, + 561.3494262695312, + 2053.650634765625, + 677.8642578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6299466490745544, + "bbox": [ + 1306.043212890625, + 2428.884033203125, + 1390.3916015625, + 2542.085205078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6112711429595947, + "bbox": [ + 237.3245849609375, + 2861.85693359375, + 321.7109069824219, + 2980.896240234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5517489314079285, + "bbox": [ + 2167.4609375, + 3164.13330078125, + 2255.414794921875, + 3237.143310546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2684604823589325, + "bbox": [ + 2159.164794921875, + 3155.559814453125, + 2260.237060546875, + 3246.5224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2544725239276886, + "bbox": [ + 245.3154754638672, + 2883.34228515625, + 316.9403991699219, + 2977.80029296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467024207115173, + "bbox": [ + 238.3568572998047, + 676.183837890625, + 1227.1839599609375, + 2350.79443359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.940246045589447, + "bbox": [ + 1308.952392578125, + 655.6648559570312, + 2273.24462890625, + 2025.9876708984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.936847448348999, + "bbox": [ + 1298.7720947265625, + 2059.05419921875, + 2299.991943359375, + 2633.1015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9263525009155273, + "bbox": [ + 240.2953643798828, + 2356.212890625, + 1219.1119384765625, + 3084.733642578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9171763062477112, + "bbox": [ + 1261.8824462890625, + 382.80078125, + 2432.9248046875, + 2838.482177734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8951767086982727, + "bbox": [ + 201.87583923339844, + 486.3996276855469, + 1247.02880859375, + 3127.574951171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6817691922187805, + "bbox": [ + 1317.1446533203125, + 561.309814453125, + 1874.561767578125, + 632.3062744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6320798993110657, + "bbox": [ + 260.888916015625, + 538.5783081054688, + 1213.7655029296875, + 628.1819458007812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5868484377861023, + "bbox": [ + 235.7426300048828, + 534.1860961914062, + 1230.2391357421875, + 665.4102172851562 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7571845054626465, + "bbox": [ + 1313.30126953125, + 464.71612548828125, + 1424.9083251953125, + 561.0454711914062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7350559234619141, + "bbox": [ + 262.83905029296875, + 437.4698791503906, + 379.729736328125, + 542.3573608398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6520333290100098, + "bbox": [ + 970.9507446289062, + 585.08740234375, + 1093.125244140625, + 702.7413330078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6486397981643677, + "bbox": [ + 1930.1192626953125, + 561.3494262695312, + 2053.650634765625, + 677.8642578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6299466490745544, + "bbox": [ + 1306.043212890625, + 2428.884033203125, + 1390.3916015625, + 2542.085205078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6112711429595947, + "bbox": [ + 237.3245849609375, + 2861.85693359375, + 321.7109069824219, + 2980.896240234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5517489314079285, + "bbox": [ + 2167.4609375, + 3164.13330078125, + 2255.414794921875, + 3237.143310546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2684604823589325, + "bbox": [ + 2159.164794921875, + 3155.559814453125, + 2260.237060546875, + 3246.5224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2544725239276886, + "bbox": [ + 245.3154754638672, + 2883.34228515625, + 316.9403991699219, + 2977.80029296875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467024207115173, + "bbox": [ + 238.3568572998047, + 676.183837890625, + 1227.1839599609375, + 2350.79443359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.940246045589447, + "bbox": [ + 1308.952392578125, + 655.6648559570312, + 2273.24462890625, + 2025.9876708984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.936847448348999, + "bbox": [ + 1298.7720947265625, + 2059.05419921875, + 2299.991943359375, + 2633.1015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9263525009155273, + "bbox": [ + 240.2953643798828, + 2356.212890625, + 1219.1119384765625, + 3084.733642578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9171763062477112, + "bbox": [ + 1261.8824462890625, + 382.80078125, + 2432.9248046875, + 2838.482177734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8951767086982727, + "bbox": [ + 201.87583923339844, + 486.3996276855469, + 1247.02880859375, + 3127.574951171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6817691922187805, + "bbox": [ + 1317.1446533203125, + 561.309814453125, + 1874.561767578125, + 632.3062744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6320798993110657, + "bbox": [ + 260.888916015625, + 538.5783081054688, + 1213.7655029296875, + 628.1819458007812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5868484377861023, + "bbox": [ + 235.7426300048828, + 534.1860961914062, + 1230.2391357421875, + 665.4102172851562 + ] + } + ], + "timestamp": "2025-10-15T21:42:12.495402" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 7.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 7.json" new file mode 100644 index 0000000..02e6e3f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 7.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 7.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.768508791923523, + "bbox": [ + 1247.5631103515625, + 462.2471008300781, + 1356.5361328125, + 559.650634765625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7568119168281555, + "bbox": [ + 223.93572998046875, + 437.9396667480469, + 335.3740539550781, + 533.7636108398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.664227306842804, + "bbox": [ + 1834.0775146484375, + 550.6853637695312, + 1959.118408203125, + 668.3765258789062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6493028402328491, + "bbox": [ + 792.1515502929688, + 525.58544921875, + 893.7704467773438, + 618.6138916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5095422863960266, + "bbox": [ + 1229.560302734375, + 2101.49853515625, + 1346.4901123046875, + 2222.722900390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4846366047859192, + "bbox": [ + 199.53390502929688, + 3131.569091796875, + 292.33056640625, + 3208.297607421875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.46805378794670105, + "bbox": [ + 210.54933166503906, + 1810.613037109375, + 323.7799987792969, + 1946.4163818359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9541044235229492, + "bbox": [ + 1238.14501953125, + 2048.781982421875, + 2219.730712890625, + 2676.8095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9409392476081848, + "bbox": [ + 191.54071044921875, + 1819.2218017578125, + 1153.790771484375, + 2522.009521484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9364492893218994, + "bbox": [ + 1232.597412109375, + 644.2908325195312, + 2185.266845703125, + 2001.259765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9210805892944336, + "bbox": [ + 213.07896423339844, + 617.7672729492188, + 1167.1640625, + 1815.6981201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9201038479804993, + "bbox": [ + 1206.663330078125, + 420.39990234375, + 2236.200439453125, + 2742.793701171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9175267815589905, + "bbox": [ + 172.26583862304688, + 394.28033447265625, + 1181.0562744140625, + 2594.19970703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7276173830032349, + "bbox": [ + 225.4040985107422, + 525.8201904296875, + 760.7993774414062, + 613.4086303710938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6856730580329895, + "bbox": [ + 1251.57080078125, + 556.6467895507812, + 1805.6676025390625, + 627.0037231445312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.768508791923523, + "bbox": [ + 1247.5631103515625, + 462.2471008300781, + 1356.5361328125, + 559.650634765625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7568119168281555, + "bbox": [ + 223.93572998046875, + 437.9396667480469, + 335.3740539550781, + 533.7636108398438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.664227306842804, + "bbox": [ + 1834.0775146484375, + 550.6853637695312, + 1959.118408203125, + 668.3765258789062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6493028402328491, + "bbox": [ + 792.1515502929688, + 525.58544921875, + 893.7704467773438, + 618.6138916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5095422863960266, + "bbox": [ + 1229.560302734375, + 2101.49853515625, + 1346.4901123046875, + 2222.722900390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4846366047859192, + "bbox": [ + 199.53390502929688, + 3131.569091796875, + 292.33056640625, + 3208.297607421875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.46805378794670105, + "bbox": [ + 210.54933166503906, + 1810.613037109375, + 323.7799987792969, + 1946.4163818359375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9541044235229492, + "bbox": [ + 1238.14501953125, + 2048.781982421875, + 2219.730712890625, + 2676.8095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9409392476081848, + "bbox": [ + 191.54071044921875, + 1819.2218017578125, + 1153.790771484375, + 2522.009521484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9364492893218994, + "bbox": [ + 1232.597412109375, + 644.2908325195312, + 2185.266845703125, + 2001.259765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9210805892944336, + "bbox": [ + 213.07896423339844, + 617.7672729492188, + 1167.1640625, + 1815.6981201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9201038479804993, + "bbox": [ + 1206.663330078125, + 420.39990234375, + 2236.200439453125, + 2742.793701171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9175267815589905, + "bbox": [ + 172.26583862304688, + 394.28033447265625, + 1181.0562744140625, + 2594.19970703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7276173830032349, + "bbox": [ + 225.4040985107422, + 525.8201904296875, + 760.7993774414062, + 613.4086303710938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6856730580329895, + "bbox": [ + 1251.57080078125, + 556.6467895507812, + 1805.6676025390625, + 627.0037231445312 + ] + } + ], + "timestamp": "2025-10-15T21:42:12.889906" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 8.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 8.json" new file mode 100644 index 0000000..99a0500 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 8.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 8.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7626340985298157, + "bbox": [ + 1287.3861083984375, + 448.95611572265625, + 1399.5364990234375, + 547.1859130859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7594113349914551, + "bbox": [ + 259.8250427246094, + 430.52459716796875, + 372.1651611328125, + 524.6627197265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6873252987861633, + "bbox": [ + 1702.630859375, + 451.0979309082031, + 1819.9349365234375, + 559.7249145507812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6730852723121643, + "bbox": [ + 903.0289916992188, + 515.3897705078125, + 1025.6162109375, + 631.7552490234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5343709588050842, + "bbox": [ + 2146.871337890625, + 3132.63916015625, + 2231.72314453125, + 3203.087646484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5065203905105591, + "bbox": [ + 494.0369873046875, + 2468.900634765625, + 598.845703125, + 2592.79150390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47991713881492615, + "bbox": [ + 1275.1580810546875, + 2180.424072265625, + 1353.587646484375, + 2268.587646484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9354473352432251, + "bbox": [ + 1277.63916015625, + 680.4096069335938, + 2248.48828125, + 1977.952880859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9317852258682251, + "bbox": [ + 1249.241455078125, + 416.5291442871094, + 2371.324951171875, + 2593.223876953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9233621954917908, + "bbox": [ + 1285.1387939453125, + 1980.9615478515625, + 2258.741455078125, + 2454.271728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.921034574508667, + "bbox": [ + 237.45864868164062, + 604.6239013671875, + 1198.7724609375, + 2790.157958984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8704062104225159, + "bbox": [ + 188.7772979736328, + 403.77447509765625, + 1205.7091064453125, + 2973.708251953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8362190127372742, + "bbox": [ + 1291.685302734375, + 543.1148071289062, + 2253.18701171875, + 671.06103515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7847903966903687, + "bbox": [ + 257.5635986328125, + 523.8179321289062, + 867.9666137695312, + 606.8668212890625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7626340985298157, + "bbox": [ + 1287.3861083984375, + 448.95611572265625, + 1399.5364990234375, + 547.1859130859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7594113349914551, + "bbox": [ + 259.8250427246094, + 430.52459716796875, + 372.1651611328125, + 524.6627197265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6873252987861633, + "bbox": [ + 1702.630859375, + 451.0979309082031, + 1819.9349365234375, + 559.7249145507812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6730852723121643, + "bbox": [ + 903.0289916992188, + 515.3897705078125, + 1025.6162109375, + 631.7552490234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5343709588050842, + "bbox": [ + 2146.871337890625, + 3132.63916015625, + 2231.72314453125, + 3203.087646484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5065203905105591, + "bbox": [ + 494.0369873046875, + 2468.900634765625, + 598.845703125, + 2592.79150390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47991713881492615, + "bbox": [ + 1275.1580810546875, + 2180.424072265625, + 1353.587646484375, + 2268.587646484375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9354473352432251, + "bbox": [ + 1277.63916015625, + 680.4096069335938, + 2248.48828125, + 1977.952880859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9317852258682251, + "bbox": [ + 1249.241455078125, + 416.5291442871094, + 2371.324951171875, + 2593.223876953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9233621954917908, + "bbox": [ + 1285.1387939453125, + 1980.9615478515625, + 2258.741455078125, + 2454.271728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.921034574508667, + "bbox": [ + 237.45864868164062, + 604.6239013671875, + 1198.7724609375, + 2790.157958984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8704062104225159, + "bbox": [ + 188.7772979736328, + 403.77447509765625, + 1205.7091064453125, + 2973.708251953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8362190127372742, + "bbox": [ + 1291.685302734375, + 543.1148071289062, + 2253.18701171875, + 671.06103515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7847903966903687, + "bbox": [ + 257.5635986328125, + 523.8179321289062, + 867.9666137695312, + 606.8668212890625 + ] + } + ], + "timestamp": "2025-10-15T21:42:13.290779" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 9.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 9.json" new file mode 100644 index 0000000..e3acb45 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 5\355\232\214 - 9.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ 5แ„’แ…ฌ - 9.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7508177757263184, + "bbox": [ + 1173.4302978515625, + 425.2012939453125, + 1279.53125, + 514.1151733398438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7502933740615845, + "bbox": [ + 210.20669555664062, + 403.5700378417969, + 319.5332336425781, + 495.5364074707031 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6541925668716431, + "bbox": [ + 430.15576171875, + 398.63671875, + 552.0100708007812, + 514.6303100585938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6131829023361206, + "bbox": [ + 1551.9039306640625, + 402.5128479003906, + 1686.8448486328125, + 528.0980224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6118751168251038, + "bbox": [ + 1151.0018310546875, + 2709.41552734375, + 1222.4666748046875, + 2790.322509765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49283769726753235, + "bbox": [ + 191.50885009765625, + 2584.095947265625, + 264.8513488769531, + 2669.792236328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.42905670404434204, + "bbox": [ + 191.80838012695312, + 2918.882568359375, + 278.0151062011719, + 2989.57421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9661281704902649, + "bbox": [ + 188.98069763183594, + 599.98193359375, + 1078.7130126953125, + 2446.7841796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9403825998306274, + "bbox": [ + 1159.5589599609375, + 624.0, + 2042.2353515625, + 2404.83056640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9308292269706726, + "bbox": [ + 1151.96142578125, + 2414.4365234375, + 2050.163330078125, + 2832.35546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9123905301094055, + "bbox": [ + 152.0648956298828, + 369.7189025878906, + 1102.7684326171875, + 2821.31396484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9080262780189514, + "bbox": [ + 185.9227294921875, + 2474.90283203125, + 986.0703735351562, + 2802.582763671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8346694111824036, + "bbox": [ + 1140.543701171875, + 450.7506408691406, + 2096.47900390625, + 2896.9814453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7973261475563049, + "bbox": [ + 1138.9320068359375, + 518.4557495117188, + 2072.438232421875, + 645.1550903320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7943465113639832, + "bbox": [ + 208.7053985595703, + 494.49334716796875, + 1100.00732421875, + 610.1264038085938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7508177757263184, + "bbox": [ + 1173.4302978515625, + 425.2012939453125, + 1279.53125, + 514.1151733398438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7502933740615845, + "bbox": [ + 210.20669555664062, + 403.5700378417969, + 319.5332336425781, + 495.5364074707031 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6541925668716431, + "bbox": [ + 430.15576171875, + 398.63671875, + 552.0100708007812, + 514.6303100585938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6131829023361206, + "bbox": [ + 1551.9039306640625, + 402.5128479003906, + 1686.8448486328125, + 528.0980224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6118751168251038, + "bbox": [ + 1151.0018310546875, + 2709.41552734375, + 1222.4666748046875, + 2790.322509765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49283769726753235, + "bbox": [ + 191.50885009765625, + 2584.095947265625, + 264.8513488769531, + 2669.792236328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.42905670404434204, + "bbox": [ + 191.80838012695312, + 2918.882568359375, + 278.0151062011719, + 2989.57421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9661281704902649, + "bbox": [ + 188.98069763183594, + 599.98193359375, + 1078.7130126953125, + 2446.7841796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9403825998306274, + "bbox": [ + 1159.5589599609375, + 624.0, + 2042.2353515625, + 2404.83056640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9308292269706726, + "bbox": [ + 1151.96142578125, + 2414.4365234375, + 2050.163330078125, + 2832.35546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9123905301094055, + "bbox": [ + 152.0648956298828, + 369.7189025878906, + 1102.7684326171875, + 2821.31396484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9080262780189514, + "bbox": [ + 185.9227294921875, + 2474.90283203125, + 986.0703735351562, + 2802.582763671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8346694111824036, + "bbox": [ + 1140.543701171875, + 450.7506408691406, + 2096.47900390625, + 2896.9814453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7973261475563049, + "bbox": [ + 1138.9320068359375, + 518.4557495117188, + 2072.438232421875, + 645.1550903320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7943465113639832, + "bbox": [ + 208.7053985595703, + 494.49334716796875, + 1100.00732421875, + 610.1264038085938 + ] + } + ], + "timestamp": "2025-10-15T21:42:13.661800" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 18.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 18.json" new file mode 100644 index 0000000..b2c26ff --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 18.json" @@ -0,0 +1,604 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 18.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7988360524177551, + "bbox": [ + 266.6395568847656, + 1754.8955078125, + 373.715087890625, + 1844.17041015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7963445782661438, + "bbox": [ + 1283.26123046875, + 2528.410888671875, + 1389.3795166015625, + 2619.096435546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7702808976173401, + "bbox": [ + 274.08935546875, + 990.58251953125, + 381.21746826171875, + 1085.0325927734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7555468082427979, + "bbox": [ + 1305.8837890625, + 511.416259765625, + 1408.949951171875, + 597.9923095703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7506996989250183, + "bbox": [ + 256.30889892578125, + 2575.3828125, + 360.0710144042969, + 2663.868408203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7245441675186157, + "bbox": [ + 1115.3079833984375, + 1888.2401123046875, + 1220.9700927734375, + 1994.5009765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.686287522315979, + "bbox": [ + 1006.14990234375, + 1182.5496826171875, + 1123.58154296875, + 1306.7569580078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6843833327293396, + "bbox": [ + 1915.1468505859375, + 2777.469970703125, + 2034.399658203125, + 2895.901611328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6344283223152161, + "bbox": [ + 1001.7526245117188, + 2786.904296875, + 1135.7393798828125, + 2915.542724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.615765392780304, + "bbox": [ + 1957.02587890625, + 1497.703369140625, + 2077.727783203125, + 1607.6060791015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5685915350914001, + "bbox": [ + 2138.949462890625, + 3133.7744140625, + 2230.209228515625, + 3208.52392578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9179354310035706, + "bbox": [ + 271.85992431640625, + 1938.2440185546875, + 1221.231689453125, + 2385.56201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9134776592254639, + "bbox": [ + 1244.6807861328125, + 469.7906188964844, + 2331.485595703125, + 1646.0828857421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9090062975883484, + "bbox": [ + 273.423828125, + 1222.642822265625, + 1067.2857666015625, + 1594.5966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9042997360229492, + "bbox": [ + 250.50770568847656, + 966.7921142578125, + 1254.7012939453125, + 1630.1319580078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8994130492210388, + "bbox": [ + 1286.73583984375, + 2752.8662109375, + 1684.2568359375, + 3114.019775390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8972051739692688, + "bbox": [ + 223.91647338867188, + 1711.00634765625, + 1255.7548828125, + 2426.257568359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8915121555328369, + "bbox": [ + 1244.8941650390625, + 2486.52978515625, + 2299.283935546875, + 3144.2822265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8828334808349609, + "bbox": [ + 207.23873901367188, + 2525.793212890625, + 1216.218505859375, + 3169.38037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8537259697914124, + "bbox": [ + 263.0040283203125, + 2737.02783203125, + 840.6228637695312, + 3097.193359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8298918008804321, + "bbox": [ + 1287.2052001953125, + 2616.00537109375, + 2243.275634765625, + 2747.1064453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8149411082267761, + "bbox": [ + 272.720947265625, + 1084.46875, + 1211.900146484375, + 1209.084228515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.801225483417511, + "bbox": [ + 1309.4150390625, + 606.8284301757812, + 2242.110595703125, + 679.174560546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7463299036026001, + "bbox": [ + 1327.240234375, + 690.3548583984375, + 2201.543701171875, + 1412.5960693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7393862009048462, + "bbox": [ + 260.7271423339844, + 2666.3134765625, + 1170.4888916015625, + 2746.1376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6692609786987305, + "bbox": [ + 254.0052490234375, + 1843.247802734375, + 1121.131103515625, + 1937.787841796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5282578468322754, + "bbox": [ + 258.3882751464844, + 1858.23583984375, + 1143.9510498046875, + 1921.92919921875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7988360524177551, + "bbox": [ + 266.6395568847656, + 1754.8955078125, + 373.715087890625, + 1844.17041015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7963445782661438, + "bbox": [ + 1283.26123046875, + 2528.410888671875, + 1389.3795166015625, + 2619.096435546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7702808976173401, + "bbox": [ + 274.08935546875, + 990.58251953125, + 381.21746826171875, + 1085.0325927734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7555468082427979, + "bbox": [ + 1305.8837890625, + 511.416259765625, + 1408.949951171875, + 597.9923095703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7506996989250183, + "bbox": [ + 256.30889892578125, + 2575.3828125, + 360.0710144042969, + 2663.868408203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7245441675186157, + "bbox": [ + 1115.3079833984375, + 1888.2401123046875, + 1220.9700927734375, + 1994.5009765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.686287522315979, + "bbox": [ + 1006.14990234375, + 1182.5496826171875, + 1123.58154296875, + 1306.7569580078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6843833327293396, + "bbox": [ + 1915.1468505859375, + 2777.469970703125, + 2034.399658203125, + 2895.901611328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6344283223152161, + "bbox": [ + 1001.7526245117188, + 2786.904296875, + 1135.7393798828125, + 2915.542724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.615765392780304, + "bbox": [ + 1957.02587890625, + 1497.703369140625, + 2077.727783203125, + 1607.6060791015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5685915350914001, + "bbox": [ + 2138.949462890625, + 3133.7744140625, + 2230.209228515625, + 3208.52392578125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9179354310035706, + "bbox": [ + 271.85992431640625, + 1938.2440185546875, + 1221.231689453125, + 2385.56201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9134776592254639, + "bbox": [ + 1244.6807861328125, + 469.7906188964844, + 2331.485595703125, + 1646.0828857421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9090062975883484, + "bbox": [ + 273.423828125, + 1222.642822265625, + 1067.2857666015625, + 1594.5966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9042997360229492, + "bbox": [ + 250.50770568847656, + 966.7921142578125, + 1254.7012939453125, + 1630.1319580078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8994130492210388, + "bbox": [ + 1286.73583984375, + 2752.8662109375, + 1684.2568359375, + 3114.019775390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8972051739692688, + "bbox": [ + 223.91647338867188, + 1711.00634765625, + 1255.7548828125, + 2426.257568359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8915121555328369, + "bbox": [ + 1244.8941650390625, + 2486.52978515625, + 2299.283935546875, + 3144.2822265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8828334808349609, + "bbox": [ + 207.23873901367188, + 2525.793212890625, + 1216.218505859375, + 3169.38037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8537259697914124, + "bbox": [ + 263.0040283203125, + 2737.02783203125, + 840.6228637695312, + 3097.193359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8298918008804321, + "bbox": [ + 1287.2052001953125, + 2616.00537109375, + 2243.275634765625, + 2747.1064453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8149411082267761, + "bbox": [ + 272.720947265625, + 1084.46875, + 1211.900146484375, + 1209.084228515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.801225483417511, + "bbox": [ + 1309.4150390625, + 606.8284301757812, + 2242.110595703125, + 679.174560546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7463299036026001, + "bbox": [ + 1327.240234375, + 690.3548583984375, + 2201.543701171875, + 1412.5960693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7393862009048462, + "bbox": [ + 260.7271423339844, + 2666.3134765625, + 1170.4888916015625, + 2746.1376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6692609786987305, + "bbox": [ + 254.0052490234375, + 1843.247802734375, + 1121.131103515625, + 1937.787841796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5282578468322754, + "bbox": [ + 258.3882751464844, + 1858.23583984375, + 1143.9510498046875, + 1921.92919921875 + ] + } + ], + "timestamp": "2025-10-15T21:42:14.012404" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 19.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 19.json" new file mode 100644 index 0000000..42bde12 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 19.json" @@ -0,0 +1,582 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 19.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7799789309501648, + "bbox": [ + 236.42135620117188, + 1491.102294921875, + 346.84930419921875, + 1585.6771240234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7617189288139343, + "bbox": [ + 219.2086181640625, + 2599.630126953125, + 330.7776184082031, + 2693.552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7551347613334656, + "bbox": [ + 251.35203552246094, + 440.0579833984375, + 364.3329772949219, + 534.511474609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7518501877784729, + "bbox": [ + 1274.0404052734375, + 2212.56005859375, + 1381.7314453125, + 2311.947021484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7396827340126038, + "bbox": [ + 1293.3111572265625, + 453.1151123046875, + 1408.1446533203125, + 547.0521240234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6511649489402771, + "bbox": [ + 998.819580078125, + 770.4944458007812, + 1127.314453125, + 898.8392333984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6420676708221436, + "bbox": [ + 901.3938598632812, + 2811.18603515625, + 1026.1092529296875, + 2942.670166015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6324604153633118, + "bbox": [ + 2007.9033203125, + 2409.888671875, + 2142.704833984375, + 2538.485107421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6264545321464539, + "bbox": [ + 940.5663452148438, + 1737.189208984375, + 1051.1849365234375, + 1845.5775146484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5935935974121094, + "bbox": [ + 1875.8968505859375, + 1064.6754150390625, + 2011.4327392578125, + 1199.8419189453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5061771273612976, + "bbox": [ + 218.67897033691406, + 3213.110595703125, + 309.2133483886719, + 3287.694091796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9349602460861206, + "bbox": [ + 195.1258087158203, + 2568.223388671875, + 1223.3797607421875, + 3204.415283203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9268251061439514, + "bbox": [ + 1274.4261474609375, + 2460.904296875, + 2240.489501953125, + 3223.320068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9231505393981934, + "bbox": [ + 1234.6695556640625, + 2191.095947265625, + 2284.1259765625, + 3254.711181640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898586630821228, + "bbox": [ + 241.22059631347656, + 1720.695068359375, + 768.417724609375, + 2097.063232421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8870161771774292, + "bbox": [ + 1294.296875, + 679.7814331054688, + 2282.68994140625, + 1039.0560302734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8789583444595337, + "bbox": [ + 195.89320373535156, + 1455.388427734375, + 1231.9229736328125, + 2160.877197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8771510720252991, + "bbox": [ + 218.3375244140625, + 421.7557067871094, + 1234.836181640625, + 1053.59765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8507099151611328, + "bbox": [ + 1278.712158203125, + 2307.6796875, + 2245.715087890625, + 2441.8017578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8405901193618774, + "bbox": [ + 220.95501708984375, + 2844.141357421875, + 488.1539001464844, + 3193.809814453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8051720261573792, + "bbox": [ + 1285.1673583984375, + 553.9171142578125, + 2265.085205078125, + 681.0060424804688 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7984182238578796, + "bbox": [ + 1257.0264892578125, + 406.44512939453125, + 2346.2001953125, + 1269.261474609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7960759401321411, + "bbox": [ + 233.32398986816406, + 2697.144287109375, + 1179.4000244140625, + 2818.571533203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7676852345466614, + "bbox": [ + 249.72409057617188, + 529.163330078125, + 1009.7285766601562, + 615.5933837890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7640076279640198, + "bbox": [ + 237.64263916015625, + 1589.1578369140625, + 1209.8028564453125, + 1719.4000244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7280345559120178, + "bbox": [ + 250.7264862060547, + 615.6535034179688, + 467.1109313964844, + 988.835205078125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7799789309501648, + "bbox": [ + 236.42135620117188, + 1491.102294921875, + 346.84930419921875, + 1585.6771240234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7617189288139343, + "bbox": [ + 219.2086181640625, + 2599.630126953125, + 330.7776184082031, + 2693.552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7551347613334656, + "bbox": [ + 251.35203552246094, + 440.0579833984375, + 364.3329772949219, + 534.511474609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7518501877784729, + "bbox": [ + 1274.0404052734375, + 2212.56005859375, + 1381.7314453125, + 2311.947021484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7396827340126038, + "bbox": [ + 1293.3111572265625, + 453.1151123046875, + 1408.1446533203125, + 547.0521240234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6511649489402771, + "bbox": [ + 998.819580078125, + 770.4944458007812, + 1127.314453125, + 898.8392333984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6420676708221436, + "bbox": [ + 901.3938598632812, + 2811.18603515625, + 1026.1092529296875, + 2942.670166015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6324604153633118, + "bbox": [ + 2007.9033203125, + 2409.888671875, + 2142.704833984375, + 2538.485107421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6264545321464539, + "bbox": [ + 940.5663452148438, + 1737.189208984375, + 1051.1849365234375, + 1845.5775146484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5935935974121094, + "bbox": [ + 1875.8968505859375, + 1064.6754150390625, + 2011.4327392578125, + 1199.8419189453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5061771273612976, + "bbox": [ + 218.67897033691406, + 3213.110595703125, + 309.2133483886719, + 3287.694091796875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9349602460861206, + "bbox": [ + 195.1258087158203, + 2568.223388671875, + 1223.3797607421875, + 3204.415283203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9268251061439514, + "bbox": [ + 1274.4261474609375, + 2460.904296875, + 2240.489501953125, + 3223.320068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9231505393981934, + "bbox": [ + 1234.6695556640625, + 2191.095947265625, + 2284.1259765625, + 3254.711181640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898586630821228, + "bbox": [ + 241.22059631347656, + 1720.695068359375, + 768.417724609375, + 2097.063232421875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8870161771774292, + "bbox": [ + 1294.296875, + 679.7814331054688, + 2282.68994140625, + 1039.0560302734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8789583444595337, + "bbox": [ + 195.89320373535156, + 1455.388427734375, + 1231.9229736328125, + 2160.877197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8771510720252991, + "bbox": [ + 218.3375244140625, + 421.7557067871094, + 1234.836181640625, + 1053.59765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8507099151611328, + "bbox": [ + 1278.712158203125, + 2307.6796875, + 2245.715087890625, + 2441.8017578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8405901193618774, + "bbox": [ + 220.95501708984375, + 2844.141357421875, + 488.1539001464844, + 3193.809814453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8051720261573792, + "bbox": [ + 1285.1673583984375, + 553.9171142578125, + 2265.085205078125, + 681.0060424804688 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7984182238578796, + "bbox": [ + 1257.0264892578125, + 406.44512939453125, + 2346.2001953125, + 1269.261474609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7960759401321411, + "bbox": [ + 233.32398986816406, + 2697.144287109375, + 1179.4000244140625, + 2818.571533203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7676852345466614, + "bbox": [ + 249.72409057617188, + 529.163330078125, + 1009.7285766601562, + 615.5933837890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7640076279640198, + "bbox": [ + 237.64263916015625, + 1589.1578369140625, + 1209.8028564453125, + 1719.4000244140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7280345559120178, + "bbox": [ + 250.7264862060547, + 615.6535034179688, + 467.1109313964844, + 988.835205078125 + ] + } + ], + "timestamp": "2025-10-15T21:42:14.360057" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 20.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 20.json" new file mode 100644 index 0000000..a2a4828 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 20.json" @@ -0,0 +1,670 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 20.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7617335915565491, + "bbox": [ + 235.94976806640625, + 1260.341552734375, + 342.07373046875, + 1358.637451171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.754991888999939, + "bbox": [ + 1227.7032470703125, + 439.0233459472656, + 1325.92724609375, + 534.3587646484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7475954294204712, + "bbox": [ + 228.6622772216797, + 2149.2431640625, + 331.0436096191406, + 2244.65673828125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.74605792760849, + "bbox": [ + 240.94383239746094, + 422.1424865722656, + 350.65338134765625, + 522.3436279296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.743106484413147, + "bbox": [ + 1008.3516845703125, + 1509.3255615234375, + 1097.95556640625, + 1610.0994873046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7280753254890442, + "bbox": [ + 1192.5535888671875, + 2321.738037109375, + 1303.6005859375, + 2422.66259765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7185413241386414, + "bbox": [ + 969.41455078125, + 2311.23828125, + 1072.1761474609375, + 2413.27392578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7015545964241028, + "bbox": [ + 1728.59228515625, + 2488.443603515625, + 1843.6575927734375, + 2602.124267578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6297272443771362, + "bbox": [ + 1671.8656005859375, + 1327.094970703125, + 1820.1619873046875, + 1466.4781494140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5902140140533447, + "bbox": [ + 864.98388671875, + 1070.56982421875, + 989.6040649414062, + 1198.7467041015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.581495463848114, + "bbox": [ + 2017.960693359375, + 3083.11376953125, + 2102.345947265625, + 3154.111572265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.44387584924697876, + "bbox": [ + 846.072021484375, + 1063.55517578125, + 1006.9411010742188, + 1216.497314453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9463142156600952, + "bbox": [ + 1212.622802734375, + 758.8275756835938, + 2160.294921875, + 1345.31591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9395202398300171, + "bbox": [ + 212.90879821777344, + 2471.366455078125, + 1130.6544189453125, + 3052.173095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.928021252155304, + "bbox": [ + 240.60340881347656, + 663.1104736328125, + 1084.81103515625, + 1016.5341186523438 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9256405234336853, + "bbox": [ + 1177.194091796875, + 2277.396484375, + 2199.388671875, + 3101.75537109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9166426062583923, + "bbox": [ + 1187.6693115234375, + 2654.62646484375, + 2140.08056640625, + 3071.5703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9090909957885742, + "bbox": [ + 154.2684326171875, + 2103.26220703125, + 1143.5704345703125, + 3115.939208984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9054855108261108, + "bbox": [ + 1205.798828125, + 386.1014404296875, + 2212.686279296875, + 1472.979248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898865818977356, + "bbox": [ + 248.88893127441406, + 1503.84423828125, + 1055.734619140625, + 1829.50634765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8959977030754089, + "bbox": [ + 1230.666748046875, + 535.18017578125, + 2149.8388671875, + 661.29052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8847728371620178, + "bbox": [ + 198.6621856689453, + 402.3240051269531, + 1187.515380859375, + 1058.36328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8811056017875671, + "bbox": [ + 213.63111877441406, + 1237.2928466796875, + 1146.5460205078125, + 1873.2451171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8396086096763611, + "bbox": [ + 228.85977172851562, + 525.4508666992188, + 1150.05810546875, + 647.6519165039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8098872303962708, + "bbox": [ + 1181.025390625, + 2419.885986328125, + 2140.873779296875, + 2545.842041015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8017297387123108, + "bbox": [ + 207.6827392578125, + 2246.136962890625, + 1117.052001953125, + 2369.760009765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7889149785041809, + "bbox": [ + 222.326416015625, + 1354.453125, + 1153.2178955078125, + 1478.2025146484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7090023756027222, + "bbox": [ + 1179.7125244140625, + 2553.3095703125, + 2135.983154296875, + 2639.6474609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6691240072250366, + "bbox": [ + 208.31613159179688, + 2379.58251953125, + 1103.410888671875, + 2471.18408203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6041886806488037, + "bbox": [ + 1207.4659423828125, + 652.74072265625, + 2144.13134765625, + 761.5387573242188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7617335915565491, + "bbox": [ + 235.94976806640625, + 1260.341552734375, + 342.07373046875, + 1358.637451171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.754991888999939, + "bbox": [ + 1227.7032470703125, + 439.0233459472656, + 1325.92724609375, + 534.3587646484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7475954294204712, + "bbox": [ + 228.6622772216797, + 2149.2431640625, + 331.0436096191406, + 2244.65673828125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.74605792760849, + "bbox": [ + 240.94383239746094, + 422.1424865722656, + 350.65338134765625, + 522.3436279296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.743106484413147, + "bbox": [ + 1008.3516845703125, + 1509.3255615234375, + 1097.95556640625, + 1610.0994873046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7280753254890442, + "bbox": [ + 1192.5535888671875, + 2321.738037109375, + 1303.6005859375, + 2422.66259765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7185413241386414, + "bbox": [ + 969.41455078125, + 2311.23828125, + 1072.1761474609375, + 2413.27392578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7015545964241028, + "bbox": [ + 1728.59228515625, + 2488.443603515625, + 1843.6575927734375, + 2602.124267578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6297272443771362, + "bbox": [ + 1671.8656005859375, + 1327.094970703125, + 1820.1619873046875, + 1466.4781494140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5902140140533447, + "bbox": [ + 864.98388671875, + 1070.56982421875, + 989.6040649414062, + 1198.7467041015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.581495463848114, + "bbox": [ + 2017.960693359375, + 3083.11376953125, + 2102.345947265625, + 3154.111572265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.44387584924697876, + "bbox": [ + 846.072021484375, + 1063.55517578125, + 1006.9411010742188, + 1216.497314453125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9463142156600952, + "bbox": [ + 1212.622802734375, + 758.8275756835938, + 2160.294921875, + 1345.31591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9395202398300171, + "bbox": [ + 212.90879821777344, + 2471.366455078125, + 1130.6544189453125, + 3052.173095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.928021252155304, + "bbox": [ + 240.60340881347656, + 663.1104736328125, + 1084.81103515625, + 1016.5341186523438 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9256405234336853, + "bbox": [ + 1177.194091796875, + 2277.396484375, + 2199.388671875, + 3101.75537109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9166426062583923, + "bbox": [ + 1187.6693115234375, + 2654.62646484375, + 2140.08056640625, + 3071.5703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9090909957885742, + "bbox": [ + 154.2684326171875, + 2103.26220703125, + 1143.5704345703125, + 3115.939208984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9054855108261108, + "bbox": [ + 1205.798828125, + 386.1014404296875, + 2212.686279296875, + 1472.979248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898865818977356, + "bbox": [ + 248.88893127441406, + 1503.84423828125, + 1055.734619140625, + 1829.50634765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8959977030754089, + "bbox": [ + 1230.666748046875, + 535.18017578125, + 2149.8388671875, + 661.29052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8847728371620178, + "bbox": [ + 198.6621856689453, + 402.3240051269531, + 1187.515380859375, + 1058.36328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8811056017875671, + "bbox": [ + 213.63111877441406, + 1237.2928466796875, + 1146.5460205078125, + 1873.2451171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8396086096763611, + "bbox": [ + 228.85977172851562, + 525.4508666992188, + 1150.05810546875, + 647.6519165039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8098872303962708, + "bbox": [ + 1181.025390625, + 2419.885986328125, + 2140.873779296875, + 2545.842041015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8017297387123108, + "bbox": [ + 207.6827392578125, + 2246.136962890625, + 1117.052001953125, + 2369.760009765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7889149785041809, + "bbox": [ + 222.326416015625, + 1354.453125, + 1153.2178955078125, + 1478.2025146484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7090023756027222, + "bbox": [ + 1179.7125244140625, + 2553.3095703125, + 2135.983154296875, + 2639.6474609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6691240072250366, + "bbox": [ + 208.31613159179688, + 2379.58251953125, + 1103.410888671875, + 2471.18408203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.6041886806488037, + "bbox": [ + 1207.4659423828125, + 652.74072265625, + 2144.13134765625, + 761.5387573242188 + ] + } + ], + "timestamp": "2025-10-15T21:42:14.703251" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 21.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 21.json" new file mode 100644 index 0000000..ec1a163 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 21.json" @@ -0,0 +1,428 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 21.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7609845399856567, + "bbox": [ + 1265.4761962890625, + 460.44146728515625, + 1372.72998046875, + 553.6536865234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7520913481712341, + "bbox": [ + 232.48519897460938, + 578.6051635742188, + 338.0008544921875, + 676.820556640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7501529455184937, + "bbox": [ + 222.1729736328125, + 1845.4884033203125, + 335.4812316894531, + 1948.3370361328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.684562087059021, + "bbox": [ + 805.4273071289062, + 2136.070556640625, + 917.5810546875, + 2245.9453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6613016128540039, + "bbox": [ + 2072.452392578125, + 2524.58740234375, + 2202.64990234375, + 2655.87548828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6394456624984741, + "bbox": [ + 903.0519409179688, + 1262.8487548828125, + 1025.203369140625, + 1389.733154296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5251138806343079, + "bbox": [ + 226.74554443359375, + 3196.202392578125, + 315.4188537597656, + 3265.424072265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3338477909564972, + "bbox": [ + 217.36712646484375, + 3186.787841796875, + 318.413818359375, + 3276.339599609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9344406127929688, + "bbox": [ + 217.66490173339844, + 759.3243408203125, + 1202.80224609375, + 1231.4263916015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267095327377319, + "bbox": [ + 1224.459228515625, + 415.92987060546875, + 2270.26220703125, + 2983.034912109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8998392820358276, + "bbox": [ + 1260.04150390625, + 2516.952392578125, + 2157.68115234375, + 2867.141845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8952497243881226, + "bbox": [ + 213.6790008544922, + 2037.1563720703125, + 619.2114868164062, + 2406.072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8887794613838196, + "bbox": [ + 178.48138427734375, + 1810.49560546875, + 1199.16845703125, + 2447.0244140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8719655871391296, + "bbox": [ + 165.6348876953125, + 537.3223266601562, + 1238.2332763671875, + 1326.4775390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8273245692253113, + "bbox": [ + 1256.1771240234375, + 642.2066650390625, + 2189.99853515625, + 2532.552490234375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7313070893287659, + "bbox": [ + 1271.173095703125, + 550.31201171875, + 1850.9947509765625, + 629.716552734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6807247996330261, + "bbox": [ + 227.22056579589844, + 671.637939453125, + 879.6678466796875, + 747.79052734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5922560691833496, + "bbox": [ + 222.93804931640625, + 1951.6728515625, + 635.1351928710938, + 2017.148681640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.14023226499557495, + "bbox": [ + 1239.450439453125, + 572.3370971679688, + 2176.5283203125, + 2568.470458984375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7609845399856567, + "bbox": [ + 1265.4761962890625, + 460.44146728515625, + 1372.72998046875, + 553.6536865234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7520913481712341, + "bbox": [ + 232.48519897460938, + 578.6051635742188, + 338.0008544921875, + 676.820556640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7501529455184937, + "bbox": [ + 222.1729736328125, + 1845.4884033203125, + 335.4812316894531, + 1948.3370361328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.684562087059021, + "bbox": [ + 805.4273071289062, + 2136.070556640625, + 917.5810546875, + 2245.9453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6613016128540039, + "bbox": [ + 2072.452392578125, + 2524.58740234375, + 2202.64990234375, + 2655.87548828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6394456624984741, + "bbox": [ + 903.0519409179688, + 1262.8487548828125, + 1025.203369140625, + 1389.733154296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5251138806343079, + "bbox": [ + 226.74554443359375, + 3196.202392578125, + 315.4188537597656, + 3265.424072265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3338477909564972, + "bbox": [ + 217.36712646484375, + 3186.787841796875, + 318.413818359375, + 3276.339599609375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9344406127929688, + "bbox": [ + 217.66490173339844, + 759.3243408203125, + 1202.80224609375, + 1231.4263916015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267095327377319, + "bbox": [ + 1224.459228515625, + 415.92987060546875, + 2270.26220703125, + 2983.034912109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8998392820358276, + "bbox": [ + 1260.04150390625, + 2516.952392578125, + 2157.68115234375, + 2867.141845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8952497243881226, + "bbox": [ + 213.6790008544922, + 2037.1563720703125, + 619.2114868164062, + 2406.072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8887794613838196, + "bbox": [ + 178.48138427734375, + 1810.49560546875, + 1199.16845703125, + 2447.0244140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8719655871391296, + "bbox": [ + 165.6348876953125, + 537.3223266601562, + 1238.2332763671875, + 1326.4775390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8273245692253113, + "bbox": [ + 1256.1771240234375, + 642.2066650390625, + 2189.99853515625, + 2532.552490234375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7313070893287659, + "bbox": [ + 1271.173095703125, + 550.31201171875, + 1850.9947509765625, + 629.716552734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6807247996330261, + "bbox": [ + 227.22056579589844, + 671.637939453125, + 879.6678466796875, + 747.79052734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5922560691833496, + "bbox": [ + 222.93804931640625, + 1951.6728515625, + 635.1351928710938, + 2017.148681640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.14023226499557495, + "bbox": [ + 1239.450439453125, + 572.3370971679688, + 2176.5283203125, + 2568.470458984375 + ] + } + ], + "timestamp": "2025-10-15T21:42:15.075448" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 22.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 22.json" new file mode 100644 index 0000000..907c929 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 22.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 22.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7795184254646301, + "bbox": [ + 281.0706787109375, + 451.1649475097656, + 395.5906066894531, + 558.5849609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7511841058731079, + "bbox": [ + 1344.153076171875, + 467.2082824707031, + 1459.4049072265625, + 567.3482055664062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6356146335601807, + "bbox": [ + 2270.834228515625, + 2073.6806640625, + 2395.575927734375, + 2190.188232421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6329180598258972, + "bbox": [ + 1056.0555419921875, + 1869.0460205078125, + 1184.586669921875, + 1997.4613037109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5557655692100525, + "bbox": [ + 2216.745361328125, + 3285.78515625, + 2307.01416015625, + 3362.14306640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.26098957657814026, + "bbox": [ + 2261.696533203125, + 2067.105712890625, + 2410.91455078125, + 2208.152587890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9346016645431519, + "bbox": [ + 217.4479217529297, + 419.4060363769531, + 1283.344482421875, + 2361.360107421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9243698120117188, + "bbox": [ + 264.8602600097656, + 642.5381469726562, + 1254.9383544921875, + 1847.2689208984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9216163158416748, + "bbox": [ + 1314.1058349609375, + 442.07421875, + 2363.4912109375, + 2464.254638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198043346405029, + "bbox": [ + 1328.26171875, + 667.154541015625, + 2336.044677734375, + 1904.79345703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9161653518676758, + "bbox": [ + 1329.2763671875, + 1947.4105224609375, + 2324.307373046875, + 2338.989013671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8980361819267273, + "bbox": [ + 271.90753173828125, + 1893.48974609375, + 878.843994140625, + 2259.13916015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7084015607833862, + "bbox": [ + 1342.1243896484375, + 567.9030151367188, + 2152.659912109375, + 641.7802734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6854962110519409, + "bbox": [ + 291.1196594238281, + 567.5558471679688, + 1138.3717041015625, + 633.0941162109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.3021327257156372, + "bbox": [ + 296.24188232421875, + 557.2056884765625, + 1147.8460693359375, + 650.6898803710938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7795184254646301, + "bbox": [ + 281.0706787109375, + 451.1649475097656, + 395.5906066894531, + 558.5849609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7511841058731079, + "bbox": [ + 1344.153076171875, + 467.2082824707031, + 1459.4049072265625, + 567.3482055664062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6356146335601807, + "bbox": [ + 2270.834228515625, + 2073.6806640625, + 2395.575927734375, + 2190.188232421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6329180598258972, + "bbox": [ + 1056.0555419921875, + 1869.0460205078125, + 1184.586669921875, + 1997.4613037109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5557655692100525, + "bbox": [ + 2216.745361328125, + 3285.78515625, + 2307.01416015625, + 3362.14306640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.26098957657814026, + "bbox": [ + 2261.696533203125, + 2067.105712890625, + 2410.91455078125, + 2208.152587890625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9346016645431519, + "bbox": [ + 217.4479217529297, + 419.4060363769531, + 1283.344482421875, + 2361.360107421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9243698120117188, + "bbox": [ + 264.8602600097656, + 642.5381469726562, + 1254.9383544921875, + 1847.2689208984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9216163158416748, + "bbox": [ + 1314.1058349609375, + 442.07421875, + 2363.4912109375, + 2464.254638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198043346405029, + "bbox": [ + 1328.26171875, + 667.154541015625, + 2336.044677734375, + 1904.79345703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9161653518676758, + "bbox": [ + 1329.2763671875, + 1947.4105224609375, + 2324.307373046875, + 2338.989013671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8980361819267273, + "bbox": [ + 271.90753173828125, + 1893.48974609375, + 878.843994140625, + 2259.13916015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7084015607833862, + "bbox": [ + 1342.1243896484375, + 567.9030151367188, + 2152.659912109375, + 641.7802734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6854962110519409, + "bbox": [ + 291.1196594238281, + 567.5558471679688, + 1138.3717041015625, + 633.0941162109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.3021327257156372, + "bbox": [ + 296.24188232421875, + 557.2056884765625, + 1147.8460693359375, + 650.6898803710938 + ] + } + ], + "timestamp": "2025-10-15T21:42:15.456656" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 23.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 23.json" new file mode 100644 index 0000000..fb5673b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 23.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 23.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654995322227478, + "bbox": [ + 228.7303924560547, + 433.2192687988281, + 345.6019287109375, + 535.1857299804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7458115816116333, + "bbox": [ + 1273.211669921875, + 456.8508605957031, + 1386.8052978515625, + 554.6439819335938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6103271245956421, + "bbox": [ + 908.0278930664062, + 2835.655517578125, + 1056.2725830078125, + 2989.95703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6039152145385742, + "bbox": [ + 1666.9869384765625, + 2479.552734375, + 1797.5343017578125, + 2601.17041015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.47475534677505493, + "bbox": [ + 217.02630615234375, + 3150.31201171875, + 308.2370300292969, + 3221.366943359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.25467148423194885, + "bbox": [ + 202.75096130371094, + 3138.69677734375, + 313.9153137207031, + 3234.106689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9485726952552795, + "bbox": [ + 206.61221313476562, + 671.940185546875, + 1193.4862060546875, + 2212.44384765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9381181001663208, + "bbox": [ + 199.09536743164062, + 2257.632568359375, + 1177.6119384765625, + 2867.08984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9314593076705933, + "bbox": [ + 1267.08740234375, + 636.4830322265625, + 2236.609130859375, + 1944.1318359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9292885661125183, + "bbox": [ + 183.15655517578125, + 421.0118408203125, + 1215.676025390625, + 2940.68994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9245951771736145, + "bbox": [ + 1228.47607421875, + 421.11102294921875, + 2355.71826171875, + 2645.02685546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9102753400802612, + "bbox": [ + 1263.0137939453125, + 2008.4429931640625, + 2251.163330078125, + 2472.57666015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8342044949531555, + "bbox": [ + 234.9220733642578, + 537.8096923828125, + 1190.3470458984375, + 665.8623046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6448330283164978, + "bbox": [ + 1283.9390869140625, + 557.1524658203125, + 1821.07470703125, + 621.3471069335938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654995322227478, + "bbox": [ + 228.7303924560547, + 433.2192687988281, + 345.6019287109375, + 535.1857299804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7458115816116333, + "bbox": [ + 1273.211669921875, + 456.8508605957031, + 1386.8052978515625, + 554.6439819335938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6103271245956421, + "bbox": [ + 908.0278930664062, + 2835.655517578125, + 1056.2725830078125, + 2989.95703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6039152145385742, + "bbox": [ + 1666.9869384765625, + 2479.552734375, + 1797.5343017578125, + 2601.17041015625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.47475534677505493, + "bbox": [ + 217.02630615234375, + 3150.31201171875, + 308.2370300292969, + 3221.366943359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.25467148423194885, + "bbox": [ + 202.75096130371094, + 3138.69677734375, + 313.9153137207031, + 3234.106689453125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9485726952552795, + "bbox": [ + 206.61221313476562, + 671.940185546875, + 1193.4862060546875, + 2212.44384765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9381181001663208, + "bbox": [ + 199.09536743164062, + 2257.632568359375, + 1177.6119384765625, + 2867.08984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9314593076705933, + "bbox": [ + 1267.08740234375, + 636.4830322265625, + 2236.609130859375, + 1944.1318359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9292885661125183, + "bbox": [ + 183.15655517578125, + 421.0118408203125, + 1215.676025390625, + 2940.68994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9245951771736145, + "bbox": [ + 1228.47607421875, + 421.11102294921875, + 2355.71826171875, + 2645.02685546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9102753400802612, + "bbox": [ + 1263.0137939453125, + 2008.4429931640625, + 2251.163330078125, + 2472.57666015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8342044949531555, + "bbox": [ + 234.9220733642578, + 537.8096923828125, + 1190.3470458984375, + 665.8623046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6448330283164978, + "bbox": [ + 1283.9390869140625, + 557.1524658203125, + 1821.07470703125, + 621.3471069335938 + ] + } + ], + "timestamp": "2025-10-15T21:42:15.850428" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 24.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 24.json" new file mode 100644 index 0000000..6cc15d5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 24.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 24.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7667497992515564, + "bbox": [ + 258.83489990234375, + 440.5694580078125, + 379.6180419921875, + 547.91552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7625042200088501, + "bbox": [ + 1327.470703125, + 462.8982849121094, + 1441.1715087890625, + 561.473876953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6474075317382812, + "bbox": [ + 1798.9244384765625, + 2369.840576171875, + 1961.3839111328125, + 2525.567626953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6122598648071289, + "bbox": [ + 1066.4884033203125, + 2331.44384765625, + 1198.9454345703125, + 2462.427001953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5640543699264526, + "bbox": [ + 2212.030517578125, + 3210.279296875, + 2301.90576171875, + 3284.257080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9440351128578186, + "bbox": [ + 230.3463134765625, + 411.798828125, + 1271.197021484375, + 2802.266845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.940769374370575, + "bbox": [ + 1333.4771728515625, + 1842.7164306640625, + 2322.935302734375, + 2382.621826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9402076601982117, + "bbox": [ + 252.21615600585938, + 629.1215209960938, + 1235.788330078125, + 2294.918212890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9322625994682312, + "bbox": [ + 1305.978759765625, + 654.1461181640625, + 2316.10107421875, + 1829.6925048828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8957377076148987, + "bbox": [ + 257.6315612792969, + 2323.16943359375, + 1185.0843505859375, + 2703.41748046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8766340017318726, + "bbox": [ + 1291.2962646484375, + 418.64752197265625, + 2390.367919921875, + 2574.923095703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7723098993301392, + "bbox": [ + 266.4828796386719, + 531.5541381835938, + 825.0005493164062, + 618.4894409179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7396525740623474, + "bbox": [ + 1328.3720703125, + 552.819580078125, + 1949.468994140625, + 637.3086547851562 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7667497992515564, + "bbox": [ + 258.83489990234375, + 440.5694580078125, + 379.6180419921875, + 547.91552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7625042200088501, + "bbox": [ + 1327.470703125, + 462.8982849121094, + 1441.1715087890625, + 561.473876953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6474075317382812, + "bbox": [ + 1798.9244384765625, + 2369.840576171875, + 1961.3839111328125, + 2525.567626953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6122598648071289, + "bbox": [ + 1066.4884033203125, + 2331.44384765625, + 1198.9454345703125, + 2462.427001953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5640543699264526, + "bbox": [ + 2212.030517578125, + 3210.279296875, + 2301.90576171875, + 3284.257080078125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9440351128578186, + "bbox": [ + 230.3463134765625, + 411.798828125, + 1271.197021484375, + 2802.266845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.940769374370575, + "bbox": [ + 1333.4771728515625, + 1842.7164306640625, + 2322.935302734375, + 2382.621826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9402076601982117, + "bbox": [ + 252.21615600585938, + 629.1215209960938, + 1235.788330078125, + 2294.918212890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9322625994682312, + "bbox": [ + 1305.978759765625, + 654.1461181640625, + 2316.10107421875, + 1829.6925048828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8957377076148987, + "bbox": [ + 257.6315612792969, + 2323.16943359375, + 1185.0843505859375, + 2703.41748046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8766340017318726, + "bbox": [ + 1291.2962646484375, + 418.64752197265625, + 2390.367919921875, + 2574.923095703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7723098993301392, + "bbox": [ + 266.4828796386719, + 531.5541381835938, + 825.0005493164062, + 618.4894409179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7396525740623474, + "bbox": [ + 1328.3720703125, + 552.819580078125, + 1949.468994140625, + 637.3086547851562 + ] + } + ], + "timestamp": "2025-10-15T21:42:16.256112" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 25.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 25.json" new file mode 100644 index 0000000..56c4f74 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 25.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 25.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7421303391456604, + "bbox": [ + 241.14080810546875, + 416.3816833496094, + 352.88690185546875, + 511.4723205566406 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7394232749938965, + "bbox": [ + 1258.4024658203125, + 429.98980712890625, + 1368.412841796875, + 526.475830078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7245084047317505, + "bbox": [ + 1801.9591064453125, + 419.2466125488281, + 1932.7330322265625, + 536.67822265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6493656635284424, + "bbox": [ + 866.092529296875, + 495.0104675292969, + 981.1055908203125, + 602.8601684570312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.42071205377578735, + "bbox": [ + 238.50132751464844, + 3077.484619140625, + 331.3274841308594, + 3155.2998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.26004695892333984, + "bbox": [ + 853.944580078125, + 485.6091003417969, + 990.0341796875, + 616.432373046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9469874501228333, + "bbox": [ + 1261.5064697265625, + 604.6077880859375, + 2195.870361328125, + 1890.533447265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9465720057487488, + "bbox": [ + 1230.3621826171875, + 385.51763916015625, + 2235.49072265625, + 2420.977294921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9135652184486389, + "bbox": [ + 211.06617736816406, + 597.3837890625, + 1168.9173583984375, + 2900.891845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8991339802742004, + "bbox": [ + 1254.18701171875, + 1947.0870361328125, + 2180.161865234375, + 2374.337646484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8678565621376038, + "bbox": [ + 167.61598205566406, + 405.13336181640625, + 1186.7459716796875, + 2929.685302734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7666568756103516, + "bbox": [ + 1270.4747314453125, + 525.1801147460938, + 2006.163818359375, + 618.0382080078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7213130593299866, + "bbox": [ + 246.58572387695312, + 508.7413635253906, + 834.2227783203125, + 587.8153076171875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7421303391456604, + "bbox": [ + 241.14080810546875, + 416.3816833496094, + 352.88690185546875, + 511.4723205566406 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7394232749938965, + "bbox": [ + 1258.4024658203125, + 429.98980712890625, + 1368.412841796875, + 526.475830078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7245084047317505, + "bbox": [ + 1801.9591064453125, + 419.2466125488281, + 1932.7330322265625, + 536.67822265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6493656635284424, + "bbox": [ + 866.092529296875, + 495.0104675292969, + 981.1055908203125, + 602.8601684570312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.42071205377578735, + "bbox": [ + 238.50132751464844, + 3077.484619140625, + 331.3274841308594, + 3155.2998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.26004695892333984, + "bbox": [ + 853.944580078125, + 485.6091003417969, + 990.0341796875, + 616.432373046875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9469874501228333, + "bbox": [ + 1261.5064697265625, + 604.6077880859375, + 2195.870361328125, + 1890.533447265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9465720057487488, + "bbox": [ + 1230.3621826171875, + 385.51763916015625, + 2235.49072265625, + 2420.977294921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9135652184486389, + "bbox": [ + 211.06617736816406, + 597.3837890625, + 1168.9173583984375, + 2900.891845703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8991339802742004, + "bbox": [ + 1254.18701171875, + 1947.0870361328125, + 2180.161865234375, + 2374.337646484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8678565621376038, + "bbox": [ + 167.61598205566406, + 405.13336181640625, + 1186.7459716796875, + 2929.685302734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7666568756103516, + "bbox": [ + 1270.4747314453125, + 525.1801147460938, + 2006.163818359375, + 618.0382080078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7213130593299866, + "bbox": [ + 246.58572387695312, + 508.7413635253906, + 834.2227783203125, + 587.8153076171875 + ] + } + ], + "timestamp": "2025-10-15T21:42:16.652673" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 26.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 26.json" new file mode 100644 index 0000000..43dcd9e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 26.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 26.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7670165300369263, + "bbox": [ + 1345.222900390625, + 455.4881286621094, + 1459.423583984375, + 551.0560913085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7657334804534912, + "bbox": [ + 287.40631103515625, + 442.2474365234375, + 404.76336669921875, + 541.477783203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6469530463218689, + "bbox": [ + 790.02783203125, + 408.6924133300781, + 915.4380493164062, + 531.4673461914062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6160662174224854, + "bbox": [ + 1708.2203369140625, + 433.8625793457031, + 1852.505615234375, + 573.0357055664062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5654496550559998, + "bbox": [ + 2232.551513671875, + 3211.634765625, + 2323.775390625, + 3290.13330078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9186155796051025, + "bbox": [ + 286.39453125, + 632.7449340820312, + 1255.2913818359375, + 2753.25439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9177879095077515, + "bbox": [ + 1344.95361328125, + 2637.765625, + 2073.613525390625, + 3003.619873046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9041714668273926, + "bbox": [ + 290.95855712890625, + 2750.672607421875, + 912.4373779296875, + 3117.7109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9039917588233948, + "bbox": [ + 1342.7130126953125, + 684.3690795898438, + 2285.545166015625, + 2577.762451171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9029384851455688, + "bbox": [ + 237.6697235107422, + 409.00830078125, + 1272.479736328125, + 3103.65869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9007740616798401, + "bbox": [ + 1310.8316650390625, + 406.6678466796875, + 2488.408203125, + 3088.4248046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8320532441139221, + "bbox": [ + 270.7789001464844, + 538.1980590820312, + 1267.8721923828125, + 671.5665893554688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8263663649559021, + "bbox": [ + 1349.6661376953125, + 557.2345581054688, + 2324.2939453125, + 679.1968383789062 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7670165300369263, + "bbox": [ + 1345.222900390625, + 455.4881286621094, + 1459.423583984375, + 551.0560913085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7657334804534912, + "bbox": [ + 287.40631103515625, + 442.2474365234375, + 404.76336669921875, + 541.477783203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6469530463218689, + "bbox": [ + 790.02783203125, + 408.6924133300781, + 915.4380493164062, + 531.4673461914062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6160662174224854, + "bbox": [ + 1708.2203369140625, + 433.8625793457031, + 1852.505615234375, + 573.0357055664062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5654496550559998, + "bbox": [ + 2232.551513671875, + 3211.634765625, + 2323.775390625, + 3290.13330078125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9186155796051025, + "bbox": [ + 286.39453125, + 632.7449340820312, + 1255.2913818359375, + 2753.25439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9177879095077515, + "bbox": [ + 1344.95361328125, + 2637.765625, + 2073.613525390625, + 3003.619873046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9041714668273926, + "bbox": [ + 290.95855712890625, + 2750.672607421875, + 912.4373779296875, + 3117.7109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9039917588233948, + "bbox": [ + 1342.7130126953125, + 684.3690795898438, + 2285.545166015625, + 2577.762451171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9029384851455688, + "bbox": [ + 237.6697235107422, + 409.00830078125, + 1272.479736328125, + 3103.65869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9007740616798401, + "bbox": [ + 1310.8316650390625, + 406.6678466796875, + 2488.408203125, + 3088.4248046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8320532441139221, + "bbox": [ + 270.7789001464844, + 538.1980590820312, + 1267.8721923828125, + 671.5665893554688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8263663649559021, + "bbox": [ + 1349.6661376953125, + 557.2345581054688, + 2324.2939453125, + 679.1968383789062 + ] + } + ], + "timestamp": "2025-10-15T21:42:17.035272" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 27.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 27.json" new file mode 100644 index 0000000..6bf0f40 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 27.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 27.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7629451751708984, + "bbox": [ + 1226.6607666015625, + 431.4805908203125, + 1332.24755859375, + 527.6419067382812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7445833086967468, + "bbox": [ + 237.05784606933594, + 417.6116943359375, + 348.8619689941406, + 513.4798583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.65446937084198, + "bbox": [ + 813.6600341796875, + 2081.550537109375, + 945.07958984375, + 2225.9970703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.638734757900238, + "bbox": [ + 1589.9998779296875, + 1989.6064453125, + 1713.710693359375, + 2105.571044921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.48045268654823303, + "bbox": [ + 221.5921173095703, + 3024.630126953125, + 306.59747314453125, + 3091.858154296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3522263765335083, + "bbox": [ + 1577.0982666015625, + 1980.409423828125, + 1728.65478515625, + 2122.312255859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.25073206424713135, + "bbox": [ + 208.8902130126953, + 3014.2138671875, + 311.88079833984375, + 3105.6123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9425053000450134, + "bbox": [ + 1210.9202880859375, + 654.5132446289062, + 2160.998779296875, + 1989.579345703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9351682662963867, + "bbox": [ + 225.16668701171875, + 581.0144653320312, + 1145.6309814453125, + 2010.2855224609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9316285252571106, + "bbox": [ + 202.10169982910156, + 394.2331848144531, + 1154.2000732421875, + 2274.050048828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9142103791236877, + "bbox": [ + 1197.5684814453125, + 473.8812255859375, + 2158.3818359375, + 2160.2890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8653833270072937, + "bbox": [ + 1219.4805908203125, + 525.8115844726562, + 2147.09765625, + 648.558349609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7658183574676514, + "bbox": [ + 245.54653930664062, + 500.9640808105469, + 990.9666137695312, + 592.4256591796875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7629451751708984, + "bbox": [ + 1226.6607666015625, + 431.4805908203125, + 1332.24755859375, + 527.6419067382812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7445833086967468, + "bbox": [ + 237.05784606933594, + 417.6116943359375, + 348.8619689941406, + 513.4798583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.65446937084198, + "bbox": [ + 813.6600341796875, + 2081.550537109375, + 945.07958984375, + 2225.9970703125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.638734757900238, + "bbox": [ + 1589.9998779296875, + 1989.6064453125, + 1713.710693359375, + 2105.571044921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.48045268654823303, + "bbox": [ + 221.5921173095703, + 3024.630126953125, + 306.59747314453125, + 3091.858154296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3522263765335083, + "bbox": [ + 1577.0982666015625, + 1980.409423828125, + 1728.65478515625, + 2122.312255859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.25073206424713135, + "bbox": [ + 208.8902130126953, + 3014.2138671875, + 311.88079833984375, + 3105.6123046875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9425053000450134, + "bbox": [ + 1210.9202880859375, + 654.5132446289062, + 2160.998779296875, + 1989.579345703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9351682662963867, + "bbox": [ + 225.16668701171875, + 581.0144653320312, + 1145.6309814453125, + 2010.2855224609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9316285252571106, + "bbox": [ + 202.10169982910156, + 394.2331848144531, + 1154.2000732421875, + 2274.050048828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9142103791236877, + "bbox": [ + 1197.5684814453125, + 473.8812255859375, + 2158.3818359375, + 2160.2890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8653833270072937, + "bbox": [ + 1219.4805908203125, + 525.8115844726562, + 2147.09765625, + 648.558349609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7658183574676514, + "bbox": [ + 245.54653930664062, + 500.9640808105469, + 990.9666137695312, + 592.4256591796875 + ] + } + ], + "timestamp": "2025-10-15T21:42:17.423270" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 28.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 28.json" new file mode 100644 index 0000000..f134cd4 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 28.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 28.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7724066376686096, + "bbox": [ + 1259.1282958984375, + 432.7243347167969, + 1366.846435546875, + 528.693603515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7565213441848755, + "bbox": [ + 270.1709899902344, + 525.3378295898438, + 379.07977294921875, + 625.3421630859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6693642139434814, + "bbox": [ + 1691.18408203125, + 2195.766357421875, + 1807.859375, + 2301.606201171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6524773836135864, + "bbox": [ + 861.5280151367188, + 2070.148681640625, + 986.4307861328125, + 2203.802978515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5644363760948181, + "bbox": [ + 2073.995849609375, + 3004.167236328125, + 2160.699951171875, + 3077.295654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.45235398411750793, + "bbox": [ + 835.8550415039062, + 2063.509521484375, + 1004.3845825195312, + 2220.439208984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2364511638879776, + "bbox": [ + 1680.267578125, + 2191.765380859375, + 1820.362060546875, + 2321.32177734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9347376823425293, + "bbox": [ + 1246.3223876953125, + 528.80517578125, + 2178.835693359375, + 1816.5362548828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9264846444129944, + "bbox": [ + 258.80523681640625, + 607.8046264648438, + 1182.5933837890625, + 1984.2490234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9128454923629761, + "bbox": [ + 1226.43896484375, + 475.4956359863281, + 2209.617431640625, + 2278.319580078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9066546559333801, + "bbox": [ + 210.298828125, + 390.4778747558594, + 1199.490478515625, + 2445.0556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898546576499939, + "bbox": [ + 1245.5506591796875, + 1840.7978515625, + 2124.052001953125, + 2214.091064453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7990778088569641, + "bbox": [ + 251.93734741210938, + 2006.59228515625, + 600.7636108398438, + 2361.75 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7903141975402832, + "bbox": [ + 246.685546875, + 406.2210998535156, + 1159.241455078125, + 498.7187805175781 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.1524120420217514, + "bbox": [ + 245.6783447265625, + 2005.6851806640625, + 902.2305908203125, + 2357.501953125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7724066376686096, + "bbox": [ + 1259.1282958984375, + 432.7243347167969, + 1366.846435546875, + 528.693603515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7565213441848755, + "bbox": [ + 270.1709899902344, + 525.3378295898438, + 379.07977294921875, + 625.3421630859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6693642139434814, + "bbox": [ + 1691.18408203125, + 2195.766357421875, + 1807.859375, + 2301.606201171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6524773836135864, + "bbox": [ + 861.5280151367188, + 2070.148681640625, + 986.4307861328125, + 2203.802978515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5644363760948181, + "bbox": [ + 2073.995849609375, + 3004.167236328125, + 2160.699951171875, + 3077.295654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.45235398411750793, + "bbox": [ + 835.8550415039062, + 2063.509521484375, + 1004.3845825195312, + 2220.439208984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2364511638879776, + "bbox": [ + 1680.267578125, + 2191.765380859375, + 1820.362060546875, + 2321.32177734375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9347376823425293, + "bbox": [ + 1246.3223876953125, + 528.80517578125, + 2178.835693359375, + 1816.5362548828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9264846444129944, + "bbox": [ + 258.80523681640625, + 607.8046264648438, + 1182.5933837890625, + 1984.2490234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9128454923629761, + "bbox": [ + 1226.43896484375, + 475.4956359863281, + 2209.617431640625, + 2278.319580078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9066546559333801, + "bbox": [ + 210.298828125, + 390.4778747558594, + 1199.490478515625, + 2445.0556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.898546576499939, + "bbox": [ + 1245.5506591796875, + 1840.7978515625, + 2124.052001953125, + 2214.091064453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7990778088569641, + "bbox": [ + 251.93734741210938, + 2006.59228515625, + 600.7636108398438, + 2361.75 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7903141975402832, + "bbox": [ + 246.685546875, + 406.2210998535156, + 1159.241455078125, + 498.7187805175781 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.1524120420217514, + "bbox": [ + 245.6783447265625, + 2005.6851806640625, + 902.2305908203125, + 2357.501953125 + ] + } + ], + "timestamp": "2025-10-15T21:42:17.783723" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 29.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 29.json" new file mode 100644 index 0000000..5d850ad --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 29.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 29.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7478845119476318, + "bbox": [ + 239.27841186523438, + 447.50390625, + 357.9844970703125, + 554.5797729492188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7387045621871948, + "bbox": [ + 1273.8121337890625, + 457.00518798828125, + 1390.1126708984375, + 561.6438598632812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209024786949158, + "bbox": [ + 1746.133056640625, + 2365.487548828125, + 1900.2987060546875, + 2518.781982421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6102827191352844, + "bbox": [ + 630.2962646484375, + 2185.74658203125, + 779.4131469726562, + 2334.837158203125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.52583247423172, + "bbox": [ + 230.3710174560547, + 3191.055419921875, + 322.3893737792969, + 3268.047607421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9472480416297913, + "bbox": [ + 1263.2137451171875, + 571.4367065429688, + 2237.711181640625, + 1790.8809814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9438791275024414, + "bbox": [ + 218.17445373535156, + 568.1755981445312, + 1196.908203125, + 1750.872314453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9330787062644958, + "bbox": [ + 1265.666259765625, + 1814.294189453125, + 2230.926025390625, + 2363.1806640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.921006977558136, + "bbox": [ + 239.6374053955078, + 1752.021240234375, + 742.9075927734375, + 2120.180908203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8912978768348694, + "bbox": [ + 1238.6619873046875, + 422.170166015625, + 2265.972900390625, + 2486.128662109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8790758848190308, + "bbox": [ + 200.7998046875, + 396.44677734375, + 1217.9090576171875, + 2299.3212890625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7478845119476318, + "bbox": [ + 239.27841186523438, + 447.50390625, + 357.9844970703125, + 554.5797729492188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7387045621871948, + "bbox": [ + 1273.8121337890625, + 457.00518798828125, + 1390.1126708984375, + 561.6438598632812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209024786949158, + "bbox": [ + 1746.133056640625, + 2365.487548828125, + 1900.2987060546875, + 2518.781982421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6102827191352844, + "bbox": [ + 630.2962646484375, + 2185.74658203125, + 779.4131469726562, + 2334.837158203125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.52583247423172, + "bbox": [ + 230.3710174560547, + 3191.055419921875, + 322.3893737792969, + 3268.047607421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9472480416297913, + "bbox": [ + 1263.2137451171875, + 571.4367065429688, + 2237.711181640625, + 1790.8809814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9438791275024414, + "bbox": [ + 218.17445373535156, + 568.1755981445312, + 1196.908203125, + 1750.872314453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9330787062644958, + "bbox": [ + 1265.666259765625, + 1814.294189453125, + 2230.926025390625, + 2363.1806640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.921006977558136, + "bbox": [ + 239.6374053955078, + 1752.021240234375, + 742.9075927734375, + 2120.180908203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8912978768348694, + "bbox": [ + 1238.6619873046875, + 422.170166015625, + 2265.972900390625, + 2486.128662109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8790758848190308, + "bbox": [ + 200.7998046875, + 396.44677734375, + 1217.9090576171875, + 2299.3212890625 + ] + } + ], + "timestamp": "2025-10-15T21:42:18.147253" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 30.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 30.json" new file mode 100644 index 0000000..c976c18 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 30.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 30.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7611750960350037, + "bbox": [ + 266.7918395996094, + 423.0800476074219, + 372.1796875, + 513.7601318359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7512646913528442, + "bbox": [ + 1241.165771484375, + 594.25732421875, + 1344.6141357421875, + 688.2560424804688 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6790172457695007, + "bbox": [ + 524.0193481445312, + 1924.8118896484375, + 658.0245361328125, + 2057.033447265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6072844862937927, + "bbox": [ + 1315.171875, + 2378.080322265625, + 1451.56494140625, + 2510.37255859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5706136226654053, + "bbox": [ + 2060.8662109375, + 2995.408447265625, + 2147.43896484375, + 3068.205322265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9384544491767883, + "bbox": [ + 259.1288146972656, + 584.7393188476562, + 1172.3184814453125, + 1911.7039794921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9344468712806702, + "bbox": [ + 1222.38525390625, + 480.3403625488281, + 2227.930419921875, + 2866.1455078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9326108694076538, + "bbox": [ + 1219.9033203125, + 707.8358154296875, + 2143.001220703125, + 2479.75146484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9125939011573792, + "bbox": [ + 219.2490692138672, + 401.7417907714844, + 1193.0205078125, + 2118.626220703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8437103629112244, + "bbox": [ + 1228.490966796875, + 2501.2138671875, + 2040.79443359375, + 2727.453857421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8432681560516357, + "bbox": [ + 1245.2083740234375, + 417.77978515625, + 2168.982666015625, + 545.6913452148438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7915722727775574, + "bbox": [ + 261.16705322265625, + 510.0828552246094, + 900.70361328125, + 598.0518798828125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7611750960350037, + "bbox": [ + 266.7918395996094, + 423.0800476074219, + 372.1796875, + 513.7601318359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7512646913528442, + "bbox": [ + 1241.165771484375, + 594.25732421875, + 1344.6141357421875, + 688.2560424804688 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6790172457695007, + "bbox": [ + 524.0193481445312, + 1924.8118896484375, + 658.0245361328125, + 2057.033447265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6072844862937927, + "bbox": [ + 1315.171875, + 2378.080322265625, + 1451.56494140625, + 2510.37255859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5706136226654053, + "bbox": [ + 2060.8662109375, + 2995.408447265625, + 2147.43896484375, + 3068.205322265625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9384544491767883, + "bbox": [ + 259.1288146972656, + 584.7393188476562, + 1172.3184814453125, + 1911.7039794921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9344468712806702, + "bbox": [ + 1222.38525390625, + 480.3403625488281, + 2227.930419921875, + 2866.1455078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9326108694076538, + "bbox": [ + 1219.9033203125, + 707.8358154296875, + 2143.001220703125, + 2479.75146484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9125939011573792, + "bbox": [ + 219.2490692138672, + 401.7417907714844, + 1193.0205078125, + 2118.626220703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8437103629112244, + "bbox": [ + 1228.490966796875, + 2501.2138671875, + 2040.79443359375, + 2727.453857421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8432681560516357, + "bbox": [ + 1245.2083740234375, + 417.77978515625, + 2168.982666015625, + 545.6913452148438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7915722727775574, + "bbox": [ + 261.16705322265625, + 510.0828552246094, + 900.70361328125, + 598.0518798828125 + ] + } + ], + "timestamp": "2025-10-15T21:42:18.514371" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 31.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 31.json" new file mode 100644 index 0000000..9b62111 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 31.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 31.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7614631652832031, + "bbox": [ + 224.5087890625, + 398.6302795410156, + 331.80224609375, + 496.1607360839844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7323277592658997, + "bbox": [ + 1180.23095703125, + 575.7809448242188, + 1284.7669677734375, + 668.2564086914062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6479072570800781, + "bbox": [ + 601.4420166015625, + 402.2400207519531, + 711.2244262695312, + 508.0434265136719 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6271153092384338, + "bbox": [ + 1510.73876953125, + 552.88916015625, + 1634.616455078125, + 673.3267211914062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5133873224258423, + "bbox": [ + 186.88575744628906, + 2911.78466796875, + 274.33282470703125, + 2982.877685546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9613595604896545, + "bbox": [ + 154.57992553710938, + 364.99127197265625, + 1111.3770751953125, + 2621.02001953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9475172162055969, + "bbox": [ + 177.88113403320312, + 536.1973266601562, + 1092.2427978515625, + 2328.58056640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9266027808189392, + "bbox": [ + 1167.377197265625, + 672.6294555664062, + 2103.595458984375, + 2225.301025390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9130634665489197, + "bbox": [ + 1157.2149658203125, + 421.1015319824219, + 2137.074462890625, + 2405.45556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8513413071632385, + "bbox": [ + 184.75196838378906, + 2349.957763671875, + 931.402587890625, + 2562.699951171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.850841760635376, + "bbox": [ + 1176.6622314453125, + 409.95831298828125, + 2102.201171875, + 538.0986938476562 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7614631652832031, + "bbox": [ + 224.5087890625, + 398.6302795410156, + 331.80224609375, + 496.1607360839844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7323277592658997, + "bbox": [ + 1180.23095703125, + 575.7809448242188, + 1284.7669677734375, + 668.2564086914062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6479072570800781, + "bbox": [ + 601.4420166015625, + 402.2400207519531, + 711.2244262695312, + 508.0434265136719 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6271153092384338, + "bbox": [ + 1510.73876953125, + 552.88916015625, + 1634.616455078125, + 673.3267211914062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5133873224258423, + "bbox": [ + 186.88575744628906, + 2911.78466796875, + 274.33282470703125, + 2982.877685546875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9613595604896545, + "bbox": [ + 154.57992553710938, + 364.99127197265625, + 1111.3770751953125, + 2621.02001953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9475172162055969, + "bbox": [ + 177.88113403320312, + 536.1973266601562, + 1092.2427978515625, + 2328.58056640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9266027808189392, + "bbox": [ + 1167.377197265625, + 672.6294555664062, + 2103.595458984375, + 2225.301025390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9130634665489197, + "bbox": [ + 1157.2149658203125, + 421.1015319824219, + 2137.074462890625, + 2405.45556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8513413071632385, + "bbox": [ + 184.75196838378906, + 2349.957763671875, + 931.402587890625, + 2562.699951171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.850841760635376, + "bbox": [ + 1176.6622314453125, + 409.95831298828125, + 2102.201171875, + 538.0986938476562 + ] + } + ], + "timestamp": "2025-10-15T21:42:18.863868" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 32.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 32.json" new file mode 100644 index 0000000..ec99b59 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 32.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 32.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7473788857460022, + "bbox": [ + 256.6462707519531, + 414.59234619140625, + 377.5392150878906, + 524.4989013671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7459302544593811, + "bbox": [ + 1277.77197265625, + 433.1217041015625, + 1394.7154541015625, + 535.6997680664062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7229082584381104, + "bbox": [ + 1688.562744140625, + 416.6376647949219, + 1821.5228271484375, + 537.8909301757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6216470003128052, + "bbox": [ + 543.21337890625, + 414.53802490234375, + 678.0364990234375, + 542.1803588867188 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.580826461315155, + "bbox": [ + 2115.922119140625, + 3121.437255859375, + 2201.80908203125, + 3193.328857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9516152143478394, + "bbox": [ + 238.84461975097656, + 550.5658569335938, + 1198.468994140625, + 2048.26318359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9407613277435303, + "bbox": [ + 1259.935791015625, + 666.7273559570312, + 2258.46240234375, + 2101.78125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.938447117805481, + "bbox": [ + 199.93731689453125, + 367.5056457519531, + 1226.080810546875, + 2285.20556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9105662703514099, + "bbox": [ + 1267.262939453125, + 2121.923828125, + 1916.944580078125, + 2553.454345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9095644354820251, + "bbox": [ + 1237.24169921875, + 400.4144287109375, + 2317.078369140625, + 2610.015380859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8045415282249451, + "bbox": [ + 1265.9334716796875, + 538.101806640625, + 2224.9912109375, + 656.2567138671875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7473788857460022, + "bbox": [ + 256.6462707519531, + 414.59234619140625, + 377.5392150878906, + 524.4989013671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7459302544593811, + "bbox": [ + 1277.77197265625, + 433.1217041015625, + 1394.7154541015625, + 535.6997680664062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7229082584381104, + "bbox": [ + 1688.562744140625, + 416.6376647949219, + 1821.5228271484375, + 537.8909301757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6216470003128052, + "bbox": [ + 543.21337890625, + 414.53802490234375, + 678.0364990234375, + 542.1803588867188 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.580826461315155, + "bbox": [ + 2115.922119140625, + 3121.437255859375, + 2201.80908203125, + 3193.328857421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9516152143478394, + "bbox": [ + 238.84461975097656, + 550.5658569335938, + 1198.468994140625, + 2048.26318359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9407613277435303, + "bbox": [ + 1259.935791015625, + 666.7273559570312, + 2258.46240234375, + 2101.78125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.938447117805481, + "bbox": [ + 199.93731689453125, + 367.5056457519531, + 1226.080810546875, + 2285.20556640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9105662703514099, + "bbox": [ + 1267.262939453125, + 2121.923828125, + 1916.944580078125, + 2553.454345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9095644354820251, + "bbox": [ + 1237.24169921875, + 400.4144287109375, + 2317.078369140625, + 2610.015380859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8045415282249451, + "bbox": [ + 1265.9334716796875, + 538.101806640625, + 2224.9912109375, + 656.2567138671875 + ] + } + ], + "timestamp": "2025-10-15T21:42:19.221550" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 33.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 33.json" new file mode 100644 index 0000000..dfb2dff --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 33.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 33.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7382001280784607, + "bbox": [ + 1159.257080078125, + 1779.679931640625, + 1266.6392822265625, + 1871.7481689453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7343220114707947, + "bbox": [ + 1176.4478759765625, + 411.1852722167969, + 1283.7557373046875, + 505.1670837402344 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6701210141181946, + "bbox": [ + 1453.3560791015625, + 371.0697021484375, + 1588.2186279296875, + 510.89605712890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6308708190917969, + "bbox": [ + 1368.5357666015625, + 1760.36962890625, + 1485.7447509765625, + 1876.999755859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4856923222541809, + "bbox": [ + 183.00831604003906, + 2886.1943359375, + 273.2265625, + 2959.83203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267694354057312, + "bbox": [ + 1125.4251708984375, + 1753.93798828125, + 2092.636962890625, + 2131.1220703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9180446267127991, + "bbox": [ + 199.50650024414062, + 527.6482543945312, + 1115.52880859375, + 2725.453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9033910036087036, + "bbox": [ + 1183.7301025390625, + 580.48046875, + 2099.0556640625, + 962.552490234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8924390077590942, + "bbox": [ + 1145.9691162109375, + 378.66009521484375, + 2142.837158203125, + 1028.6453857421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7847135066986084, + "bbox": [ + 1152.1920166015625, + 1872.78759765625, + 2045.9659423828125, + 1988.59130859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7793551683425903, + "bbox": [ + 1189.3531494140625, + 491.2174987792969, + 1700.331298828125, + 573.5440673828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6983219385147095, + "bbox": [ + 1152.140869140625, + 2010.901611328125, + 1964.4674072265625, + 2083.96435546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.225002259016037, + "bbox": [ + 1159.4427490234375, + 1859.1964111328125, + 2052.582275390625, + 1963.92236328125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7382001280784607, + "bbox": [ + 1159.257080078125, + 1779.679931640625, + 1266.6392822265625, + 1871.7481689453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7343220114707947, + "bbox": [ + 1176.4478759765625, + 411.1852722167969, + 1283.7557373046875, + 505.1670837402344 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6701210141181946, + "bbox": [ + 1453.3560791015625, + 371.0697021484375, + 1588.2186279296875, + 510.89605712890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6308708190917969, + "bbox": [ + 1368.5357666015625, + 1760.36962890625, + 1485.7447509765625, + 1876.999755859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4856923222541809, + "bbox": [ + 183.00831604003906, + 2886.1943359375, + 273.2265625, + 2959.83203125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267694354057312, + "bbox": [ + 1125.4251708984375, + 1753.93798828125, + 2092.636962890625, + 2131.1220703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9180446267127991, + "bbox": [ + 199.50650024414062, + 527.6482543945312, + 1115.52880859375, + 2725.453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9033910036087036, + "bbox": [ + 1183.7301025390625, + 580.48046875, + 2099.0556640625, + 962.552490234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8924390077590942, + "bbox": [ + 1145.9691162109375, + 378.66009521484375, + 2142.837158203125, + 1028.6453857421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7847135066986084, + "bbox": [ + 1152.1920166015625, + 1872.78759765625, + 2045.9659423828125, + 1988.59130859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7793551683425903, + "bbox": [ + 1189.3531494140625, + 491.2174987792969, + 1700.331298828125, + 573.5440673828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6983219385147095, + "bbox": [ + 1152.140869140625, + 2010.901611328125, + 1964.4674072265625, + 2083.96435546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.225002259016037, + "bbox": [ + 1159.4427490234375, + 1859.1964111328125, + 2052.582275390625, + 1963.92236328125 + ] + } + ], + "timestamp": "2025-10-15T21:42:19.595019" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 34.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 34.json" new file mode 100644 index 0000000..34f68ed --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\353\247\236\354\235\214) - 34.json" @@ -0,0 +1,472 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 34.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7631301879882812, + "bbox": [ + 1249.71240234375, + 2527.0068359375, + 1368.4134521484375, + 2629.692138671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7423908710479736, + "bbox": [ + 1259.1263427734375, + 1954.6392822265625, + 1369.4600830078125, + 2051.2158203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7371372580528259, + "bbox": [ + 1266.1046142578125, + 1191.31396484375, + 1382.3958740234375, + 1288.062255859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6443009972572327, + "bbox": [ + 1538.4713134765625, + 1176.868896484375, + 1659.90966796875, + 1292.151611328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6369273662567139, + "bbox": [ + 1479.8643798828125, + 1932.4456787109375, + 1606.90380859375, + 2058.20654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6345170140266418, + "bbox": [ + 1462.557373046875, + 2497.307373046875, + 1592.8426513671875, + 2630.5751953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5546056628227234, + "bbox": [ + 2104.216064453125, + 3072.8046875, + 2192.110595703125, + 3145.80517578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9187479615211487, + "bbox": [ + 1250.12841796875, + 2697.40576171875, + 2114.49560546875, + 3053.944580078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9182093143463135, + "bbox": [ + 1249.125732421875, + 409.1916198730469, + 2265.78955078125, + 1018.2421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8877222537994385, + "bbox": [ + 1223.094482421875, + 2473.58544921875, + 2236.861083984375, + 3072.441162109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8849437236785889, + "bbox": [ + 1251.2005615234375, + 1923.387939453125, + 2246.10205078125, + 2241.09033203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8652137517929077, + "bbox": [ + 1260.7471923828125, + 1424.1236572265625, + 2110.28955078125, + 1641.166748046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8641857504844666, + "bbox": [ + 227.31521606445312, + 488.87750244140625, + 1211.921630859375, + 3031.0078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8291875720024109, + "bbox": [ + 1241.6533203125, + 1144.5491943359375, + 2315.455078125, + 1725.8028564453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8220558166503906, + "bbox": [ + 1257.162841796875, + 1280.3243408203125, + 2217.109375, + 1413.4010009765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8107846975326538, + "bbox": [ + 1251.0623779296875, + 2118.6533203125, + 2146.95068359375, + 2227.070556640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.746609091758728, + "bbox": [ + 1248.7774658203125, + 2049.69677734375, + 2186.668212890625, + 2125.168212890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6305058598518372, + "bbox": [ + 1247.0965576171875, + 2624.22021484375, + 2026.6259765625, + 2689.923583984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6080125570297241, + "bbox": [ + 1250.698974609375, + 2610.531005859375, + 2031.059814453125, + 2704.65966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.5366713404655457, + "bbox": [ + 1230.085693359375, + 1911.0274658203125, + 2256.20703125, + 2366.303955078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.17180685698986053, + "bbox": [ + 210.44129943847656, + 1567.746826171875, + 1205.818359375, + 3082.11474609375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7631301879882812, + "bbox": [ + 1249.71240234375, + 2527.0068359375, + 1368.4134521484375, + 2629.692138671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7423908710479736, + "bbox": [ + 1259.1263427734375, + 1954.6392822265625, + 1369.4600830078125, + 2051.2158203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7371372580528259, + "bbox": [ + 1266.1046142578125, + 1191.31396484375, + 1382.3958740234375, + 1288.062255859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6443009972572327, + "bbox": [ + 1538.4713134765625, + 1176.868896484375, + 1659.90966796875, + 1292.151611328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6369273662567139, + "bbox": [ + 1479.8643798828125, + 1932.4456787109375, + 1606.90380859375, + 2058.20654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6345170140266418, + "bbox": [ + 1462.557373046875, + 2497.307373046875, + 1592.8426513671875, + 2630.5751953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5546056628227234, + "bbox": [ + 2104.216064453125, + 3072.8046875, + 2192.110595703125, + 3145.80517578125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9187479615211487, + "bbox": [ + 1250.12841796875, + 2697.40576171875, + 2114.49560546875, + 3053.944580078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9182093143463135, + "bbox": [ + 1249.125732421875, + 409.1916198730469, + 2265.78955078125, + 1018.2421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8877222537994385, + "bbox": [ + 1223.094482421875, + 2473.58544921875, + 2236.861083984375, + 3072.441162109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8849437236785889, + "bbox": [ + 1251.2005615234375, + 1923.387939453125, + 2246.10205078125, + 2241.09033203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8652137517929077, + "bbox": [ + 1260.7471923828125, + 1424.1236572265625, + 2110.28955078125, + 1641.166748046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8641857504844666, + "bbox": [ + 227.31521606445312, + 488.87750244140625, + 1211.921630859375, + 3031.0078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8291875720024109, + "bbox": [ + 1241.6533203125, + 1144.5491943359375, + 2315.455078125, + 1725.8028564453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8220558166503906, + "bbox": [ + 1257.162841796875, + 1280.3243408203125, + 2217.109375, + 1413.4010009765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8107846975326538, + "bbox": [ + 1251.0623779296875, + 2118.6533203125, + 2146.95068359375, + 2227.070556640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.746609091758728, + "bbox": [ + 1248.7774658203125, + 2049.69677734375, + 2186.668212890625, + 2125.168212890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6305058598518372, + "bbox": [ + 1247.0965576171875, + 2624.22021484375, + 2026.6259765625, + 2689.923583984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6080125570297241, + "bbox": [ + 1250.698974609375, + 2610.531005859375, + 2031.059814453125, + 2704.65966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.5366713404655457, + "bbox": [ + 1230.085693359375, + 1911.0274658203125, + 2256.20703125, + 2366.303955078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.17180685698986053, + "bbox": [ + 210.44129943847656, + 1567.746826171875, + 1205.818359375, + 3082.11474609375 + ] + } + ], + "timestamp": "2025-10-15T21:42:19.949438" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 18.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 18.json" new file mode 100644 index 0000000..5e384ca --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 18.json" @@ -0,0 +1,626 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 18.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7910915017127991, + "bbox": [ + 230.35317993164062, + 1696.62548828125, + 334.7241516113281, + 1784.8590087890625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7894256711006165, + "bbox": [ + 1218.0115966796875, + 499.1844482421875, + 1315.185546875, + 585.120361328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7800495028495789, + "bbox": [ + 219.83982849121094, + 2433.24365234375, + 324.06781005859375, + 2523.5966796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7800227999687195, + "bbox": [ + 239.15411376953125, + 962.5027465820312, + 340.45233154296875, + 1054.2579345703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7776979804039001, + "bbox": [ + 1196.5953369140625, + 2442.850341796875, + 1298.6729736328125, + 2528.152099609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6733511090278625, + "bbox": [ + 892.2962036132812, + 2695.182373046875, + 1007.4478149414062, + 2813.342529296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6496018171310425, + "bbox": [ + 1804.4677734375, + 2683.58984375, + 1921.677978515625, + 2796.089111328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6390625834465027, + "bbox": [ + 932.2650146484375, + 1918.0496826171875, + 1055.667724609375, + 2042.06884765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6274062991142273, + "bbox": [ + 978.3050537109375, + 1159.1876220703125, + 1103.3677978515625, + 1278.367431640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5472032427787781, + "bbox": [ + 217.8408203125, + 3010.2392578125, + 304.44696044921875, + 3082.525390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.511578381061554, + "bbox": [ + 1709.371337890625, + 1615.722412109375, + 1900.1365966796875, + 1773.5428466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4107294976711273, + "bbox": [ + 1377.29296875, + 875.92822265625, + 1439.489501953125, + 949.4154663085938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2509668171405792, + "bbox": [ + 204.6452178955078, + 3002.928466796875, + 307.5387268066406, + 3090.580322265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9257043600082397, + "bbox": [ + 1300.98583984375, + 724.2887573242188, + 2048.181396484375, + 1450.59765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9178515672683716, + "bbox": [ + 179.17300415039062, + 2406.8076171875, + 1148.363525390625, + 3016.5009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9130489230155945, + "bbox": [ + 205.57872009277344, + 921.8033447265625, + 1166.1492919921875, + 1615.3475341796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9111249446868896, + "bbox": [ + 242.34658813476562, + 1913.02587890625, + 822.146484375, + 2268.8994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9072135090827942, + "bbox": [ + 1169.2891845703125, + 467.41357421875, + 2180.331787109375, + 1808.6070556640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9000824093818665, + "bbox": [ + 199.4387664794922, + 1655.28759765625, + 1168.10986328125, + 2285.64404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8855061531066895, + "bbox": [ + 246.6758575439453, + 1181.281494140625, + 1045.549560546875, + 1539.4656982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8815263509750366, + "bbox": [ + 1183.1241455078125, + 2416.802734375, + 2178.5849609375, + 3055.8701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8798478245735168, + "bbox": [ + 1194.4471435546875, + 2670.7724609375, + 1709.8223876953125, + 3002.341552734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8509026765823364, + "bbox": [ + 225.53494262695312, + 2525.226318359375, + 1133.4140625, + 2648.425537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8382829427719116, + "bbox": [ + 1198.4517822265625, + 2535.956787109375, + 2102.91748046875, + 2654.66650390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8237183094024658, + "bbox": [ + 1206.3433837890625, + 584.2828979492188, + 2124.816162109375, + 708.138916015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8142625689506531, + "bbox": [ + 248.7885284423828, + 1053.3914794921875, + 1132.5595703125, + 1170.868896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8042677044868469, + "bbox": [ + 239.74069213867188, + 1792.6939697265625, + 1123.04052734375, + 1909.8460693359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7668336629867554, + "bbox": [ + 223.9656524658203, + 2652.184814453125, + 522.0737915039062, + 3002.47314453125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7910915017127991, + "bbox": [ + 230.35317993164062, + 1696.62548828125, + 334.7241516113281, + 1784.8590087890625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7894256711006165, + "bbox": [ + 1218.0115966796875, + 499.1844482421875, + 1315.185546875, + 585.120361328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7800495028495789, + "bbox": [ + 219.83982849121094, + 2433.24365234375, + 324.06781005859375, + 2523.5966796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7800227999687195, + "bbox": [ + 239.15411376953125, + 962.5027465820312, + 340.45233154296875, + 1054.2579345703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7776979804039001, + "bbox": [ + 1196.5953369140625, + 2442.850341796875, + 1298.6729736328125, + 2528.152099609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6733511090278625, + "bbox": [ + 892.2962036132812, + 2695.182373046875, + 1007.4478149414062, + 2813.342529296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6496018171310425, + "bbox": [ + 1804.4677734375, + 2683.58984375, + 1921.677978515625, + 2796.089111328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6390625834465027, + "bbox": [ + 932.2650146484375, + 1918.0496826171875, + 1055.667724609375, + 2042.06884765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6274062991142273, + "bbox": [ + 978.3050537109375, + 1159.1876220703125, + 1103.3677978515625, + 1278.367431640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5472032427787781, + "bbox": [ + 217.8408203125, + 3010.2392578125, + 304.44696044921875, + 3082.525390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.511578381061554, + "bbox": [ + 1709.371337890625, + 1615.722412109375, + 1900.1365966796875, + 1773.5428466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4107294976711273, + "bbox": [ + 1377.29296875, + 875.92822265625, + 1439.489501953125, + 949.4154663085938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2509668171405792, + "bbox": [ + 204.6452178955078, + 3002.928466796875, + 307.5387268066406, + 3090.580322265625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9257043600082397, + "bbox": [ + 1300.98583984375, + 724.2887573242188, + 2048.181396484375, + 1450.59765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9178515672683716, + "bbox": [ + 179.17300415039062, + 2406.8076171875, + 1148.363525390625, + 3016.5009765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9130489230155945, + "bbox": [ + 205.57872009277344, + 921.8033447265625, + 1166.1492919921875, + 1615.3475341796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9111249446868896, + "bbox": [ + 242.34658813476562, + 1913.02587890625, + 822.146484375, + 2268.8994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9072135090827942, + "bbox": [ + 1169.2891845703125, + 467.41357421875, + 2180.331787109375, + 1808.6070556640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9000824093818665, + "bbox": [ + 199.4387664794922, + 1655.28759765625, + 1168.10986328125, + 2285.64404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8855061531066895, + "bbox": [ + 246.6758575439453, + 1181.281494140625, + 1045.549560546875, + 1539.4656982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8815263509750366, + "bbox": [ + 1183.1241455078125, + 2416.802734375, + 2178.5849609375, + 3055.8701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8798478245735168, + "bbox": [ + 1194.4471435546875, + 2670.7724609375, + 1709.8223876953125, + 3002.341552734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8509026765823364, + "bbox": [ + 225.53494262695312, + 2525.226318359375, + 1133.4140625, + 2648.425537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8382829427719116, + "bbox": [ + 1198.4517822265625, + 2535.956787109375, + 2102.91748046875, + 2654.66650390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8237183094024658, + "bbox": [ + 1206.3433837890625, + 584.2828979492188, + 2124.816162109375, + 708.138916015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8142625689506531, + "bbox": [ + 248.7885284423828, + 1053.3914794921875, + 1132.5595703125, + 1170.868896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8042677044868469, + "bbox": [ + 239.74069213867188, + 1792.6939697265625, + 1123.04052734375, + 1909.8460693359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7668336629867554, + "bbox": [ + 223.9656524658203, + 2652.184814453125, + 522.0737915039062, + 3002.47314453125 + ] + } + ], + "timestamp": "2025-10-15T21:42:20.321822" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 19.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 19.json" new file mode 100644 index 0000000..19a89d5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 19.json" @@ -0,0 +1,648 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 19.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7806082963943481, + "bbox": [ + 260.4742126464844, + 2552.689208984375, + 367.7405090332031, + 2644.792236328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7665067315101624, + "bbox": [ + 1281.30517578125, + 2187.93798828125, + 1388.53076171875, + 2285.638427734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7657893896102905, + "bbox": [ + 270.83685302734375, + 1464.469482421875, + 379.5198669433594, + 1557.2265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7619249820709229, + "bbox": [ + 275.1424255371094, + 433.4808044433594, + 388.0682067871094, + 525.6077270507812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7584542036056519, + "bbox": [ + 1290.5780029296875, + 441.8584289550781, + 1400.74658203125, + 534.2255249023438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6924356818199158, + "bbox": [ + 2001.152099609375, + 2359.5966796875, + 2114.89990234375, + 2471.18310546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6541412472724915, + "bbox": [ + 879.8652954101562, + 865.1585083007812, + 1005.1033935546875, + 994.0985717773438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6507939696311951, + "bbox": [ + 1800.3455810546875, + 1109.87158203125, + 1931.7371826171875, + 1240.5052490234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6496552228927612, + "bbox": [ + 908.044189453125, + 2073.95751953125, + 1030.516845703125, + 2202.4150390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6331442594528198, + "bbox": [ + 820.9244995117188, + 2823.184814453125, + 963.7505493164062, + 2962.852294921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5729832053184509, + "bbox": [ + 2134.70849609375, + 3167.5390625, + 2216.06640625, + 3236.526123046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.25601625442504883, + "bbox": [ + 889.1231079101562, + 2065.851318359375, + 1047.9351806640625, + 2213.17236328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.23071812093257904, + "bbox": [ + 1782.7469482421875, + 1102.794189453125, + 1946.5107421875, + 1255.462158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9307416677474976, + "bbox": [ + 1266.3680419921875, + 2402.033935546875, + 2219.42724609375, + 3127.4052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9289821982383728, + "bbox": [ + 1239.5794677734375, + 2138.07763671875, + 2238.72998046875, + 3161.428466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025497436523438, + "bbox": [ + 184.88475036621094, + 2505.998291015625, + 1225.9521484375, + 3198.6708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8965824246406555, + "bbox": [ + 222.63108825683594, + 390.1928405761719, + 1225.00830078125, + 1027.4793701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8800339102745056, + "bbox": [ + 1297.4991455078125, + 672.8602905273438, + 2058.8916015625, + 1009.163818359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8681506514549255, + "bbox": [ + 1287.49072265625, + 537.6287231445312, + 2234.968017578125, + 662.1790771484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8671602010726929, + "bbox": [ + 262.3607177734375, + 2643.1083984375, + 1194.009521484375, + 2770.321044921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8658437728881836, + "bbox": [ + 1258.4461669921875, + 399.8854675292969, + 2268.444580078125, + 1280.9931640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8502557873725891, + "bbox": [ + 267.3343200683594, + 2775.281982421875, + 573.3631591796875, + 3151.489501953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8367086052894592, + "bbox": [ + 1284.1024169921875, + 2285.1767578125, + 2232.129638671875, + 2409.434814453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8356109261512756, + "bbox": [ + 262.9279479980469, + 1692.6763916015625, + 828.67724609375, + 2061.722900390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8067290782928467, + "bbox": [ + 271.2767639160156, + 1562.9161376953125, + 1221.2308349609375, + 1686.8173828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7971253991127014, + "bbox": [ + 177.5136260986328, + 1399.8631591796875, + 1232.65673828125, + 2254.543701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7488017678260803, + "bbox": [ + 273.7868957519531, + 518.4130859375, + 1018.0195922851562, + 603.6983642578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5752869844436646, + "bbox": [ + 279.17352294921875, + 602.251220703125, + 579.3604125976562, + 960.1095581054688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.48882952332496643, + "bbox": [ + 278.0295104980469, + 604.2296752929688, + 909.8511352539062, + 973.5428466796875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7806082963943481, + "bbox": [ + 260.4742126464844, + 2552.689208984375, + 367.7405090332031, + 2644.792236328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7665067315101624, + "bbox": [ + 1281.30517578125, + 2187.93798828125, + 1388.53076171875, + 2285.638427734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7657893896102905, + "bbox": [ + 270.83685302734375, + 1464.469482421875, + 379.5198669433594, + 1557.2265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7619249820709229, + "bbox": [ + 275.1424255371094, + 433.4808044433594, + 388.0682067871094, + 525.6077270507812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7584542036056519, + "bbox": [ + 1290.5780029296875, + 441.8584289550781, + 1400.74658203125, + 534.2255249023438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6924356818199158, + "bbox": [ + 2001.152099609375, + 2359.5966796875, + 2114.89990234375, + 2471.18310546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6541412472724915, + "bbox": [ + 879.8652954101562, + 865.1585083007812, + 1005.1033935546875, + 994.0985717773438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6507939696311951, + "bbox": [ + 1800.3455810546875, + 1109.87158203125, + 1931.7371826171875, + 1240.5052490234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6496552228927612, + "bbox": [ + 908.044189453125, + 2073.95751953125, + 1030.516845703125, + 2202.4150390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6331442594528198, + "bbox": [ + 820.9244995117188, + 2823.184814453125, + 963.7505493164062, + 2962.852294921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5729832053184509, + "bbox": [ + 2134.70849609375, + 3167.5390625, + 2216.06640625, + 3236.526123046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.25601625442504883, + "bbox": [ + 889.1231079101562, + 2065.851318359375, + 1047.9351806640625, + 2213.17236328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.23071812093257904, + "bbox": [ + 1782.7469482421875, + 1102.794189453125, + 1946.5107421875, + 1255.462158203125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9307416677474976, + "bbox": [ + 1266.3680419921875, + 2402.033935546875, + 2219.42724609375, + 3127.4052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9289821982383728, + "bbox": [ + 1239.5794677734375, + 2138.07763671875, + 2238.72998046875, + 3161.428466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025497436523438, + "bbox": [ + 184.88475036621094, + 2505.998291015625, + 1225.9521484375, + 3198.6708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8965824246406555, + "bbox": [ + 222.63108825683594, + 390.1928405761719, + 1225.00830078125, + 1027.4793701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8800339102745056, + "bbox": [ + 1297.4991455078125, + 672.8602905273438, + 2058.8916015625, + 1009.163818359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8681506514549255, + "bbox": [ + 1287.49072265625, + 537.6287231445312, + 2234.968017578125, + 662.1790771484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8671602010726929, + "bbox": [ + 262.3607177734375, + 2643.1083984375, + 1194.009521484375, + 2770.321044921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8658437728881836, + "bbox": [ + 1258.4461669921875, + 399.8854675292969, + 2268.444580078125, + 1280.9931640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8502557873725891, + "bbox": [ + 267.3343200683594, + 2775.281982421875, + 573.3631591796875, + 3151.489501953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8367086052894592, + "bbox": [ + 1284.1024169921875, + 2285.1767578125, + 2232.129638671875, + 2409.434814453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8356109261512756, + "bbox": [ + 262.9279479980469, + 1692.6763916015625, + 828.67724609375, + 2061.722900390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8067290782928467, + "bbox": [ + 271.2767639160156, + 1562.9161376953125, + 1221.2308349609375, + 1686.8173828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7971253991127014, + "bbox": [ + 177.5136260986328, + 1399.8631591796875, + 1232.65673828125, + 2254.543701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7488017678260803, + "bbox": [ + 273.7868957519531, + 518.4130859375, + 1018.0195922851562, + 603.6983642578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5752869844436646, + "bbox": [ + 279.17352294921875, + 602.251220703125, + 579.3604125976562, + 960.1095581054688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.48882952332496643, + "bbox": [ + 278.0295104980469, + 604.2296752929688, + 909.8511352539062, + 973.5428466796875 + ] + } + ], + "timestamp": "2025-10-15T21:42:19.919632" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 20.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 20.json" new file mode 100644 index 0000000..15457fd --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 20.json" @@ -0,0 +1,670 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 20.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.770004391670227, + "bbox": [ + 227.8684844970703, + 1394.197509765625, + 337.5234069824219, + 1495.2420654296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.768976092338562, + "bbox": [ + 217.39999389648438, + 2215.935791015625, + 331.8891906738281, + 2320.3251953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7578659057617188, + "bbox": [ + 1280.75146484375, + 2218.473388671875, + 1387.6768798828125, + 2317.35400390625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7428791522979736, + "bbox": [ + 230.2537078857422, + 444.76806640625, + 342.75421142578125, + 551.8841552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.739993155002594, + "bbox": [ + 1291.6243896484375, + 457.6066589355469, + 1401.493896484375, + 560.59228515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7256499528884888, + "bbox": [ + 1888.666748046875, + 2395.322509765625, + 1995.644287109375, + 2497.0751953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7168436646461487, + "bbox": [ + 988.0191040039062, + 617.763671875, + 1097.1043701171875, + 717.18359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7033721804618835, + "bbox": [ + 969.8660278320312, + 2384.013671875, + 1093.8612060546875, + 2494.57080078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6732162237167358, + "bbox": [ + 958.989990234375, + 1541.8289794921875, + 1085.7752685546875, + 1663.0765380859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6503382921218872, + "bbox": [ + 1884.4066162109375, + 1448.2974853515625, + 2012.322265625, + 1577.9632568359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5782093405723572, + "bbox": [ + 218.05003356933594, + 3255.59326171875, + 308.6983947753906, + 3329.9345703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.22545643150806427, + "bbox": [ + 210.63072204589844, + 3244.712646484375, + 316.4281921386719, + 3338.673583984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9425860047340393, + "bbox": [ + 1283.8472900390625, + 789.8594970703125, + 2292.91015625, + 1424.7850341796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9388155341148376, + "bbox": [ + 196.3930206298828, + 2556.99072265625, + 1195.829833984375, + 3240.28125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.938155472278595, + "bbox": [ + 1276.2421875, + 2564.715576171875, + 2290.51220703125, + 3244.47802734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9302681088447571, + "bbox": [ + 226.6257781982422, + 685.9007568359375, + 1215.5958251953125, + 1297.10302734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9289887547492981, + "bbox": [ + 1247.750732421875, + 2183.6572265625, + 2317.90869140625, + 3290.12841796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9199828505516052, + "bbox": [ + 146.8144989013672, + 2176.79638671875, + 1212.3533935546875, + 3283.78271484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9105452299118042, + "bbox": [ + 222.23834228515625, + 1648.3890380859375, + 1200.869873046875, + 2109.9423828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9011641144752502, + "bbox": [ + 1242.2508544921875, + 384.0574035644531, + 2459.2666015625, + 1617.397216796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8988088369369507, + "bbox": [ + 180.63937377929688, + 1359.5283203125, + 1229.5303955078125, + 2150.76708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8803334832191467, + "bbox": [ + 190.84584045410156, + 421.8017883300781, + 1230.582763671875, + 1341.2467041015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8684792518615723, + "bbox": [ + 222.4640655517578, + 2309.5390625, + 1195.539306640625, + 2443.471435546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8513786792755127, + "bbox": [ + 1286.2598876953125, + 553.5436401367188, + 2295.742919921875, + 691.4363403320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8354985117912292, + "bbox": [ + 223.97247314453125, + 1489.9429931640625, + 1221.075439453125, + 1626.068603515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8143616914749146, + "bbox": [ + 198.7401580810547, + 2449.326416015625, + 1178.1917724609375, + 2555.345458984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.811147153377533, + "bbox": [ + 1282.1292724609375, + 2456.3984375, + 2263.775146484375, + 2565.2275390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8096005916595459, + "bbox": [ + 1283.961669921875, + 2313.198486328125, + 2263.112060546875, + 2448.741943359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7948641777038574, + "bbox": [ + 222.3987274169922, + 544.5414428710938, + 1204.582763671875, + 685.6777954101562 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5346129536628723, + "bbox": [ + 1286.0950927734375, + 688.2029418945312, + 2281.003173828125, + 798.1704711914062 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.770004391670227, + "bbox": [ + 227.8684844970703, + 1394.197509765625, + 337.5234069824219, + 1495.2420654296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.768976092338562, + "bbox": [ + 217.39999389648438, + 2215.935791015625, + 331.8891906738281, + 2320.3251953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7578659057617188, + "bbox": [ + 1280.75146484375, + 2218.473388671875, + 1387.6768798828125, + 2317.35400390625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7428791522979736, + "bbox": [ + 230.2537078857422, + 444.76806640625, + 342.75421142578125, + 551.8841552734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.739993155002594, + "bbox": [ + 1291.6243896484375, + 457.6066589355469, + 1401.493896484375, + 560.59228515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7256499528884888, + "bbox": [ + 1888.666748046875, + 2395.322509765625, + 1995.644287109375, + 2497.0751953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7168436646461487, + "bbox": [ + 988.0191040039062, + 617.763671875, + 1097.1043701171875, + 717.18359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7033721804618835, + "bbox": [ + 969.8660278320312, + 2384.013671875, + 1093.8612060546875, + 2494.57080078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6732162237167358, + "bbox": [ + 958.989990234375, + 1541.8289794921875, + 1085.7752685546875, + 1663.0765380859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6503382921218872, + "bbox": [ + 1884.4066162109375, + 1448.2974853515625, + 2012.322265625, + 1577.9632568359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5782093405723572, + "bbox": [ + 218.05003356933594, + 3255.59326171875, + 308.6983947753906, + 3329.9345703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.22545643150806427, + "bbox": [ + 210.63072204589844, + 3244.712646484375, + 316.4281921386719, + 3338.673583984375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9425860047340393, + "bbox": [ + 1283.8472900390625, + 789.8594970703125, + 2292.91015625, + 1424.7850341796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9388155341148376, + "bbox": [ + 196.3930206298828, + 2556.99072265625, + 1195.829833984375, + 3240.28125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.938155472278595, + "bbox": [ + 1276.2421875, + 2564.715576171875, + 2290.51220703125, + 3244.47802734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9302681088447571, + "bbox": [ + 226.6257781982422, + 685.9007568359375, + 1215.5958251953125, + 1297.10302734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9289887547492981, + "bbox": [ + 1247.750732421875, + 2183.6572265625, + 2317.90869140625, + 3290.12841796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9199828505516052, + "bbox": [ + 146.8144989013672, + 2176.79638671875, + 1212.3533935546875, + 3283.78271484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9105452299118042, + "bbox": [ + 222.23834228515625, + 1648.3890380859375, + 1200.869873046875, + 2109.9423828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9011641144752502, + "bbox": [ + 1242.2508544921875, + 384.0574035644531, + 2459.2666015625, + 1617.397216796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8988088369369507, + "bbox": [ + 180.63937377929688, + 1359.5283203125, + 1229.5303955078125, + 2150.76708984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8803334832191467, + "bbox": [ + 190.84584045410156, + 421.8017883300781, + 1230.582763671875, + 1341.2467041015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8684792518615723, + "bbox": [ + 222.4640655517578, + 2309.5390625, + 1195.539306640625, + 2443.471435546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8513786792755127, + "bbox": [ + 1286.2598876953125, + 553.5436401367188, + 2295.742919921875, + 691.4363403320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8354985117912292, + "bbox": [ + 223.97247314453125, + 1489.9429931640625, + 1221.075439453125, + 1626.068603515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8143616914749146, + "bbox": [ + 198.7401580810547, + 2449.326416015625, + 1178.1917724609375, + 2555.345458984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.811147153377533, + "bbox": [ + 1282.1292724609375, + 2456.3984375, + 2263.775146484375, + 2565.2275390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8096005916595459, + "bbox": [ + 1283.961669921875, + 2313.198486328125, + 2263.112060546875, + 2448.741943359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7948641777038574, + "bbox": [ + 222.3987274169922, + 544.5414428710938, + 1204.582763671875, + 685.6777954101562 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5346129536628723, + "bbox": [ + 1286.0950927734375, + 688.2029418945312, + 2281.003173828125, + 798.1704711914062 + ] + } + ], + "timestamp": "2025-10-15T21:42:20.285621" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 21.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 21.json" new file mode 100644 index 0000000..0894f5c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 21.json" @@ -0,0 +1,406 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 21.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7600154280662537, + "bbox": [ + 248.6562042236328, + 1725.99072265625, + 355.55767822265625, + 1828.3558349609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7479546070098877, + "bbox": [ + 1250.4852294921875, + 436.2503356933594, + 1355.2362060546875, + 533.615478515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.733197808265686, + "bbox": [ + 253.00140380859375, + 554.424072265625, + 357.7325134277344, + 653.5487670898438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7327031493186951, + "bbox": [ + 1043.0130615234375, + 681.7967529296875, + 1143.5816650390625, + 795.373046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6604880690574646, + "bbox": [ + 1955.669189453125, + 2711.767333984375, + 2072.642333984375, + 2829.921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6193154454231262, + "bbox": [ + 795.8218994140625, + 1958.0054931640625, + 928.4794311523438, + 2093.172119140625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6105974912643433, + "bbox": [ + 2074.02490234375, + 3095.677490234375, + 2155.341064453125, + 3166.094482421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2603116035461426, + "bbox": [ + 1938.94189453125, + 2704.4921875, + 2085.761474609375, + 2843.463134765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9225572943687439, + "bbox": [ + 248.07408142089844, + 735.6043090820312, + 1129.4544677734375, + 1107.1153564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9154878854751587, + "bbox": [ + 1216.0084228515625, + 411.1801452636719, + 2155.84326171875, + 2885.19921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9094707369804382, + "bbox": [ + 1260.2086181640625, + 661.39111328125, + 2104.07861328125, + 2299.278564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8934165835380554, + "bbox": [ + 194.86402893066406, + 1692.945068359375, + 1178.694580078125, + 2305.255126953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8931736350059509, + "bbox": [ + 233.5961151123047, + 525.005859375, + 1198.8087158203125, + 1167.3118896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8930615186691284, + "bbox": [ + 1231.3604736328125, + 2298.90087890625, + 2059.439453125, + 2670.651123046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.888836145401001, + "bbox": [ + 248.04222106933594, + 1906.90625, + 645.3184204101562, + 2270.5087890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7547680139541626, + "bbox": [ + 1246.5848388671875, + 537.1744995117188, + 1830.3382568359375, + 609.3684692382812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7489905953407288, + "bbox": [ + 245.0144500732422, + 1816.89306640625, + 646.7540893554688, + 1899.2235107421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7435820698738098, + "bbox": [ + 251.01722717285156, + 639.7962646484375, + 884.8085327148438, + 721.9888916015625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7600154280662537, + "bbox": [ + 248.6562042236328, + 1725.99072265625, + 355.55767822265625, + 1828.3558349609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7479546070098877, + "bbox": [ + 1250.4852294921875, + 436.2503356933594, + 1355.2362060546875, + 533.615478515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.733197808265686, + "bbox": [ + 253.00140380859375, + 554.424072265625, + 357.7325134277344, + 653.5487670898438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7327031493186951, + "bbox": [ + 1043.0130615234375, + 681.7967529296875, + 1143.5816650390625, + 795.373046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6604880690574646, + "bbox": [ + 1955.669189453125, + 2711.767333984375, + 2072.642333984375, + 2829.921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6193154454231262, + "bbox": [ + 795.8218994140625, + 1958.0054931640625, + 928.4794311523438, + 2093.172119140625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6105974912643433, + "bbox": [ + 2074.02490234375, + 3095.677490234375, + 2155.341064453125, + 3166.094482421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2603116035461426, + "bbox": [ + 1938.94189453125, + 2704.4921875, + 2085.761474609375, + 2843.463134765625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9225572943687439, + "bbox": [ + 248.07408142089844, + 735.6043090820312, + 1129.4544677734375, + 1107.1153564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9154878854751587, + "bbox": [ + 1216.0084228515625, + 411.1801452636719, + 2155.84326171875, + 2885.19921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9094707369804382, + "bbox": [ + 1260.2086181640625, + 661.39111328125, + 2104.07861328125, + 2299.278564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8934165835380554, + "bbox": [ + 194.86402893066406, + 1692.945068359375, + 1178.694580078125, + 2305.255126953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8931736350059509, + "bbox": [ + 233.5961151123047, + 525.005859375, + 1198.8087158203125, + 1167.3118896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8930615186691284, + "bbox": [ + 1231.3604736328125, + 2298.90087890625, + 2059.439453125, + 2670.651123046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.888836145401001, + "bbox": [ + 248.04222106933594, + 1906.90625, + 645.3184204101562, + 2270.5087890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7547680139541626, + "bbox": [ + 1246.5848388671875, + 537.1744995117188, + 1830.3382568359375, + 609.3684692382812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7489905953407288, + "bbox": [ + 245.0144500732422, + 1816.89306640625, + 646.7540893554688, + 1899.2235107421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7435820698738098, + "bbox": [ + 251.01722717285156, + 639.7962646484375, + 884.8085327148438, + 721.9888916015625 + ] + } + ], + "timestamp": "2025-10-15T21:42:20.738537" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 22.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 22.json" new file mode 100644 index 0000000..d24ac09 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 22.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 22.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.749894917011261, + "bbox": [ + 1292.4083251953125, + 466.3904113769531, + 1405.4862060546875, + 561.9081420898438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7435379028320312, + "bbox": [ + 234.83375549316406, + 447.31365966796875, + 348.72137451171875, + 547.6092529296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7019142508506775, + "bbox": [ + 1079.914794921875, + 555.5654296875, + 1189.1385498046875, + 659.0630493164062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6580477952957153, + "bbox": [ + 2200.89111328125, + 561.7781982421875, + 2296.7607421875, + 651.3455200195312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4683842957019806, + "bbox": [ + 231.07928466796875, + 3243.40673828125, + 324.36322021484375, + 3316.35546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9489567875862122, + "bbox": [ + 1289.3067626953125, + 2134.713623046875, + 2290.681396484375, + 2813.06689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9251753091812134, + "bbox": [ + 1288.3204345703125, + 660.3208618164062, + 2266.946533203125, + 2095.79248046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9172502160072327, + "bbox": [ + 224.95050048828125, + 643.0343017578125, + 1208.8421630859375, + 1602.077392578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9071513414382935, + "bbox": [ + 1244.216064453125, + 364.0979309082031, + 2436.4111328125, + 2889.01123046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.89444500207901, + "bbox": [ + 223.46446228027344, + 1652.935791015625, + 763.1084594726562, + 2026.03466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8889840245246887, + "bbox": [ + 159.27928161621094, + 460.1064147949219, + 1243.0948486328125, + 2116.891845703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7696119546890259, + "bbox": [ + 250.4680938720703, + 539.6641235351562, + 1028.5584716796875, + 640.7518920898438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7385724186897278, + "bbox": [ + 1301.8558349609375, + 565.8190307617188, + 2100.14404296875, + 632.9581298828125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.749894917011261, + "bbox": [ + 1292.4083251953125, + 466.3904113769531, + 1405.4862060546875, + 561.9081420898438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7435379028320312, + "bbox": [ + 234.83375549316406, + 447.31365966796875, + 348.72137451171875, + 547.6092529296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7019142508506775, + "bbox": [ + 1079.914794921875, + 555.5654296875, + 1189.1385498046875, + 659.0630493164062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6580477952957153, + "bbox": [ + 2200.89111328125, + 561.7781982421875, + 2296.7607421875, + 651.3455200195312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4683842957019806, + "bbox": [ + 231.07928466796875, + 3243.40673828125, + 324.36322021484375, + 3316.35546875 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9489567875862122, + "bbox": [ + 1289.3067626953125, + 2134.713623046875, + 2290.681396484375, + 2813.06689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9251753091812134, + "bbox": [ + 1288.3204345703125, + 660.3208618164062, + 2266.946533203125, + 2095.79248046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9172502160072327, + "bbox": [ + 224.95050048828125, + 643.0343017578125, + 1208.8421630859375, + 1602.077392578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9071513414382935, + "bbox": [ + 1244.216064453125, + 364.0979309082031, + 2436.4111328125, + 2889.01123046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.89444500207901, + "bbox": [ + 223.46446228027344, + 1652.935791015625, + 763.1084594726562, + 2026.03466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8889840245246887, + "bbox": [ + 159.27928161621094, + 460.1064147949219, + 1243.0948486328125, + 2116.891845703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7696119546890259, + "bbox": [ + 250.4680938720703, + 539.6641235351562, + 1028.5584716796875, + 640.7518920898438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7385724186897278, + "bbox": [ + 1301.8558349609375, + 565.8190307617188, + 2100.14404296875, + 632.9581298828125 + ] + } + ], + "timestamp": "2025-10-15T21:42:21.123823" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 23.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 23.json" new file mode 100644 index 0000000..e778e77 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 23.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 23.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7583073973655701, + "bbox": [ + 1315.4588623046875, + 458.1630859375, + 1427.9962158203125, + 557.2672119140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.749862015247345, + "bbox": [ + 258.67315673828125, + 438.832763671875, + 377.02880859375, + 543.326171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6795905828475952, + "bbox": [ + 977.0494995117188, + 2400.445068359375, + 1092.5443115234375, + 2517.457275390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6604072451591492, + "bbox": [ + 2010.1856689453125, + 2505.9365234375, + 2133.678466796875, + 2630.3076171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5867871642112732, + "bbox": [ + 2188.0361328125, + 3215.247314453125, + 2278.178466796875, + 3290.709716796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9407867789268494, + "bbox": [ + 196.7617950439453, + 470.0298156738281, + 1258.81298828125, + 2477.304443359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9302079677581787, + "bbox": [ + 247.22377014160156, + 684.0687866210938, + 1240.1390380859375, + 1915.2335205078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9238818883895874, + "bbox": [ + 1304.8209228515625, + 650.1387329101562, + 2271.716064453125, + 1859.27587890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9183475375175476, + "bbox": [ + 1305.7777099609375, + 1913.403564453125, + 2286.17041015625, + 2540.195068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.894358217716217, + "bbox": [ + 1270.8870849609375, + 463.6681823730469, + 2308.056396484375, + 2585.648193359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8862616419792175, + "bbox": [ + 256.6649169921875, + 1972.3564453125, + 1237.6002197265625, + 2403.973876953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8266939520835876, + "bbox": [ + 258.3373107910156, + 542.9675903320312, + 1237.476806640625, + 672.9326171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6949105858802795, + "bbox": [ + 1320.3643798828125, + 557.3768310546875, + 1859.4832763671875, + 637.4200439453125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7583073973655701, + "bbox": [ + 1315.4588623046875, + 458.1630859375, + 1427.9962158203125, + 557.2672119140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.749862015247345, + "bbox": [ + 258.67315673828125, + 438.832763671875, + 377.02880859375, + 543.326171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6795905828475952, + "bbox": [ + 977.0494995117188, + 2400.445068359375, + 1092.5443115234375, + 2517.457275390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6604072451591492, + "bbox": [ + 2010.1856689453125, + 2505.9365234375, + 2133.678466796875, + 2630.3076171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5867871642112732, + "bbox": [ + 2188.0361328125, + 3215.247314453125, + 2278.178466796875, + 3290.709716796875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9407867789268494, + "bbox": [ + 196.7617950439453, + 470.0298156738281, + 1258.81298828125, + 2477.304443359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9302079677581787, + "bbox": [ + 247.22377014160156, + 684.0687866210938, + 1240.1390380859375, + 1915.2335205078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9238818883895874, + "bbox": [ + 1304.8209228515625, + 650.1387329101562, + 2271.716064453125, + 1859.27587890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9183475375175476, + "bbox": [ + 1305.7777099609375, + 1913.403564453125, + 2286.17041015625, + 2540.195068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.894358217716217, + "bbox": [ + 1270.8870849609375, + 463.6681823730469, + 2308.056396484375, + 2585.648193359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8862616419792175, + "bbox": [ + 256.6649169921875, + 1972.3564453125, + 1237.6002197265625, + 2403.973876953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8266939520835876, + "bbox": [ + 258.3373107910156, + 542.9675903320312, + 1237.476806640625, + 672.9326171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6949105858802795, + "bbox": [ + 1320.3643798828125, + 557.3768310546875, + 1859.4832763671875, + 637.4200439453125 + ] + } + ], + "timestamp": "2025-10-15T21:42:21.529891" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 24.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 24.json" new file mode 100644 index 0000000..8de7583 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 24.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 24.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7603040337562561, + "bbox": [ + 1243.0264892578125, + 440.6341857910156, + 1355.69091796875, + 539.8180541992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7409763336181641, + "bbox": [ + 209.2268829345703, + 424.6160888671875, + 327.13189697265625, + 528.352783203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7084857821464539, + "bbox": [ + 1952.000244140625, + 2788.70263671875, + 2066.78076171875, + 2907.456298828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6180035471916199, + "bbox": [ + 932.4114990234375, + 2666.3642578125, + 1069.0654296875, + 2802.71728515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5591386556625366, + "bbox": [ + 207.4577178955078, + 3149.909423828125, + 296.1625671386719, + 3225.72705078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9445685148239136, + "bbox": [ + 1233.0321044921875, + 2203.9228515625, + 2217.4091796875, + 2813.353515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9393221735954285, + "bbox": [ + 207.30430603027344, + 633.2778930664062, + 1163.526611328125, + 2006.29248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9351040720939636, + "bbox": [ + 197.83212280273438, + 2020.2059326171875, + 1170.059814453125, + 2679.5615234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9278611540794373, + "bbox": [ + 1230.6417236328125, + 634.27099609375, + 2199.768798828125, + 2182.162353515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8942872881889343, + "bbox": [ + 131.9254150390625, + 369.9350280761719, + 1191.67431640625, + 2865.7119140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8931431770324707, + "bbox": [ + 1200.5067138671875, + 395.0010986328125, + 2260.846923828125, + 2937.7626953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7773128747940063, + "bbox": [ + 1248.9613037109375, + 530.0830688476562, + 1852.842041015625, + 618.823486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7031071186065674, + "bbox": [ + 217.8101806640625, + 525.7796020507812, + 766.0855712890625, + 614.9223022460938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7603040337562561, + "bbox": [ + 1243.0264892578125, + 440.6341857910156, + 1355.69091796875, + 539.8180541992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7409763336181641, + "bbox": [ + 209.2268829345703, + 424.6160888671875, + 327.13189697265625, + 528.352783203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7084857821464539, + "bbox": [ + 1952.000244140625, + 2788.70263671875, + 2066.78076171875, + 2907.456298828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6180035471916199, + "bbox": [ + 932.4114990234375, + 2666.3642578125, + 1069.0654296875, + 2802.71728515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5591386556625366, + "bbox": [ + 207.4577178955078, + 3149.909423828125, + 296.1625671386719, + 3225.72705078125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9445685148239136, + "bbox": [ + 1233.0321044921875, + 2203.9228515625, + 2217.4091796875, + 2813.353515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9393221735954285, + "bbox": [ + 207.30430603027344, + 633.2778930664062, + 1163.526611328125, + 2006.29248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9351040720939636, + "bbox": [ + 197.83212280273438, + 2020.2059326171875, + 1170.059814453125, + 2679.5615234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9278611540794373, + "bbox": [ + 1230.6417236328125, + 634.27099609375, + 2199.768798828125, + 2182.162353515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8942872881889343, + "bbox": [ + 131.9254150390625, + 369.9350280761719, + 1191.67431640625, + 2865.7119140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8931431770324707, + "bbox": [ + 1200.5067138671875, + 395.0010986328125, + 2260.846923828125, + 2937.7626953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7773128747940063, + "bbox": [ + 1248.9613037109375, + 530.0830688476562, + 1852.842041015625, + 618.823486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7031071186065674, + "bbox": [ + 217.8101806640625, + 525.7796020507812, + 766.0855712890625, + 614.9223022460938 + ] + } + ], + "timestamp": "2025-10-15T21:42:21.927331" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 25.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 25.json" new file mode 100644 index 0000000..842f243 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 25.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 25.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7470338940620422, + "bbox": [ + 1306.45263671875, + 444.80322265625, + 1428.02392578125, + 547.4015502929688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7452173233032227, + "bbox": [ + 257.1669616699219, + 439.913818359375, + 372.7599182128906, + 540.7339477539062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6380429863929749, + "bbox": [ + 1803.7135009765625, + 423.1590881347656, + 1928.1517333984375, + 535.1259155273438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5977344512939453, + "bbox": [ + 2205.128173828125, + 3191.2490234375, + 2298.59521484375, + 3269.12451171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5877411365509033, + "bbox": [ + 1056.515380859375, + 2646.32470703125, + 1188.398193359375, + 2776.163330078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5483492016792297, + "bbox": [ + 1049.000732421875, + 2641.85791015625, + 1208.7122802734375, + 2795.390869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9478623270988464, + "bbox": [ + 1269.507568359375, + 351.0958251953125, + 2454.247802734375, + 2677.606689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9334686994552612, + "bbox": [ + 1311.277099609375, + 625.7213134765625, + 2296.871826171875, + 2002.0159912109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9183816313743591, + "bbox": [ + 1304.6392822265625, + 2017.734130859375, + 2327.0908203125, + 2410.439697265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8889895081520081, + "bbox": [ + 210.6180419921875, + 408.8851318359375, + 1256.8125, + 2745.53125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7976266145706177, + "bbox": [ + 248.84210205078125, + 622.2708740234375, + 1245.0836181640625, + 2713.327392578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7661908268928528, + "bbox": [ + 255.46864318847656, + 529.7603149414062, + 923.6224975585938, + 621.5368041992188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.754187822341919, + "bbox": [ + 1312.457275390625, + 552.1898803710938, + 2230.454345703125, + 616.1677856445312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7470338940620422, + "bbox": [ + 1306.45263671875, + 444.80322265625, + 1428.02392578125, + 547.4015502929688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7452173233032227, + "bbox": [ + 257.1669616699219, + 439.913818359375, + 372.7599182128906, + 540.7339477539062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6380429863929749, + "bbox": [ + 1803.7135009765625, + 423.1590881347656, + 1928.1517333984375, + 535.1259155273438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5977344512939453, + "bbox": [ + 2205.128173828125, + 3191.2490234375, + 2298.59521484375, + 3269.12451171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5877411365509033, + "bbox": [ + 1056.515380859375, + 2646.32470703125, + 1188.398193359375, + 2776.163330078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5483492016792297, + "bbox": [ + 1049.000732421875, + 2641.85791015625, + 1208.7122802734375, + 2795.390869140625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9478623270988464, + "bbox": [ + 1269.507568359375, + 351.0958251953125, + 2454.247802734375, + 2677.606689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9334686994552612, + "bbox": [ + 1311.277099609375, + 625.7213134765625, + 2296.871826171875, + 2002.0159912109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9183816313743591, + "bbox": [ + 1304.6392822265625, + 2017.734130859375, + 2327.0908203125, + 2410.439697265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8889895081520081, + "bbox": [ + 210.6180419921875, + 408.8851318359375, + 1256.8125, + 2745.53125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7976266145706177, + "bbox": [ + 248.84210205078125, + 622.2708740234375, + 1245.0836181640625, + 2713.327392578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7661908268928528, + "bbox": [ + 255.46864318847656, + 529.7603149414062, + 923.6224975585938, + 621.5368041992188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.754187822341919, + "bbox": [ + 1312.457275390625, + 552.1898803710938, + 2230.454345703125, + 616.1677856445312 + ] + } + ], + "timestamp": "2025-10-15T21:42:22.332829" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 26.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 26.json" new file mode 100644 index 0000000..b27678a --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 26.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 26.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7639952301979065, + "bbox": [ + 1279.1861572265625, + 458.4612731933594, + 1395.311279296875, + 556.8256225585938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.748790979385376, + "bbox": [ + 218.9242706298828, + 445.974609375, + 337.1281433105469, + 550.1585083007812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7392202615737915, + "bbox": [ + 1083.750244140625, + 607.2634887695312, + 1192.764892578125, + 723.4690551757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6924455761909485, + "bbox": [ + 2156.49755859375, + 548.27001953125, + 2283.60400390625, + 676.18359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5407971739768982, + "bbox": [ + 233.24972534179688, + 3240.1552734375, + 331.2944030761719, + 3322.29638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443373084068298, + "bbox": [ + 224.71253967285156, + 619.0139770507812, + 1161.943359375, + 2465.961669921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9408209323883057, + "bbox": [ + 1287.1007080078125, + 651.6947021484375, + 2247.23779296875, + 2650.708740234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9366406798362732, + "bbox": [ + 204.81118774414062, + 400.9768981933594, + 1211.562744140625, + 2886.3173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9093062877655029, + "bbox": [ + 227.8299560546875, + 2447.629150390625, + 1153.9886474609375, + 2813.974853515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8991206884384155, + "bbox": [ + 1294.5072021484375, + 2643.141357421875, + 2100.5361328125, + 3015.75341796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8794580101966858, + "bbox": [ + 1249.0592041015625, + 381.87432861328125, + 2306.8974609375, + 3035.4580078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8281888365745544, + "bbox": [ + 227.48216247558594, + 549.6765747070312, + 1202.5408935546875, + 676.5394287109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7056913375854492, + "bbox": [ + 1292.6578369140625, + 548.9569702148438, + 2129.958984375, + 647.6627197265625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7639952301979065, + "bbox": [ + 1279.1861572265625, + 458.4612731933594, + 1395.311279296875, + 556.8256225585938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.748790979385376, + "bbox": [ + 218.9242706298828, + 445.974609375, + 337.1281433105469, + 550.1585083007812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7392202615737915, + "bbox": [ + 1083.750244140625, + 607.2634887695312, + 1192.764892578125, + 723.4690551757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6924455761909485, + "bbox": [ + 2156.49755859375, + 548.27001953125, + 2283.60400390625, + 676.18359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5407971739768982, + "bbox": [ + 233.24972534179688, + 3240.1552734375, + 331.2944030761719, + 3322.29638671875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443373084068298, + "bbox": [ + 224.71253967285156, + 619.0139770507812, + 1161.943359375, + 2465.961669921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9408209323883057, + "bbox": [ + 1287.1007080078125, + 651.6947021484375, + 2247.23779296875, + 2650.708740234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9366406798362732, + "bbox": [ + 204.81118774414062, + 400.9768981933594, + 1211.562744140625, + 2886.3173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9093062877655029, + "bbox": [ + 227.8299560546875, + 2447.629150390625, + 1153.9886474609375, + 2813.974853515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8991206884384155, + "bbox": [ + 1294.5072021484375, + 2643.141357421875, + 2100.5361328125, + 3015.75341796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8794580101966858, + "bbox": [ + 1249.0592041015625, + 381.87432861328125, + 2306.8974609375, + 3035.4580078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8281888365745544, + "bbox": [ + 227.48216247558594, + 549.6765747070312, + 1202.5408935546875, + 676.5394287109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7056913375854492, + "bbox": [ + 1292.6578369140625, + 548.9569702148438, + 2129.958984375, + 647.6627197265625 + ] + } + ], + "timestamp": "2025-10-15T21:42:22.725829" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 27.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 27.json" new file mode 100644 index 0000000..eee35bc --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 27.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 27.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7563045024871826, + "bbox": [ + 1265.173095703125, + 445.1062316894531, + 1371.8775634765625, + 538.3765869140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.744890570640564, + "bbox": [ + 245.68658447265625, + 430.6427307128906, + 362.5268859863281, + 533.1149291992188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6402556896209717, + "bbox": [ + 2003.559326171875, + 2111.378662109375, + 2122.32421875, + 2227.587158203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209704875946045, + "bbox": [ + 844.4823608398438, + 2039.5562744140625, + 976.6078491210938, + 2167.306396484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.566334068775177, + "bbox": [ + 2114.655029296875, + 3107.4013671875, + 2202.24853515625, + 3177.225830078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9525284767150879, + "bbox": [ + 247.88026428222656, + 618.3157348632812, + 1198.6685791015625, + 1942.540771484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9316564798355103, + "bbox": [ + 1242.405517578125, + 679.2432250976562, + 2217.74951171875, + 2047.7322998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9290622472763062, + "bbox": [ + 1227.5899658203125, + 344.68780517578125, + 2310.302001953125, + 2262.320068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.923385500907898, + "bbox": [ + 192.93392944335938, + 393.9797668457031, + 1226.361572265625, + 2281.7314453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8416505455970764, + "bbox": [ + 1241.6961669921875, + 537.61083984375, + 2195.19873046875, + 663.6416625976562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7822521328926086, + "bbox": [ + 263.68463134765625, + 524.5269165039062, + 930.4883422851562, + 618.067138671875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7563045024871826, + "bbox": [ + 1265.173095703125, + 445.1062316894531, + 1371.8775634765625, + 538.3765869140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.744890570640564, + "bbox": [ + 245.68658447265625, + 430.6427307128906, + 362.5268859863281, + 533.1149291992188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6402556896209717, + "bbox": [ + 2003.559326171875, + 2111.378662109375, + 2122.32421875, + 2227.587158203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209704875946045, + "bbox": [ + 844.4823608398438, + 2039.5562744140625, + 976.6078491210938, + 2167.306396484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.566334068775177, + "bbox": [ + 2114.655029296875, + 3107.4013671875, + 2202.24853515625, + 3177.225830078125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9525284767150879, + "bbox": [ + 247.88026428222656, + 618.3157348632812, + 1198.6685791015625, + 1942.540771484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9316564798355103, + "bbox": [ + 1242.405517578125, + 679.2432250976562, + 2217.74951171875, + 2047.7322998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9290622472763062, + "bbox": [ + 1227.5899658203125, + 344.68780517578125, + 2310.302001953125, + 2262.320068359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.923385500907898, + "bbox": [ + 192.93392944335938, + 393.9797668457031, + 1226.361572265625, + 2281.7314453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8416505455970764, + "bbox": [ + 1241.6961669921875, + 537.61083984375, + 2195.19873046875, + 663.6416625976562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7822521328926086, + "bbox": [ + 263.68463134765625, + 524.5269165039062, + 930.4883422851562, + 618.067138671875 + ] + } + ], + "timestamp": "2025-10-15T21:42:23.100840" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 28.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 28.json" new file mode 100644 index 0000000..bbcf210 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 28.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 28.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7671974301338196, + "bbox": [ + 1208.6292724609375, + 427.62286376953125, + 1318.9957275390625, + 526.7385864257812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7321566343307495, + "bbox": [ + 202.8789520263672, + 540.8079223632812, + 313.92156982421875, + 644.37060546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254521608352661, + "bbox": [ + 866.705322265625, + 2150.987060546875, + 1014.4402465820312, + 2308.591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6054081320762634, + "bbox": [ + 880.777099609375, + 2158.013427734375, + 1018.0807495117188, + 2278.903564453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5955401062965393, + "bbox": [ + 1854.700439453125, + 2137.65478515625, + 1999.0965576171875, + 2275.367431640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5244964957237244, + "bbox": [ + 215.26780700683594, + 3034.26806640625, + 306.5033874511719, + 3107.3369140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9458028078079224, + "bbox": [ + 182.71018981933594, + 449.1365051269531, + 1153.0537109375, + 2508.34228515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9444642663002014, + "bbox": [ + 192.87725830078125, + 638.905029296875, + 1128.5235595703125, + 2079.979248046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9300796389579773, + "bbox": [ + 1186.2178955078125, + 417.3510437011719, + 2177.8935546875, + 2314.64697265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.928514838218689, + "bbox": [ + 1203.641357421875, + 527.40283203125, + 2157.0087890625, + 1736.680419921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9088085293769836, + "bbox": [ + 223.0669708251953, + 2115.339111328125, + 628.1900024414062, + 2468.33642578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8840155005455017, + "bbox": [ + 1212.266845703125, + 1744.49169921875, + 2010.3941650390625, + 2110.579833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6840057969093323, + "bbox": [ + 207.73658752441406, + 416.903076171875, + 1124.740966796875, + 491.5888977050781 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7671974301338196, + "bbox": [ + 1208.6292724609375, + 427.62286376953125, + 1318.9957275390625, + 526.7385864257812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7321566343307495, + "bbox": [ + 202.8789520263672, + 540.8079223632812, + 313.92156982421875, + 644.37060546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6254521608352661, + "bbox": [ + 866.705322265625, + 2150.987060546875, + 1014.4402465820312, + 2308.591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6054081320762634, + "bbox": [ + 880.777099609375, + 2158.013427734375, + 1018.0807495117188, + 2278.903564453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5955401062965393, + "bbox": [ + 1854.700439453125, + 2137.65478515625, + 1999.0965576171875, + 2275.367431640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5244964957237244, + "bbox": [ + 215.26780700683594, + 3034.26806640625, + 306.5033874511719, + 3107.3369140625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9458028078079224, + "bbox": [ + 182.71018981933594, + 449.1365051269531, + 1153.0537109375, + 2508.34228515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9444642663002014, + "bbox": [ + 192.87725830078125, + 638.905029296875, + 1128.5235595703125, + 2079.979248046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9300796389579773, + "bbox": [ + 1186.2178955078125, + 417.3510437011719, + 2177.8935546875, + 2314.64697265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.928514838218689, + "bbox": [ + 1203.641357421875, + 527.40283203125, + 2157.0087890625, + 1736.680419921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9088085293769836, + "bbox": [ + 223.0669708251953, + 2115.339111328125, + 628.1900024414062, + 2468.33642578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8840155005455017, + "bbox": [ + 1212.266845703125, + 1744.49169921875, + 2010.3941650390625, + 2110.579833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6840057969093323, + "bbox": [ + 207.73658752441406, + 416.903076171875, + 1124.740966796875, + 491.5888977050781 + ] + } + ], + "timestamp": "2025-10-15T21:42:23.450963" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 29.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 29.json" new file mode 100644 index 0000000..84ccdbb --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 29.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 29.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7490072846412659, + "bbox": [ + 244.7371368408203, + 411.09942626953125, + 360.1676025390625, + 514.1549682617188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7359649538993835, + "bbox": [ + 1248.7650146484375, + 423.65740966796875, + 1360.45947265625, + 527.7479248046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6369026899337769, + "bbox": [ + 803.07666015625, + 363.80731201171875, + 919.5338134765625, + 476.9936828613281 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6240957975387573, + "bbox": [ + 1743.98291015625, + 392.9949951171875, + 1887.8016357421875, + 535.5162353515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5925480723381042, + "bbox": [ + 2095.988525390625, + 3039.96044921875, + 2179.296875, + 3109.859130859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9367966055870056, + "bbox": [ + 240.4109649658203, + 1794.9713134765625, + 1176.377197265625, + 2451.74853515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9272936582565308, + "bbox": [ + 1219.8980712890625, + 313.4834899902344, + 2307.443359375, + 2510.211669921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9262723922729492, + "bbox": [ + 1248.688232421875, + 531.0572509765625, + 2184.9443359375, + 1996.3455810546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9128106236457825, + "bbox": [ + 237.52662658691406, + 535.4241943359375, + 1183.2330322265625, + 1727.9837646484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9073975086212158, + "bbox": [ + 1248.099853515625, + 2049.310791015625, + 2173.978515625, + 2444.32470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.895458996295929, + "bbox": [ + 202.3297119140625, + 383.0038757324219, + 1199.4635009765625, + 2504.403076171875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7490072846412659, + "bbox": [ + 244.7371368408203, + 411.09942626953125, + 360.1676025390625, + 514.1549682617188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7359649538993835, + "bbox": [ + 1248.7650146484375, + 423.65740966796875, + 1360.45947265625, + 527.7479248046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6369026899337769, + "bbox": [ + 803.07666015625, + 363.80731201171875, + 919.5338134765625, + 476.9936828613281 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6240957975387573, + "bbox": [ + 1743.98291015625, + 392.9949951171875, + 1887.8016357421875, + 535.5162353515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5925480723381042, + "bbox": [ + 2095.988525390625, + 3039.96044921875, + 2179.296875, + 3109.859130859375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9367966055870056, + "bbox": [ + 240.4109649658203, + 1794.9713134765625, + 1176.377197265625, + 2451.74853515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9272936582565308, + "bbox": [ + 1219.8980712890625, + 313.4834899902344, + 2307.443359375, + 2510.211669921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9262723922729492, + "bbox": [ + 1248.688232421875, + 531.0572509765625, + 2184.9443359375, + 1996.3455810546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9128106236457825, + "bbox": [ + 237.52662658691406, + 535.4241943359375, + 1183.2330322265625, + 1727.9837646484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9073975086212158, + "bbox": [ + 1248.099853515625, + 2049.310791015625, + 2173.978515625, + 2444.32470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.895458996295929, + "bbox": [ + 202.3297119140625, + 383.0038757324219, + 1199.4635009765625, + 2504.403076171875 + ] + } + ], + "timestamp": "2025-10-15T21:42:23.797449" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 30.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 30.json" new file mode 100644 index 0000000..6cb885a --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 30.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 30.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7478122711181641, + "bbox": [ + 217.45802307128906, + 434.11572265625, + 329.8018798828125, + 534.5653686523438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7416979074478149, + "bbox": [ + 1252.624267578125, + 613.5382690429688, + 1365.750732421875, + 714.379150390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6869469881057739, + "bbox": [ + 856.775146484375, + 426.5235290527344, + 982.0392456054688, + 545.2455444335938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5516640543937683, + "bbox": [ + 1717.7908935546875, + 548.8966674804688, + 1872.585693359375, + 704.7841186523438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5431124567985535, + "bbox": [ + 226.42828369140625, + 3128.82470703125, + 319.4625549316406, + 3203.689453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9370722770690918, + "bbox": [ + 222.5220489501953, + 619.6429443359375, + 1179.1151123046875, + 1887.2254638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9255450367927551, + "bbox": [ + 1251.167724609375, + 726.2056274414062, + 2220.2802734375, + 2536.865966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9112128019332886, + "bbox": [ + 1225.432373046875, + 421.2862854003906, + 2296.282958984375, + 2931.954345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8925390839576721, + "bbox": [ + 176.34066772460938, + 418.58099365234375, + 1195.7926025390625, + 2148.531494140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8900695443153381, + "bbox": [ + 1248.7115478515625, + 2554.833740234375, + 2065.1611328125, + 2785.1220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7875652313232422, + "bbox": [ + 224.31771850585938, + 533.2552490234375, + 866.4579467773438, + 615.2509155273438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7478898763656616, + "bbox": [ + 1237.149658203125, + 445.45220947265625, + 2243.2041015625, + 582.273681640625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7478122711181641, + "bbox": [ + 217.45802307128906, + 434.11572265625, + 329.8018798828125, + 534.5653686523438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7416979074478149, + "bbox": [ + 1252.624267578125, + 613.5382690429688, + 1365.750732421875, + 714.379150390625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6869469881057739, + "bbox": [ + 856.775146484375, + 426.5235290527344, + 982.0392456054688, + 545.2455444335938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5516640543937683, + "bbox": [ + 1717.7908935546875, + 548.8966674804688, + 1872.585693359375, + 704.7841186523438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5431124567985535, + "bbox": [ + 226.42828369140625, + 3128.82470703125, + 319.4625549316406, + 3203.689453125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9370722770690918, + "bbox": [ + 222.5220489501953, + 619.6429443359375, + 1179.1151123046875, + 1887.2254638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9255450367927551, + "bbox": [ + 1251.167724609375, + 726.2056274414062, + 2220.2802734375, + 2536.865966796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9112128019332886, + "bbox": [ + 1225.432373046875, + 421.2862854003906, + 2296.282958984375, + 2931.954345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8925390839576721, + "bbox": [ + 176.34066772460938, + 418.58099365234375, + 1195.7926025390625, + 2148.531494140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8900695443153381, + "bbox": [ + 1248.7115478515625, + 2554.833740234375, + 2065.1611328125, + 2785.1220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7875652313232422, + "bbox": [ + 224.31771850585938, + 533.2552490234375, + 866.4579467773438, + 615.2509155273438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7478898763656616, + "bbox": [ + 1237.149658203125, + 445.45220947265625, + 2243.2041015625, + 582.273681640625 + ] + } + ], + "timestamp": "2025-10-15T21:42:24.166790" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 31.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 31.json" new file mode 100644 index 0000000..3c9eb79 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 31.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 31.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7441417574882507, + "bbox": [ + 1305.3585205078125, + 619.4505615234375, + 1417.764892578125, + 716.9970703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7384775280952454, + "bbox": [ + 251.1217041015625, + 437.8577575683594, + 376.6976623535156, + 545.1366577148438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6475614309310913, + "bbox": [ + 1891.146484375, + 617.232666015625, + 2035.8447265625, + 749.7539672851562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209352612495422, + "bbox": [ + 828.2235107421875, + 416.9590148925781, + 962.45947265625, + 551.1586303710938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5551373362541199, + "bbox": [ + 1909.77294921875, + 622.6658935546875, + 2027.289794921875, + 734.7251586914062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5413956046104431, + "bbox": [ + 2182.302734375, + 3172.290771484375, + 2271.317138671875, + 3245.958740234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9492501616477966, + "bbox": [ + 240.32864379882812, + 570.3783569335938, + 1214.3411865234375, + 2140.682861328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9143268465995789, + "bbox": [ + 1274.05859375, + 461.7174377441406, + 2405.643310546875, + 2612.79052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9052168130874634, + "bbox": [ + 197.6411590576172, + 388.117431640625, + 1249.6856689453125, + 2462.703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9047935605049133, + "bbox": [ + 1281.997802734375, + 738.0966186523438, + 2272.8759765625, + 2533.966796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8775144219398499, + "bbox": [ + 241.9989471435547, + 2166.552734375, + 1097.3011474609375, + 2391.599853515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8400033116340637, + "bbox": [ + 1290.3184814453125, + 446.5696716308594, + 2311.39794921875, + 587.3668212890625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7441417574882507, + "bbox": [ + 1305.3585205078125, + 619.4505615234375, + 1417.764892578125, + 716.9970703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7384775280952454, + "bbox": [ + 251.1217041015625, + 437.8577575683594, + 376.6976623535156, + 545.1366577148438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6475614309310913, + "bbox": [ + 1891.146484375, + 617.232666015625, + 2035.8447265625, + 749.7539672851562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6209352612495422, + "bbox": [ + 828.2235107421875, + 416.9590148925781, + 962.45947265625, + 551.1586303710938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5551373362541199, + "bbox": [ + 1909.77294921875, + 622.6658935546875, + 2027.289794921875, + 734.7251586914062 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5413956046104431, + "bbox": [ + 2182.302734375, + 3172.290771484375, + 2271.317138671875, + 3245.958740234375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9492501616477966, + "bbox": [ + 240.32864379882812, + 570.3783569335938, + 1214.3411865234375, + 2140.682861328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9143268465995789, + "bbox": [ + 1274.05859375, + 461.7174377441406, + 2405.643310546875, + 2612.79052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9052168130874634, + "bbox": [ + 197.6411590576172, + 388.117431640625, + 1249.6856689453125, + 2462.703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9047935605049133, + "bbox": [ + 1281.997802734375, + 738.0966186523438, + 2272.8759765625, + 2533.966796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8775144219398499, + "bbox": [ + 241.9989471435547, + 2166.552734375, + 1097.3011474609375, + 2391.599853515625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8400033116340637, + "bbox": [ + 1290.3184814453125, + 446.5696716308594, + 2311.39794921875, + 587.3668212890625 + ] + } + ], + "timestamp": "2025-10-15T21:42:24.554527" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 32.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 32.json" new file mode 100644 index 0000000..0f3e059 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 32.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 32.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7425358295440674, + "bbox": [ + 1218.9185791015625, + 437.5244445800781, + 1331.3175048828125, + 533.504638671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7329147458076477, + "bbox": [ + 202.97158813476562, + 421.9583740234375, + 320.283935546875, + 526.1498413085938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6677577495574951, + "bbox": [ + 1692.0718994140625, + 415.6666564941406, + 1818.622802734375, + 536.9111328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6237303614616394, + "bbox": [ + 784.9873046875, + 393.5762023925781, + 908.3550415039062, + 524.736572265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5060696005821228, + "bbox": [ + 219.06663513183594, + 3053.544921875, + 307.7846374511719, + 3124.40869140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.949751615524292, + "bbox": [ + 181.42724609375, + 551.2989501953125, + 1153.4652099609375, + 2190.4150390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9353466629981995, + "bbox": [ + 1206.99365234375, + 695.146240234375, + 2175.642578125, + 2246.903564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.922912061214447, + "bbox": [ + 173.48036193847656, + 387.88653564453125, + 1174.7154541015625, + 2288.66943359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9220249652862549, + "bbox": [ + 1206.2884521484375, + 397.27252197265625, + 2184.733642578125, + 2712.7158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9049123525619507, + "bbox": [ + 1216.1568603515625, + 2264.42138671875, + 1793.39453125, + 2695.1259765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8492533564567566, + "bbox": [ + 1201.4556884765625, + 533.108154296875, + 2151.549560546875, + 656.1810302734375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7425358295440674, + "bbox": [ + 1218.9185791015625, + 437.5244445800781, + 1331.3175048828125, + 533.504638671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7329147458076477, + "bbox": [ + 202.97158813476562, + 421.9583740234375, + 320.283935546875, + 526.1498413085938 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6677577495574951, + "bbox": [ + 1692.0718994140625, + 415.6666564941406, + 1818.622802734375, + 536.9111328125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6237303614616394, + "bbox": [ + 784.9873046875, + 393.5762023925781, + 908.3550415039062, + 524.736572265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5060696005821228, + "bbox": [ + 219.06663513183594, + 3053.544921875, + 307.7846374511719, + 3124.40869140625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.949751615524292, + "bbox": [ + 181.42724609375, + 551.2989501953125, + 1153.4652099609375, + 2190.4150390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9353466629981995, + "bbox": [ + 1206.99365234375, + 695.146240234375, + 2175.642578125, + 2246.903564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.922912061214447, + "bbox": [ + 173.48036193847656, + 387.88653564453125, + 1174.7154541015625, + 2288.66943359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9220249652862549, + "bbox": [ + 1206.2884521484375, + 397.27252197265625, + 2184.733642578125, + 2712.7158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9049123525619507, + "bbox": [ + 1216.1568603515625, + 2264.42138671875, + 1793.39453125, + 2695.1259765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8492533564567566, + "bbox": [ + 1201.4556884765625, + 533.108154296875, + 2151.549560546875, + 656.1810302734375 + ] + } + ], + "timestamp": "2025-10-15T21:42:24.956002" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 33.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 33.json" new file mode 100644 index 0000000..77debd7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 33.json" @@ -0,0 +1,384 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 33.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7465360164642334, + "bbox": [ + 1268.0550537109375, + 1946.707763671875, + 1382.6402587890625, + 2048.778564453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7267874479293823, + "bbox": [ + 1272.652099609375, + 443.0932922363281, + 1387.7669677734375, + 542.75537109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.651939332485199, + "bbox": [ + 1852.0780029296875, + 1141.5936279296875, + 1974.8770751953125, + 1256.622802734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6356967687606812, + "bbox": [ + 903.1343994140625, + 2354.328857421875, + 1027.98681640625, + 2482.572021484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6191906332969666, + "bbox": [ + 2123.530029296875, + 3110.798828125, + 2211.611083984375, + 3187.519287109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5796049237251282, + "bbox": [ + 1822.7315673828125, + 2390.33544921875, + 1959.0860595703125, + 2531.3896484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5343111157417297, + "bbox": [ + 1810.602294921875, + 2378.51806640625, + 1997.11279296875, + 2553.020751953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.48504820466041565, + "bbox": [ + 1842.450439453125, + 1137.1331787109375, + 1990.340087890625, + 1273.8870849609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.22974027693271637, + "bbox": [ + 885.6092529296875, + 2345.51220703125, + 1047.627685546875, + 2498.6982421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9189755320549011, + "bbox": [ + 216.62596130371094, + 514.4877319335938, + 1218.9073486328125, + 2331.495849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9152743220329285, + "bbox": [ + 1278.2694091796875, + 618.062255859375, + 2219.734619140625, + 1154.516357421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8925208449363708, + "bbox": [ + 1251.394775390625, + 410.710693359375, + 2291.44970703125, + 1327.9617919921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8547224998474121, + "bbox": [ + 1268.6759033203125, + 2034.6221923828125, + 2205.525390625, + 2157.5576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8407100439071655, + "bbox": [ + 1277.8563232421875, + 2162.852783203125, + 2155.653076171875, + 2278.419189453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8065725564956665, + "bbox": [ + 1235.706787109375, + 1906.808837890625, + 2250.329833984375, + 2590.80224609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7864087224006653, + "bbox": [ + 1283.74267578125, + 525.3441772460938, + 1844.7650146484375, + 613.0578002929688 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.735100507736206, + "bbox": [ + 221.11167907714844, + 290.04388427734375, + 1217.345703125, + 2520.044677734375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7465360164642334, + "bbox": [ + 1268.0550537109375, + 1946.707763671875, + 1382.6402587890625, + 2048.778564453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7267874479293823, + "bbox": [ + 1272.652099609375, + 443.0932922363281, + 1387.7669677734375, + 542.75537109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.651939332485199, + "bbox": [ + 1852.0780029296875, + 1141.5936279296875, + 1974.8770751953125, + 1256.622802734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6356967687606812, + "bbox": [ + 903.1343994140625, + 2354.328857421875, + 1027.98681640625, + 2482.572021484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6191906332969666, + "bbox": [ + 2123.530029296875, + 3110.798828125, + 2211.611083984375, + 3187.519287109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5796049237251282, + "bbox": [ + 1822.7315673828125, + 2390.33544921875, + 1959.0860595703125, + 2531.3896484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5343111157417297, + "bbox": [ + 1810.602294921875, + 2378.51806640625, + 1997.11279296875, + 2553.020751953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.48504820466041565, + "bbox": [ + 1842.450439453125, + 1137.1331787109375, + 1990.340087890625, + 1273.8870849609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.22974027693271637, + "bbox": [ + 885.6092529296875, + 2345.51220703125, + 1047.627685546875, + 2498.6982421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9189755320549011, + "bbox": [ + 216.62596130371094, + 514.4877319335938, + 1218.9073486328125, + 2331.495849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9152743220329285, + "bbox": [ + 1278.2694091796875, + 618.062255859375, + 2219.734619140625, + 1154.516357421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8925208449363708, + "bbox": [ + 1251.394775390625, + 410.710693359375, + 2291.44970703125, + 1327.9617919921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8547224998474121, + "bbox": [ + 1268.6759033203125, + 2034.6221923828125, + 2205.525390625, + 2157.5576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8407100439071655, + "bbox": [ + 1277.8563232421875, + 2162.852783203125, + 2155.653076171875, + 2278.419189453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8065725564956665, + "bbox": [ + 1235.706787109375, + 1906.808837890625, + 2250.329833984375, + 2590.80224609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7864087224006653, + "bbox": [ + 1283.74267578125, + 525.3441772460938, + 1844.7650146484375, + 613.0578002929688 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.735100507736206, + "bbox": [ + 221.11167907714844, + 290.04388427734375, + 1217.345703125, + 2520.044677734375 + ] + } + ], + "timestamp": "2025-10-15T21:42:25.371418" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 34.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 34.json" new file mode 100644 index 0000000..2c9e430 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204 \353\217\231\352\267\270\353\235\274\353\257\270 (\355\213\200\353\246\274) - 34.json" @@ -0,0 +1,428 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„ƒแ…ฉแ†ผแ„€แ…ณแ„…แ…กแ„†แ…ต (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 34.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7781926393508911, + "bbox": [ + 1174.4473876953125, + 1686.5008544921875, + 1284.2032470703125, + 1783.850830078125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7510513067245483, + "bbox": [ + 1181.91552734375, + 939.6041870117188, + 1292.602294921875, + 1033.9320068359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7372850179672241, + "bbox": [ + 1174.50537109375, + 2255.149658203125, + 1283.459716796875, + 2348.498291015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7137385606765747, + "bbox": [ + 1606.68115234375, + 898.678466796875, + 1711.3818359375, + 1001.8609619140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.671506941318512, + "bbox": [ + 1615.319580078125, + 1671.7012939453125, + 1728.802734375, + 1781.5047607421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6139318943023682, + "bbox": [ + 1613.926025390625, + 2223.26904296875, + 1749.8485107421875, + 2356.7177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5193522572517395, + "bbox": [ + 202.40505981445312, + 2935.1513671875, + 287.6956787109375, + 3007.1943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9420422315597534, + "bbox": [ + 1174.9542236328125, + 2420.994140625, + 2085.4755859375, + 2926.9267578125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9323466420173645, + "bbox": [ + 1148.2633056640625, + 383.50079345703125, + 2117.773681640625, + 735.6179809570312 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9067971110343933, + "bbox": [ + 180.83953857421875, + 771.261474609375, + 1113.4952392578125, + 2942.336181640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8982246518135071, + "bbox": [ + 1134.5289306640625, + 2207.236572265625, + 2111.487548828125, + 2978.97802734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8889222145080566, + "bbox": [ + 1169.5894775390625, + 1157.7430419921875, + 1977.7525634765625, + 1388.2022705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8770790696144104, + "bbox": [ + 1159.0941162109375, + 877.7720947265625, + 2132.783203125, + 1449.4947509765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8737181425094604, + "bbox": [ + 1153.5150146484375, + 1640.8978271484375, + 2132.93359375, + 1984.821044921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8346871137619019, + "bbox": [ + 1171.3275146484375, + 1032.1533203125, + 2074.8056640625, + 1147.1588134765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8261359930038452, + "bbox": [ + 1159.975341796875, + 1847.9400634765625, + 2031.1605224609375, + 1942.773681640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7757102251052856, + "bbox": [ + 1172.5452880859375, + 1775.2913818359375, + 2091.083251953125, + 1846.134521484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6931411623954773, + "bbox": [ + 1169.341552734375, + 2350.129638671875, + 1977.834228515625, + 2414.37255859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.33718404173851013, + "bbox": [ + 174.7861785888672, + 789.3289184570312, + 1128.7498779296875, + 3119.5009765625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7781926393508911, + "bbox": [ + 1174.4473876953125, + 1686.5008544921875, + 1284.2032470703125, + 1783.850830078125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7510513067245483, + "bbox": [ + 1181.91552734375, + 939.6041870117188, + 1292.602294921875, + 1033.9320068359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7372850179672241, + "bbox": [ + 1174.50537109375, + 2255.149658203125, + 1283.459716796875, + 2348.498291015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7137385606765747, + "bbox": [ + 1606.68115234375, + 898.678466796875, + 1711.3818359375, + 1001.8609619140625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.671506941318512, + "bbox": [ + 1615.319580078125, + 1671.7012939453125, + 1728.802734375, + 1781.5047607421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6139318943023682, + "bbox": [ + 1613.926025390625, + 2223.26904296875, + 1749.8485107421875, + 2356.7177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5193522572517395, + "bbox": [ + 202.40505981445312, + 2935.1513671875, + 287.6956787109375, + 3007.1943359375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9420422315597534, + "bbox": [ + 1174.9542236328125, + 2420.994140625, + 2085.4755859375, + 2926.9267578125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9323466420173645, + "bbox": [ + 1148.2633056640625, + 383.50079345703125, + 2117.773681640625, + 735.6179809570312 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9067971110343933, + "bbox": [ + 180.83953857421875, + 771.261474609375, + 1113.4952392578125, + 2942.336181640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8982246518135071, + "bbox": [ + 1134.5289306640625, + 2207.236572265625, + 2111.487548828125, + 2978.97802734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8889222145080566, + "bbox": [ + 1169.5894775390625, + 1157.7430419921875, + 1977.7525634765625, + 1388.2022705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8770790696144104, + "bbox": [ + 1159.0941162109375, + 877.7720947265625, + 2132.783203125, + 1449.4947509765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8737181425094604, + "bbox": [ + 1153.5150146484375, + 1640.8978271484375, + 2132.93359375, + 1984.821044921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8346871137619019, + "bbox": [ + 1171.3275146484375, + 1032.1533203125, + 2074.8056640625, + 1147.1588134765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8261359930038452, + "bbox": [ + 1159.975341796875, + 1847.9400634765625, + 2031.1605224609375, + 1942.773681640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7757102251052856, + "bbox": [ + 1172.5452880859375, + 1775.2913818359375, + 2091.083251953125, + 1846.134521484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6931411623954773, + "bbox": [ + 1169.341552734375, + 2350.129638671875, + 1977.834228515625, + 2414.37255859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.33718404173851013, + "bbox": [ + 174.7861785888672, + 789.3289184570312, + 1128.7498779296875, + 3119.5009765625 + ] + } + ], + "timestamp": "2025-10-15T21:42:25.797255" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 1.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 1.json" new file mode 100644 index 0000000..2facf2e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 1.json" @@ -0,0 +1,604 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 1.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7983983755111694, + "bbox": [ + 1283.0810546875, + 1325.125732421875, + 1384.5260009765625, + 1416.30517578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7833477854728699, + "bbox": [ + 1270.5338134765625, + 517.6687622070312, + 1370.0843505859375, + 604.6702270507812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7758641242980957, + "bbox": [ + 299.525634765625, + 2626.5654296875, + 403.6762390136719, + 2715.09521484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7672030329704285, + "bbox": [ + 1295.678955078125, + 2624.228515625, + 1397.1365966796875, + 2711.986572265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7534511089324951, + "bbox": [ + 252.71568298339844, + 1017.978759765625, + 359.1546325683594, + 1113.8841552734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5481052398681641, + "bbox": [ + 2150.65478515625, + 3157.123779296875, + 2214.282958984375, + 3223.521240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5346898436546326, + "bbox": [ + 299.5550537109375, + 2967.251708984375, + 380.8943176269531, + 3063.773193359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5339068174362183, + "bbox": [ + 263.4315490722656, + 1373.9403076171875, + 340.1243896484375, + 1462.311767578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4563981890678406, + "bbox": [ + 1281.653564453125, + 896.8413696289062, + 1335.547119140625, + 968.05224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.44000840187072754, + "bbox": [ + 1297.4481201171875, + 2913.19091796875, + 1367.2335205078125, + 2994.41650390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.33058685064315796, + "bbox": [ + 1282.7811279296875, + 867.6663818359375, + 1362.669921875, + 981.5889282226562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.31872302293777466, + "bbox": [ + 1282.557861328125, + 877.6746215820312, + 1345.3052978515625, + 972.828369140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9117227792739868, + "bbox": [ + 1311.9637451171875, + 2798.298583984375, + 1734.390869140625, + 3133.28125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.910882830619812, + "bbox": [ + 263.6938781738281, + 2601.31787109375, + 1244.248291015625, + 3169.282470703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9080847501754761, + "bbox": [ + 273.4270324707031, + 1251.4666748046875, + 1193.434814453125, + 1611.5238037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8978163599967957, + "bbox": [ + 309.0304260253906, + 2800.632568359375, + 1195.1446533203125, + 3142.251953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8972594738006592, + "bbox": [ + 1255.6527099609375, + 1290.3077392578125, + 2243.359130859375, + 2541.968994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8952165842056274, + "bbox": [ + 237.6722869873047, + 986.0549926757812, + 1225.9930419921875, + 1638.569580078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8858779072761536, + "bbox": [ + 1287.703369140625, + 2612.586669921875, + 2259.971435546875, + 3154.13134765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8842043876647949, + "bbox": [ + 1231.833740234375, + 497.8525085449219, + 2235.005615234375, + 1078.83203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8692703247070312, + "bbox": [ + 1296.16259765625, + 1421.6787109375, + 2222.47216796875, + 1539.3712158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8480411171913147, + "bbox": [ + 1261.0084228515625, + 684.3721313476562, + 1693.477294921875, + 1047.2835693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8372505903244019, + "bbox": [ + 255.3374786376953, + 1111.43408203125, + 1194.5457763671875, + 1241.8060302734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7672603130340576, + "bbox": [ + 1275.9937744140625, + 598.87646484375, + 2159.73095703125, + 691.5820922851562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6891952753067017, + "bbox": [ + 296.5080261230469, + 2720.46337890625, + 1117.2606201171875, + 2783.51220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6798402070999146, + "bbox": [ + 1286.1678466796875, + 2722.088623046875, + 2128.16064453125, + 2783.493408203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5077571272850037, + "bbox": [ + 1267.4857177734375, + 619.4249267578125, + 2184.38818359375, + 681.4090576171875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7983983755111694, + "bbox": [ + 1283.0810546875, + 1325.125732421875, + 1384.5260009765625, + 1416.30517578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7833477854728699, + "bbox": [ + 1270.5338134765625, + 517.6687622070312, + 1370.0843505859375, + 604.6702270507812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7758641242980957, + "bbox": [ + 299.525634765625, + 2626.5654296875, + 403.6762390136719, + 2715.09521484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7672030329704285, + "bbox": [ + 1295.678955078125, + 2624.228515625, + 1397.1365966796875, + 2711.986572265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7534511089324951, + "bbox": [ + 252.71568298339844, + 1017.978759765625, + 359.1546325683594, + 1113.8841552734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5481052398681641, + "bbox": [ + 2150.65478515625, + 3157.123779296875, + 2214.282958984375, + 3223.521240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5346898436546326, + "bbox": [ + 299.5550537109375, + 2967.251708984375, + 380.8943176269531, + 3063.773193359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5339068174362183, + "bbox": [ + 263.4315490722656, + 1373.9403076171875, + 340.1243896484375, + 1462.311767578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4563981890678406, + "bbox": [ + 1281.653564453125, + 896.8413696289062, + 1335.547119140625, + 968.05224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.44000840187072754, + "bbox": [ + 1297.4481201171875, + 2913.19091796875, + 1367.2335205078125, + 2994.41650390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.33058685064315796, + "bbox": [ + 1282.7811279296875, + 867.6663818359375, + 1362.669921875, + 981.5889282226562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.31872302293777466, + "bbox": [ + 1282.557861328125, + 877.6746215820312, + 1345.3052978515625, + 972.828369140625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9117227792739868, + "bbox": [ + 1311.9637451171875, + 2798.298583984375, + 1734.390869140625, + 3133.28125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.910882830619812, + "bbox": [ + 263.6938781738281, + 2601.31787109375, + 1244.248291015625, + 3169.282470703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9080847501754761, + "bbox": [ + 273.4270324707031, + 1251.4666748046875, + 1193.434814453125, + 1611.5238037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8978163599967957, + "bbox": [ + 309.0304260253906, + 2800.632568359375, + 1195.1446533203125, + 3142.251953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8972594738006592, + "bbox": [ + 1255.6527099609375, + 1290.3077392578125, + 2243.359130859375, + 2541.968994140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8952165842056274, + "bbox": [ + 237.6722869873047, + 986.0549926757812, + 1225.9930419921875, + 1638.569580078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8858779072761536, + "bbox": [ + 1287.703369140625, + 2612.586669921875, + 2259.971435546875, + 3154.13134765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8842043876647949, + "bbox": [ + 1231.833740234375, + 497.8525085449219, + 2235.005615234375, + 1078.83203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8692703247070312, + "bbox": [ + 1296.16259765625, + 1421.6787109375, + 2222.47216796875, + 1539.3712158203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8480411171913147, + "bbox": [ + 1261.0084228515625, + 684.3721313476562, + 1693.477294921875, + 1047.2835693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8372505903244019, + "bbox": [ + 255.3374786376953, + 1111.43408203125, + 1194.5457763671875, + 1241.8060302734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7672603130340576, + "bbox": [ + 1275.9937744140625, + 598.87646484375, + 2159.73095703125, + 691.5820922851562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6891952753067017, + "bbox": [ + 296.5080261230469, + 2720.46337890625, + 1117.2606201171875, + 2783.51220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6798402070999146, + "bbox": [ + 1286.1678466796875, + 2722.088623046875, + 2128.16064453125, + 2783.493408203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5077571272850037, + "bbox": [ + 1267.4857177734375, + 619.4249267578125, + 2184.38818359375, + 681.4090576171875 + ] + } + ], + "timestamp": "2025-10-15T21:42:26.250360" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 10.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 10.json" new file mode 100644 index 0000000..8093a19 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 10.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 10.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7498956322669983, + "bbox": [ + 1253.09423828125, + 437.26129150390625, + 1363.0908203125, + 535.4747314453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7466577887535095, + "bbox": [ + 219.9500274658203, + 420.7716064453125, + 334.8387145996094, + 521.4635009765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4943804442882538, + "bbox": [ + 1236.9693603515625, + 2108.3427734375, + 1322.0042724609375, + 2210.2109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4773181080818176, + "bbox": [ + 205.4591827392578, + 3102.048828125, + 301.423095703125, + 3179.406494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4750249981880188, + "bbox": [ + 212.13185119628906, + 2420.391845703125, + 289.6446228027344, + 2508.38916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3371717929840088, + "bbox": [ + 1240.31298828125, + 2094.489990234375, + 1353.9873046875, + 2211.92529296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9598448276519775, + "bbox": [ + 198.72532653808594, + 416.22711181640625, + 1188.51025390625, + 2551.113525390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9463230967521667, + "bbox": [ + 220.7576446533203, + 652.781494140625, + 1173.3251953125, + 2095.71826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357991814613342, + "bbox": [ + 1227.901123046875, + 646.3494262695312, + 2223.19091796875, + 2263.518798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9165553450584412, + "bbox": [ + 1222.325439453125, + 399.36920166015625, + 2270.02099609375, + 2440.1201171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9154998660087585, + "bbox": [ + 210.45138549804688, + 2084.444091796875, + 1149.6212158203125, + 2539.61328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8472641110420227, + "bbox": [ + 1243.5191650390625, + 526.148681640625, + 2203.15625, + 658.5746459960938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8187816739082336, + "bbox": [ + 226.65904235839844, + 517.9035034179688, + 1171.0238037109375, + 643.3629760742188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7498956322669983, + "bbox": [ + 1253.09423828125, + 437.26129150390625, + 1363.0908203125, + 535.4747314453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7466577887535095, + "bbox": [ + 219.9500274658203, + 420.7716064453125, + 334.8387145996094, + 521.4635009765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4943804442882538, + "bbox": [ + 1236.9693603515625, + 2108.3427734375, + 1322.0042724609375, + 2210.2109375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4773181080818176, + "bbox": [ + 205.4591827392578, + 3102.048828125, + 301.423095703125, + 3179.406494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4750249981880188, + "bbox": [ + 212.13185119628906, + 2420.391845703125, + 289.6446228027344, + 2508.38916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3371717929840088, + "bbox": [ + 1240.31298828125, + 2094.489990234375, + 1353.9873046875, + 2211.92529296875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9598448276519775, + "bbox": [ + 198.72532653808594, + 416.22711181640625, + 1188.51025390625, + 2551.113525390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9463230967521667, + "bbox": [ + 220.7576446533203, + 652.781494140625, + 1173.3251953125, + 2095.71826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357991814613342, + "bbox": [ + 1227.901123046875, + 646.3494262695312, + 2223.19091796875, + 2263.518798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9165553450584412, + "bbox": [ + 1222.325439453125, + 399.36920166015625, + 2270.02099609375, + 2440.1201171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9154998660087585, + "bbox": [ + 210.45138549804688, + 2084.444091796875, + 1149.6212158203125, + 2539.61328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8472641110420227, + "bbox": [ + 1243.5191650390625, + 526.148681640625, + 2203.15625, + 658.5746459960938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8187816739082336, + "bbox": [ + 226.65904235839844, + 517.9035034179688, + 1171.0238037109375, + 643.3629760742188 + ] + } + ], + "timestamp": "2025-10-15T21:42:26.690416" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 11.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 11.json" new file mode 100644 index 0000000..3f1f8a9 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 11.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 11.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.769625186920166, + "bbox": [ + 1193.9013671875, + 411.6297912597656, + 1294.7420654296875, + 504.9017028808594 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7410354614257812, + "bbox": [ + 239.9515838623047, + 510.9247741699219, + 348.0657958984375, + 612.8770141601562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6081646084785461, + "bbox": [ + 1181.966552734375, + 1769.7359619140625, + 1272.2777099609375, + 1870.7689208984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5379481911659241, + "bbox": [ + 1975.5869140625, + 2919.9306640625, + 2056.822021484375, + 2988.044921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5209168791770935, + "bbox": [ + 239.58367919921875, + 1824.7596435546875, + 292.6419372558594, + 1897.9163818359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267647862434387, + "bbox": [ + 193.06170654296875, + 451.1763916015625, + 1133.93701171875, + 2170.513427734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9236084222793579, + "bbox": [ + 235.49276733398438, + 606.1898803710938, + 1123.8157958984375, + 1818.8232421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9209499359130859, + "bbox": [ + 1186.902099609375, + 505.4231872558594, + 2087.885498046875, + 1746.8739013671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9179527163505554, + "bbox": [ + 1165.9041748046875, + 374.26458740234375, + 2118.08154296875, + 2219.896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9094914793968201, + "bbox": [ + 1170.4171142578125, + 1762.361328125, + 1886.2886962890625, + 2140.8681640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8502747416496277, + "bbox": [ + 230.94947814941406, + 1819.18017578125, + 515.2252197265625, + 2171.938720703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.16945244371891022, + "bbox": [ + 245.3971405029297, + 392.58917236328125, + 1108.775634765625, + 477.5325927734375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.769625186920166, + "bbox": [ + 1193.9013671875, + 411.6297912597656, + 1294.7420654296875, + 504.9017028808594 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7410354614257812, + "bbox": [ + 239.9515838623047, + 510.9247741699219, + 348.0657958984375, + 612.8770141601562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6081646084785461, + "bbox": [ + 1181.966552734375, + 1769.7359619140625, + 1272.2777099609375, + 1870.7689208984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5379481911659241, + "bbox": [ + 1975.5869140625, + 2919.9306640625, + 2056.822021484375, + 2988.044921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5209168791770935, + "bbox": [ + 239.58367919921875, + 1824.7596435546875, + 292.6419372558594, + 1897.9163818359375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9267647862434387, + "bbox": [ + 193.06170654296875, + 451.1763916015625, + 1133.93701171875, + 2170.513427734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9236084222793579, + "bbox": [ + 235.49276733398438, + 606.1898803710938, + 1123.8157958984375, + 1818.8232421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9209499359130859, + "bbox": [ + 1186.902099609375, + 505.4231872558594, + 2087.885498046875, + 1746.8739013671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9179527163505554, + "bbox": [ + 1165.9041748046875, + 374.26458740234375, + 2118.08154296875, + 2219.896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9094914793968201, + "bbox": [ + 1170.4171142578125, + 1762.361328125, + 1886.2886962890625, + 2140.8681640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8502747416496277, + "bbox": [ + 230.94947814941406, + 1819.18017578125, + 515.2252197265625, + 2171.938720703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.16945244371891022, + "bbox": [ + 245.3971405029297, + 392.58917236328125, + 1108.775634765625, + 477.5325927734375 + ] + } + ], + "timestamp": "2025-10-15T21:42:27.120048" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 12.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 12.json" new file mode 100644 index 0000000..abd7d47 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 12.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 12.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7562362551689148, + "bbox": [ + 1160.1668701171875, + 408.057373046875, + 1263.46435546875, + 504.8369140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7475709319114685, + "bbox": [ + 200.54055786132812, + 394.1004943847656, + 308.0591735839844, + 492.9911804199219 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5514852404594421, + "bbox": [ + 1153.5855712890625, + 2008.839111328125, + 1242.3758544921875, + 2121.357177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5247412323951721, + "bbox": [ + 188.00927734375, + 2913.408447265625, + 270.85369873046875, + 2981.86181640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.45308178663253784, + "bbox": [ + 184.98451232910156, + 1756.4378662109375, + 266.897216796875, + 1865.091064453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9482830762863159, + "bbox": [ + 1152.7852783203125, + 509.9342956542969, + 2051.6015625, + 1937.4033203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9468105435371399, + "bbox": [ + 185.42393493652344, + 501.5539855957031, + 1088.8555908203125, + 1771.2637939453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9409053921699524, + "bbox": [ + 68.03823852539062, + 324.8498229980469, + 1131.4425048828125, + 2235.022216796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9293498396873474, + "bbox": [ + 1139.730224609375, + 1965.3916015625, + 2068.163330078125, + 2555.632080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.914040744304657, + "bbox": [ + 1129.5128173828125, + 309.1934814453125, + 2129.876953125, + 2587.1640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8962591886520386, + "bbox": [ + 166.27484130859375, + 1776.977783203125, + 1066.45751953125, + 2153.0712890625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7562362551689148, + "bbox": [ + 1160.1668701171875, + 408.057373046875, + 1263.46435546875, + 504.8369140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7475709319114685, + "bbox": [ + 200.54055786132812, + 394.1004943847656, + 308.0591735839844, + 492.9911804199219 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5514852404594421, + "bbox": [ + 1153.5855712890625, + 2008.839111328125, + 1242.3758544921875, + 2121.357177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5247412323951721, + "bbox": [ + 188.00927734375, + 2913.408447265625, + 270.85369873046875, + 2981.86181640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.45308178663253784, + "bbox": [ + 184.98451232910156, + 1756.4378662109375, + 266.897216796875, + 1865.091064453125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9482830762863159, + "bbox": [ + 1152.7852783203125, + 509.9342956542969, + 2051.6015625, + 1937.4033203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9468105435371399, + "bbox": [ + 185.42393493652344, + 501.5539855957031, + 1088.8555908203125, + 1771.2637939453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9409053921699524, + "bbox": [ + 68.03823852539062, + 324.8498229980469, + 1131.4425048828125, + 2235.022216796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9293498396873474, + "bbox": [ + 1139.730224609375, + 1965.3916015625, + 2068.163330078125, + 2555.632080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.914040744304657, + "bbox": [ + 1129.5128173828125, + 309.1934814453125, + 2129.876953125, + 2587.1640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8962591886520386, + "bbox": [ + 166.27484130859375, + 1776.977783203125, + 1066.45751953125, + 2153.0712890625 + ] + } + ], + "timestamp": "2025-10-15T21:42:27.508385" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 13.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 13.json" new file mode 100644 index 0000000..0ac64e5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 13.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 13.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7680276036262512, + "bbox": [ + 278.3542785644531, + 457.345947265625, + 395.1463928222656, + 558.2904052734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7644332051277161, + "bbox": [ + 1357.119140625, + 654.5264282226562, + 1472.816650390625, + 760.7462768554688 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5698052048683167, + "bbox": [ + 2257.1025390625, + 3295.5244140625, + 2349.038818359375, + 3371.6279296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5080156326293945, + "bbox": [ + 1832.9876708984375, + 2895.34326171875, + 1917.37451171875, + 2993.5810546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47311776876449585, + "bbox": [ + 1828.94580078125, + 2892.5390625, + 1942.0557861328125, + 3001.663818359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4436294138431549, + "bbox": [ + 344.9924621582031, + 1654.6114501953125, + 435.7452087402344, + 1774.8326416015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.25038841366767883, + "bbox": [ + 351.0723876953125, + 1667.418212890625, + 425.6062316894531, + 1769.4010009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9496482014656067, + "bbox": [ + 262.9560241699219, + 651.1697387695312, + 1285.721923828125, + 2209.787353515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9147956967353821, + "bbox": [ + 206.30442810058594, + 422.3699645996094, + 1310.095947265625, + 2428.255615234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.907930314540863, + "bbox": [ + 1311.4210205078125, + 508.7779235839844, + 2433.566162109375, + 3251.7216796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9047802090644836, + "bbox": [ + 1337.1585693359375, + 785.3707275390625, + 2373.08154296875, + 2874.9697265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8832629323005676, + "bbox": [ + 1360.2425537109375, + 463.0682678222656, + 2380.642578125, + 606.2174682617188 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8688421845436096, + "bbox": [ + 1329.946533203125, + 2905.05078125, + 2234.341796875, + 3161.738525390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8258352279663086, + "bbox": [ + 276.62689208984375, + 555.5448608398438, + 955.1264038085938, + 650.677978515625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7680276036262512, + "bbox": [ + 278.3542785644531, + 457.345947265625, + 395.1463928222656, + 558.2904052734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7644332051277161, + "bbox": [ + 1357.119140625, + 654.5264282226562, + 1472.816650390625, + 760.7462768554688 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5698052048683167, + "bbox": [ + 2257.1025390625, + 3295.5244140625, + 2349.038818359375, + 3371.6279296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5080156326293945, + "bbox": [ + 1832.9876708984375, + 2895.34326171875, + 1917.37451171875, + 2993.5810546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47311776876449585, + "bbox": [ + 1828.94580078125, + 2892.5390625, + 1942.0557861328125, + 3001.663818359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4436294138431549, + "bbox": [ + 344.9924621582031, + 1654.6114501953125, + 435.7452087402344, + 1774.8326416015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.25038841366767883, + "bbox": [ + 351.0723876953125, + 1667.418212890625, + 425.6062316894531, + 1769.4010009765625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9496482014656067, + "bbox": [ + 262.9560241699219, + 651.1697387695312, + 1285.721923828125, + 2209.787353515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9147956967353821, + "bbox": [ + 206.30442810058594, + 422.3699645996094, + 1310.095947265625, + 2428.255615234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.907930314540863, + "bbox": [ + 1311.4210205078125, + 508.7779235839844, + 2433.566162109375, + 3251.7216796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9047802090644836, + "bbox": [ + 1337.1585693359375, + 785.3707275390625, + 2373.08154296875, + 2874.9697265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8832629323005676, + "bbox": [ + 1360.2425537109375, + 463.0682678222656, + 2380.642578125, + 606.2174682617188 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8688421845436096, + "bbox": [ + 1329.946533203125, + 2905.05078125, + 2234.341796875, + 3161.738525390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8258352279663086, + "bbox": [ + 276.62689208984375, + 555.5448608398438, + 955.1264038085938, + 650.677978515625 + ] + } + ], + "timestamp": "2025-10-15T21:42:27.923826" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 14.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 14.json" new file mode 100644 index 0000000..b443c2c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 14.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 14.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7571019530296326, + "bbox": [ + 1319.928466796875, + 643.2127075195312, + 1440.204345703125, + 750.6448974609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7395848631858826, + "bbox": [ + 225.2307586669922, + 444.5059509277344, + 354.924560546875, + 558.2901611328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5535116791725159, + "bbox": [ + 214.28953552246094, + 3301.438720703125, + 306.5604248046875, + 3377.03466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.545263946056366, + "bbox": [ + 1978.4940185546875, + 2234.808349609375, + 2083.9951171875, + 2356.7978515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5419098138809204, + "bbox": [ + 205.3944854736328, + 2366.942626953125, + 292.9066162109375, + 2467.761474609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.29056352376937866, + "bbox": [ + 218.72137451171875, + 2375.827392578125, + 287.6325378417969, + 2459.669677734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9417833089828491, + "bbox": [ + 201.4429473876953, + 596.1659545898438, + 1235.79541015625, + 2282.4345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9353044629096985, + "bbox": [ + 165.16282653808594, + 419.957275390625, + 1270.2552490234375, + 2599.68994140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198238849639893, + "bbox": [ + 1300.49609375, + 750.6350708007812, + 2356.668212890625, + 2524.529541015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9177219271659851, + "bbox": [ + 1299.2945556640625, + 441.6905517578125, + 2422.601806640625, + 2665.2197265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8577864766120911, + "bbox": [ + 204.6634521484375, + 2300.43896484375, + 1129.145263671875, + 2550.255126953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5652002096176147, + "bbox": [ + 1317.556884765625, + 450.5865478515625, + 2337.7607421875, + 591.3380126953125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7571019530296326, + "bbox": [ + 1319.928466796875, + 643.2127075195312, + 1440.204345703125, + 750.6448974609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7395848631858826, + "bbox": [ + 225.2307586669922, + 444.5059509277344, + 354.924560546875, + 558.2901611328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5535116791725159, + "bbox": [ + 214.28953552246094, + 3301.438720703125, + 306.5604248046875, + 3377.03466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.545263946056366, + "bbox": [ + 1978.4940185546875, + 2234.808349609375, + 2083.9951171875, + 2356.7978515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5419098138809204, + "bbox": [ + 205.3944854736328, + 2366.942626953125, + 292.9066162109375, + 2467.761474609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.29056352376937866, + "bbox": [ + 218.72137451171875, + 2375.827392578125, + 287.6325378417969, + 2459.669677734375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9417833089828491, + "bbox": [ + 201.4429473876953, + 596.1659545898438, + 1235.79541015625, + 2282.4345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9353044629096985, + "bbox": [ + 165.16282653808594, + 419.957275390625, + 1270.2552490234375, + 2599.68994140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198238849639893, + "bbox": [ + 1300.49609375, + 750.6350708007812, + 2356.668212890625, + 2524.529541015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9177219271659851, + "bbox": [ + 1299.2945556640625, + 441.6905517578125, + 2422.601806640625, + 2665.2197265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8577864766120911, + "bbox": [ + 204.6634521484375, + 2300.43896484375, + 1129.145263671875, + 2550.255126953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5652002096176147, + "bbox": [ + 1317.556884765625, + 450.5865478515625, + 2337.7607421875, + 591.3380126953125 + ] + } + ], + "timestamp": "2025-10-15T21:42:28.365365" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 15.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 15.json" new file mode 100644 index 0000000..07b77f7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 15.json" @@ -0,0 +1,252 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 15.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7386469841003418, + "bbox": [ + 1308.0301513671875, + 438.7203369140625, + 1429.345703125, + 543.7706909179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.738272488117218, + "bbox": [ + 267.5554504394531, + 424.9104309082031, + 387.3697204589844, + 534.2511596679688 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5815479159355164, + "bbox": [ + 2180.595458984375, + 3174.380615234375, + 2270.413330078125, + 3247.901611328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5765143036842346, + "bbox": [ + 1312.6749267578125, + 2663.98388671875, + 1398.4183349609375, + 2774.806396484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.473430871963501, + "bbox": [ + 295.23846435546875, + 1291.9967041015625, + 372.9425354003906, + 1392.6434326171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.959924042224884, + "bbox": [ + 1308.38037109375, + 676.193115234375, + 2288.805908203125, + 2516.53369140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9263380765914917, + "bbox": [ + 243.09495544433594, + 546.7361450195312, + 1230.0963134765625, + 2322.612548828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.913431704044342, + "bbox": [ + 232.9462127685547, + 321.7449645996094, + 1244.2493896484375, + 2416.34326171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9119288325309753, + "bbox": [ + 1274.6981201171875, + 436.9805603027344, + 2373.663330078125, + 3026.113037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8863656520843506, + "bbox": [ + 1309.9918212890625, + 2484.562255859375, + 1955.0662841796875, + 2939.748046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8755819797515869, + "bbox": [ + 1309.408935546875, + 542.5592041015625, + 2286.833984375, + 671.601806640625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7386469841003418, + "bbox": [ + 1308.0301513671875, + 438.7203369140625, + 1429.345703125, + 543.7706909179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.738272488117218, + "bbox": [ + 267.5554504394531, + 424.9104309082031, + 387.3697204589844, + 534.2511596679688 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5815479159355164, + "bbox": [ + 2180.595458984375, + 3174.380615234375, + 2270.413330078125, + 3247.901611328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5765143036842346, + "bbox": [ + 1312.6749267578125, + 2663.98388671875, + 1398.4183349609375, + 2774.806396484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.473430871963501, + "bbox": [ + 295.23846435546875, + 1291.9967041015625, + 372.9425354003906, + 1392.6434326171875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.959924042224884, + "bbox": [ + 1308.38037109375, + 676.193115234375, + 2288.805908203125, + 2516.53369140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9263380765914917, + "bbox": [ + 243.09495544433594, + 546.7361450195312, + 1230.0963134765625, + 2322.612548828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.913431704044342, + "bbox": [ + 232.9462127685547, + 321.7449645996094, + 1244.2493896484375, + 2416.34326171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9119288325309753, + "bbox": [ + 1274.6981201171875, + 436.9805603027344, + 2373.663330078125, + 3026.113037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8863656520843506, + "bbox": [ + 1309.9918212890625, + 2484.562255859375, + 1955.0662841796875, + 2939.748046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8755819797515869, + "bbox": [ + 1309.408935546875, + 542.5592041015625, + 2286.833984375, + 671.601806640625 + ] + } + ], + "timestamp": "2025-10-15T21:42:28.785872" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 16.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 16.json" new file mode 100644 index 0000000..5ea842b --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 16.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 16.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7566924095153809, + "bbox": [ + 1303.558837890625, + 463.9815368652344, + 1428.698974609375, + 574.919189453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7408478260040283, + "bbox": [ + 1299.2528076171875, + 2036.307861328125, + 1423.756103515625, + 2141.32373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6828992962837219, + "bbox": [ + 1313.28662109375, + 1025.3017578125, + 1415.196044921875, + 1129.6080322265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5258637070655823, + "bbox": [ + 216.9156494140625, + 3269.890625, + 311.3939514160156, + 3347.684814453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.42604172229766846, + "bbox": [ + 1891.65625, + 2270.4970703125, + 1953.131103515625, + 2355.619384765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9320166110992432, + "bbox": [ + 1274.0712890625, + 2034.815185546875, + 2329.8359375, + 2405.299560546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9268423318862915, + "bbox": [ + 1322.0179443359375, + 647.7603759765625, + 2351.85693359375, + 1205.0968017578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9122989773750305, + "bbox": [ + 1282.268310546875, + 432.29107666015625, + 2418.70556640625, + 1345.0736083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8509558439254761, + "bbox": [ + 196.17742919921875, + 569.5825805664062, + 1249.0784912109375, + 2550.984130859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8253114819526672, + "bbox": [ + 1290.557373046875, + 2133.1572265625, + 2298.28369140625, + 2260.04541015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7797009944915771, + "bbox": [ + 1315.5189208984375, + 565.0599365234375, + 1881.8953857421875, + 645.9404907226562 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6387441754341125, + "bbox": [ + 1291.7265625, + 2259.445556640625, + 2258.3974609375, + 2376.928955078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.3375714123249054, + "bbox": [ + 1305.10009765625, + 2278.071044921875, + 2218.874755859375, + 2362.13134765625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7566924095153809, + "bbox": [ + 1303.558837890625, + 463.9815368652344, + 1428.698974609375, + 574.919189453125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7408478260040283, + "bbox": [ + 1299.2528076171875, + 2036.307861328125, + 1423.756103515625, + 2141.32373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6828992962837219, + "bbox": [ + 1313.28662109375, + 1025.3017578125, + 1415.196044921875, + 1129.6080322265625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5258637070655823, + "bbox": [ + 216.9156494140625, + 3269.890625, + 311.3939514160156, + 3347.684814453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.42604172229766846, + "bbox": [ + 1891.65625, + 2270.4970703125, + 1953.131103515625, + 2355.619384765625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9320166110992432, + "bbox": [ + 1274.0712890625, + 2034.815185546875, + 2329.8359375, + 2405.299560546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9268423318862915, + "bbox": [ + 1322.0179443359375, + 647.7603759765625, + 2351.85693359375, + 1205.0968017578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9122989773750305, + "bbox": [ + 1282.268310546875, + 432.29107666015625, + 2418.70556640625, + 1345.0736083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8509558439254761, + "bbox": [ + 196.17742919921875, + 569.5825805664062, + 1249.0784912109375, + 2550.984130859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8253114819526672, + "bbox": [ + 1290.557373046875, + 2133.1572265625, + 2298.28369140625, + 2260.04541015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7797009944915771, + "bbox": [ + 1315.5189208984375, + 565.0599365234375, + 1881.8953857421875, + 645.9404907226562 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6387441754341125, + "bbox": [ + 1291.7265625, + 2259.445556640625, + 2258.3974609375, + 2376.928955078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.3375714123249054, + "bbox": [ + 1305.10009765625, + 2278.071044921875, + 2218.874755859375, + 2362.13134765625 + ] + } + ], + "timestamp": "2025-10-15T21:42:29.201271" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 17.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 17.json" new file mode 100644 index 0000000..0c0d8c3 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 17.json" @@ -0,0 +1,406 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 17.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7485170960426331, + "bbox": [ + 1228.128662109375, + 1429.826904296875, + 1336.8826904296875, + 1521.368408203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7410387396812439, + "bbox": [ + 1219.1810302734375, + 2010.50048828125, + 1331.3731689453125, + 2108.992431640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7382306456565857, + "bbox": [ + 1218.4896240234375, + 2418.4912109375, + 1332.4351806640625, + 2519.4248046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6166597008705139, + "bbox": [ + 1228.687255859375, + 2907.854248046875, + 1285.19189453125, + 2979.4755859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.564454197883606, + "bbox": [ + 2053.67041015625, + 3009.162841796875, + 2136.96875, + 3076.246337890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5624663829803467, + "bbox": [ + 1666.3101806640625, + 1693.443115234375, + 1751.0045166015625, + 1790.0400390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5183578729629517, + "bbox": [ + 1566.604736328125, + 2163.695556640625, + 1660.8863525390625, + 2264.471923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9359051585197449, + "bbox": [ + 223.7063751220703, + 546.440185546875, + 1180.1690673828125, + 2950.478515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9159271717071533, + "bbox": [ + 1195.490966796875, + 1949.8662109375, + 2196.252685546875, + 2333.4384765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9141084551811218, + "bbox": [ + 1199.5240478515625, + 395.34307861328125, + 2173.250732421875, + 1297.2220458984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9124875068664551, + "bbox": [ + 1216.6912841796875, + 2583.717041015625, + 2127.26318359375, + 2980.590576171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8947314023971558, + "bbox": [ + 1187.8404541015625, + 2390.708740234375, + 2175.625244140625, + 2998.51220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8858322501182556, + "bbox": [ + 1216.5596923828125, + 1520.9996337890625, + 2167.90576171875, + 1640.150634765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.858069658279419, + "bbox": [ + 1197.7967529296875, + 1401.124267578125, + 2234.5712890625, + 1876.79541015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8350728154182434, + "bbox": [ + 1214.2359619140625, + 1655.3553466796875, + 2000.2890625, + 1856.89013671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8085700869560242, + "bbox": [ + 1224.291259765625, + 2508.45849609375, + 1859.20947265625, + 2596.18408203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7542762160301208, + "bbox": [ + 1220.1319580078125, + 2098.65234375, + 2135.69287109375, + 2196.173095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6814409494400024, + "bbox": [ + 1206.3046875, + 2164.535400390625, + 2086.9326171875, + 2286.73828125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7485170960426331, + "bbox": [ + 1228.128662109375, + 1429.826904296875, + 1336.8826904296875, + 1521.368408203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7410387396812439, + "bbox": [ + 1219.1810302734375, + 2010.50048828125, + 1331.3731689453125, + 2108.992431640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7382306456565857, + "bbox": [ + 1218.4896240234375, + 2418.4912109375, + 1332.4351806640625, + 2519.4248046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6166597008705139, + "bbox": [ + 1228.687255859375, + 2907.854248046875, + 1285.19189453125, + 2979.4755859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.564454197883606, + "bbox": [ + 2053.67041015625, + 3009.162841796875, + 2136.96875, + 3076.246337890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5624663829803467, + "bbox": [ + 1666.3101806640625, + 1693.443115234375, + 1751.0045166015625, + 1790.0400390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5183578729629517, + "bbox": [ + 1566.604736328125, + 2163.695556640625, + 1660.8863525390625, + 2264.471923828125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9359051585197449, + "bbox": [ + 223.7063751220703, + 546.440185546875, + 1180.1690673828125, + 2950.478515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9159271717071533, + "bbox": [ + 1195.490966796875, + 1949.8662109375, + 2196.252685546875, + 2333.4384765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9141084551811218, + "bbox": [ + 1199.5240478515625, + 395.34307861328125, + 2173.250732421875, + 1297.2220458984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9124875068664551, + "bbox": [ + 1216.6912841796875, + 2583.717041015625, + 2127.26318359375, + 2980.590576171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8947314023971558, + "bbox": [ + 1187.8404541015625, + 2390.708740234375, + 2175.625244140625, + 2998.51220703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8858322501182556, + "bbox": [ + 1216.5596923828125, + 1520.9996337890625, + 2167.90576171875, + 1640.150634765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.858069658279419, + "bbox": [ + 1197.7967529296875, + 1401.124267578125, + 2234.5712890625, + 1876.79541015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8350728154182434, + "bbox": [ + 1214.2359619140625, + 1655.3553466796875, + 2000.2890625, + 1856.89013671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8085700869560242, + "bbox": [ + 1224.291259765625, + 2508.45849609375, + 1859.20947265625, + 2596.18408203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7542762160301208, + "bbox": [ + 1220.1319580078125, + 2098.65234375, + 2135.69287109375, + 2196.173095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6814409494400024, + "bbox": [ + 1206.3046875, + 2164.535400390625, + 2086.9326171875, + 2286.73828125 + ] + } + ], + "timestamp": "2025-10-15T21:42:29.607835" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 2.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 2.json" new file mode 100644 index 0000000..6d30c65 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 2.json" @@ -0,0 +1,604 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 2.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.773139476776123, + "bbox": [ + 192.2500762939453, + 2584.900146484375, + 301.58831787109375, + 2677.50341796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7676541209220886, + "bbox": [ + 1215.4931640625, + 2238.238037109375, + 1320.641357421875, + 2333.06787109375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7633708715438843, + "bbox": [ + 206.25807189941406, + 1510.27099609375, + 314.306640625, + 1601.9495849609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7526618838310242, + "bbox": [ + 1228.820068359375, + 449.1214599609375, + 1338.8291015625, + 541.99658203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7422521114349365, + "bbox": [ + 211.4695587158203, + 436.35723876953125, + 324.2906188964844, + 529.6375122070312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7195858955383301, + "bbox": [ + 1232.6488037109375, + 955.6524658203125, + 1290.787109375, + 1031.388671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6265618205070496, + "bbox": [ + 192.98904418945312, + 3015.14794921875, + 254.03233337402344, + 3094.64501953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5657617449760437, + "bbox": [ + 208.47308349609375, + 1718.9996337890625, + 296.2408142089844, + 1834.0938720703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.500086784362793, + "bbox": [ + 1210.1043701171875, + 2697.981689453125, + 1316.89990234375, + 2825.78271484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4743703007698059, + "bbox": [ + 211.9891357421875, + 866.4877319335938, + 287.8264465332031, + 957.8651733398438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3897053301334381, + "bbox": [ + 190.72596740722656, + 3190.45654296875, + 283.2001647949219, + 3268.12841796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9433939456939697, + "bbox": [ + 1206.7149658203125, + 2435.04345703125, + 2162.81982421875, + 3187.415283203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9314338564872742, + "bbox": [ + 179.29930114746094, + 407.8069763183594, + 1171.303955078125, + 1019.8289794921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9252327680587769, + "bbox": [ + 152.95619201660156, + 2565.73388671875, + 1161.3707275390625, + 3191.96875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9056389927864075, + "bbox": [ + 1169.372314453125, + 2183.521484375, + 2209.51171875, + 3185.657958984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9019029140472412, + "bbox": [ + 1223.5853271484375, + 684.700927734375, + 2057.514404296875, + 1057.96826171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8933302760124207, + "bbox": [ + 205.90478515625, + 1685.59423828125, + 793.9609985351562, + 2062.454345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.89143967628479, + "bbox": [ + 161.6622314453125, + 1473.24609375, + 1177.6116943359375, + 2111.179443359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8466437458992004, + "bbox": [ + 1211.3382568359375, + 544.82373046875, + 2171.995361328125, + 674.3635864257812 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8367560505867004, + "bbox": [ + 1180.5792236328125, + 400.8259582519531, + 2270.049560546875, + 1222.7286376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8104263544082642, + "bbox": [ + 211.9488525390625, + 518.5576782226562, + 946.94580078125, + 615.2498779296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8092429041862488, + "bbox": [ + 199.29608154296875, + 2832.9716796875, + 442.92041015625, + 3173.62744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8091081380844116, + "bbox": [ + 188.92068481445312, + 2686.10888671875, + 1140.5042724609375, + 2805.667724609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7639308571815491, + "bbox": [ + 205.1981964111328, + 1596.6451416015625, + 1013.4995727539062, + 1683.8123779296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5721950531005859, + "bbox": [ + 1207.5059814453125, + 2335.354248046875, + 2131.326171875, + 2416.983154296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.3128732144832611, + "bbox": [ + 222.141357421875, + 605.5153198242188, + 556.7269897460938, + 965.7357788085938 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.27527865767478943, + "bbox": [ + 219.0604705810547, + 604.6409301757812, + 761.763671875, + 972.642333984375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.773139476776123, + "bbox": [ + 192.2500762939453, + 2584.900146484375, + 301.58831787109375, + 2677.50341796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7676541209220886, + "bbox": [ + 1215.4931640625, + 2238.238037109375, + 1320.641357421875, + 2333.06787109375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7633708715438843, + "bbox": [ + 206.25807189941406, + 1510.27099609375, + 314.306640625, + 1601.9495849609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7526618838310242, + "bbox": [ + 1228.820068359375, + 449.1214599609375, + 1338.8291015625, + 541.99658203125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7422521114349365, + "bbox": [ + 211.4695587158203, + 436.35723876953125, + 324.2906188964844, + 529.6375122070312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7195858955383301, + "bbox": [ + 1232.6488037109375, + 955.6524658203125, + 1290.787109375, + 1031.388671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6265618205070496, + "bbox": [ + 192.98904418945312, + 3015.14794921875, + 254.03233337402344, + 3094.64501953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5657617449760437, + "bbox": [ + 208.47308349609375, + 1718.9996337890625, + 296.2408142089844, + 1834.0938720703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.500086784362793, + "bbox": [ + 1210.1043701171875, + 2697.981689453125, + 1316.89990234375, + 2825.78271484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4743703007698059, + "bbox": [ + 211.9891357421875, + 866.4877319335938, + 287.8264465332031, + 957.8651733398438 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3897053301334381, + "bbox": [ + 190.72596740722656, + 3190.45654296875, + 283.2001647949219, + 3268.12841796875 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9433939456939697, + "bbox": [ + 1206.7149658203125, + 2435.04345703125, + 2162.81982421875, + 3187.415283203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9314338564872742, + "bbox": [ + 179.29930114746094, + 407.8069763183594, + 1171.303955078125, + 1019.8289794921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9252327680587769, + "bbox": [ + 152.95619201660156, + 2565.73388671875, + 1161.3707275390625, + 3191.96875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9056389927864075, + "bbox": [ + 1169.372314453125, + 2183.521484375, + 2209.51171875, + 3185.657958984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9019029140472412, + "bbox": [ + 1223.5853271484375, + 684.700927734375, + 2057.514404296875, + 1057.96826171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8933302760124207, + "bbox": [ + 205.90478515625, + 1685.59423828125, + 793.9609985351562, + 2062.454345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.89143967628479, + "bbox": [ + 161.6622314453125, + 1473.24609375, + 1177.6116943359375, + 2111.179443359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8466437458992004, + "bbox": [ + 1211.3382568359375, + 544.82373046875, + 2171.995361328125, + 674.3635864257812 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8367560505867004, + "bbox": [ + 1180.5792236328125, + 400.8259582519531, + 2270.049560546875, + 1222.7286376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8104263544082642, + "bbox": [ + 211.9488525390625, + 518.5576782226562, + 946.94580078125, + 615.2498779296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8092429041862488, + "bbox": [ + 199.29608154296875, + 2832.9716796875, + 442.92041015625, + 3173.62744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8091081380844116, + "bbox": [ + 188.92068481445312, + 2686.10888671875, + 1140.5042724609375, + 2805.667724609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7639308571815491, + "bbox": [ + 205.1981964111328, + 1596.6451416015625, + 1013.4995727539062, + 1683.8123779296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5721950531005859, + "bbox": [ + 1207.5059814453125, + 2335.354248046875, + 2131.326171875, + 2416.983154296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.3128732144832611, + "bbox": [ + 222.141357421875, + 605.5153198242188, + 556.7269897460938, + 965.7357788085938 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.27527865767478943, + "bbox": [ + 219.0604705810547, + 604.6409301757812, + 761.763671875, + 972.642333984375 + ] + } + ], + "timestamp": "2025-10-15T21:42:30.072016" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 3.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 3.json" new file mode 100644 index 0000000..309fd3e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 3.json" @@ -0,0 +1,692 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 3.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.763209342956543, + "bbox": [ + 1314.411865234375, + 449.1679992675781, + 1423.410400390625, + 551.4131469726562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7545271515846252, + "bbox": [ + 257.5189208984375, + 1282.41845703125, + 370.71868896484375, + 1386.22021484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7480810284614563, + "bbox": [ + 1295.855224609375, + 2191.54638671875, + 1405.607421875, + 2287.02392578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7448151707649231, + "bbox": [ + 266.94952392578125, + 441.7080383300781, + 379.1337585449219, + 544.2326049804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7343556880950928, + "bbox": [ + 249.61859130859375, + 2308.408447265625, + 362.1669006347656, + 2410.77294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6138310432434082, + "bbox": [ + 235.81959533691406, + 3015.343017578125, + 308.1266174316406, + 3117.077880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5855740308761597, + "bbox": [ + 1303.1883544921875, + 1280.341796875, + 1396.1474609375, + 1385.2835693359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5771365165710449, + "bbox": [ + 2172.08837890625, + 3216.8466796875, + 2267.779541015625, + 3299.461669921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.554063081741333, + "bbox": [ + 265.5001525878906, + 653.8616943359375, + 357.20526123046875, + 758.0416259765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5282912850379944, + "bbox": [ + 268.5801696777344, + 1494.091064453125, + 356.52252197265625, + 1587.99609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4771351218223572, + "bbox": [ + 258.55584716796875, + 1483.3260498046875, + 376.03424072265625, + 1602.6806640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4733010530471802, + "bbox": [ + 1288.043212890625, + 3010.6591796875, + 1381.97509765625, + 3124.916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3831689655780792, + "bbox": [ + 245.97938537597656, + 3033.33349609375, + 309.8055725097656, + 3116.13330078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9388336539268494, + "bbox": [ + 1281.742431640625, + 2518.37158203125, + 2271.1201171875, + 3199.3701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9373374581336975, + "bbox": [ + 241.59617614746094, + 2645.763427734375, + 1216.6578369140625, + 3193.408935546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9359375238418579, + "bbox": [ + 1300.2862548828125, + 783.489013671875, + 2307.87548828125, + 1465.9833984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9321898818016052, + "bbox": [ + 247.10382080078125, + 1512.0419921875, + 1228.8599853515625, + 2191.217041015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.928565502166748, + "bbox": [ + 214.58412170410156, + 1255.245849609375, + 1241.388916015625, + 2219.69287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9172302484512329, + "bbox": [ + 200.93795776367188, + 402.0989074707031, + 1252.154052734375, + 1219.3779296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.912268877029419, + "bbox": [ + 1260.694580078125, + 2125.35205078125, + 2291.84033203125, + 3219.77197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9112990498542786, + "bbox": [ + 180.5989227294922, + 2265.222900390625, + 1249.9031982421875, + 3237.217529296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9095674753189087, + "bbox": [ + 252.14273071289062, + 672.3754272460938, + 1230.1636962890625, + 1175.6072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9001824855804443, + "bbox": [ + 1260.8485107421875, + 394.76519775390625, + 2400.4462890625, + 1522.1595458984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8762091398239136, + "bbox": [ + 1278.30078125, + 2421.822509765625, + 2266.958740234375, + 2530.472900390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8707284331321716, + "bbox": [ + 240.9610595703125, + 537.4722290039062, + 1230.8153076171875, + 677.4971923828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.862907886505127, + "bbox": [ + 249.6811981201172, + 1374.184326171875, + 1226.9427490234375, + 1501.307861328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8625087141990662, + "bbox": [ + 225.2228240966797, + 2404.477783203125, + 1220.9378662109375, + 2536.891845703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8577516674995422, + "bbox": [ + 1316.193359375, + 683.9502563476562, + 2294.273681640625, + 778.3448486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8393417596817017, + "bbox": [ + 1289.963623046875, + 2280.35595703125, + 2277.13427734375, + 2411.633056640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8281707167625427, + "bbox": [ + 1313.4229736328125, + 542.356689453125, + 2290.7119140625, + 671.3619995117188 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5733320116996765, + "bbox": [ + 241.21707153320312, + 2533.07763671875, + 1205.958740234375, + 2650.150146484375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.763209342956543, + "bbox": [ + 1314.411865234375, + 449.1679992675781, + 1423.410400390625, + 551.4131469726562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7545271515846252, + "bbox": [ + 257.5189208984375, + 1282.41845703125, + 370.71868896484375, + 1386.22021484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7480810284614563, + "bbox": [ + 1295.855224609375, + 2191.54638671875, + 1405.607421875, + 2287.02392578125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7448151707649231, + "bbox": [ + 266.94952392578125, + 441.7080383300781, + 379.1337585449219, + 544.2326049804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7343556880950928, + "bbox": [ + 249.61859130859375, + 2308.408447265625, + 362.1669006347656, + 2410.77294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6138310432434082, + "bbox": [ + 235.81959533691406, + 3015.343017578125, + 308.1266174316406, + 3117.077880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5855740308761597, + "bbox": [ + 1303.1883544921875, + 1280.341796875, + 1396.1474609375, + 1385.2835693359375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5771365165710449, + "bbox": [ + 2172.08837890625, + 3216.8466796875, + 2267.779541015625, + 3299.461669921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.554063081741333, + "bbox": [ + 265.5001525878906, + 653.8616943359375, + 357.20526123046875, + 758.0416259765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5282912850379944, + "bbox": [ + 268.5801696777344, + 1494.091064453125, + 356.52252197265625, + 1587.99609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4771351218223572, + "bbox": [ + 258.55584716796875, + 1483.3260498046875, + 376.03424072265625, + 1602.6806640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4733010530471802, + "bbox": [ + 1288.043212890625, + 3010.6591796875, + 1381.97509765625, + 3124.916015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3831689655780792, + "bbox": [ + 245.97938537597656, + 3033.33349609375, + 309.8055725097656, + 3116.13330078125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9388336539268494, + "bbox": [ + 1281.742431640625, + 2518.37158203125, + 2271.1201171875, + 3199.3701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9373374581336975, + "bbox": [ + 241.59617614746094, + 2645.763427734375, + 1216.6578369140625, + 3193.408935546875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9359375238418579, + "bbox": [ + 1300.2862548828125, + 783.489013671875, + 2307.87548828125, + 1465.9833984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9321898818016052, + "bbox": [ + 247.10382080078125, + 1512.0419921875, + 1228.8599853515625, + 2191.217041015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.928565502166748, + "bbox": [ + 214.58412170410156, + 1255.245849609375, + 1241.388916015625, + 2219.69287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9172302484512329, + "bbox": [ + 200.93795776367188, + 402.0989074707031, + 1252.154052734375, + 1219.3779296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.912268877029419, + "bbox": [ + 1260.694580078125, + 2125.35205078125, + 2291.84033203125, + 3219.77197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9112990498542786, + "bbox": [ + 180.5989227294922, + 2265.222900390625, + 1249.9031982421875, + 3237.217529296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9095674753189087, + "bbox": [ + 252.14273071289062, + 672.3754272460938, + 1230.1636962890625, + 1175.6072998046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9001824855804443, + "bbox": [ + 1260.8485107421875, + 394.76519775390625, + 2400.4462890625, + 1522.1595458984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8762091398239136, + "bbox": [ + 1278.30078125, + 2421.822509765625, + 2266.958740234375, + 2530.472900390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8707284331321716, + "bbox": [ + 240.9610595703125, + 537.4722290039062, + 1230.8153076171875, + 677.4971923828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.862907886505127, + "bbox": [ + 249.6811981201172, + 1374.184326171875, + 1226.9427490234375, + 1501.307861328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8625087141990662, + "bbox": [ + 225.2228240966797, + 2404.477783203125, + 1220.9378662109375, + 2536.891845703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8577516674995422, + "bbox": [ + 1316.193359375, + 683.9502563476562, + 2294.273681640625, + 778.3448486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8393417596817017, + "bbox": [ + 1289.963623046875, + 2280.35595703125, + 2277.13427734375, + 2411.633056640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8281707167625427, + "bbox": [ + 1313.4229736328125, + 542.356689453125, + 2290.7119140625, + 671.3619995117188 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5733320116996765, + "bbox": [ + 241.21707153320312, + 2533.07763671875, + 1205.958740234375, + 2650.150146484375 + ] + } + ], + "timestamp": "2025-10-15T21:42:30.462871" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 4.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 4.json" new file mode 100644 index 0000000..bc633cd --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 4.json" @@ -0,0 +1,384 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 4.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.778863251209259, + "bbox": [ + 1191.870361328125, + 415.920654296875, + 1295.2523193359375, + 511.8294982910156 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7557286620140076, + "bbox": [ + 205.35946655273438, + 525.6177978515625, + 309.5257263183594, + 624.0623168945312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7311107516288757, + "bbox": [ + 191.5093536376953, + 1722.0103759765625, + 302.2926025390625, + 1822.052490234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.656991720199585, + "bbox": [ + 1179.72705078125, + 2347.092041015625, + 1269.48974609375, + 2454.12109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5569954514503479, + "bbox": [ + 207.88653564453125, + 667.4052124023438, + 305.1193542480469, + 774.6541137695312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5301179885864258, + "bbox": [ + 193.0784912109375, + 3003.834716796875, + 277.7440185546875, + 3074.09326171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4741879105567932, + "bbox": [ + 192.82325744628906, + 2013.6138916015625, + 263.5181884765625, + 2098.947021484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9225581288337708, + "bbox": [ + 195.69033813476562, + 677.9916381835938, + 1114.3905029296875, + 1050.36376953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9136741757392883, + "bbox": [ + 1188.46435546875, + 595.431396484375, + 2074.439697265625, + 2184.782470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9106642007827759, + "bbox": [ + 1155.7833251953125, + 365.0885925292969, + 2194.62548828125, + 2737.09619140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9093073010444641, + "bbox": [ + 1181.6075439453125, + 2230.82275390625, + 1947.29541015625, + 2602.575927734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9043163061141968, + "bbox": [ + 171.7726593017578, + 496.01177978515625, + 1160.2034912109375, + 1133.364990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8974544405937195, + "bbox": [ + 187.04861450195312, + 1895.8814697265625, + 604.8574829101562, + 2249.16015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8833035230636597, + "bbox": [ + 123.42131042480469, + 1684.7811279296875, + 1139.8331298828125, + 2313.213623046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7732571959495544, + "bbox": [ + 1197.5740966796875, + 499.45263671875, + 1779.0638427734375, + 579.8079223632812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6505650281906128, + "bbox": [ + 200.16371154785156, + 613.4199829101562, + 825.3067016601562, + 688.7120971679688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6393455862998962, + "bbox": [ + 193.83375549316406, + 1818.899658203125, + 593.0745849609375, + 1897.2552490234375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.778863251209259, + "bbox": [ + 1191.870361328125, + 415.920654296875, + 1295.2523193359375, + 511.8294982910156 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7557286620140076, + "bbox": [ + 205.35946655273438, + 525.6177978515625, + 309.5257263183594, + 624.0623168945312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7311107516288757, + "bbox": [ + 191.5093536376953, + 1722.0103759765625, + 302.2926025390625, + 1822.052490234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.656991720199585, + "bbox": [ + 1179.72705078125, + 2347.092041015625, + 1269.48974609375, + 2454.12109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5569954514503479, + "bbox": [ + 207.88653564453125, + 667.4052124023438, + 305.1193542480469, + 774.6541137695312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5301179885864258, + "bbox": [ + 193.0784912109375, + 3003.834716796875, + 277.7440185546875, + 3074.09326171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4741879105567932, + "bbox": [ + 192.82325744628906, + 2013.6138916015625, + 263.5181884765625, + 2098.947021484375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9225581288337708, + "bbox": [ + 195.69033813476562, + 677.9916381835938, + 1114.3905029296875, + 1050.36376953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9136741757392883, + "bbox": [ + 1188.46435546875, + 595.431396484375, + 2074.439697265625, + 2184.782470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9106642007827759, + "bbox": [ + 1155.7833251953125, + 365.0885925292969, + 2194.62548828125, + 2737.09619140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9093073010444641, + "bbox": [ + 1181.6075439453125, + 2230.82275390625, + 1947.29541015625, + 2602.575927734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9043163061141968, + "bbox": [ + 171.7726593017578, + 496.01177978515625, + 1160.2034912109375, + 1133.364990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8974544405937195, + "bbox": [ + 187.04861450195312, + 1895.8814697265625, + 604.8574829101562, + 2249.16015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8833035230636597, + "bbox": [ + 123.42131042480469, + 1684.7811279296875, + 1139.8331298828125, + 2313.213623046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7732571959495544, + "bbox": [ + 1197.5740966796875, + 499.45263671875, + 1779.0638427734375, + 579.8079223632812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6505650281906128, + "bbox": [ + 200.16371154785156, + 613.4199829101562, + 825.3067016601562, + 688.7120971679688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6393455862998962, + "bbox": [ + 193.83375549316406, + 1818.899658203125, + 593.0745849609375, + 1897.2552490234375 + ] + } + ], + "timestamp": "2025-10-15T21:42:30.848169" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 5.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 5.json" new file mode 100644 index 0000000..2804b8d --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 5.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 5.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7590410709381104, + "bbox": [ + 1244.9266357421875, + 424.6640319824219, + 1355.979248046875, + 520.8428344726562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7537903785705566, + "bbox": [ + 253.0414581298828, + 411.5349426269531, + 358.78839111328125, + 509.7574462890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6539319157600403, + "bbox": [ + 1243.7724609375, + 2317.952880859375, + 1325.805419921875, + 2428.751220703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.549699604511261, + "bbox": [ + 2068.84375, + 3059.930908203125, + 2155.918212890625, + 3130.73388671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5082973837852478, + "bbox": [ + 236.89224243164062, + 2123.05078125, + 305.14068603515625, + 2199.552978515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9484599828720093, + "bbox": [ + 246.9534454345703, + 595.8448486328125, + 1161.034423828125, + 1878.875732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9476075768470764, + "bbox": [ + 201.04127502441406, + 389.6425476074219, + 1180.9970703125, + 2343.943359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9343069791793823, + "bbox": [ + 1232.7979736328125, + 594.7357177734375, + 2174.822998046875, + 1935.1080322265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.927017092704773, + "bbox": [ + 1211.080078125, + 383.5271301269531, + 2214.51806640625, + 2570.34619140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9178480505943298, + "bbox": [ + 1237.7528076171875, + 2024.776123046875, + 2168.660400390625, + 2481.8115234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9051907062530518, + "bbox": [ + 239.8685760498047, + 1937.699462890625, + 768.4166870117188, + 2281.149169921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7685898542404175, + "bbox": [ + 1260.042236328125, + 518.130615234375, + 2010.4139404296875, + 608.478271484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.691926896572113, + "bbox": [ + 249.53062438964844, + 496.96636962890625, + 972.8667602539062, + 575.5149536132812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6241666674613953, + "bbox": [ + 1247.048583984375, + 528.7554321289062, + 2026.0137939453125, + 592.5413818359375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7590410709381104, + "bbox": [ + 1244.9266357421875, + 424.6640319824219, + 1355.979248046875, + 520.8428344726562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7537903785705566, + "bbox": [ + 253.0414581298828, + 411.5349426269531, + 358.78839111328125, + 509.7574462890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6539319157600403, + "bbox": [ + 1243.7724609375, + 2317.952880859375, + 1325.805419921875, + 2428.751220703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.549699604511261, + "bbox": [ + 2068.84375, + 3059.930908203125, + 2155.918212890625, + 3130.73388671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5082973837852478, + "bbox": [ + 236.89224243164062, + 2123.05078125, + 305.14068603515625, + 2199.552978515625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9484599828720093, + "bbox": [ + 246.9534454345703, + 595.8448486328125, + 1161.034423828125, + 1878.875732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9476075768470764, + "bbox": [ + 201.04127502441406, + 389.6425476074219, + 1180.9970703125, + 2343.943359375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9343069791793823, + "bbox": [ + 1232.7979736328125, + 594.7357177734375, + 2174.822998046875, + 1935.1080322265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.927017092704773, + "bbox": [ + 1211.080078125, + 383.5271301269531, + 2214.51806640625, + 2570.34619140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9178480505943298, + "bbox": [ + 1237.7528076171875, + 2024.776123046875, + 2168.660400390625, + 2481.8115234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9051907062530518, + "bbox": [ + 239.8685760498047, + 1937.699462890625, + 768.4166870117188, + 2281.149169921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7685898542404175, + "bbox": [ + 1260.042236328125, + 518.130615234375, + 2010.4139404296875, + 608.478271484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.691926896572113, + "bbox": [ + 249.53062438964844, + 496.96636962890625, + 972.8667602539062, + 575.5149536132812 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6241666674613953, + "bbox": [ + 1247.048583984375, + 528.7554321289062, + 2026.0137939453125, + 592.5413818359375 + ] + } + ], + "timestamp": "2025-10-15T21:42:31.204328" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 6.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 6.json" new file mode 100644 index 0000000..d057489 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 6.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 6.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491795420646667, + "bbox": [ + 1223.7366943359375, + 428.72467041015625, + 1333.751953125, + 525.1738891601562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7411307692527771, + "bbox": [ + 214.4866943359375, + 413.9234313964844, + 327.1632385253906, + 512.0313110351562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5187163949012756, + "bbox": [ + 196.06837463378906, + 3050.721435546875, + 284.88629150390625, + 3125.38623046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5107085704803467, + "bbox": [ + 196.14381408691406, + 2442.447998046875, + 279.31195068359375, + 2561.37939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49005451798439026, + "bbox": [ + 1210.2567138671875, + 2374.678955078125, + 1300.98779296875, + 2484.461669921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9435957670211792, + "bbox": [ + 164.20184326171875, + 377.003173828125, + 1158.844970703125, + 2636.35546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9418251514434814, + "bbox": [ + 197.4623565673828, + 644.52685546875, + 1149.731689453125, + 1956.58447265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9379463791847229, + "bbox": [ + 180.2716827392578, + 2041.52490234375, + 1140.852783203125, + 2646.2470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9261289238929749, + "bbox": [ + 1216.048828125, + 580.7479858398438, + 2171.823486328125, + 2260.050048828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9239684343338013, + "bbox": [ + 1205.02490234375, + 2325.142578125, + 2121.4384765625, + 2695.517333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9028078317642212, + "bbox": [ + 1184.0750732421875, + 381.66583251953125, + 2195.732421875, + 2805.02392578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8230200409889221, + "bbox": [ + 201.6152801513672, + 507.9662780761719, + 1148.1668701171875, + 634.564453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7481492757797241, + "bbox": [ + 1232.4373779296875, + 508.6654357910156, + 1765.220947265625, + 595.0596313476562 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491795420646667, + "bbox": [ + 1223.7366943359375, + 428.72467041015625, + 1333.751953125, + 525.1738891601562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7411307692527771, + "bbox": [ + 214.4866943359375, + 413.9234313964844, + 327.1632385253906, + 512.0313110351562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5187163949012756, + "bbox": [ + 196.06837463378906, + 3050.721435546875, + 284.88629150390625, + 3125.38623046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5107085704803467, + "bbox": [ + 196.14381408691406, + 2442.447998046875, + 279.31195068359375, + 2561.37939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49005451798439026, + "bbox": [ + 1210.2567138671875, + 2374.678955078125, + 1300.98779296875, + 2484.461669921875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9435957670211792, + "bbox": [ + 164.20184326171875, + 377.003173828125, + 1158.844970703125, + 2636.35546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9418251514434814, + "bbox": [ + 197.4623565673828, + 644.52685546875, + 1149.731689453125, + 1956.58447265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9379463791847229, + "bbox": [ + 180.2716827392578, + 2041.52490234375, + 1140.852783203125, + 2646.2470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9261289238929749, + "bbox": [ + 1216.048828125, + 580.7479858398438, + 2171.823486328125, + 2260.050048828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9239684343338013, + "bbox": [ + 1205.02490234375, + 2325.142578125, + 2121.4384765625, + 2695.517333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9028078317642212, + "bbox": [ + 1184.0750732421875, + 381.66583251953125, + 2195.732421875, + 2805.02392578125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8230200409889221, + "bbox": [ + 201.6152801513672, + 507.9662780761719, + 1148.1668701171875, + 634.564453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7481492757797241, + "bbox": [ + 1232.4373779296875, + 508.6654357910156, + 1765.220947265625, + 595.0596313476562 + ] + } + ], + "timestamp": "2025-10-15T21:42:31.572107" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 7.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 7.json" new file mode 100644 index 0000000..0098eb0 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 7.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 7.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7612056732177734, + "bbox": [ + 1325.2484130859375, + 448.3669738769531, + 1441.96484375, + 550.7628784179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7573733329772949, + "bbox": [ + 263.52923583984375, + 439.2020568847656, + 381.2477111816406, + 540.640869140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6630344986915588, + "bbox": [ + 1323.3297119140625, + 2406.1513671875, + 1412.327392578125, + 2526.4814453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5677933692932129, + "bbox": [ + 2203.697265625, + 3219.5830078125, + 2302.647216796875, + 3301.492431640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.529183566570282, + "bbox": [ + 255.1278533935547, + 1998.453125, + 356.11474609375, + 2127.900390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4180631637573242, + "bbox": [ + 1309.0074462890625, + 2403.96240234375, + 1428.2066650390625, + 2535.266357421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9539963006973267, + "bbox": [ + 1326.5028076171875, + 638.5123291015625, + 2320.687255859375, + 2125.1123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9492160081863403, + "bbox": [ + 243.94677734375, + 629.4617919921875, + 1244.364013671875, + 1888.191650390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9468057155609131, + "bbox": [ + 1325.242919921875, + 2178.634033203125, + 2327.711669921875, + 2737.770263671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9402197599411011, + "bbox": [ + 1282.40234375, + 356.3473205566406, + 2475.557861328125, + 2846.28564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.937237560749054, + "bbox": [ + 217.1188507080078, + 389.8701171875, + 1259.607666015625, + 2691.2763671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9347747564315796, + "bbox": [ + 240.94369506835938, + 1957.65087890625, + 1248.9676513671875, + 2597.036376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7310627102851868, + "bbox": [ + 1336.3514404296875, + 543.7594604492188, + 1944.1654052734375, + 627.0003662109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6655001640319824, + "bbox": [ + 259.629638671875, + 531.927001953125, + 823.11572265625, + 618.2756958007812 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7612056732177734, + "bbox": [ + 1325.2484130859375, + 448.3669738769531, + 1441.96484375, + 550.7628784179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7573733329772949, + "bbox": [ + 263.52923583984375, + 439.2020568847656, + 381.2477111816406, + 540.640869140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6630344986915588, + "bbox": [ + 1323.3297119140625, + 2406.1513671875, + 1412.327392578125, + 2526.4814453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5677933692932129, + "bbox": [ + 2203.697265625, + 3219.5830078125, + 2302.647216796875, + 3301.492431640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.529183566570282, + "bbox": [ + 255.1278533935547, + 1998.453125, + 356.11474609375, + 2127.900390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4180631637573242, + "bbox": [ + 1309.0074462890625, + 2403.96240234375, + 1428.2066650390625, + 2535.266357421875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9539963006973267, + "bbox": [ + 1326.5028076171875, + 638.5123291015625, + 2320.687255859375, + 2125.1123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9492160081863403, + "bbox": [ + 243.94677734375, + 629.4617919921875, + 1244.364013671875, + 1888.191650390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9468057155609131, + "bbox": [ + 1325.242919921875, + 2178.634033203125, + 2327.711669921875, + 2737.770263671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9402197599411011, + "bbox": [ + 1282.40234375, + 356.3473205566406, + 2475.557861328125, + 2846.28564453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.937237560749054, + "bbox": [ + 217.1188507080078, + 389.8701171875, + 1259.607666015625, + 2691.2763671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9347747564315796, + "bbox": [ + 240.94369506835938, + 1957.65087890625, + 1248.9676513671875, + 2597.036376953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7310627102851868, + "bbox": [ + 1336.3514404296875, + 543.7594604492188, + 1944.1654052734375, + 627.0003662109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6655001640319824, + "bbox": [ + 259.629638671875, + 531.927001953125, + 823.11572265625, + 618.2756958007812 + ] + } + ], + "timestamp": "2025-10-15T21:42:31.979155" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 8.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 8.json" new file mode 100644 index 0000000..18f7eb1 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 8.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 8.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7588344812393188, + "bbox": [ + 1191.49951171875, + 403.5597839355469, + 1300.09814453125, + 500.7749938964844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7518787980079651, + "bbox": [ + 211.57595825195312, + 401.6043701171875, + 317.3182067871094, + 489.6629638671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6756214499473572, + "bbox": [ + 749.4872436523438, + 2684.63330078125, + 805.3353881835938, + 2754.498291015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5186352133750916, + "bbox": [ + 1176.7537841796875, + 2172.101806640625, + 1268.2066650390625, + 2281.197998046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.49068084359169006, + "bbox": [ + 197.5060577392578, + 2962.158447265625, + 286.7390441894531, + 3036.118896484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9395431876182556, + "bbox": [ + 1144.3035888671875, + 331.2355651855469, + 2226.7216796875, + 2531.980712890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9320506453514099, + "bbox": [ + 1174.18115234375, + 580.43115234375, + 2109.4140625, + 1887.785888671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9272489547729492, + "bbox": [ + 1176.2601318359375, + 1942.9906005859375, + 2106.0146484375, + 2358.02197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9073701500892639, + "bbox": [ + 138.0968017578125, + 457.8233947753906, + 1128.2633056640625, + 2944.27490234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9056805372238159, + "bbox": [ + 168.82777404785156, + 799.6654052734375, + 1123.5394287109375, + 3011.501708984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7156044840812683, + "bbox": [ + 207.78250122070312, + 488.5344543457031, + 777.79736328125, + 563.3496704101562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5013728141784668, + "bbox": [ + 1190.416748046875, + 496.51605224609375, + 2013.04248046875, + 570.550048828125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7588344812393188, + "bbox": [ + 1191.49951171875, + 403.5597839355469, + 1300.09814453125, + 500.7749938964844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7518787980079651, + "bbox": [ + 211.57595825195312, + 401.6043701171875, + 317.3182067871094, + 489.6629638671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6756214499473572, + "bbox": [ + 749.4872436523438, + 2684.63330078125, + 805.3353881835938, + 2754.498291015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5186352133750916, + "bbox": [ + 1176.7537841796875, + 2172.101806640625, + 1268.2066650390625, + 2281.197998046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.49068084359169006, + "bbox": [ + 197.5060577392578, + 2962.158447265625, + 286.7390441894531, + 3036.118896484375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9395431876182556, + "bbox": [ + 1144.3035888671875, + 331.2355651855469, + 2226.7216796875, + 2531.980712890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9320506453514099, + "bbox": [ + 1174.18115234375, + 580.43115234375, + 2109.4140625, + 1887.785888671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9272489547729492, + "bbox": [ + 1176.2601318359375, + 1942.9906005859375, + 2106.0146484375, + 2358.02197265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9073701500892639, + "bbox": [ + 138.0968017578125, + 457.8233947753906, + 1128.2633056640625, + 2944.27490234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9056805372238159, + "bbox": [ + 168.82777404785156, + 799.6654052734375, + 1123.5394287109375, + 3011.501708984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7156044840812683, + "bbox": [ + 207.78250122070312, + 488.5344543457031, + 777.79736328125, + 563.3496704101562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.5013728141784668, + "bbox": [ + 1190.416748046875, + 496.51605224609375, + 2013.04248046875, + 570.550048828125 + ] + } + ], + "timestamp": "2025-10-15T21:42:32.396102" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 9.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 9.json" new file mode 100644 index 0000000..699a0d8 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\353\247\236\354\235\214) - 9.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„†แ…กแ†ฝแ„‹แ…ณแ†ท) - 9.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7407278418540955, + "bbox": [ + 255.2974853515625, + 418.0464172363281, + 371.5840148925781, + 517.6305541992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.73762446641922, + "bbox": [ + 1266.562255859375, + 430.7855529785156, + 1379.7364501953125, + 528.1295776367188 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6129497289657593, + "bbox": [ + 256.64495849609375, + 2696.13232421875, + 339.9280700683594, + 2795.55810546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5788566470146179, + "bbox": [ + 1268.5531005859375, + 2682.50732421875, + 1360.7955322265625, + 2796.12939453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.560023307800293, + "bbox": [ + 2111.072509765625, + 3090.164794921875, + 2196.01416015625, + 3163.5751953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9463841319084167, + "bbox": [ + 234.2601318359375, + 635.1507568359375, + 1182.9820556640625, + 2453.857177734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9330389499664307, + "bbox": [ + 193.59645080566406, + 370.2449035644531, + 1223.2989501953125, + 2869.853271484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9254768490791321, + "bbox": [ + 1255.192626953125, + 2508.532958984375, + 2160.4423828125, + 2887.697509765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9240542650222778, + "bbox": [ + 1249.451904296875, + 662.1696166992188, + 2177.839599609375, + 2505.013671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9159631729125977, + "bbox": [ + 1218.432373046875, + 391.7794189453125, + 2360.726318359375, + 2950.974365234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.904816210269928, + "bbox": [ + 236.9214630126953, + 2465.253662109375, + 1179.156494140625, + 2821.782470703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8692476153373718, + "bbox": [ + 255.6144256591797, + 517.9653930664062, + 1190.3916015625, + 637.4789428710938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8335717916488647, + "bbox": [ + 1271.274658203125, + 527.8038330078125, + 2215.580322265625, + 647.83203125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7407278418540955, + "bbox": [ + 255.2974853515625, + 418.0464172363281, + 371.5840148925781, + 517.6305541992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.73762446641922, + "bbox": [ + 1266.562255859375, + 430.7855529785156, + 1379.7364501953125, + 528.1295776367188 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6129497289657593, + "bbox": [ + 256.64495849609375, + 2696.13232421875, + 339.9280700683594, + 2795.55810546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5788566470146179, + "bbox": [ + 1268.5531005859375, + 2682.50732421875, + 1360.7955322265625, + 2796.12939453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.560023307800293, + "bbox": [ + 2111.072509765625, + 3090.164794921875, + 2196.01416015625, + 3163.5751953125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9463841319084167, + "bbox": [ + 234.2601318359375, + 635.1507568359375, + 1182.9820556640625, + 2453.857177734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9330389499664307, + "bbox": [ + 193.59645080566406, + 370.2449035644531, + 1223.2989501953125, + 2869.853271484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9254768490791321, + "bbox": [ + 1255.192626953125, + 2508.532958984375, + 2160.4423828125, + 2887.697509765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9240542650222778, + "bbox": [ + 1249.451904296875, + 662.1696166992188, + 2177.839599609375, + 2505.013671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9159631729125977, + "bbox": [ + 1218.432373046875, + 391.7794189453125, + 2360.726318359375, + 2950.974365234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.904816210269928, + "bbox": [ + 236.9214630126953, + 2465.253662109375, + 1179.156494140625, + 2821.782470703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8692476153373718, + "bbox": [ + 255.6144256591797, + 517.9653930664062, + 1190.3916015625, + 637.4789428710938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8335717916488647, + "bbox": [ + 1271.274658203125, + 527.8038330078125, + 2215.580322265625, + 647.83203125 + ] + } + ], + "timestamp": "2025-10-15T21:42:32.815033" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 18.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 18.json" new file mode 100644 index 0000000..6b275f6 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 18.json" @@ -0,0 +1,692 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 18.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7846184968948364, + "bbox": [ + 1299.5025634765625, + 2579.77587890625, + 1403.5953369140625, + 2668.6572265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7759642601013184, + "bbox": [ + 1311.9716796875, + 499.1026916503906, + 1415.04541015625, + 586.4191284179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7688509821891785, + "bbox": [ + 277.18115234375, + 983.3073120117188, + 385.6111145019531, + 1079.220703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7686595916748047, + "bbox": [ + 281.42486572265625, + 1812.1678466796875, + 389.3860168457031, + 1902.4697265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7683885097503662, + "bbox": [ + 275.0069274902344, + 2575.080322265625, + 378.5321044921875, + 2662.817626953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6927738785743713, + "bbox": [ + 284.9305725097656, + 1272.8846435546875, + 346.3131408691406, + 1350.852294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6015613079071045, + "bbox": [ + 281.03338623046875, + 2236.856689453125, + 344.9021911621094, + 2316.61376953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5922463536262512, + "bbox": [ + 1652.839111328125, + 1372.059326171875, + 1732.7091064453125, + 1467.650634765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5721011757850647, + "bbox": [ + 1644.0538330078125, + 1366.1192626953125, + 1747.117919921875, + 1488.8909912109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5473920106887817, + "bbox": [ + 274.6693115234375, + 2840.498291015625, + 363.9375, + 2959.8251953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47175300121307373, + "bbox": [ + 1300.7203369140625, + 2852.48876953125, + 1369.9244384765625, + 2956.456298828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2746185064315796, + "bbox": [ + 274.9037780761719, + 3113.80322265625, + 339.4065856933594, + 3182.939697265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2637054920196533, + "bbox": [ + 1301.8348388671875, + 2873.325927734375, + 1362.2965087890625, + 2953.63671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9293239712715149, + "bbox": [ + 1266.37890625, + 476.09173583984375, + 2383.884765625, + 1645.0438232421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9134370684623718, + "bbox": [ + 218.10020446777344, + 940.7481689453125, + 1272.26220703125, + 1695.993408203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9127632975578308, + "bbox": [ + 242.83966064453125, + 2518.5888671875, + 1235.6380615234375, + 3124.789306640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9111214876174927, + "bbox": [ + 1303.947021484375, + 790.7500610351562, + 2278.843017578125, + 1575.8875732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9110651016235352, + "bbox": [ + 246.1043701171875, + 1774.0943603515625, + 1276.2115478515625, + 2395.957275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9026702642440796, + "bbox": [ + 279.34564208984375, + 1205.5506591796875, + 1070.8385009765625, + 1589.974365234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9004862308502197, + "bbox": [ + 288.5530700683594, + 1988.044677734375, + 1097.0166015625, + 2346.018798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8881144523620605, + "bbox": [ + 1285.2596435546875, + 2520.07275390625, + 2363.521728515625, + 3152.701416015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8513363599777222, + "bbox": [ + 1303.148193359375, + 2755.71630859375, + 1679.3857421875, + 3103.17333984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8495510220527649, + "bbox": [ + 277.11761474609375, + 2754.44677734375, + 887.9896240234375, + 3090.192626953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8236514329910278, + "bbox": [ + 1299.0938720703125, + 591.206298828125, + 2275.47607421875, + 726.4122314453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7922306060791016, + "bbox": [ + 269.9949645996094, + 1078.7987060546875, + 1232.0540771484375, + 1208.58837890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7671198844909668, + "bbox": [ + 1307.8310546875, + 2763.368896484375, + 1836.4410400390625, + 3105.093994140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7585636973381042, + "bbox": [ + 1307.326416015625, + 2657.321533203125, + 2123.777099609375, + 2754.283203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7545921206474304, + "bbox": [ + 291.4330749511719, + 2657.18310546875, + 1180.22998046875, + 2765.054931640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6911676526069641, + "bbox": [ + 271.2880554199219, + 1901.6171875, + 1129.6876220703125, + 1982.912841796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.18145117163658142, + "bbox": [ + 1306.4901123046875, + 2765.097900390625, + 2052.065673828125, + 3111.32470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.1613447517156601, + "bbox": [ + 787.3344116210938, + 0.0, + 2318.010986328125, + 1246.785400390625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7846184968948364, + "bbox": [ + 1299.5025634765625, + 2579.77587890625, + 1403.5953369140625, + 2668.6572265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7759642601013184, + "bbox": [ + 1311.9716796875, + 499.1026916503906, + 1415.04541015625, + 586.4191284179688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7688509821891785, + "bbox": [ + 277.18115234375, + 983.3073120117188, + 385.6111145019531, + 1079.220703125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7686595916748047, + "bbox": [ + 281.42486572265625, + 1812.1678466796875, + 389.3860168457031, + 1902.4697265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7683885097503662, + "bbox": [ + 275.0069274902344, + 2575.080322265625, + 378.5321044921875, + 2662.817626953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6927738785743713, + "bbox": [ + 284.9305725097656, + 1272.8846435546875, + 346.3131408691406, + 1350.852294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6015613079071045, + "bbox": [ + 281.03338623046875, + 2236.856689453125, + 344.9021911621094, + 2316.61376953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5922463536262512, + "bbox": [ + 1652.839111328125, + 1372.059326171875, + 1732.7091064453125, + 1467.650634765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5721011757850647, + "bbox": [ + 1644.0538330078125, + 1366.1192626953125, + 1747.117919921875, + 1488.8909912109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5473920106887817, + "bbox": [ + 274.6693115234375, + 2840.498291015625, + 363.9375, + 2959.8251953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47175300121307373, + "bbox": [ + 1300.7203369140625, + 2852.48876953125, + 1369.9244384765625, + 2956.456298828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2746185064315796, + "bbox": [ + 274.9037780761719, + 3113.80322265625, + 339.4065856933594, + 3182.939697265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2637054920196533, + "bbox": [ + 1301.8348388671875, + 2873.325927734375, + 1362.2965087890625, + 2953.63671875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9293239712715149, + "bbox": [ + 1266.37890625, + 476.09173583984375, + 2383.884765625, + 1645.0438232421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9134370684623718, + "bbox": [ + 218.10020446777344, + 940.7481689453125, + 1272.26220703125, + 1695.993408203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9127632975578308, + "bbox": [ + 242.83966064453125, + 2518.5888671875, + 1235.6380615234375, + 3124.789306640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9111214876174927, + "bbox": [ + 1303.947021484375, + 790.7500610351562, + 2278.843017578125, + 1575.8875732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9110651016235352, + "bbox": [ + 246.1043701171875, + 1774.0943603515625, + 1276.2115478515625, + 2395.957275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9026702642440796, + "bbox": [ + 279.34564208984375, + 1205.5506591796875, + 1070.8385009765625, + 1589.974365234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9004862308502197, + "bbox": [ + 288.5530700683594, + 1988.044677734375, + 1097.0166015625, + 2346.018798828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8881144523620605, + "bbox": [ + 1285.2596435546875, + 2520.07275390625, + 2363.521728515625, + 3152.701416015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8513363599777222, + "bbox": [ + 1303.148193359375, + 2755.71630859375, + 1679.3857421875, + 3103.17333984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8495510220527649, + "bbox": [ + 277.11761474609375, + 2754.44677734375, + 887.9896240234375, + 3090.192626953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8236514329910278, + "bbox": [ + 1299.0938720703125, + 591.206298828125, + 2275.47607421875, + 726.4122314453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7922306060791016, + "bbox": [ + 269.9949645996094, + 1078.7987060546875, + 1232.0540771484375, + 1208.58837890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7671198844909668, + "bbox": [ + 1307.8310546875, + 2763.368896484375, + 1836.4410400390625, + 3105.093994140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7585636973381042, + "bbox": [ + 1307.326416015625, + 2657.321533203125, + 2123.777099609375, + 2754.283203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7545921206474304, + "bbox": [ + 291.4330749511719, + 2657.18310546875, + 1180.22998046875, + 2765.054931640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6911676526069641, + "bbox": [ + 271.2880554199219, + 1901.6171875, + 1129.6876220703125, + 1982.912841796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.18145117163658142, + "bbox": [ + 1306.4901123046875, + 2765.097900390625, + 2052.065673828125, + 3111.32470703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.1613447517156601, + "bbox": [ + 787.3344116210938, + 0.0, + 2318.010986328125, + 1246.785400390625 + ] + } + ], + "timestamp": "2025-10-15T21:42:33.236275" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 19.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 19.json" new file mode 100644 index 0000000..366dbc0 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 19.json" @@ -0,0 +1,648 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 19.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.776886522769928, + "bbox": [ + 283.5733642578125, + 2426.473876953125, + 387.6286926269531, + 2512.195068359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7768315076828003, + "bbox": [ + 1266.2724609375, + 413.9976501464844, + 1366.1689453125, + 501.0334167480469 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7644055485725403, + "bbox": [ + 1249.869384765625, + 2046.2265625, + 1352.7569580078125, + 2140.320556640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7643024921417236, + "bbox": [ + 295.2785949707031, + 407.83740234375, + 399.2215576171875, + 494.1003723144531 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7611289620399475, + "bbox": [ + 289.8592224121094, + 1422.781005859375, + 394.20849609375, + 1510.9014892578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5970655679702759, + "bbox": [ + 287.11077880859375, + 2700.139404296875, + 345.15118408203125, + 2774.53515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5823915004730225, + "bbox": [ + 2077.378173828125, + 3010.5712890625, + 2142.211669921875, + 3077.97265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5772170424461365, + "bbox": [ + 291.4651184082031, + 1834.798583984375, + 359.6415100097656, + 1916.8997802734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5558503866195679, + "bbox": [ + 296.27001953125, + 745.8803100585938, + 370.512451171875, + 836.5371704101562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4381183385848999, + "bbox": [ + 1263.4603271484375, + 734.3966674804688, + 1341.9556884765625, + 844.0040283203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3939880430698395, + "bbox": [ + 1244.367431640625, + 2406.23046875, + 1320.1290283203125, + 2528.68603515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3665919601917267, + "bbox": [ + 1245.845458984375, + 2434.719970703125, + 1306.94970703125, + 2514.757568359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2390291690826416, + "bbox": [ + 1263.19189453125, + 747.9443359375, + 1330.3409423828125, + 835.8890380859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9369932413101196, + "bbox": [ + 1242.16064453125, + 2264.775390625, + 2156.21435546875, + 2980.147705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9147666692733765, + "bbox": [ + 1213.319091796875, + 2002.53759765625, + 2254.7412109375, + 3020.351806640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025638699531555, + "bbox": [ + 1224.840087890625, + 369.44952392578125, + 2228.216552734375, + 1138.3333740234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9012763500213623, + "bbox": [ + 1256.3372802734375, + 630.2367553710938, + 2183.962158203125, + 1048.2635498046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.879751443862915, + "bbox": [ + 1250.16064453125, + 2137.86962890625, + 2157.86328125, + 2254.598388671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8764828443527222, + "bbox": [ + 219.86053466796875, + 341.5624694824219, + 1197.3204345703125, + 982.4178466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8693755269050598, + "bbox": [ + 194.22976684570312, + 2379.40380859375, + 1211.2135009765625, + 3035.416015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.841931939125061, + "bbox": [ + 281.1965637207031, + 1585.2760009765625, + 796.1295166015625, + 1933.79052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8362790942192078, + "bbox": [ + 195.65646362304688, + 1355.9951171875, + 1216.2904052734375, + 2024.539794921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8332664370536804, + "bbox": [ + 300.0977478027344, + 485.620361328125, + 1005.7455444335938, + 575.8887329101562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8241668343544006, + "bbox": [ + 276.8126220703125, + 2512.34716796875, + 1193.011962890625, + 2636.438720703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8082225918769836, + "bbox": [ + 1238.1475830078125, + 499.14422607421875, + 2168.482666015625, + 623.4498291015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7346722483634949, + "bbox": [ + 272.5602111816406, + 2625.090576171875, + 843.850830078125, + 2981.4912109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7311903834342957, + "bbox": [ + 295.2333068847656, + 1503.4769287109375, + 1181.2420654296875, + 1591.7735595703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6637079119682312, + "bbox": [ + 292.0624084472656, + 574.4183959960938, + 801.4624633789062, + 921.5722045898438 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5581426024436951, + "bbox": [ + 285.98358154296875, + 570.8383178710938, + 1041.527099609375, + 930.4381103515625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.776886522769928, + "bbox": [ + 283.5733642578125, + 2426.473876953125, + 387.6286926269531, + 2512.195068359375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7768315076828003, + "bbox": [ + 1266.2724609375, + 413.9976501464844, + 1366.1689453125, + 501.0334167480469 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7644055485725403, + "bbox": [ + 1249.869384765625, + 2046.2265625, + 1352.7569580078125, + 2140.320556640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7643024921417236, + "bbox": [ + 295.2785949707031, + 407.83740234375, + 399.2215576171875, + 494.1003723144531 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7611289620399475, + "bbox": [ + 289.8592224121094, + 1422.781005859375, + 394.20849609375, + 1510.9014892578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5970655679702759, + "bbox": [ + 287.11077880859375, + 2700.139404296875, + 345.15118408203125, + 2774.53515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5823915004730225, + "bbox": [ + 2077.378173828125, + 3010.5712890625, + 2142.211669921875, + 3077.97265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5772170424461365, + "bbox": [ + 291.4651184082031, + 1834.798583984375, + 359.6415100097656, + 1916.8997802734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5558503866195679, + "bbox": [ + 296.27001953125, + 745.8803100585938, + 370.512451171875, + 836.5371704101562 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4381183385848999, + "bbox": [ + 1263.4603271484375, + 734.3966674804688, + 1341.9556884765625, + 844.0040283203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3939880430698395, + "bbox": [ + 1244.367431640625, + 2406.23046875, + 1320.1290283203125, + 2528.68603515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3665919601917267, + "bbox": [ + 1245.845458984375, + 2434.719970703125, + 1306.94970703125, + 2514.757568359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2390291690826416, + "bbox": [ + 1263.19189453125, + 747.9443359375, + 1330.3409423828125, + 835.8890380859375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9369932413101196, + "bbox": [ + 1242.16064453125, + 2264.775390625, + 2156.21435546875, + 2980.147705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9147666692733765, + "bbox": [ + 1213.319091796875, + 2002.53759765625, + 2254.7412109375, + 3020.351806640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025638699531555, + "bbox": [ + 1224.840087890625, + 369.44952392578125, + 2228.216552734375, + 1138.3333740234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9012763500213623, + "bbox": [ + 1256.3372802734375, + 630.2367553710938, + 2183.962158203125, + 1048.2635498046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.879751443862915, + "bbox": [ + 1250.16064453125, + 2137.86962890625, + 2157.86328125, + 2254.598388671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8764828443527222, + "bbox": [ + 219.86053466796875, + 341.5624694824219, + 1197.3204345703125, + 982.4178466796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8693755269050598, + "bbox": [ + 194.22976684570312, + 2379.40380859375, + 1211.2135009765625, + 3035.416015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.841931939125061, + "bbox": [ + 281.1965637207031, + 1585.2760009765625, + 796.1295166015625, + 1933.79052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8362790942192078, + "bbox": [ + 195.65646362304688, + 1355.9951171875, + 1216.2904052734375, + 2024.539794921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8332664370536804, + "bbox": [ + 300.0977478027344, + 485.620361328125, + 1005.7455444335938, + 575.8887329101562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8241668343544006, + "bbox": [ + 276.8126220703125, + 2512.34716796875, + 1193.011962890625, + 2636.438720703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8082225918769836, + "bbox": [ + 1238.1475830078125, + 499.14422607421875, + 2168.482666015625, + 623.4498291015625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7346722483634949, + "bbox": [ + 272.5602111816406, + 2625.090576171875, + 843.850830078125, + 2981.4912109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7311903834342957, + "bbox": [ + 295.2333068847656, + 1503.4769287109375, + 1181.2420654296875, + 1591.7735595703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.6637079119682312, + "bbox": [ + 292.0624084472656, + 574.4183959960938, + 801.4624633789062, + 921.5722045898438 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5581426024436951, + "bbox": [ + 285.98358154296875, + 570.8383178710938, + 1041.527099609375, + 930.4381103515625 + ] + } + ], + "timestamp": "2025-10-15T21:42:33.660183" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 20.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 20.json" new file mode 100644 index 0000000..aa4bea3 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 20.json" @@ -0,0 +1,692 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 20.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7683119177818298, + "bbox": [ + 1294.6053466796875, + 2186.27197265625, + 1405.178955078125, + 2287.918701171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7465526461601257, + "bbox": [ + 1301.8123779296875, + 450.5603942871094, + 1409.76416015625, + 550.3806762695312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7413792014122009, + "bbox": [ + 259.5576477050781, + 1291.7227783203125, + 371.1444091796875, + 1393.9207763671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7396041750907898, + "bbox": [ + 266.5613708496094, + 2373.946533203125, + 377.9087829589844, + 2472.917724609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7320401668548584, + "bbox": [ + 254.419921875, + 450.9359130859375, + 367.9903869628906, + 554.7522583007812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6151673197746277, + "bbox": [ + 267.76898193359375, + 2670.884521484375, + 335.87518310546875, + 2772.5595703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5330805778503418, + "bbox": [ + 264.5439453125, + 1882.8548583984375, + 345.8608703613281, + 1997.4920654296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.517382800579071, + "bbox": [ + 1291.6021728515625, + 2740.08203125, + 1384.17333984375, + 2858.27734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47035977244377136, + "bbox": [ + 259.740966796875, + 805.1583251953125, + 344.5245056152344, + 908.6259155273438 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4395650327205658, + "bbox": [ + 1305.577880859375, + 1286.509765625, + 1379.93017578125, + 1394.7322998046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2608482539653778, + "bbox": [ + 260.96734619140625, + 814.7350463867188, + 329.8089599609375, + 903.3792114257812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23759527504444122, + "bbox": [ + 1306.128173828125, + 1300.0406494140625, + 1368.4461669921875, + 1388.9654541015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23563717305660248, + "bbox": [ + 261.4866638183594, + 2656.289794921875, + 357.9808044433594, + 2783.037353515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9357314705848694, + "bbox": [ + 263.1419677734375, + 1534.25341796875, + 1229.466064453125, + 2205.520751953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9351439476013184, + "bbox": [ + 1288.099853515625, + 785.0848388671875, + 2283.196533203125, + 1479.415771484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9332083463668823, + "bbox": [ + 1287.0062255859375, + 2522.52734375, + 2307.506591796875, + 3211.444580078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9296055436134338, + "bbox": [ + 253.7504425048828, + 2669.001953125, + 1225.1944580078125, + 3185.684814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9240237474441528, + "bbox": [ + 1242.92919921875, + 2138.17919921875, + 2508.63916015625, + 3288.89599609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9096837043762207, + "bbox": [ + 179.63861083984375, + 416.0799560546875, + 1265.3074951171875, + 1215.5218505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9057604670524597, + "bbox": [ + 249.77549743652344, + 693.5044555664062, + 1229.744384765625, + 1131.046630859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9057407975196838, + "bbox": [ + 180.18362426757812, + 1231.96044921875, + 1233.4793701171875, + 2291.24267578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8987570405006409, + "bbox": [ + 95.62633514404297, + 2318.595947265625, + 1257.8924560546875, + 3234.850341796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8982102274894714, + "bbox": [ + 1243.2581787109375, + 381.5397033691406, + 2506.340576171875, + 1607.3770751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8445404171943665, + "bbox": [ + 1292.8731689453125, + 549.1233520507812, + 2278.39013671875, + 686.5225830078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8079210519790649, + "bbox": [ + 1290.36083984375, + 2417.9638671875, + 2293.914794921875, + 2526.770751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8078394532203674, + "bbox": [ + 256.3052062988281, + 2459.707763671875, + 1217.355224609375, + 2586.982666015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8025450110435486, + "bbox": [ + 243.53396606445312, + 550.616943359375, + 1228.8731689453125, + 680.1709594726562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7976649403572083, + "bbox": [ + 255.0074920654297, + 1390.3236083984375, + 1221.2130126953125, + 1517.3192138671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7810220718383789, + "bbox": [ + 1295.839111328125, + 2278.012939453125, + 2276.5224609375, + 2417.0380859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7180396318435669, + "bbox": [ + 234.9778289794922, + 2600.342041015625, + 1204.498779296875, + 2697.6337890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5510781407356262, + "bbox": [ + 1290.2784423828125, + 682.504638671875, + 2280.008544921875, + 789.3525390625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7683119177818298, + "bbox": [ + 1294.6053466796875, + 2186.27197265625, + 1405.178955078125, + 2287.918701171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7465526461601257, + "bbox": [ + 1301.8123779296875, + 450.5603942871094, + 1409.76416015625, + 550.3806762695312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7413792014122009, + "bbox": [ + 259.5576477050781, + 1291.7227783203125, + 371.1444091796875, + 1393.9207763671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7396041750907898, + "bbox": [ + 266.5613708496094, + 2373.946533203125, + 377.9087829589844, + 2472.917724609375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7320401668548584, + "bbox": [ + 254.419921875, + 450.9359130859375, + 367.9903869628906, + 554.7522583007812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6151673197746277, + "bbox": [ + 267.76898193359375, + 2670.884521484375, + 335.87518310546875, + 2772.5595703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5330805778503418, + "bbox": [ + 264.5439453125, + 1882.8548583984375, + 345.8608703613281, + 1997.4920654296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.517382800579071, + "bbox": [ + 1291.6021728515625, + 2740.08203125, + 1384.17333984375, + 2858.27734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47035977244377136, + "bbox": [ + 259.740966796875, + 805.1583251953125, + 344.5245056152344, + 908.6259155273438 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4395650327205658, + "bbox": [ + 1305.577880859375, + 1286.509765625, + 1379.93017578125, + 1394.7322998046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2608482539653778, + "bbox": [ + 260.96734619140625, + 814.7350463867188, + 329.8089599609375, + 903.3792114257812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23759527504444122, + "bbox": [ + 1306.128173828125, + 1300.0406494140625, + 1368.4461669921875, + 1388.9654541015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23563717305660248, + "bbox": [ + 261.4866638183594, + 2656.289794921875, + 357.9808044433594, + 2783.037353515625 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9357314705848694, + "bbox": [ + 263.1419677734375, + 1534.25341796875, + 1229.466064453125, + 2205.520751953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9351439476013184, + "bbox": [ + 1288.099853515625, + 785.0848388671875, + 2283.196533203125, + 1479.415771484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9332083463668823, + "bbox": [ + 1287.0062255859375, + 2522.52734375, + 2307.506591796875, + 3211.444580078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9296055436134338, + "bbox": [ + 253.7504425048828, + 2669.001953125, + 1225.1944580078125, + 3185.684814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9240237474441528, + "bbox": [ + 1242.92919921875, + 2138.17919921875, + 2508.63916015625, + 3288.89599609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9096837043762207, + "bbox": [ + 179.63861083984375, + 416.0799560546875, + 1265.3074951171875, + 1215.5218505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9057604670524597, + "bbox": [ + 249.77549743652344, + 693.5044555664062, + 1229.744384765625, + 1131.046630859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9057407975196838, + "bbox": [ + 180.18362426757812, + 1231.96044921875, + 1233.4793701171875, + 2291.24267578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8987570405006409, + "bbox": [ + 95.62633514404297, + 2318.595947265625, + 1257.8924560546875, + 3234.850341796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8982102274894714, + "bbox": [ + 1243.2581787109375, + 381.5397033691406, + 2506.340576171875, + 1607.3770751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8445404171943665, + "bbox": [ + 1292.8731689453125, + 549.1233520507812, + 2278.39013671875, + 686.5225830078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8079210519790649, + "bbox": [ + 1290.36083984375, + 2417.9638671875, + 2293.914794921875, + 2526.770751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8078394532203674, + "bbox": [ + 256.3052062988281, + 2459.707763671875, + 1217.355224609375, + 2586.982666015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8025450110435486, + "bbox": [ + 243.53396606445312, + 550.616943359375, + 1228.8731689453125, + 680.1709594726562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7976649403572083, + "bbox": [ + 255.0074920654297, + 1390.3236083984375, + 1221.2130126953125, + 1517.3192138671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7810220718383789, + "bbox": [ + 1295.839111328125, + 2278.012939453125, + 2276.5224609375, + 2417.0380859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.7180396318435669, + "bbox": [ + 234.9778289794922, + 2600.342041015625, + 1204.498779296875, + 2697.6337890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.5510781407356262, + "bbox": [ + 1290.2784423828125, + 682.504638671875, + 2280.008544921875, + 789.3525390625 + ] + } + ], + "timestamp": "2025-10-15T21:42:34.043990" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 21.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 21.json" new file mode 100644 index 0000000..71a9d37 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 21.json" @@ -0,0 +1,428 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 21.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7755255103111267, + "bbox": [ + 278.7999267578125, + 577.7952270507812, + 389.59356689453125, + 679.859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7565394043922424, + "bbox": [ + 296.09716796875, + 1798.5341796875, + 409.3768005371094, + 1900.365478515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7444714903831482, + "bbox": [ + 1322.7049560546875, + 448.2289733886719, + 1433.8587646484375, + 544.5680541992188 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.629237711429596, + "bbox": [ + 282.9502868652344, + 821.1759033203125, + 347.4347839355469, + 899.3653564453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5262008309364319, + "bbox": [ + 2222.088134765625, + 3173.7548828125, + 2288.16455078125, + 3244.7802734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49576127529144287, + "bbox": [ + 1334.5206298828125, + 2519.017822265625, + 1412.8782958984375, + 2613.996826171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4206846356391907, + "bbox": [ + 299.3791198730469, + 2170.7138671875, + 365.9861145019531, + 2253.27294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22485481202602386, + "bbox": [ + 1337.4964599609375, + 2530.310546875, + 1402.6473388671875, + 2607.80517578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9287400841712952, + "bbox": [ + 1306.3515625, + 431.64556884765625, + 2378.428466796875, + 2747.514404296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9176496267318726, + "bbox": [ + 1340.85595703125, + 659.8131713867188, + 2278.302734375, + 2171.390869140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.911493718624115, + "bbox": [ + 1332.449951171875, + 2255.69873046875, + 2300.87841796875, + 2629.593505859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9001783132553101, + "bbox": [ + 215.18112182617188, + 1728.2930908203125, + 1254.460693359375, + 2491.9404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8969367146492004, + "bbox": [ + 278.4331970214844, + 765.9695434570312, + 1163.850341796875, + 1149.8345947265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8511821627616882, + "bbox": [ + 296.6651611328125, + 1977.7093505859375, + 669.780029296875, + 2368.931884765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8454031348228455, + "bbox": [ + 221.4619140625, + 554.1069946289062, + 1264.8031005859375, + 1322.068359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7742727994918823, + "bbox": [ + 281.0895690917969, + 673.0726318359375, + 944.4588012695312, + 743.7951049804688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7531977891921997, + "bbox": [ + 1326.954833984375, + 541.9246215820312, + 1915.188232421875, + 619.284912109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6431077718734741, + "bbox": [ + 296.1228942871094, + 1894.5391845703125, + 694.1431884765625, + 1966.3424072265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.14548256993293762, + "bbox": [ + 309.6708984375, + 1889.41357421875, + 1176.5767822265625, + 1962.09326171875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7755255103111267, + "bbox": [ + 278.7999267578125, + 577.7952270507812, + 389.59356689453125, + 679.859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7565394043922424, + "bbox": [ + 296.09716796875, + 1798.5341796875, + 409.3768005371094, + 1900.365478515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7444714903831482, + "bbox": [ + 1322.7049560546875, + 448.2289733886719, + 1433.8587646484375, + 544.5680541992188 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.629237711429596, + "bbox": [ + 282.9502868652344, + 821.1759033203125, + 347.4347839355469, + 899.3653564453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5262008309364319, + "bbox": [ + 2222.088134765625, + 3173.7548828125, + 2288.16455078125, + 3244.7802734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49576127529144287, + "bbox": [ + 1334.5206298828125, + 2519.017822265625, + 1412.8782958984375, + 2613.996826171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4206846356391907, + "bbox": [ + 299.3791198730469, + 2170.7138671875, + 365.9861145019531, + 2253.27294921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22485481202602386, + "bbox": [ + 1337.4964599609375, + 2530.310546875, + 1402.6473388671875, + 2607.80517578125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9287400841712952, + "bbox": [ + 1306.3515625, + 431.64556884765625, + 2378.428466796875, + 2747.514404296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9176496267318726, + "bbox": [ + 1340.85595703125, + 659.8131713867188, + 2278.302734375, + 2171.390869140625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.911493718624115, + "bbox": [ + 1332.449951171875, + 2255.69873046875, + 2300.87841796875, + 2629.593505859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9001783132553101, + "bbox": [ + 215.18112182617188, + 1728.2930908203125, + 1254.460693359375, + 2491.9404296875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8969367146492004, + "bbox": [ + 278.4331970214844, + 765.9695434570312, + 1163.850341796875, + 1149.8345947265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8511821627616882, + "bbox": [ + 296.6651611328125, + 1977.7093505859375, + 669.780029296875, + 2368.931884765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8454031348228455, + "bbox": [ + 221.4619140625, + 554.1069946289062, + 1264.8031005859375, + 1322.068359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7742727994918823, + "bbox": [ + 281.0895690917969, + 673.0726318359375, + 944.4588012695312, + 743.7951049804688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7531977891921997, + "bbox": [ + 1326.954833984375, + 541.9246215820312, + 1915.188232421875, + 619.284912109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6431077718734741, + "bbox": [ + 296.1228942871094, + 1894.5391845703125, + 694.1431884765625, + 1966.3424072265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.14548256993293762, + "bbox": [ + 309.6708984375, + 1889.41357421875, + 1176.5767822265625, + 1962.09326171875 + ] + } + ], + "timestamp": "2025-10-15T21:42:34.458263" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 22.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 22.json" new file mode 100644 index 0000000..59e0a7e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 22.json" @@ -0,0 +1,164 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 22.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7464569807052612, + "bbox": [ + 239.90000915527344, + 436.77703857421875, + 355.4010009765625, + 542.0134887695312 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9374851584434509, + "bbox": [ + 217.72842407226562, + 557.4828491210938, + 1207.46875, + 1882.2918701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9336852431297302, + "bbox": [ + 1268.0975341796875, + 1816.1700439453125, + 2234.017822265625, + 2323.7080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9251554012298584, + "bbox": [ + 1257.7198486328125, + 335.0719299316406, + 2276.373291015625, + 2427.7158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9245746731758118, + "bbox": [ + 1269.748291015625, + 620.04296875, + 2251.647705078125, + 1839.697021484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9057725667953491, + "bbox": [ + 187.8255615234375, + 315.9036560058594, + 1218.9857177734375, + 2285.388671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.48269322514533997, + "bbox": [ + 1280.476318359375, + 534.2542114257812, + 2159.66943359375, + 620.7685546875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7464569807052612, + "bbox": [ + 239.90000915527344, + 436.77703857421875, + 355.4010009765625, + 542.0134887695312 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9374851584434509, + "bbox": [ + 217.72842407226562, + 557.4828491210938, + 1207.46875, + 1882.2918701171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9336852431297302, + "bbox": [ + 1268.0975341796875, + 1816.1700439453125, + 2234.017822265625, + 2323.7080078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9251554012298584, + "bbox": [ + 1257.7198486328125, + 335.0719299316406, + 2276.373291015625, + 2427.7158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9245746731758118, + "bbox": [ + 1269.748291015625, + 620.04296875, + 2251.647705078125, + 1839.697021484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9057725667953491, + "bbox": [ + 187.8255615234375, + 315.9036560058594, + 1218.9857177734375, + 2285.388671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.48269322514533997, + "bbox": [ + 1280.476318359375, + 534.2542114257812, + 2159.66943359375, + 620.7685546875 + ] + } + ], + "timestamp": "2025-10-15T21:42:34.833494" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 23.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 23.json" new file mode 100644 index 0000000..95896f9 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 23.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 23.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7408531308174133, + "bbox": [ + 287.06646728515625, + 449.28607177734375, + 410.17767333984375, + 557.0758666992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7263175845146179, + "bbox": [ + 1360.0926513671875, + 458.1968688964844, + 1482.261474609375, + 564.0873413085938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5333561301231384, + "bbox": [ + 1349.552001953125, + 2101.04052734375, + 1418.1453857421875, + 2195.279296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.22785744071006775, + "bbox": [ + 2264.17626953125, + 3246.12060546875, + 2333.58837890625, + 3319.25390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9693681001663208, + "bbox": [ + 231.01339721679688, + 391.47076416015625, + 1288.99462890625, + 2860.60546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9644021391868591, + "bbox": [ + 273.0490417480469, + 678.5719604492188, + 1275.4842529296875, + 2203.12109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9547895193099976, + "bbox": [ + 1352.018798828125, + 646.2605590820312, + 2353.725830078125, + 2035.519775390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.925831139087677, + "bbox": [ + 293.6109619140625, + 2205.3525390625, + 1274.806640625, + 2737.760986328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9235560894012451, + "bbox": [ + 1345.933837890625, + 2062.98583984375, + 2352.359130859375, + 2724.531982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9206604957580566, + "bbox": [ + 1337.7620849609375, + 410.28399658203125, + 2390.07470703125, + 2833.5146484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7335054874420166, + "bbox": [ + 285.7752380371094, + 560.9447021484375, + 1292.3006591796875, + 675.047607421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6728856563568115, + "bbox": [ + 1367.9661865234375, + 547.0529174804688, + 1979.1614990234375, + 629.7887573242188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7408531308174133, + "bbox": [ + 287.06646728515625, + 449.28607177734375, + 410.17767333984375, + 557.0758666992188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7263175845146179, + "bbox": [ + 1360.0926513671875, + 458.1968688964844, + 1482.261474609375, + 564.0873413085938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5333561301231384, + "bbox": [ + 1349.552001953125, + 2101.04052734375, + 1418.1453857421875, + 2195.279296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.22785744071006775, + "bbox": [ + 2264.17626953125, + 3246.12060546875, + 2333.58837890625, + 3319.25390625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9693681001663208, + "bbox": [ + 231.01339721679688, + 391.47076416015625, + 1288.99462890625, + 2860.60546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9644021391868591, + "bbox": [ + 273.0490417480469, + 678.5719604492188, + 1275.4842529296875, + 2203.12109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9547895193099976, + "bbox": [ + 1352.018798828125, + 646.2605590820312, + 2353.725830078125, + 2035.519775390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.925831139087677, + "bbox": [ + 293.6109619140625, + 2205.3525390625, + 1274.806640625, + 2737.760986328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9235560894012451, + "bbox": [ + 1345.933837890625, + 2062.98583984375, + 2352.359130859375, + 2724.531982421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9206604957580566, + "bbox": [ + 1337.7620849609375, + 410.28399658203125, + 2390.07470703125, + 2833.5146484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7335054874420166, + "bbox": [ + 285.7752380371094, + 560.9447021484375, + 1292.3006591796875, + 675.047607421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6728856563568115, + "bbox": [ + 1367.9661865234375, + 547.0529174804688, + 1979.1614990234375, + 629.7887573242188 + ] + } + ], + "timestamp": "2025-10-15T21:42:35.249293" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 24.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 24.json" new file mode 100644 index 0000000..4931cfb --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 24.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 24.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7499555945396423, + "bbox": [ + 1291.2161865234375, + 438.009033203125, + 1405.6112060546875, + 538.0480346679688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7326586842536926, + "bbox": [ + 227.97157287597656, + 428.57269287109375, + 343.1900634765625, + 528.3182373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5441185235977173, + "bbox": [ + 1281.55322265625, + 2111.874755859375, + 1383.5269775390625, + 2240.95361328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49203798174858093, + "bbox": [ + 1293.846923828125, + 2114.91943359375, + 1375.3638916015625, + 2225.69873046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.413155734539032, + "bbox": [ + 210.71299743652344, + 2712.188720703125, + 288.1453552246094, + 2827.98828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3804877698421478, + "bbox": [ + 209.66197204589844, + 3172.32421875, + 281.32183837890625, + 3241.4794921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3566216826438904, + "bbox": [ + 213.76446533203125, + 2725.703125, + 277.2315368652344, + 2820.79638671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9519443511962891, + "bbox": [ + 1290.3035888671875, + 614.5211791992188, + 2283.529541015625, + 2095.49169921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9456939697265625, + "bbox": [ + 193.9445037841797, + 607.7117919921875, + 1208.30419921875, + 2376.8505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9412693977355957, + "bbox": [ + 1268.4588623046875, + 2126.5390625, + 2307.359375, + 2783.716552734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9335028529167175, + "bbox": [ + 201.33453369140625, + 2403.188232421875, + 1200.840087890625, + 3049.89306640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9077781438827515, + "bbox": [ + 1246.1876220703125, + 378.7965393066406, + 2389.033447265625, + 2864.5546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9028221368789673, + "bbox": [ + 174.9167938232422, + 402.5443115234375, + 1220.2403564453125, + 3064.48291015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.791551947593689, + "bbox": [ + 1293.18701171875, + 532.70458984375, + 1906.813232421875, + 619.83203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6859422326087952, + "bbox": [ + 222.75241088867188, + 528.7889404296875, + 798.6803588867188, + 604.3812255859375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7499555945396423, + "bbox": [ + 1291.2161865234375, + 438.009033203125, + 1405.6112060546875, + 538.0480346679688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7326586842536926, + "bbox": [ + 227.97157287597656, + 428.57269287109375, + 343.1900634765625, + 528.3182373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5441185235977173, + "bbox": [ + 1281.55322265625, + 2111.874755859375, + 1383.5269775390625, + 2240.95361328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49203798174858093, + "bbox": [ + 1293.846923828125, + 2114.91943359375, + 1375.3638916015625, + 2225.69873046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.413155734539032, + "bbox": [ + 210.71299743652344, + 2712.188720703125, + 288.1453552246094, + 2827.98828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3804877698421478, + "bbox": [ + 209.66197204589844, + 3172.32421875, + 281.32183837890625, + 3241.4794921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3566216826438904, + "bbox": [ + 213.76446533203125, + 2725.703125, + 277.2315368652344, + 2820.79638671875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9519443511962891, + "bbox": [ + 1290.3035888671875, + 614.5211791992188, + 2283.529541015625, + 2095.49169921875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9456939697265625, + "bbox": [ + 193.9445037841797, + 607.7117919921875, + 1208.30419921875, + 2376.8505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9412693977355957, + "bbox": [ + 1268.4588623046875, + 2126.5390625, + 2307.359375, + 2783.716552734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9335028529167175, + "bbox": [ + 201.33453369140625, + 2403.188232421875, + 1200.840087890625, + 3049.89306640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9077781438827515, + "bbox": [ + 1246.1876220703125, + 378.7965393066406, + 2389.033447265625, + 2864.5546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9028221368789673, + "bbox": [ + 174.9167938232422, + 402.5443115234375, + 1220.2403564453125, + 3064.48291015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.791551947593689, + "bbox": [ + 1293.18701171875, + 532.70458984375, + 1906.813232421875, + 619.83203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6859422326087952, + "bbox": [ + 222.75241088867188, + 528.7889404296875, + 798.6803588867188, + 604.3812255859375 + ] + } + ], + "timestamp": "2025-10-15T21:42:35.665625" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 25.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 25.json" new file mode 100644 index 0000000..a5eec3f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 25.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 25.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7588517665863037, + "bbox": [ + 253.2764892578125, + 421.21722412109375, + 362.099365234375, + 511.5015563964844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.744519054889679, + "bbox": [ + 1281.52734375, + 426.3513488769531, + 1394.95166015625, + 525.2432250976562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5451107025146484, + "bbox": [ + 2151.921142578125, + 3101.869873046875, + 2222.90576171875, + 3173.123291015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5401171445846558, + "bbox": [ + 577.0313110351562, + 2279.5029296875, + 647.5426025390625, + 2382.59375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5006833076477051, + "bbox": [ + 572.7830810546875, + 2262.6181640625, + 669.4131469726562, + 2384.542724609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4181232750415802, + "bbox": [ + 1276.4649658203125, + 2208.54296875, + 1349.0118408203125, + 2294.375244140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9257944822311401, + "bbox": [ + 223.26390075683594, + 588.3057861328125, + 1191.5623779296875, + 2844.76806640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9230045676231384, + "bbox": [ + 1238.033447265625, + 349.1878662109375, + 2369.723388671875, + 2524.9853515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9217695593833923, + "bbox": [ + 1265.813720703125, + 612.49658203125, + 2246.471435546875, + 1843.5926513671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8942376375198364, + "bbox": [ + 181.24403381347656, + 365.82989501953125, + 1205.1279296875, + 2894.113037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.886620819568634, + "bbox": [ + 1281.673828125, + 1952.19580078125, + 2204.450439453125, + 2329.89794921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7905508875846863, + "bbox": [ + 1284.2349853515625, + 523.783203125, + 2242.9775390625, + 595.498046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7832826375961304, + "bbox": [ + 251.33091735839844, + 499.77655029296875, + 885.39453125, + 589.5597534179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6460133194923401, + "bbox": [ + 1276.4615478515625, + 515.9039916992188, + 2240.80078125, + 618.1329345703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7588517665863037, + "bbox": [ + 253.2764892578125, + 421.21722412109375, + 362.099365234375, + 511.5015563964844 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.744519054889679, + "bbox": [ + 1281.52734375, + 426.3513488769531, + 1394.95166015625, + 525.2432250976562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5451107025146484, + "bbox": [ + 2151.921142578125, + 3101.869873046875, + 2222.90576171875, + 3173.123291015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5401171445846558, + "bbox": [ + 577.0313110351562, + 2279.5029296875, + 647.5426025390625, + 2382.59375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5006833076477051, + "bbox": [ + 572.7830810546875, + 2262.6181640625, + 669.4131469726562, + 2384.542724609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4181232750415802, + "bbox": [ + 1276.4649658203125, + 2208.54296875, + 1349.0118408203125, + 2294.375244140625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9257944822311401, + "bbox": [ + 223.26390075683594, + 588.3057861328125, + 1191.5623779296875, + 2844.76806640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9230045676231384, + "bbox": [ + 1238.033447265625, + 349.1878662109375, + 2369.723388671875, + 2524.9853515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9217695593833923, + "bbox": [ + 1265.813720703125, + 612.49658203125, + 2246.471435546875, + 1843.5926513671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8942376375198364, + "bbox": [ + 181.24403381347656, + 365.82989501953125, + 1205.1279296875, + 2894.113037109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.886620819568634, + "bbox": [ + 1281.673828125, + 1952.19580078125, + 2204.450439453125, + 2329.89794921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7905508875846863, + "bbox": [ + 1284.2349853515625, + 523.783203125, + 2242.9775390625, + 595.498046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7832826375961304, + "bbox": [ + 251.33091735839844, + 499.77655029296875, + 885.39453125, + 589.5597534179688 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6460133194923401, + "bbox": [ + 1276.4615478515625, + 515.9039916992188, + 2240.80078125, + 618.1329345703125 + ] + } + ], + "timestamp": "2025-10-15T21:42:36.126571" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 26.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 26.json" new file mode 100644 index 0000000..eda0a45 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 26.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 26.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7596745491027832, + "bbox": [ + 1288.18359375, + 449.7130126953125, + 1403.3021240234375, + 546.7435913085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7418139576911926, + "bbox": [ + 215.77146911621094, + 435.322998046875, + 334.2380676269531, + 538.6536865234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5511476993560791, + "bbox": [ + 209.92529296875, + 3225.406494140625, + 279.00347900390625, + 3298.470947265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4902820885181427, + "bbox": [ + 204.9746856689453, + 2785.687255859375, + 293.31475830078125, + 2901.49853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3675852417945862, + "bbox": [ + 1280.572509765625, + 2682.492431640625, + 1362.28466796875, + 2775.82275390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.24419505894184113, + "bbox": [ + 207.1783905029297, + 2798.9833984375, + 281.4012756347656, + 2894.383056640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9641221761703491, + "bbox": [ + 222.19129943847656, + 690.30078125, + 1191.4837646484375, + 2709.96435546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9178310632705688, + "bbox": [ + 1289.8916015625, + 737.4950561523438, + 2264.526123046875, + 2532.69775390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.910405695438385, + "bbox": [ + 1275.86328125, + 2561.068115234375, + 2248.11083984375, + 2929.56591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9098260402679443, + "bbox": [ + 205.25616455078125, + 2758.667236328125, + 965.216796875, + 3104.0439453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.893539547920227, + "bbox": [ + 1256.6043701171875, + 408.494140625, + 2377.472412109375, + 3074.17919921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8921395540237427, + "bbox": [ + 180.58187866210938, + 497.1212158203125, + 1220.1986083984375, + 3193.210693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8459108471870422, + "bbox": [ + 1290.4840087890625, + 552.0759887695312, + 2277.9189453125, + 681.0967407226562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.84539794921875, + "bbox": [ + 212.72360229492188, + 539.130126953125, + 1205.5245361328125, + 662.7799682617188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7596745491027832, + "bbox": [ + 1288.18359375, + 449.7130126953125, + 1403.3021240234375, + 546.7435913085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7418139576911926, + "bbox": [ + 215.77146911621094, + 435.322998046875, + 334.2380676269531, + 538.6536865234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5511476993560791, + "bbox": [ + 209.92529296875, + 3225.406494140625, + 279.00347900390625, + 3298.470947265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4902820885181427, + "bbox": [ + 204.9746856689453, + 2785.687255859375, + 293.31475830078125, + 2901.49853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3675852417945862, + "bbox": [ + 1280.572509765625, + 2682.492431640625, + 1362.28466796875, + 2775.82275390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.24419505894184113, + "bbox": [ + 207.1783905029297, + 2798.9833984375, + 281.4012756347656, + 2894.383056640625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9641221761703491, + "bbox": [ + 222.19129943847656, + 690.30078125, + 1191.4837646484375, + 2709.96435546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9178310632705688, + "bbox": [ + 1289.8916015625, + 737.4950561523438, + 2264.526123046875, + 2532.69775390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.910405695438385, + "bbox": [ + 1275.86328125, + 2561.068115234375, + 2248.11083984375, + 2929.56591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9098260402679443, + "bbox": [ + 205.25616455078125, + 2758.667236328125, + 965.216796875, + 3104.0439453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.893539547920227, + "bbox": [ + 1256.6043701171875, + 408.494140625, + 2377.472412109375, + 3074.17919921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8921395540237427, + "bbox": [ + 180.58187866210938, + 497.1212158203125, + 1220.1986083984375, + 3193.210693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8459108471870422, + "bbox": [ + 1290.4840087890625, + 552.0759887695312, + 2277.9189453125, + 681.0967407226562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.84539794921875, + "bbox": [ + 212.72360229492188, + 539.130126953125, + 1205.5245361328125, + 662.7799682617188 + ] + } + ], + "timestamp": "2025-10-15T21:42:36.539561" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 27.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 27.json" new file mode 100644 index 0000000..9b802ff --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 27.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 27.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7638723850250244, + "bbox": [ + 1330.3487548828125, + 449.0606689453125, + 1443.7520751953125, + 548.515869140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7412780523300171, + "bbox": [ + 256.0634460449219, + 436.2818908691406, + 374.9673767089844, + 540.9154663085938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5307528972625732, + "bbox": [ + 2229.40625, + 3239.025634765625, + 2306.802734375, + 3315.8076171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48615193367004395, + "bbox": [ + 829.5568237304688, + 1822.3836669921875, + 917.01708984375, + 1947.096435546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.34501194953918457, + "bbox": [ + 1663.9466552734375, + 1079.282958984375, + 1767.3944091796875, + 1186.89599609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.34173306822776794, + "bbox": [ + 832.4179077148438, + 1850.501708984375, + 905.244140625, + 1942.8924560546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.32376375794410706, + "bbox": [ + 1675.54638671875, + 1102.3599853515625, + 1734.1160888671875, + 1174.1597900390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22445310652256012, + "bbox": [ + 1671.8634033203125, + 1089.52587890625, + 1749.6319580078125, + 1179.9449462890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.951564371585846, + "bbox": [ + 240.27755737304688, + 613.5882568359375, + 1250.046142578125, + 2042.783203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9317596554756165, + "bbox": [ + 181.37548828125, + 390.0022888183594, + 1270.5513916015625, + 2413.478515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9204766154289246, + "bbox": [ + 1312.3494873046875, + 677.1195678710938, + 2370.054931640625, + 2456.36083984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9020445942878723, + "bbox": [ + 1301.4417724609375, + 393.9384460449219, + 2398.073974609375, + 2544.815673828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8693385720252991, + "bbox": [ + 1321.2469482421875, + 540.7301635742188, + 2330.0556640625, + 681.1175537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7307010293006897, + "bbox": [ + 258.93499755859375, + 527.5663452148438, + 996.69677734375, + 610.9852905273438 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7638723850250244, + "bbox": [ + 1330.3487548828125, + 449.0606689453125, + 1443.7520751953125, + 548.515869140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7412780523300171, + "bbox": [ + 256.0634460449219, + 436.2818908691406, + 374.9673767089844, + 540.9154663085938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5307528972625732, + "bbox": [ + 2229.40625, + 3239.025634765625, + 2306.802734375, + 3315.8076171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48615193367004395, + "bbox": [ + 829.5568237304688, + 1822.3836669921875, + 917.01708984375, + 1947.096435546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.34501194953918457, + "bbox": [ + 1663.9466552734375, + 1079.282958984375, + 1767.3944091796875, + 1186.89599609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.34173306822776794, + "bbox": [ + 832.4179077148438, + 1850.501708984375, + 905.244140625, + 1942.8924560546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.32376375794410706, + "bbox": [ + 1675.54638671875, + 1102.3599853515625, + 1734.1160888671875, + 1174.1597900390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22445310652256012, + "bbox": [ + 1671.8634033203125, + 1089.52587890625, + 1749.6319580078125, + 1179.9449462890625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.951564371585846, + "bbox": [ + 240.27755737304688, + 613.5882568359375, + 1250.046142578125, + 2042.783203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9317596554756165, + "bbox": [ + 181.37548828125, + 390.0022888183594, + 1270.5513916015625, + 2413.478515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9204766154289246, + "bbox": [ + 1312.3494873046875, + 677.1195678710938, + 2370.054931640625, + 2456.36083984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9020445942878723, + "bbox": [ + 1301.4417724609375, + 393.9384460449219, + 2398.073974609375, + 2544.815673828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8693385720252991, + "bbox": [ + 1321.2469482421875, + 540.7301635742188, + 2330.0556640625, + 681.1175537109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7307010293006897, + "bbox": [ + 258.93499755859375, + 527.5663452148438, + 996.69677734375, + 610.9852905273438 + ] + } + ], + "timestamp": "2025-10-15T21:42:36.948460" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 28.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 28.json" new file mode 100644 index 0000000..749259c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 28.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 28.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7706470489501953, + "bbox": [ + 1270.4822998046875, + 445.1375732421875, + 1387.30029296875, + 548.8352661132812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7398648262023926, + "bbox": [ + 208.3574676513672, + 558.369873046875, + 326.0821838378906, + 671.6571044921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.673129141330719, + "bbox": [ + 210.5732879638672, + 2352.39111328125, + 270.662841796875, + 2427.5390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5725505352020264, + "bbox": [ + 204.86293029785156, + 3192.977294921875, + 271.15777587890625, + 3263.29052734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47195759415626526, + "bbox": [ + 1260.0882568359375, + 2394.65478515625, + 1357.42333984375, + 2518.730712890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.946494460105896, + "bbox": [ + 1252.6865234375, + 584.6635131835938, + 2282.361083984375, + 2264.861083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9423710107803345, + "bbox": [ + 189.21725463867188, + 671.4733276367188, + 1187.787841796875, + 2095.35693359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9383378624916077, + "bbox": [ + 159.18954467773438, + 424.1270446777344, + 1211.526611328125, + 2757.468505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.924258291721344, + "bbox": [ + 1260.0135498046875, + 2356.609130859375, + 2272.234375, + 2848.530029296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025425910949707, + "bbox": [ + 1242.078857421875, + 357.2750549316406, + 2318.62890625, + 2940.401611328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7688406109809875, + "bbox": [ + 198.8504180908203, + 2142.577880859375, + 534.9755859375, + 2509.209716796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.524790346622467, + "bbox": [ + 196.96731567382812, + 430.1003112792969, + 1168.8123779296875, + 509.7503356933594 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7706470489501953, + "bbox": [ + 1270.4822998046875, + 445.1375732421875, + 1387.30029296875, + 548.8352661132812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7398648262023926, + "bbox": [ + 208.3574676513672, + 558.369873046875, + 326.0821838378906, + 671.6571044921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.673129141330719, + "bbox": [ + 210.5732879638672, + 2352.39111328125, + 270.662841796875, + 2427.5390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5725505352020264, + "bbox": [ + 204.86293029785156, + 3192.977294921875, + 271.15777587890625, + 3263.29052734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47195759415626526, + "bbox": [ + 1260.0882568359375, + 2394.65478515625, + 1357.42333984375, + 2518.730712890625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.946494460105896, + "bbox": [ + 1252.6865234375, + 584.6635131835938, + 2282.361083984375, + 2264.861083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9423710107803345, + "bbox": [ + 189.21725463867188, + 671.4733276367188, + 1187.787841796875, + 2095.35693359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9383378624916077, + "bbox": [ + 159.18954467773438, + 424.1270446777344, + 1211.526611328125, + 2757.468505859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.924258291721344, + "bbox": [ + 1260.0135498046875, + 2356.609130859375, + 2272.234375, + 2848.530029296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9025425910949707, + "bbox": [ + 1242.078857421875, + 357.2750549316406, + 2318.62890625, + 2940.401611328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7688406109809875, + "bbox": [ + 198.8504180908203, + 2142.577880859375, + 534.9755859375, + 2509.209716796875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.524790346622467, + "bbox": [ + 196.96731567382812, + 430.1003112792969, + 1168.8123779296875, + 509.7503356933594 + ] + } + ], + "timestamp": "2025-10-15T21:42:37.341034" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 29.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 29.json" new file mode 100644 index 0000000..7f1d1f4 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 29.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 29.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7501577734947205, + "bbox": [ + 1325.4620361328125, + 448.038330078125, + 1439.882568359375, + 551.6939697265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7451260089874268, + "bbox": [ + 255.96917724609375, + 434.606689453125, + 379.2396240234375, + 544.2586059570312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5935863256454468, + "bbox": [ + 1317.526123046875, + 2395.2587890625, + 1410.2218017578125, + 2508.357177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5673851370811462, + "bbox": [ + 2232.501953125, + 3219.645751953125, + 2298.851318359375, + 3290.481689453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5436837077140808, + "bbox": [ + 236.4222412109375, + 2440.740966796875, + 317.3433532714844, + 2560.536376953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3088797628879547, + "bbox": [ + 2225.019775390625, + 3211.59619140625, + 2305.6044921875, + 3297.51806640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9517142176628113, + "bbox": [ + 243.9226837158203, + 563.9421997070312, + 1249.5345458984375, + 1963.65625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9423195719718933, + "bbox": [ + 238.99754333496094, + 1966.3900146484375, + 1248.7452392578125, + 2645.022705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9315354228019714, + "bbox": [ + 201.7589111328125, + 331.1204833984375, + 1267.9127197265625, + 2793.51953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9239529967308044, + "bbox": [ + 1313.292724609375, + 586.2428588867188, + 2333.1875, + 2290.515869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.90784752368927, + "bbox": [ + 1281.184326171875, + 357.16607666015625, + 2436.878173828125, + 2839.7822265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9017939567565918, + "bbox": [ + 1308.8287353515625, + 2346.03076171875, + 2255.67236328125, + 2751.169921875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7501577734947205, + "bbox": [ + 1325.4620361328125, + 448.038330078125, + 1439.882568359375, + 551.6939697265625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7451260089874268, + "bbox": [ + 255.96917724609375, + 434.606689453125, + 379.2396240234375, + 544.2586059570312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5935863256454468, + "bbox": [ + 1317.526123046875, + 2395.2587890625, + 1410.2218017578125, + 2508.357177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5673851370811462, + "bbox": [ + 2232.501953125, + 3219.645751953125, + 2298.851318359375, + 3290.481689453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5436837077140808, + "bbox": [ + 236.4222412109375, + 2440.740966796875, + 317.3433532714844, + 2560.536376953125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3088797628879547, + "bbox": [ + 2225.019775390625, + 3211.59619140625, + 2305.6044921875, + 3297.51806640625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9517142176628113, + "bbox": [ + 243.9226837158203, + 563.9421997070312, + 1249.5345458984375, + 1963.65625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9423195719718933, + "bbox": [ + 238.99754333496094, + 1966.3900146484375, + 1248.7452392578125, + 2645.022705078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9315354228019714, + "bbox": [ + 201.7589111328125, + 331.1204833984375, + 1267.9127197265625, + 2793.51953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9239529967308044, + "bbox": [ + 1313.292724609375, + 586.2428588867188, + 2333.1875, + 2290.515869140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.90784752368927, + "bbox": [ + 1281.184326171875, + 357.16607666015625, + 2436.878173828125, + 2839.7822265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9017939567565918, + "bbox": [ + 1308.8287353515625, + 2346.03076171875, + 2255.67236328125, + 2751.169921875 + ] + } + ], + "timestamp": "2025-10-15T21:42:37.739906" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 30.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 30.json" new file mode 100644 index 0000000..5a1633e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 30.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 30.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7524389624595642, + "bbox": [ + 218.1105194091797, + 432.3792419433594, + 331.2661437988281, + 529.723876953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7431447505950928, + "bbox": [ + 1268.9561767578125, + 620.7142944335938, + 1380.503173828125, + 719.0180053710938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5657069683074951, + "bbox": [ + 203.51329040527344, + 3163.104736328125, + 270.4930725097656, + 3233.476318359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5415539741516113, + "bbox": [ + 210.21817016601562, + 1502.0819091796875, + 302.5581359863281, + 1635.3358154296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.497967004776001, + "bbox": [ + 1263.3370361328125, + 2694.544677734375, + 1360.75927734375, + 2815.271240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.27456340193748474, + "bbox": [ + 1259.626220703125, + 2730.238037109375, + 1317.905517578125, + 2812.861328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9465410113334656, + "bbox": [ + 203.84593200683594, + 606.2454833984375, + 1176.6834716796875, + 1973.0828857421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.915999174118042, + "bbox": [ + 155.33132934570312, + 399.47796630859375, + 1211.4317626953125, + 2130.087158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9147048592567444, + "bbox": [ + 1251.8206787109375, + 705.6549682617188, + 2268.6123046875, + 2709.52783203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8729478716850281, + "bbox": [ + 1249.799560546875, + 2707.37744140625, + 2087.024658203125, + 2977.895751953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8509178161621094, + "bbox": [ + 1226.6080322265625, + 405.0224304199219, + 2359.810791015625, + 3058.579833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8282656073570251, + "bbox": [ + 1253.253173828125, + 436.8195495605469, + 2259.229248046875, + 574.5007934570312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7515450716018677, + "bbox": [ + 223.15435791015625, + 521.2745361328125, + 923.1041870117188, + 614.8323974609375 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7524389624595642, + "bbox": [ + 218.1105194091797, + 432.3792419433594, + 331.2661437988281, + 529.723876953125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7431447505950928, + "bbox": [ + 1268.9561767578125, + 620.7142944335938, + 1380.503173828125, + 719.0180053710938 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5657069683074951, + "bbox": [ + 203.51329040527344, + 3163.104736328125, + 270.4930725097656, + 3233.476318359375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5415539741516113, + "bbox": [ + 210.21817016601562, + 1502.0819091796875, + 302.5581359863281, + 1635.3358154296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.497967004776001, + "bbox": [ + 1263.3370361328125, + 2694.544677734375, + 1360.75927734375, + 2815.271240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.27456340193748474, + "bbox": [ + 1259.626220703125, + 2730.238037109375, + 1317.905517578125, + 2812.861328125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9465410113334656, + "bbox": [ + 203.84593200683594, + 606.2454833984375, + 1176.6834716796875, + 1973.0828857421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.915999174118042, + "bbox": [ + 155.33132934570312, + 399.47796630859375, + 1211.4317626953125, + 2130.087158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9147048592567444, + "bbox": [ + 1251.8206787109375, + 705.6549682617188, + 2268.6123046875, + 2709.52783203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8729478716850281, + "bbox": [ + 1249.799560546875, + 2707.37744140625, + 2087.024658203125, + 2977.895751953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8509178161621094, + "bbox": [ + 1226.6080322265625, + 405.0224304199219, + 2359.810791015625, + 3058.579833984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8282656073570251, + "bbox": [ + 1253.253173828125, + 436.8195495605469, + 2259.229248046875, + 574.5007934570312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7515450716018677, + "bbox": [ + 223.15435791015625, + 521.2745361328125, + 923.1041870117188, + 614.8323974609375 + ] + } + ], + "timestamp": "2025-10-15T21:42:38.131287" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 31.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 31.json" new file mode 100644 index 0000000..a4a13ee --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 31.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 31.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.757439374923706, + "bbox": [ + 251.25486755371094, + 443.82220458984375, + 377.39044189453125, + 555.3685302734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7536944150924683, + "bbox": [ + 1320.012451171875, + 631.9494018554688, + 1439.536865234375, + 735.8262939453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5715716481208801, + "bbox": [ + 2220.909912109375, + 3227.278564453125, + 2297.780029296875, + 3301.607177734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5012226104736328, + "bbox": [ + 1343.55908203125, + 1359.9927978515625, + 1457.388427734375, + 1484.091552734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4293169677257538, + "bbox": [ + 249.9940643310547, + 2473.937744140625, + 323.93194580078125, + 2561.1884765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22854651510715485, + "bbox": [ + 1344.647705078125, + 1378.2685546875, + 1439.79345703125, + 1479.3126220703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9552593231201172, + "bbox": [ + 185.90904235839844, + 406.054443359375, + 1261.943115234375, + 2722.56396484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9472499489784241, + "bbox": [ + 216.91537475585938, + 587.9608154296875, + 1221.4420166015625, + 2392.9052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9072291254997253, + "bbox": [ + 1296.498046875, + 430.9252014160156, + 2412.779541015625, + 2568.98779296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8981093168258667, + "bbox": [ + 1300.797607421875, + 732.6492309570312, + 2319.101318359375, + 2452.923095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8867239356040955, + "bbox": [ + 239.82240295410156, + 2410.149658203125, + 1120.15966796875, + 2645.758544921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6936172842979431, + "bbox": [ + 1314.6751708984375, + 442.8094787597656, + 2340.904541015625, + 583.9773559570312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.757439374923706, + "bbox": [ + 251.25486755371094, + 443.82220458984375, + 377.39044189453125, + 555.3685302734375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7536944150924683, + "bbox": [ + 1320.012451171875, + 631.9494018554688, + 1439.536865234375, + 735.8262939453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5715716481208801, + "bbox": [ + 2220.909912109375, + 3227.278564453125, + 2297.780029296875, + 3301.607177734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5012226104736328, + "bbox": [ + 1343.55908203125, + 1359.9927978515625, + 1457.388427734375, + 1484.091552734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4293169677257538, + "bbox": [ + 249.9940643310547, + 2473.937744140625, + 323.93194580078125, + 2561.1884765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22854651510715485, + "bbox": [ + 1344.647705078125, + 1378.2685546875, + 1439.79345703125, + 1479.3126220703125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9552593231201172, + "bbox": [ + 185.90904235839844, + 406.054443359375, + 1261.943115234375, + 2722.56396484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9472499489784241, + "bbox": [ + 216.91537475585938, + 587.9608154296875, + 1221.4420166015625, + 2392.9052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9072291254997253, + "bbox": [ + 1296.498046875, + 430.9252014160156, + 2412.779541015625, + 2568.98779296875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8981093168258667, + "bbox": [ + 1300.797607421875, + 732.6492309570312, + 2319.101318359375, + 2452.923095703125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8867239356040955, + "bbox": [ + 239.82240295410156, + 2410.149658203125, + 1120.15966796875, + 2645.758544921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6936172842979431, + "bbox": [ + 1314.6751708984375, + 442.8094787597656, + 2340.904541015625, + 583.9773559570312 + ] + } + ], + "timestamp": "2025-10-15T21:42:38.531081" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 32.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 32.json" new file mode 100644 index 0000000..7baa3b5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 32.json" @@ -0,0 +1,274 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 32.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7537367343902588, + "bbox": [ + 215.76312255859375, + 431.362060546875, + 339.2625427246094, + 540.633544921875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7403443455696106, + "bbox": [ + 1288.9766845703125, + 438.431640625, + 1410.3887939453125, + 543.279052734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6039438843727112, + "bbox": [ + 449.89678955078125, + 1637.0438232421875, + 543.3538208007812, + 1755.72119140625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.545609176158905, + "bbox": [ + 200.62168884277344, + 3214.473388671875, + 271.7879333496094, + 3286.687744140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5373581647872925, + "bbox": [ + 1275.1387939453125, + 2615.8154296875, + 1366.220947265625, + 2740.909912109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3767046332359314, + "bbox": [ + 1267.4312744140625, + 2612.901611328125, + 1385.57958984375, + 2753.568359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9467175602912903, + "bbox": [ + 178.8080596923828, + 369.65167236328125, + 1239.1895751953125, + 2232.146240234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9442576169967651, + "bbox": [ + 205.36691284179688, + 570.5679321289062, + 1213.5880126953125, + 2127.832763671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9394538402557373, + "bbox": [ + 1274.2745361328125, + 676.3482666015625, + 2299.51318359375, + 2592.802001953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8979507088661194, + "bbox": [ + 1265.6138916015625, + 2590.404296875, + 1988.0531005859375, + 3063.463134765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.879187285900116, + "bbox": [ + 1247.9554443359375, + 417.18487548828125, + 2382.702880859375, + 3104.080322265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.795914888381958, + "bbox": [ + 1281.336181640625, + 538.7757568359375, + 2282.024658203125, + 676.7781982421875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7537367343902588, + "bbox": [ + 215.76312255859375, + 431.362060546875, + 339.2625427246094, + 540.633544921875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7403443455696106, + "bbox": [ + 1288.9766845703125, + 438.431640625, + 1410.3887939453125, + 543.279052734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6039438843727112, + "bbox": [ + 449.89678955078125, + 1637.0438232421875, + 543.3538208007812, + 1755.72119140625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.545609176158905, + "bbox": [ + 200.62168884277344, + 3214.473388671875, + 271.7879333496094, + 3286.687744140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5373581647872925, + "bbox": [ + 1275.1387939453125, + 2615.8154296875, + 1366.220947265625, + 2740.909912109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3767046332359314, + "bbox": [ + 1267.4312744140625, + 2612.901611328125, + 1385.57958984375, + 2753.568359375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9467175602912903, + "bbox": [ + 178.8080596923828, + 369.65167236328125, + 1239.1895751953125, + 2232.146240234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9442576169967651, + "bbox": [ + 205.36691284179688, + 570.5679321289062, + 1213.5880126953125, + 2127.832763671875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9394538402557373, + "bbox": [ + 1274.2745361328125, + 676.3482666015625, + 2299.51318359375, + 2592.802001953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8979507088661194, + "bbox": [ + 1265.6138916015625, + 2590.404296875, + 1988.0531005859375, + 3063.463134765625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.879187285900116, + "bbox": [ + 1247.9554443359375, + 417.18487548828125, + 2382.702880859375, + 3104.080322265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.795914888381958, + "bbox": [ + 1281.336181640625, + 538.7757568359375, + 2282.024658203125, + 676.7781982421875 + ] + } + ], + "timestamp": "2025-10-15T21:42:38.971866" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 33.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 33.json" new file mode 100644 index 0000000..8637aaa --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 33.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 33.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7411893010139465, + "bbox": [ + 1300.99951171875, + 1884.986328125, + 1414.5931396484375, + 1984.8748779296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7399178743362427, + "bbox": [ + 1303.1260986328125, + 441.34423828125, + 1426.8656005859375, + 547.0007934570312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5413951277732849, + "bbox": [ + 2199.412841796875, + 3162.26513671875, + 2270.846923828125, + 3232.426513671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5286170244216919, + "bbox": [ + 1670.9439697265625, + 2077.5595703125, + 1775.7470703125, + 2204.891845703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47840628027915955, + "bbox": [ + 1309.3226318359375, + 677.20849609375, + 1383.680908203125, + 760.7073364257812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2938893139362335, + "bbox": [ + 1303.7100830078125, + 666.0673217773438, + 1395.251220703125, + 772.9533081054688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.912496030330658, + "bbox": [ + 1300.3553466796875, + 618.7408447265625, + 2320.264404296875, + 1013.4635620117188 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.907829225063324, + "bbox": [ + 233.6698760986328, + 500.5492858886719, + 1214.142578125, + 2870.9140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8595885634422302, + "bbox": [ + 1268.8282470703125, + 406.6799621582031, + 2359.125244140625, + 1070.231689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8345154523849487, + "bbox": [ + 1308.2244873046875, + 1970.0843505859375, + 2278.702392578125, + 2102.19873046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8244978189468384, + "bbox": [ + 1281.503662109375, + 1879.2235107421875, + 2317.342041015625, + 2247.312744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.801175057888031, + "bbox": [ + 1313.3333740234375, + 539.0196533203125, + 1917.875732421875, + 620.1353759765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7592750787734985, + "bbox": [ + 1302.6474609375, + 2099.78076171875, + 2209.174072265625, + 2216.144287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7527307868003845, + "bbox": [ + 1259.6568603515625, + 1818.8466796875, + 2363.342041015625, + 2542.586669921875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7411893010139465, + "bbox": [ + 1300.99951171875, + 1884.986328125, + 1414.5931396484375, + 1984.8748779296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7399178743362427, + "bbox": [ + 1303.1260986328125, + 441.34423828125, + 1426.8656005859375, + 547.0007934570312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5413951277732849, + "bbox": [ + 2199.412841796875, + 3162.26513671875, + 2270.846923828125, + 3232.426513671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5286170244216919, + "bbox": [ + 1670.9439697265625, + 2077.5595703125, + 1775.7470703125, + 2204.891845703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.47840628027915955, + "bbox": [ + 1309.3226318359375, + 677.20849609375, + 1383.680908203125, + 760.7073364257812 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2938893139362335, + "bbox": [ + 1303.7100830078125, + 666.0673217773438, + 1395.251220703125, + 772.9533081054688 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.912496030330658, + "bbox": [ + 1300.3553466796875, + 618.7408447265625, + 2320.264404296875, + 1013.4635620117188 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.907829225063324, + "bbox": [ + 233.6698760986328, + 500.5492858886719, + 1214.142578125, + 2870.9140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8595885634422302, + "bbox": [ + 1268.8282470703125, + 406.6799621582031, + 2359.125244140625, + 1070.231689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8345154523849487, + "bbox": [ + 1308.2244873046875, + 1970.0843505859375, + 2278.702392578125, + 2102.19873046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8244978189468384, + "bbox": [ + 1281.503662109375, + 1879.2235107421875, + 2317.342041015625, + 2247.312744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.801175057888031, + "bbox": [ + 1313.3333740234375, + 539.0196533203125, + 1917.875732421875, + 620.1353759765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7592750787734985, + "bbox": [ + 1302.6474609375, + 2099.78076171875, + 2209.174072265625, + 2216.144287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.7527307868003845, + "bbox": [ + 1259.6568603515625, + 1818.8466796875, + 2363.342041015625, + 2542.586669921875 + ] + } + ], + "timestamp": "2025-10-15T21:42:39.396952" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 34.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 34.json" new file mode 100644 index 0000000..2f3fc07 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/annotations/routed_result_2022 \354\213\244\354\240\204\355\216\270 \354\262\264\355\201\254 (\355\213\200\353\246\274) - 34.json" @@ -0,0 +1,494 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์‹ค์ „ํŽธ/2022 แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซแ„‘แ…งแ†ซ แ„Žแ…ฆแ„แ…ณ (แ„แ…ณแ†ฏแ„…แ…ตแ†ท) - 34.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491088509559631, + "bbox": [ + 1160.76953125, + 2333.6337890625, + 1273.255126953125, + 2430.89013671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7468457221984863, + "bbox": [ + 1172.97900390625, + 1334.2735595703125, + 1285.610595703125, + 1430.9822998046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7360896468162537, + "bbox": [ + 1166.3289794921875, + 1921.4727783203125, + 1274.552001953125, + 2017.7860107421875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5627599358558655, + "bbox": [ + 188.8057098388672, + 2960.930908203125, + 251.6896514892578, + 3027.109619140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5433753728866577, + "bbox": [ + 1176.138427734375, + 2457.60009765625, + 1257.6358642578125, + 2565.6689453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5327596068382263, + "bbox": [ + 1165.512939453125, + 2455.51220703125, + 1268.2003173828125, + 2580.243408203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48111236095428467, + "bbox": [ + 1171.7445068359375, + 1667.20751953125, + 1252.659423828125, + 1760.013671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3576454818248749, + "bbox": [ + 1522.5712890625, + 2090.10888671875, + 1577.92724609375, + 2159.05224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3199736475944519, + "bbox": [ + 1516.66455078125, + 2065.78369140625, + 1619.7232666015625, + 2176.07080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22252248227596283, + "bbox": [ + 1519.90087890625, + 2074.296142578125, + 1589.55224609375, + 2164.406005859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9160225987434387, + "bbox": [ + 164.7313232421875, + 553.2631225585938, + 1113.3837890625, + 2936.509521484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9152095913887024, + "bbox": [ + 1158.708251953125, + 396.1984558105469, + 2105.56591796875, + 1295.8599853515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9100043773651123, + "bbox": [ + 1169.5513916015625, + 2488.27978515625, + 2103.4541015625, + 2962.3154296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9066509008407593, + "bbox": [ + 1136.8170166015625, + 1853.5128173828125, + 2144.7626953125, + 2266.220703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9039163589477539, + "bbox": [ + 1143.0206298828125, + 2310.55322265625, + 2167.1904296875, + 3061.783203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8926684260368347, + "bbox": [ + 1178.4119873046875, + 2075.851318359375, + 2026.3492431640625, + 2201.259765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8925706148147583, + "bbox": [ + 1164.1436767578125, + 1562.869873046875, + 2048.20947265625, + 1784.335205078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8855495452880859, + "bbox": [ + 1171.2210693359375, + 1432.71826171875, + 2088.3916015625, + 1549.0565185546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8439065217971802, + "bbox": [ + 1159.432861328125, + 1303.171142578125, + 2137.692138671875, + 1878.1734619140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7733128666877747, + "bbox": [ + 1176.855224609375, + 2012.6065673828125, + 2074.808837890625, + 2086.485595703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7340794801712036, + "bbox": [ + 1165.768310546875, + 2420.44482421875, + 1776.43359375, + 2503.021484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.3301795423030853, + "bbox": [ + 115.9123306274414, + 1127.7506103515625, + 1101.5943603515625, + 3083.561279296875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7491088509559631, + "bbox": [ + 1160.76953125, + 2333.6337890625, + 1273.255126953125, + 2430.89013671875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7468457221984863, + "bbox": [ + 1172.97900390625, + 1334.2735595703125, + 1285.610595703125, + 1430.9822998046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7360896468162537, + "bbox": [ + 1166.3289794921875, + 1921.4727783203125, + 1274.552001953125, + 2017.7860107421875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5627599358558655, + "bbox": [ + 188.8057098388672, + 2960.930908203125, + 251.6896514892578, + 3027.109619140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5433753728866577, + "bbox": [ + 1176.138427734375, + 2457.60009765625, + 1257.6358642578125, + 2565.6689453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5327596068382263, + "bbox": [ + 1165.512939453125, + 2455.51220703125, + 1268.2003173828125, + 2580.243408203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48111236095428467, + "bbox": [ + 1171.7445068359375, + 1667.20751953125, + 1252.659423828125, + 1760.013671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3576454818248749, + "bbox": [ + 1522.5712890625, + 2090.10888671875, + 1577.92724609375, + 2159.05224609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3199736475944519, + "bbox": [ + 1516.66455078125, + 2065.78369140625, + 1619.7232666015625, + 2176.07080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22252248227596283, + "bbox": [ + 1519.90087890625, + 2074.296142578125, + 1589.55224609375, + 2164.406005859375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9160225987434387, + "bbox": [ + 164.7313232421875, + 553.2631225585938, + 1113.3837890625, + 2936.509521484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9152095913887024, + "bbox": [ + 1158.708251953125, + 396.1984558105469, + 2105.56591796875, + 1295.8599853515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9100043773651123, + "bbox": [ + 1169.5513916015625, + 2488.27978515625, + 2103.4541015625, + 2962.3154296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9066509008407593, + "bbox": [ + 1136.8170166015625, + 1853.5128173828125, + 2144.7626953125, + 2266.220703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9039163589477539, + "bbox": [ + 1143.0206298828125, + 2310.55322265625, + 2167.1904296875, + 3061.783203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8926684260368347, + "bbox": [ + 1178.4119873046875, + 2075.851318359375, + 2026.3492431640625, + 2201.259765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8925706148147583, + "bbox": [ + 1164.1436767578125, + 1562.869873046875, + 2048.20947265625, + 1784.335205078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8855495452880859, + "bbox": [ + 1171.2210693359375, + 1432.71826171875, + 2088.3916015625, + 1549.0565185546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8439065217971802, + "bbox": [ + 1159.432861328125, + 1303.171142578125, + 2137.692138671875, + 1878.1734619140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7733128666877747, + "bbox": [ + 1176.855224609375, + 2012.6065673828125, + 2074.808837890625, + 2086.485595703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7340794801712036, + "bbox": [ + 1165.768310546875, + 2420.44482421875, + 1776.43359375, + 2503.021484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.3301795423030853, + "bbox": [ + 115.9123306274414, + 1127.7506103515625, + 1101.5943603515625, + 3083.561279296875 + ] + } + ], + "timestamp": "2025-10-15T21:42:39.785599" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/routing_results_summary.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/routing_results_summary.json" new file mode 100644 index 0000000..d2ef989 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\213\244\354\240\204\355\216\270/routing_results_summary.json" @@ -0,0 +1,33 @@ +{ + "total_images": 85, + "processed_images": 85, + "total_detections": 1435, + "average_detections_per_image": 16.88235294117647, + "class_counts": { + "answer_option": 206, + "english_content": 147, + "korean_content": 208, + "section": 232, + "page_number": 93, + "problem_number": 224, + "answer_1": 167, + "answer_2": 158 + }, + "average_confidence": 0.742743023326588, + "routing_strategy": { + "small_objects": [ + "problem_number", + "answer_2", + "page_number", + "answer_1" + ], + "large_objects": [ + "section", + "answer_option", + "korean_content", + "english_content" + ], + "small_model_conf": 0.22, + "large_model_conf": 0.12 + } +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 38.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 38.json" new file mode 100644 index 0000000..f6aa4c6 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 38.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 38.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7850658893585205, + "bbox": [ + 1245.004638671875, + 444.0091552734375, + 1349.467529296875, + 531.5126342773438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654370069503784, + "bbox": [ + 214.3993682861328, + 427.22271728515625, + 318.3274230957031, + 516.9413452148438 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6831666231155396, + "bbox": [ + 196.97161865234375, + 2384.95947265625, + 271.91229248046875, + 2470.052978515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6807867884635925, + "bbox": [ + 859.1079711914062, + 478.5378723144531, + 981.0159301757812, + 592.7740478515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6585734486579895, + "bbox": [ + 1744.1968994140625, + 421.41668701171875, + 1868.040771484375, + 539.2625122070312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5486059784889221, + "bbox": [ + 198.19703674316406, + 3122.937744140625, + 262.08868408203125, + 3192.882080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5204101800918579, + "bbox": [ + 1230.80322265625, + 2077.01611328125, + 1313.129638671875, + 2178.70263671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2878696620464325, + "bbox": [ + 1236.32666015625, + 2084.52099609375, + 1299.093505859375, + 2177.623291015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9623130559921265, + "bbox": [ + 207.51609802246094, + 388.75640869140625, + 1174.981201171875, + 2691.782470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9469709992408752, + "bbox": [ + 220.479736328125, + 609.2149658203125, + 1145.5208740234375, + 2318.5673828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9439365863800049, + "bbox": [ + 1239.0762939453125, + 623.738525390625, + 2181.610107421875, + 2075.578857421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9404712915420532, + "bbox": [ + 1214.403076171875, + 385.86895751953125, + 2225.052734375, + 2566.18115234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9193567633628845, + "bbox": [ + 203.88946533203125, + 2331.926025390625, + 916.0518188476562, + 2682.495849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8635926842689514, + "bbox": [ + 1236.4417724609375, + 2086.396240234375, + 1765.524658203125, + 2494.394775390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8282334804534912, + "bbox": [ + 1253.0677490234375, + 534.4161376953125, + 2029.6082763671875, + 632.1238403320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8022109270095825, + "bbox": [ + 219.03334045410156, + 521.4546508789062, + 800.873046875, + 601.1928100585938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7850658893585205, + "bbox": [ + 1245.004638671875, + 444.0091552734375, + 1349.467529296875, + 531.5126342773438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654370069503784, + "bbox": [ + 214.3993682861328, + 427.22271728515625, + 318.3274230957031, + 516.9413452148438 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6831666231155396, + "bbox": [ + 196.97161865234375, + 2384.95947265625, + 271.91229248046875, + 2470.052978515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6807867884635925, + "bbox": [ + 859.1079711914062, + 478.5378723144531, + 981.0159301757812, + 592.7740478515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6585734486579895, + "bbox": [ + 1744.1968994140625, + 421.41668701171875, + 1868.040771484375, + 539.2625122070312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5486059784889221, + "bbox": [ + 198.19703674316406, + 3122.937744140625, + 262.08868408203125, + 3192.882080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5204101800918579, + "bbox": [ + 1230.80322265625, + 2077.01611328125, + 1313.129638671875, + 2178.70263671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2878696620464325, + "bbox": [ + 1236.32666015625, + 2084.52099609375, + 1299.093505859375, + 2177.623291015625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9623130559921265, + "bbox": [ + 207.51609802246094, + 388.75640869140625, + 1174.981201171875, + 2691.782470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9469709992408752, + "bbox": [ + 220.479736328125, + 609.2149658203125, + 1145.5208740234375, + 2318.5673828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9439365863800049, + "bbox": [ + 1239.0762939453125, + 623.738525390625, + 2181.610107421875, + 2075.578857421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9404712915420532, + "bbox": [ + 1214.403076171875, + 385.86895751953125, + 2225.052734375, + 2566.18115234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9193567633628845, + "bbox": [ + 203.88946533203125, + 2331.926025390625, + 916.0518188476562, + 2682.495849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8635926842689514, + "bbox": [ + 1236.4417724609375, + 2086.396240234375, + 1765.524658203125, + 2494.394775390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8282334804534912, + "bbox": [ + 1253.0677490234375, + 534.4161376953125, + 2029.6082763671875, + 632.1238403320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8022109270095825, + "bbox": [ + 219.03334045410156, + 521.4546508789062, + 800.873046875, + 601.1928100585938 + ] + } + ], + "timestamp": "2025-10-15T21:43:22.254768" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 39.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 39.json" new file mode 100644 index 0000000..8a636de --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 39.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 39.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7705318927764893, + "bbox": [ + 1335.5081787109375, + 453.4455261230469, + 1438.02001953125, + 543.862060546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7528239488601685, + "bbox": [ + 272.1936340332031, + 441.65704345703125, + 378.8155517578125, + 531.9685668945312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6945548057556152, + "bbox": [ + 878.6261596679688, + 497.85687255859375, + 991.0343627929688, + 617.134033203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.643441379070282, + "bbox": [ + 241.22537231445312, + 2593.587646484375, + 317.70770263671875, + 2678.981689453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6320832371711731, + "bbox": [ + 1742.81982421875, + 443.4820251464844, + 1867.21533203125, + 555.793701171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5415790677070618, + "bbox": [ + 2218.605224609375, + 3235.1162109375, + 2291.90380859375, + 3310.81982421875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2517617642879486, + "bbox": [ + 2200.31103515625, + 3226.35107421875, + 2298.653076171875, + 3322.5771484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9083693027496338, + "bbox": [ + 1294.9228515625, + 447.8087463378906, + 2355.884765625, + 2303.7451171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9019496440887451, + "bbox": [ + 1321.7520751953125, + 626.2509155273438, + 2311.973388671875, + 1855.4375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9001947641372681, + "bbox": [ + 224.91502380371094, + 2533.6220703125, + 1243.6923828125, + 2913.085693359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.896881103515625, + "bbox": [ + 228.53538513183594, + 408.3642578125, + 1254.3138427734375, + 3113.564208984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8927276134490967, + "bbox": [ + 265.60845947265625, + 624.4931640625, + 1236.8133544921875, + 2506.95458984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8398045897483826, + "bbox": [ + 1314.0621337890625, + 1818.96923828125, + 1849.0626220703125, + 2223.958984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8349809050559998, + "bbox": [ + 271.5494079589844, + 536.8231811523438, + 878.4813842773438, + 615.4722290039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7630285024642944, + "bbox": [ + 1343.740234375, + 540.97216796875, + 2137.949462890625, + 635.5275268554688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7705318927764893, + "bbox": [ + 1335.5081787109375, + 453.4455261230469, + 1438.02001953125, + 543.862060546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7528239488601685, + "bbox": [ + 272.1936340332031, + 441.65704345703125, + 378.8155517578125, + 531.9685668945312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6945548057556152, + "bbox": [ + 878.6261596679688, + 497.85687255859375, + 991.0343627929688, + 617.134033203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.643441379070282, + "bbox": [ + 241.22537231445312, + 2593.587646484375, + 317.70770263671875, + 2678.981689453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6320832371711731, + "bbox": [ + 1742.81982421875, + 443.4820251464844, + 1867.21533203125, + 555.793701171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5415790677070618, + "bbox": [ + 2218.605224609375, + 3235.1162109375, + 2291.90380859375, + 3310.81982421875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2517617642879486, + "bbox": [ + 2200.31103515625, + 3226.35107421875, + 2298.653076171875, + 3322.5771484375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9083693027496338, + "bbox": [ + 1294.9228515625, + 447.8087463378906, + 2355.884765625, + 2303.7451171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9019496440887451, + "bbox": [ + 1321.7520751953125, + 626.2509155273438, + 2311.973388671875, + 1855.4375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9001947641372681, + "bbox": [ + 224.91502380371094, + 2533.6220703125, + 1243.6923828125, + 2913.085693359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.896881103515625, + "bbox": [ + 228.53538513183594, + 408.3642578125, + 1254.3138427734375, + 3113.564208984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8927276134490967, + "bbox": [ + 265.60845947265625, + 624.4931640625, + 1236.8133544921875, + 2506.95458984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8398045897483826, + "bbox": [ + 1314.0621337890625, + 1818.96923828125, + 1849.0626220703125, + 2223.958984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8349809050559998, + "bbox": [ + 271.5494079589844, + 536.8231811523438, + 878.4813842773438, + 615.4722290039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7630285024642944, + "bbox": [ + 1343.740234375, + 540.97216796875, + 2137.949462890625, + 635.5275268554688 + ] + } + ], + "timestamp": "2025-10-15T21:43:22.737629" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 40.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 40.json" new file mode 100644 index 0000000..8886a1f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 40.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 40.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654352188110352, + "bbox": [ + 1225.0933837890625, + 429.0877990722656, + 1328.6439208984375, + 514.9036865234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7562647461891174, + "bbox": [ + 226.2820281982422, + 420.0055236816406, + 322.644775390625, + 505.904541015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7214211225509644, + "bbox": [ + 835.6333618164062, + 518.2304077148438, + 927.5881958007812, + 609.849853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6707378029823303, + "bbox": [ + 1711.8406982421875, + 426.275146484375, + 1813.7047119140625, + 513.9613037109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6110719442367554, + "bbox": [ + 206.29953002929688, + 2173.352783203125, + 288.9198303222656, + 2261.854736328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5850449204444885, + "bbox": [ + 213.97677612304688, + 3030.710205078125, + 272.8304138183594, + 3097.380126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5558397769927979, + "bbox": [ + 1218.1103515625, + 1939.59326171875, + 1277.22607421875, + 2008.6546630859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9454506039619446, + "bbox": [ + 1207.9368896484375, + 1878.02197265625, + 2146.3828125, + 2442.2734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9415259957313538, + "bbox": [ + 218.802001953125, + 595.69189453125, + 1134.3333740234375, + 1872.0609130859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9283991456031799, + "bbox": [ + 1222.4478759765625, + 609.94775390625, + 2139.650634765625, + 1838.4598388671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.924217164516449, + "bbox": [ + 1204.2374267578125, + 397.7838439941406, + 2166.80224609375, + 2461.242431640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9125683903694153, + "bbox": [ + 204.62210083007812, + 391.5213928222656, + 1162.757080078125, + 2356.0625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9055758118629456, + "bbox": [ + 231.21624755859375, + 1882.1463623046875, + 1141.70068359375, + 2308.773681640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7925806045532227, + "bbox": [ + 1229.46337890625, + 514.5020751953125, + 1993.301513671875, + 612.98486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7691817283630371, + "bbox": [ + 230.06353759765625, + 508.97686767578125, + 750.6973266601562, + 583.2625122070312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654352188110352, + "bbox": [ + 1225.0933837890625, + 429.0877990722656, + 1328.6439208984375, + 514.9036865234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7562647461891174, + "bbox": [ + 226.2820281982422, + 420.0055236816406, + 322.644775390625, + 505.904541015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7214211225509644, + "bbox": [ + 835.6333618164062, + 518.2304077148438, + 927.5881958007812, + 609.849853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6707378029823303, + "bbox": [ + 1711.8406982421875, + 426.275146484375, + 1813.7047119140625, + 513.9613037109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6110719442367554, + "bbox": [ + 206.29953002929688, + 2173.352783203125, + 288.9198303222656, + 2261.854736328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5850449204444885, + "bbox": [ + 213.97677612304688, + 3030.710205078125, + 272.8304138183594, + 3097.380126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5558397769927979, + "bbox": [ + 1218.1103515625, + 1939.59326171875, + 1277.22607421875, + 2008.6546630859375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9454506039619446, + "bbox": [ + 1207.9368896484375, + 1878.02197265625, + 2146.3828125, + 2442.2734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9415259957313538, + "bbox": [ + 218.802001953125, + 595.69189453125, + 1134.3333740234375, + 1872.0609130859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9283991456031799, + "bbox": [ + 1222.4478759765625, + 609.94775390625, + 2139.650634765625, + 1838.4598388671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.924217164516449, + "bbox": [ + 1204.2374267578125, + 397.7838439941406, + 2166.80224609375, + 2461.242431640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9125683903694153, + "bbox": [ + 204.62210083007812, + 391.5213928222656, + 1162.757080078125, + 2356.0625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9055758118629456, + "bbox": [ + 231.21624755859375, + 1882.1463623046875, + 1141.70068359375, + 2308.773681640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7925806045532227, + "bbox": [ + 1229.46337890625, + 514.5020751953125, + 1993.301513671875, + 612.98486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7691817283630371, + "bbox": [ + 230.06353759765625, + 508.97686767578125, + 750.6973266601562, + 583.2625122070312 + ] + } + ], + "timestamp": "2025-10-15T21:43:23.128262" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 41.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 41.json" new file mode 100644 index 0000000..711d2cd --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 41.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 41.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7704930901527405, + "bbox": [ + 1278.50390625, + 428.1532287597656, + 1378.7559814453125, + 516.4186401367188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7660089731216431, + "bbox": [ + 272.17938232421875, + 417.98846435546875, + 373.4778137207031, + 503.37646484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6935708522796631, + "bbox": [ + 1022.9564208984375, + 511.60992431640625, + 1137.188232421875, + 624.1637573242188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6412867903709412, + "bbox": [ + 1560.87841796875, + 396.8089599609375, + 1692.5703125, + 526.0737915039062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6085079312324524, + "bbox": [ + 252.24537658691406, + 2051.8115234375, + 320.007568359375, + 2129.72509765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5714181661605835, + "bbox": [ + 2121.674072265625, + 3071.4169921875, + 2187.406982421875, + 3139.539306640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5603699088096619, + "bbox": [ + 1259.2344970703125, + 2335.939697265625, + 1324.157958984375, + 2410.65771484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9606887102127075, + "bbox": [ + 212.1630096435547, + 374.3209228515625, + 1214.235107421875, + 2447.73291015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9581459164619446, + "bbox": [ + 252.73916625976562, + 590.4154663085938, + 1191.886474609375, + 1924.550048828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9495642185211182, + "bbox": [ + 1226.61181640625, + 384.3192443847656, + 2342.485107421875, + 2732.600341796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9430052638053894, + "bbox": [ + 1264.0965576171875, + 609.1795043945312, + 2210.238037109375, + 2103.279052734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9215652942657471, + "bbox": [ + 1258.311279296875, + 2145.02685546875, + 2219.642822265625, + 2623.100830078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8931517601013184, + "bbox": [ + 246.94166564941406, + 1987.853515625, + 1193.8262939453125, + 2344.37939453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7632874250411987, + "bbox": [ + 278.0298767089844, + 512.6778564453125, + 809.997314453125, + 583.1834106445312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7256768941879272, + "bbox": [ + 1278.171875, + 525.3020629882812, + 2074.1826171875, + 608.5372314453125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7704930901527405, + "bbox": [ + 1278.50390625, + 428.1532287597656, + 1378.7559814453125, + 516.4186401367188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7660089731216431, + "bbox": [ + 272.17938232421875, + 417.98846435546875, + 373.4778137207031, + 503.37646484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6935708522796631, + "bbox": [ + 1022.9564208984375, + 511.60992431640625, + 1137.188232421875, + 624.1637573242188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6412867903709412, + "bbox": [ + 1560.87841796875, + 396.8089599609375, + 1692.5703125, + 526.0737915039062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6085079312324524, + "bbox": [ + 252.24537658691406, + 2051.8115234375, + 320.007568359375, + 2129.72509765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5714181661605835, + "bbox": [ + 2121.674072265625, + 3071.4169921875, + 2187.406982421875, + 3139.539306640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5603699088096619, + "bbox": [ + 1259.2344970703125, + 2335.939697265625, + 1324.157958984375, + 2410.65771484375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9606887102127075, + "bbox": [ + 212.1630096435547, + 374.3209228515625, + 1214.235107421875, + 2447.73291015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9581459164619446, + "bbox": [ + 252.73916625976562, + 590.4154663085938, + 1191.886474609375, + 1924.550048828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9495642185211182, + "bbox": [ + 1226.61181640625, + 384.3192443847656, + 2342.485107421875, + 2732.600341796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9430052638053894, + "bbox": [ + 1264.0965576171875, + 609.1795043945312, + 2210.238037109375, + 2103.279052734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9215652942657471, + "bbox": [ + 1258.311279296875, + 2145.02685546875, + 2219.642822265625, + 2623.100830078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8931517601013184, + "bbox": [ + 246.94166564941406, + 1987.853515625, + 1193.8262939453125, + 2344.37939453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7632874250411987, + "bbox": [ + 278.0298767089844, + 512.6778564453125, + 809.997314453125, + 583.1834106445312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7256768941879272, + "bbox": [ + 1278.171875, + 525.3020629882812, + 2074.1826171875, + 608.5372314453125 + ] + } + ], + "timestamp": "2025-10-15T21:43:23.574899" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 42.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 42.json" new file mode 100644 index 0000000..710304a --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 42.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 42.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7746860980987549, + "bbox": [ + 1305.7808837890625, + 463.9405212402344, + 1411.87353515625, + 556.7373657226562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7627440094947815, + "bbox": [ + 253.69287109375, + 439.0149230957031, + 361.7425231933594, + 532.6146240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7203215956687927, + "bbox": [ + 233.90243530273438, + 2254.19482421875, + 300.6990051269531, + 2334.261962890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7125086784362793, + "bbox": [ + 851.4931030273438, + 540.1419067382812, + 957.6577758789062, + 650.2022094726562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6795146465301514, + "bbox": [ + 1893.40625, + 542.3942260742188, + 2008.872802734375, + 650.734619140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5904086828231812, + "bbox": [ + 1262.9464111328125, + 2482.47802734375, + 1350.1436767578125, + 2604.143310546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5448732972145081, + "bbox": [ + 220.23251342773438, + 3208.184326171875, + 284.95208740234375, + 3279.4912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9502140283584595, + "bbox": [ + 1289.65869140625, + 651.6404418945312, + 2255.57275390625, + 2115.330078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9488906264305115, + "bbox": [ + 223.61814880371094, + 2123.25341796875, + 1197.5814208984375, + 2667.544189453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9457461833953857, + "bbox": [ + 245.62489318847656, + 628.8764038085938, + 1215.645263671875, + 2108.302978515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9445514678955078, + "bbox": [ + 1278.370361328125, + 2126.092529296875, + 2276.478271484375, + 2815.958740234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.929721474647522, + "bbox": [ + 210.7411346435547, + 454.82073974609375, + 1238.378662109375, + 2681.951416015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9281341433525085, + "bbox": [ + 1273.3570556640625, + 445.7247619628906, + 2294.51416015625, + 2824.548095703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7607080936431885, + "bbox": [ + 1305.3443603515625, + 558.714111328125, + 1858.5296630859375, + 642.2191162109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7370347380638123, + "bbox": [ + 260.9091491699219, + 535.5781860351562, + 806.7699584960938, + 616.169189453125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7746860980987549, + "bbox": [ + 1305.7808837890625, + 463.9405212402344, + 1411.87353515625, + 556.7373657226562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7627440094947815, + "bbox": [ + 253.69287109375, + 439.0149230957031, + 361.7425231933594, + 532.6146240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7203215956687927, + "bbox": [ + 233.90243530273438, + 2254.19482421875, + 300.6990051269531, + 2334.261962890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7125086784362793, + "bbox": [ + 851.4931030273438, + 540.1419067382812, + 957.6577758789062, + 650.2022094726562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6795146465301514, + "bbox": [ + 1893.40625, + 542.3942260742188, + 2008.872802734375, + 650.734619140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5904086828231812, + "bbox": [ + 1262.9464111328125, + 2482.47802734375, + 1350.1436767578125, + 2604.143310546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5448732972145081, + "bbox": [ + 220.23251342773438, + 3208.184326171875, + 284.95208740234375, + 3279.4912109375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9502140283584595, + "bbox": [ + 1289.65869140625, + 651.6404418945312, + 2255.57275390625, + 2115.330078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9488906264305115, + "bbox": [ + 223.61814880371094, + 2123.25341796875, + 1197.5814208984375, + 2667.544189453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9457461833953857, + "bbox": [ + 245.62489318847656, + 628.8764038085938, + 1215.645263671875, + 2108.302978515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9445514678955078, + "bbox": [ + 1278.370361328125, + 2126.092529296875, + 2276.478271484375, + 2815.958740234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.929721474647522, + "bbox": [ + 210.7411346435547, + 454.82073974609375, + 1238.378662109375, + 2681.951416015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9281341433525085, + "bbox": [ + 1273.3570556640625, + 445.7247619628906, + 2294.51416015625, + 2824.548095703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7607080936431885, + "bbox": [ + 1305.3443603515625, + 558.714111328125, + 1858.5296630859375, + 642.2191162109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7370347380638123, + "bbox": [ + 260.9091491699219, + 535.5781860351562, + 806.7699584960938, + 616.169189453125 + ] + } + ], + "timestamp": "2025-10-15T21:43:23.269848" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 43.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 43.json" new file mode 100644 index 0000000..280afd6 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 43.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 43.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.8039552569389343, + "bbox": [ + 1288.2667236328125, + 444.808837890625, + 1388.116943359375, + 532.298828125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7848572134971619, + "bbox": [ + 270.17645263671875, + 429.76080322265625, + 370.3000793457031, + 515.5499877929688 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7206164002418518, + "bbox": [ + 236.4505615234375, + 2172.7607421875, + 312.0801086425781, + 2253.761474609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7093446850776672, + "bbox": [ + 922.391845703125, + 527.2451782226562, + 1029.745361328125, + 627.534912109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6879465579986572, + "bbox": [ + 1882.165771484375, + 524.4732666015625, + 1998.200927734375, + 628.2763671875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5427035093307495, + "bbox": [ + 2125.669677734375, + 3136.19189453125, + 2187.322998046875, + 3201.577880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5274348855018616, + "bbox": [ + 1262.73388671875, + 2312.609130859375, + 1320.851318359375, + 2389.0048828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3918744921684265, + "bbox": [ + 2117.759765625, + 3127.5185546875, + 2193.734375, + 3206.89599609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467979669570923, + "bbox": [ + 259.1834716796875, + 611.2193603515625, + 1194.6339111328125, + 2043.5908203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9431027770042419, + "bbox": [ + 231.5713653564453, + 2046.8077392578125, + 1185.7298583984375, + 2710.495361328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.941900908946991, + "bbox": [ + 1250.595703125, + 2301.87841796875, + 2210.11083984375, + 2994.392333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9391692280769348, + "bbox": [ + 216.26011657714844, + 382.04595947265625, + 1217.029541015625, + 2752.213623046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.937053382396698, + "bbox": [ + 1256.363525390625, + 630.2880249023438, + 2206.486328125, + 2283.434814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9227409958839417, + "bbox": [ + 1247.66259765625, + 402.3257141113281, + 2226.161376953125, + 3002.470947265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8329855799674988, + "bbox": [ + 1288.8583984375, + 540.76904296875, + 1827.7896728515625, + 619.51416015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.786961019039154, + "bbox": [ + 269.44342041015625, + 519.3678588867188, + 807.2881469726562, + 598.6730346679688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.8039552569389343, + "bbox": [ + 1288.2667236328125, + 444.808837890625, + 1388.116943359375, + 532.298828125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7848572134971619, + "bbox": [ + 270.17645263671875, + 429.76080322265625, + 370.3000793457031, + 515.5499877929688 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7206164002418518, + "bbox": [ + 236.4505615234375, + 2172.7607421875, + 312.0801086425781, + 2253.761474609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7093446850776672, + "bbox": [ + 922.391845703125, + 527.2451782226562, + 1029.745361328125, + 627.534912109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6879465579986572, + "bbox": [ + 1882.165771484375, + 524.4732666015625, + 1998.200927734375, + 628.2763671875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5427035093307495, + "bbox": [ + 2125.669677734375, + 3136.19189453125, + 2187.322998046875, + 3201.577880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5274348855018616, + "bbox": [ + 1262.73388671875, + 2312.609130859375, + 1320.851318359375, + 2389.0048828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3918744921684265, + "bbox": [ + 2117.759765625, + 3127.5185546875, + 2193.734375, + 3206.89599609375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467979669570923, + "bbox": [ + 259.1834716796875, + 611.2193603515625, + 1194.6339111328125, + 2043.5908203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9431027770042419, + "bbox": [ + 231.5713653564453, + 2046.8077392578125, + 1185.7298583984375, + 2710.495361328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.941900908946991, + "bbox": [ + 1250.595703125, + 2301.87841796875, + 2210.11083984375, + 2994.392333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9391692280769348, + "bbox": [ + 216.26011657714844, + 382.04595947265625, + 1217.029541015625, + 2752.213623046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.937053382396698, + "bbox": [ + 1256.363525390625, + 630.2880249023438, + 2206.486328125, + 2283.434814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9227409958839417, + "bbox": [ + 1247.66259765625, + 402.3257141113281, + 2226.161376953125, + 3002.470947265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8329855799674988, + "bbox": [ + 1288.8583984375, + 540.76904296875, + 1827.7896728515625, + 619.51416015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.786961019039154, + "bbox": [ + 269.44342041015625, + 519.3678588867188, + 807.2881469726562, + 598.6730346679688 + ] + } + ], + "timestamp": "2025-10-15T21:43:23.713488" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 44.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 44.json" new file mode 100644 index 0000000..e67e1c3 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 44.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 44.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7845910787582397, + "bbox": [ + 245.999267578125, + 445.87652587890625, + 345.4327697753906, + 536.3497924804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7820394039154053, + "bbox": [ + 1294.6217041015625, + 456.06939697265625, + 1399.06005859375, + 545.6227416992188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6507018208503723, + "bbox": [ + 863.2969970703125, + 2590.098876953125, + 987.869140625, + 2712.94482421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6207662224769592, + "bbox": [ + 1852.10986328125, + 2410.89453125, + 1978.6109619140625, + 2541.1328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5552783608436584, + "bbox": [ + 199.14100646972656, + 3208.264404296875, + 264.80889892578125, + 3279.2373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5505495667457581, + "bbox": [ + 1270.28271484375, + 2046.583984375, + 1333.0772705078125, + 2125.27880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4882269501686096, + "bbox": [ + 214.9437255859375, + 2250.5615234375, + 307.1544189453125, + 2379.091064453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9374234676361084, + "bbox": [ + 209.8842315673828, + 1890.6182861328125, + 1179.4910888671875, + 2573.814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9263067245483398, + "bbox": [ + 235.85838317871094, + 626.661376953125, + 1208.9600830078125, + 1908.19873046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9254040122032166, + "bbox": [ + 1256.765869140625, + 445.131591796875, + 2286.751708984375, + 2384.210205078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.924713134765625, + "bbox": [ + 215.1496124267578, + 408.5166015625, + 1213.23828125, + 2603.1298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.922139585018158, + "bbox": [ + 1270.826904296875, + 1921.19091796875, + 2255.972412109375, + 2349.409912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9161280393600464, + "bbox": [ + 1282.2891845703125, + 640.4149169921875, + 2251.07666015625, + 1867.8896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.78031986951828, + "bbox": [ + 1297.1019287109375, + 554.3802490234375, + 1878.3837890625, + 637.9168701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7180740237236023, + "bbox": [ + 246.48385620117188, + 536.1273803710938, + 819.8499755859375, + 613.4973754882812 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7845910787582397, + "bbox": [ + 245.999267578125, + 445.87652587890625, + 345.4327697753906, + 536.3497924804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7820394039154053, + "bbox": [ + 1294.6217041015625, + 456.06939697265625, + 1399.06005859375, + 545.6227416992188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6507018208503723, + "bbox": [ + 863.2969970703125, + 2590.098876953125, + 987.869140625, + 2712.94482421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6207662224769592, + "bbox": [ + 1852.10986328125, + 2410.89453125, + 1978.6109619140625, + 2541.1328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5552783608436584, + "bbox": [ + 199.14100646972656, + 3208.264404296875, + 264.80889892578125, + 3279.2373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5505495667457581, + "bbox": [ + 1270.28271484375, + 2046.583984375, + 1333.0772705078125, + 2125.27880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4882269501686096, + "bbox": [ + 214.9437255859375, + 2250.5615234375, + 307.1544189453125, + 2379.091064453125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9374234676361084, + "bbox": [ + 209.8842315673828, + 1890.6182861328125, + 1179.4910888671875, + 2573.814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9263067245483398, + "bbox": [ + 235.85838317871094, + 626.661376953125, + 1208.9600830078125, + 1908.19873046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9254040122032166, + "bbox": [ + 1256.765869140625, + 445.131591796875, + 2286.751708984375, + 2384.210205078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.924713134765625, + "bbox": [ + 215.1496124267578, + 408.5166015625, + 1213.23828125, + 2603.1298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.922139585018158, + "bbox": [ + 1270.826904296875, + 1921.19091796875, + 2255.972412109375, + 2349.409912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9161280393600464, + "bbox": [ + 1282.2891845703125, + 640.4149169921875, + 2251.07666015625, + 1867.8896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.78031986951828, + "bbox": [ + 1297.1019287109375, + 554.3802490234375, + 1878.3837890625, + 637.9168701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7180740237236023, + "bbox": [ + 246.48385620117188, + 536.1273803710938, + 819.8499755859375, + 613.4973754882812 + ] + } + ], + "timestamp": "2025-10-15T21:43:24.152413" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 45.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 45.json" new file mode 100644 index 0000000..e274c4c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 45.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 45.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7931270599365234, + "bbox": [ + 1311.9981689453125, + 436.4145812988281, + 1407.85888671875, + 521.4217529296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7587273716926575, + "bbox": [ + 316.2994689941406, + 421.86138916015625, + 416.55242919921875, + 508.7156677246094 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6463793516159058, + "bbox": [ + 937.572998046875, + 2624.193115234375, + 1057.8326416015625, + 2742.765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.624078094959259, + "bbox": [ + 1725.593994140625, + 2667.236328125, + 1852.017578125, + 2782.94189453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5799404382705688, + "bbox": [ + 2124.63916015625, + 3055.417236328125, + 2192.68017578125, + 3124.4306640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5614355802536011, + "bbox": [ + 1269.6162109375, + 2240.910400390625, + 1342.140625, + 2329.63330078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4390317499637604, + "bbox": [ + 264.9559020996094, + 2333.263427734375, + 339.5945129394531, + 2441.2021484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.35075685381889343, + "bbox": [ + 1704.2557373046875, + 2650.145751953125, + 1869.216796875, + 2805.676025390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9529445767402649, + "bbox": [ + 257.5992736816406, + 384.68408203125, + 1220.3992919921875, + 2706.79248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9502235651016235, + "bbox": [ + 268.4039611816406, + 2051.927978515625, + 1199.833251953125, + 2624.282470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9471122026443481, + "bbox": [ + 298.0169372558594, + 596.5098876953125, + 1223.0772705078125, + 2023.62939453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9348850846290588, + "bbox": [ + 1285.727783203125, + 599.9483032226562, + 2221.41259765625, + 2188.06201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9252095818519592, + "bbox": [ + 1270.8231201171875, + 411.1346435546875, + 2251.297607421875, + 2815.730712890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9032801389694214, + "bbox": [ + 1278.500244140625, + 2195.905029296875, + 2214.2451171875, + 2656.06201171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8423024415969849, + "bbox": [ + 1304.7052001953125, + 529.2310180664062, + 1871.400146484375, + 609.80126953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7191998958587646, + "bbox": [ + 311.24237060546875, + 513.063232421875, + 866.3126831054688, + 588.3631591796875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7931270599365234, + "bbox": [ + 1311.9981689453125, + 436.4145812988281, + 1407.85888671875, + 521.4217529296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7587273716926575, + "bbox": [ + 316.2994689941406, + 421.86138916015625, + 416.55242919921875, + 508.7156677246094 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6463793516159058, + "bbox": [ + 937.572998046875, + 2624.193115234375, + 1057.8326416015625, + 2742.765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.624078094959259, + "bbox": [ + 1725.593994140625, + 2667.236328125, + 1852.017578125, + 2782.94189453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5799404382705688, + "bbox": [ + 2124.63916015625, + 3055.417236328125, + 2192.68017578125, + 3124.4306640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5614355802536011, + "bbox": [ + 1269.6162109375, + 2240.910400390625, + 1342.140625, + 2329.63330078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4390317499637604, + "bbox": [ + 264.9559020996094, + 2333.263427734375, + 339.5945129394531, + 2441.2021484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.35075685381889343, + "bbox": [ + 1704.2557373046875, + 2650.145751953125, + 1869.216796875, + 2805.676025390625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9529445767402649, + "bbox": [ + 257.5992736816406, + 384.68408203125, + 1220.3992919921875, + 2706.79248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9502235651016235, + "bbox": [ + 268.4039611816406, + 2051.927978515625, + 1199.833251953125, + 2624.282470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9471122026443481, + "bbox": [ + 298.0169372558594, + 596.5098876953125, + 1223.0772705078125, + 2023.62939453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9348850846290588, + "bbox": [ + 1285.727783203125, + 599.9483032226562, + 2221.41259765625, + 2188.06201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9252095818519592, + "bbox": [ + 1270.8231201171875, + 411.1346435546875, + 2251.297607421875, + 2815.730712890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9032801389694214, + "bbox": [ + 1278.500244140625, + 2195.905029296875, + 2214.2451171875, + 2656.06201171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8423024415969849, + "bbox": [ + 1304.7052001953125, + 529.2310180664062, + 1871.400146484375, + 609.80126953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7191998958587646, + "bbox": [ + 311.24237060546875, + 513.063232421875, + 866.3126831054688, + 588.3631591796875 + ] + } + ], + "timestamp": "2025-10-15T21:43:24.588446" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 46.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 46.json" new file mode 100644 index 0000000..cca52da --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 46.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 46.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7843865156173706, + "bbox": [ + 1207.572509765625, + 415.8751525878906, + 1308.035400390625, + 502.2336120605469 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7566031813621521, + "bbox": [ + 226.0583953857422, + 399.6450500488281, + 324.3490905761719, + 485.2010192871094 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6890085935592651, + "bbox": [ + 1808.068603515625, + 459.8889465332031, + 1940.491943359375, + 589.8876342773438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6784251928329468, + "bbox": [ + 826.2779541015625, + 434.4393615722656, + 944.7090454101562, + 554.8372192382812 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6009083390235901, + "bbox": [ + 206.2031707763672, + 3002.328857421875, + 265.1278381347656, + 3065.1064453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3886060118675232, + "bbox": [ + 910.659912109375, + 1870.14306640625, + 979.3333740234375, + 1958.6322021484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.35170474648475647, + "bbox": [ + 1611.9703369140625, + 2503.47412109375, + 1703.369873046875, + 2615.57763671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.26060688495635986, + "bbox": [ + 912.573974609375, + 1881.109130859375, + 971.9015502929688, + 1952.630126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22912733256816864, + "bbox": [ + 1615.51953125, + 2521.79345703125, + 1687.4873046875, + 2604.911865234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.933727502822876, + "bbox": [ + 174.71627807617188, + 393.9068603515625, + 1133.452880859375, + 2354.1494140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9207546710968018, + "bbox": [ + 1170.7996826171875, + 380.8194885253906, + 2101.07568359375, + 2811.97705078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9101459980010986, + "bbox": [ + 188.31361389160156, + 597.335205078125, + 1109.9005126953125, + 2330.333740234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8943648338317871, + "bbox": [ + 1185.260009765625, + 601.4429931640625, + 2085.86865234375, + 2775.410400390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7673927545547485, + "bbox": [ + 1197.0540771484375, + 504.17291259765625, + 1756.362060546875, + 590.1963500976562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6961699724197388, + "bbox": [ + 245.38504028320312, + 488.6070556640625, + 800.1921997070312, + 559.661376953125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7843865156173706, + "bbox": [ + 1207.572509765625, + 415.8751525878906, + 1308.035400390625, + 502.2336120605469 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7566031813621521, + "bbox": [ + 226.0583953857422, + 399.6450500488281, + 324.3490905761719, + 485.2010192871094 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6890085935592651, + "bbox": [ + 1808.068603515625, + 459.8889465332031, + 1940.491943359375, + 589.8876342773438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6784251928329468, + "bbox": [ + 826.2779541015625, + 434.4393615722656, + 944.7090454101562, + 554.8372192382812 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6009083390235901, + "bbox": [ + 206.2031707763672, + 3002.328857421875, + 265.1278381347656, + 3065.1064453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3886060118675232, + "bbox": [ + 910.659912109375, + 1870.14306640625, + 979.3333740234375, + 1958.6322021484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.35170474648475647, + "bbox": [ + 1611.9703369140625, + 2503.47412109375, + 1703.369873046875, + 2615.57763671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.26060688495635986, + "bbox": [ + 912.573974609375, + 1881.109130859375, + 971.9015502929688, + 1952.630126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22912733256816864, + "bbox": [ + 1615.51953125, + 2521.79345703125, + 1687.4873046875, + 2604.911865234375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.933727502822876, + "bbox": [ + 174.71627807617188, + 393.9068603515625, + 1133.452880859375, + 2354.1494140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9207546710968018, + "bbox": [ + 1170.7996826171875, + 380.8194885253906, + 2101.07568359375, + 2811.97705078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9101459980010986, + "bbox": [ + 188.31361389160156, + 597.335205078125, + 1109.9005126953125, + 2330.333740234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8943648338317871, + "bbox": [ + 1185.260009765625, + 601.4429931640625, + 2085.86865234375, + 2775.410400390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7673927545547485, + "bbox": [ + 1197.0540771484375, + 504.17291259765625, + 1756.362060546875, + 590.1963500976562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6961699724197388, + "bbox": [ + 245.38504028320312, + 488.6070556640625, + 800.1921997070312, + 559.661376953125 + ] + } + ], + "timestamp": "2025-10-15T21:43:25.006462" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 47.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 47.json" new file mode 100644 index 0000000..100a91c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 47.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 47.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7637745141983032, + "bbox": [ + 1281.3331298828125, + 431.3254699707031, + 1382.662109375, + 518.2401123046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7615582346916199, + "bbox": [ + 268.7275390625, + 417.9487609863281, + 370.343994140625, + 505.3556213378906 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.700963020324707, + "bbox": [ + 902.0318603515625, + 500.62420654296875, + 1018.945556640625, + 615.0596923828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6734440326690674, + "bbox": [ + 1860.009521484375, + 480.6521911621094, + 1980.3133544921875, + 592.3084716796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6073032021522522, + "bbox": [ + 1380.986083984375, + 1583.1798095703125, + 1476.1507568359375, + 1692.702880859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5591750741004944, + "bbox": [ + 2115.88623046875, + 3100.304443359375, + 2179.758544921875, + 3167.580322265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48304539918899536, + "bbox": [ + 817.1116333007812, + 1908.6402587890625, + 920.1727905273438, + 2031.4873046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.23558421432971954, + "bbox": [ + 2108.99072265625, + 3092.55517578125, + 2185.157470703125, + 3175.589111328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22681589424610138, + "bbox": [ + 821.4630737304688, + 1920.0452880859375, + 899.2451171875, + 2024.4661865234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9371247887611389, + "bbox": [ + 1250.2119140625, + 394.1856994628906, + 2216.448974609375, + 2530.40185546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9193915128707886, + "bbox": [ + 241.201904296875, + 451.201416015625, + 1214.4248046875, + 2637.3427734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9149619340896606, + "bbox": [ + 1258.4056396484375, + 613.6257934570312, + 2198.619140625, + 2501.471923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.895502507686615, + "bbox": [ + 257.1153869628906, + 601.7205200195312, + 1192.04345703125, + 2638.293212890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8659393191337585, + "bbox": [ + 269.3448486328125, + 508.31427001953125, + 867.6799926757812, + 593.4024047851562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7746074795722961, + "bbox": [ + 1276.8433837890625, + 523.4634399414062, + 1831.685791015625, + 597.4881591796875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7637745141983032, + "bbox": [ + 1281.3331298828125, + 431.3254699707031, + 1382.662109375, + 518.2401123046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7615582346916199, + "bbox": [ + 268.7275390625, + 417.9487609863281, + 370.343994140625, + 505.3556213378906 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.700963020324707, + "bbox": [ + 902.0318603515625, + 500.62420654296875, + 1018.945556640625, + 615.0596923828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6734440326690674, + "bbox": [ + 1860.009521484375, + 480.6521911621094, + 1980.3133544921875, + 592.3084716796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6073032021522522, + "bbox": [ + 1380.986083984375, + 1583.1798095703125, + 1476.1507568359375, + 1692.702880859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5591750741004944, + "bbox": [ + 2115.88623046875, + 3100.304443359375, + 2179.758544921875, + 3167.580322265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48304539918899536, + "bbox": [ + 817.1116333007812, + 1908.6402587890625, + 920.1727905273438, + 2031.4873046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.23558421432971954, + "bbox": [ + 2108.99072265625, + 3092.55517578125, + 2185.157470703125, + 3175.589111328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22681589424610138, + "bbox": [ + 821.4630737304688, + 1920.0452880859375, + 899.2451171875, + 2024.4661865234375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9371247887611389, + "bbox": [ + 1250.2119140625, + 394.1856994628906, + 2216.448974609375, + 2530.40185546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9193915128707886, + "bbox": [ + 241.201904296875, + 451.201416015625, + 1214.4248046875, + 2637.3427734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9149619340896606, + "bbox": [ + 1258.4056396484375, + 613.6257934570312, + 2198.619140625, + 2501.471923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.895502507686615, + "bbox": [ + 257.1153869628906, + 601.7205200195312, + 1192.04345703125, + 2638.293212890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8659393191337585, + "bbox": [ + 269.3448486328125, + 508.31427001953125, + 867.6799926757812, + 593.4024047851562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7746074795722961, + "bbox": [ + 1276.8433837890625, + 523.4634399414062, + 1831.685791015625, + 597.4881591796875 + ] + } + ], + "timestamp": "2025-10-15T21:43:25.399830" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 48.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 48.json" new file mode 100644 index 0000000..8b96a81 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 48.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 48.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.761832594871521, + "bbox": [ + 1194.5025634765625, + 426.0437927246094, + 1294.8182373046875, + 513.5643920898438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7558843493461609, + "bbox": [ + 217.1937713623047, + 421.4517517089844, + 317.0434875488281, + 509.03997802734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6906967759132385, + "bbox": [ + 766.6115112304688, + 2271.959716796875, + 879.8487548828125, + 2390.0087890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5859882235527039, + "bbox": [ + 1611.577392578125, + 2178.003173828125, + 1733.277099609375, + 2301.035888671875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5273987650871277, + "bbox": [ + 220.9464569091797, + 2976.860107421875, + 283.26971435546875, + 3043.1962890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5247274041175842, + "bbox": [ + 222.21620178222656, + 2126.157958984375, + 281.7179870605469, + 2200.72412109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3841470181941986, + "bbox": [ + 1595.612060546875, + 2172.345947265625, + 1747.837158203125, + 2315.735595703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3773598372936249, + "bbox": [ + 1186.9813232421875, + 1777.7135009765625, + 1257.454833984375, + 1863.5328369140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9491549730300903, + "bbox": [ + 197.5543975830078, + 419.8193664550781, + 1135.0311279296875, + 2313.736083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9441031813621521, + "bbox": [ + 213.30897521972656, + 654.7716064453125, + 1122.309326171875, + 1899.614990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.938422441482544, + "bbox": [ + 1191.224365234375, + 1727.22412109375, + 2086.506103515625, + 2171.40869140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9156239628791809, + "bbox": [ + 1183.12451171875, + 603.550537109375, + 2094.80810546875, + 1739.456787109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.914038360118866, + "bbox": [ + 1177.0543212890625, + 418.02117919921875, + 2119.41650390625, + 2233.0517578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9041059613227844, + "bbox": [ + 226.46212768554688, + 1946.5125732421875, + 1031.5899658203125, + 2272.9189453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8196301460266113, + "bbox": [ + 212.6968231201172, + 506.2052001953125, + 1110.7606201171875, + 632.6334838867188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.686562180519104, + "bbox": [ + 1190.712890625, + 520.4950561523438, + 2061.48388671875, + 583.3331909179688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.761832594871521, + "bbox": [ + 1194.5025634765625, + 426.0437927246094, + 1294.8182373046875, + 513.5643920898438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7558843493461609, + "bbox": [ + 217.1937713623047, + 421.4517517089844, + 317.0434875488281, + 509.03997802734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6906967759132385, + "bbox": [ + 766.6115112304688, + 2271.959716796875, + 879.8487548828125, + 2390.0087890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5859882235527039, + "bbox": [ + 1611.577392578125, + 2178.003173828125, + 1733.277099609375, + 2301.035888671875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5273987650871277, + "bbox": [ + 220.9464569091797, + 2976.860107421875, + 283.26971435546875, + 3043.1962890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5247274041175842, + "bbox": [ + 222.21620178222656, + 2126.157958984375, + 281.7179870605469, + 2200.72412109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3841470181941986, + "bbox": [ + 1595.612060546875, + 2172.345947265625, + 1747.837158203125, + 2315.735595703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3773598372936249, + "bbox": [ + 1186.9813232421875, + 1777.7135009765625, + 1257.454833984375, + 1863.5328369140625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9491549730300903, + "bbox": [ + 197.5543975830078, + 419.8193664550781, + 1135.0311279296875, + 2313.736083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9441031813621521, + "bbox": [ + 213.30897521972656, + 654.7716064453125, + 1122.309326171875, + 1899.614990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.938422441482544, + "bbox": [ + 1191.224365234375, + 1727.22412109375, + 2086.506103515625, + 2171.40869140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9156239628791809, + "bbox": [ + 1183.12451171875, + 603.550537109375, + 2094.80810546875, + 1739.456787109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.914038360118866, + "bbox": [ + 1177.0543212890625, + 418.02117919921875, + 2119.41650390625, + 2233.0517578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9041059613227844, + "bbox": [ + 226.46212768554688, + 1946.5125732421875, + 1031.5899658203125, + 2272.9189453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8196301460266113, + "bbox": [ + 212.6968231201172, + 506.2052001953125, + 1110.7606201171875, + 632.6334838867188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.686562180519104, + "bbox": [ + 1190.712890625, + 520.4950561523438, + 2061.48388671875, + 583.3331909179688 + ] + } + ], + "timestamp": "2025-10-15T21:43:25.783379" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 49.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 49.json" new file mode 100644 index 0000000..2806cd7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 49.json" @@ -0,0 +1,384 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 49.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.780134916305542, + "bbox": [ + 256.15020751953125, + 434.1932067871094, + 354.1650695800781, + 519.278076171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7795239686965942, + "bbox": [ + 1252.0650634765625, + 438.5823974609375, + 1348.4190673828125, + 524.1647338867188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7196395993232727, + "bbox": [ + 848.813232421875, + 2407.525634765625, + 954.1893920898438, + 2511.158935546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5952417254447937, + "bbox": [ + 1658.5916748046875, + 2422.9990234375, + 1790.88720703125, + 2557.6962890625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5826197266578674, + "bbox": [ + 2081.43798828125, + 3065.691162109375, + 2148.2568359375, + 3136.514892578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5644999146461487, + "bbox": [ + 1244.0379638671875, + 2074.459228515625, + 1308.9884033203125, + 2153.791015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4584798514842987, + "bbox": [ + 258.18878173828125, + 1936.684326171875, + 318.6199951171875, + 2011.361083984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.25767257809638977, + "bbox": [ + 1643.815673828125, + 2413.978271484375, + 1810.749267578125, + 2571.27783203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23458905518054962, + "bbox": [ + 1238.3782958984375, + 2060.038330078125, + 1321.0302734375, + 2162.014404296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9619943499565125, + "bbox": [ + 233.8098907470703, + 435.261962890625, + 1196.7174072265625, + 2478.4482421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9512573480606079, + "bbox": [ + 251.65020751953125, + 659.0870361328125, + 1168.5526123046875, + 1916.99609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9458175301551819, + "bbox": [ + 1240.2913818359375, + 618.889892578125, + 2155.150634765625, + 1860.6180419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9365116953849792, + "bbox": [ + 1222.9481201171875, + 431.4078674316406, + 2173.12548828125, + 2549.2587890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9321571588516235, + "bbox": [ + 1242.382568359375, + 1898.4298095703125, + 2160.006103515625, + 2353.427978515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8854532837867737, + "bbox": [ + 262.89263916015625, + 1914.3111572265625, + 1145.04052734375, + 2293.63525390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484488725662231, + "bbox": [ + 253.18734741210938, + 523.8699951171875, + 1163.755126953125, + 646.6802368164062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6665724515914917, + "bbox": [ + 1255.01318359375, + 530.4454956054688, + 2061.2529296875, + 598.1119995117188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.780134916305542, + "bbox": [ + 256.15020751953125, + 434.1932067871094, + 354.1650695800781, + 519.278076171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7795239686965942, + "bbox": [ + 1252.0650634765625, + 438.5823974609375, + 1348.4190673828125, + 524.1647338867188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7196395993232727, + "bbox": [ + 848.813232421875, + 2407.525634765625, + 954.1893920898438, + 2511.158935546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5952417254447937, + "bbox": [ + 1658.5916748046875, + 2422.9990234375, + 1790.88720703125, + 2557.6962890625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5826197266578674, + "bbox": [ + 2081.43798828125, + 3065.691162109375, + 2148.2568359375, + 3136.514892578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5644999146461487, + "bbox": [ + 1244.0379638671875, + 2074.459228515625, + 1308.9884033203125, + 2153.791015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4584798514842987, + "bbox": [ + 258.18878173828125, + 1936.684326171875, + 318.6199951171875, + 2011.361083984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.25767257809638977, + "bbox": [ + 1643.815673828125, + 2413.978271484375, + 1810.749267578125, + 2571.27783203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23458905518054962, + "bbox": [ + 1238.3782958984375, + 2060.038330078125, + 1321.0302734375, + 2162.014404296875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9619943499565125, + "bbox": [ + 233.8098907470703, + 435.261962890625, + 1196.7174072265625, + 2478.4482421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9512573480606079, + "bbox": [ + 251.65020751953125, + 659.0870361328125, + 1168.5526123046875, + 1916.99609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9458175301551819, + "bbox": [ + 1240.2913818359375, + 618.889892578125, + 2155.150634765625, + 1860.6180419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9365116953849792, + "bbox": [ + 1222.9481201171875, + 431.4078674316406, + 2173.12548828125, + 2549.2587890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9321571588516235, + "bbox": [ + 1242.382568359375, + 1898.4298095703125, + 2160.006103515625, + 2353.427978515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8854532837867737, + "bbox": [ + 262.89263916015625, + 1914.3111572265625, + 1145.04052734375, + 2293.63525390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484488725662231, + "bbox": [ + 253.18734741210938, + 523.8699951171875, + 1163.755126953125, + 646.6802368164062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6665724515914917, + "bbox": [ + 1255.01318359375, + 530.4454956054688, + 2061.2529296875, + 598.1119995117188 + ] + } + ], + "timestamp": "2025-10-15T21:43:26.165593" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 50.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 50.json" new file mode 100644 index 0000000..eff9059 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 50.json" @@ -0,0 +1,384 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 50.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7904474139213562, + "bbox": [ + 1305.9730224609375, + 454.6781005859375, + 1411.0693359375, + 544.9685668945312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7630218863487244, + "bbox": [ + 262.91156005859375, + 436.4554138183594, + 368.8863830566406, + 529.860107421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6920769214630127, + "bbox": [ + 1632.2176513671875, + 433.8262023925781, + 1750.3948974609375, + 545.2208862304688 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.690771222114563, + "bbox": [ + 843.9723510742188, + 427.2707824707031, + 955.9827270507812, + 537.5853881835938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6154984831809998, + "bbox": [ + 1289.9635009765625, + 2731.99072265625, + 1354.92236328125, + 2809.833984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5829889178276062, + "bbox": [ + 249.4376678466797, + 3182.93896484375, + 311.1623229980469, + 3248.7451171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3711366057395935, + "bbox": [ + 254.37771606445312, + 2672.283935546875, + 322.44378662109375, + 2751.8310546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3064165711402893, + "bbox": [ + 253.32247924804688, + 2638.01953125, + 333.4209899902344, + 2756.7998046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2254997342824936, + "bbox": [ + 240.2407989501953, + 3173.567138671875, + 318.4705810546875, + 3259.79931640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9421749711036682, + "bbox": [ + 1284.8690185546875, + 680.3593139648438, + 2261.192138671875, + 2588.590576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9301369786262512, + "bbox": [ + 255.45822143554688, + 2468.455078125, + 1138.59619140625, + 2827.376708984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9293893575668335, + "bbox": [ + 243.26011657714844, + 665.6390991210938, + 1212.5750732421875, + 2456.0751953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9261131882667542, + "bbox": [ + 229.2140350341797, + 374.9838562011719, + 1237.4315185546875, + 2898.684326171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9104871153831482, + "bbox": [ + 1297.6397705078125, + 2601.8232421875, + 2172.830078125, + 2952.422607421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9095256924629211, + "bbox": [ + 1289.8665771484375, + 412.5694885253906, + 2283.015869140625, + 3025.748046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8420007824897766, + "bbox": [ + 260.91064453125, + 528.5440063476562, + 1229.6417236328125, + 668.8494873046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8399321436882019, + "bbox": [ + 1298.3521728515625, + 549.59326171875, + 2259.93115234375, + 679.4110107421875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7904474139213562, + "bbox": [ + 1305.9730224609375, + 454.6781005859375, + 1411.0693359375, + 544.9685668945312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7630218863487244, + "bbox": [ + 262.91156005859375, + 436.4554138183594, + 368.8863830566406, + 529.860107421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6920769214630127, + "bbox": [ + 1632.2176513671875, + 433.8262023925781, + 1750.3948974609375, + 545.2208862304688 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.690771222114563, + "bbox": [ + 843.9723510742188, + 427.2707824707031, + 955.9827270507812, + 537.5853881835938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6154984831809998, + "bbox": [ + 1289.9635009765625, + 2731.99072265625, + 1354.92236328125, + 2809.833984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5829889178276062, + "bbox": [ + 249.4376678466797, + 3182.93896484375, + 311.1623229980469, + 3248.7451171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3711366057395935, + "bbox": [ + 254.37771606445312, + 2672.283935546875, + 322.44378662109375, + 2751.8310546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3064165711402893, + "bbox": [ + 253.32247924804688, + 2638.01953125, + 333.4209899902344, + 2756.7998046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2254997342824936, + "bbox": [ + 240.2407989501953, + 3173.567138671875, + 318.4705810546875, + 3259.79931640625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9421749711036682, + "bbox": [ + 1284.8690185546875, + 680.3593139648438, + 2261.192138671875, + 2588.590576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9301369786262512, + "bbox": [ + 255.45822143554688, + 2468.455078125, + 1138.59619140625, + 2827.376708984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9293893575668335, + "bbox": [ + 243.26011657714844, + 665.6390991210938, + 1212.5750732421875, + 2456.0751953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9261131882667542, + "bbox": [ + 229.2140350341797, + 374.9838562011719, + 1237.4315185546875, + 2898.684326171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9104871153831482, + "bbox": [ + 1297.6397705078125, + 2601.8232421875, + 2172.830078125, + 2952.422607421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9095256924629211, + "bbox": [ + 1289.8665771484375, + 412.5694885253906, + 2283.015869140625, + 3025.748046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8420007824897766, + "bbox": [ + 260.91064453125, + 528.5440063476562, + 1229.6417236328125, + 668.8494873046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8399321436882019, + "bbox": [ + 1298.3521728515625, + 549.59326171875, + 2259.93115234375, + 679.4110107421875 + ] + } + ], + "timestamp": "2025-10-15T21:43:26.560093" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 51.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 51.json" new file mode 100644 index 0000000..2574723 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 51.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 51.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7854154706001282, + "bbox": [ + 290.4771423339844, + 417.18902587890625, + 390.0992431640625, + 501.3641357421875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7761234045028687, + "bbox": [ + 1289.3033447265625, + 423.1119384765625, + 1388.7099609375, + 510.2628479003906 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7106432318687439, + "bbox": [ + 1285.0648193359375, + 2797.974609375, + 1343.6654052734375, + 2871.871826171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6930999755859375, + "bbox": [ + 287.39227294921875, + 2351.132080078125, + 351.663330078125, + 2428.945068359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6618533134460449, + "bbox": [ + 807.1292724609375, + 2736.12109375, + 925.4517211914062, + 2843.675048828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6608365774154663, + "bbox": [ + 2022.101806640625, + 2627.602294921875, + 2141.164306640625, + 2744.98046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.551425576210022, + "bbox": [ + 2134.673583984375, + 3041.867919921875, + 2197.433837890625, + 3108.06103515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.42401012778282166, + "bbox": [ + 790.3473510742188, + 2725.0234375, + 935.4253540039062, + 2861.962158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357022643089294, + "bbox": [ + 1287.615478515625, + 627.7685546875, + 2196.891357421875, + 2592.86572265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198180437088013, + "bbox": [ + 298.74517822265625, + 643.5359497070312, + 1195.21337890625, + 2302.4326171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9115281701087952, + "bbox": [ + 255.140380859375, + 375.18609619140625, + 1216.0118408203125, + 2847.78173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9038777947425842, + "bbox": [ + 284.9263916015625, + 2293.08251953125, + 1032.755615234375, + 2654.053466796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8992204070091248, + "bbox": [ + 1281.1580810546875, + 2612.266357421875, + 2019.0830078125, + 2947.741455078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.868629515171051, + "bbox": [ + 1257.5802001953125, + 399.0816955566406, + 2218.2685546875, + 2938.5888671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8370141983032227, + "bbox": [ + 1290.6041259765625, + 520.753662109375, + 2202.096923828125, + 637.7318725585938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8265472054481506, + "bbox": [ + 282.6708068847656, + 510.51275634765625, + 1186.576416015625, + 632.8124389648438 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7854154706001282, + "bbox": [ + 290.4771423339844, + 417.18902587890625, + 390.0992431640625, + 501.3641357421875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7761234045028687, + "bbox": [ + 1289.3033447265625, + 423.1119384765625, + 1388.7099609375, + 510.2628479003906 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7106432318687439, + "bbox": [ + 1285.0648193359375, + 2797.974609375, + 1343.6654052734375, + 2871.871826171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6930999755859375, + "bbox": [ + 287.39227294921875, + 2351.132080078125, + 351.663330078125, + 2428.945068359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6618533134460449, + "bbox": [ + 807.1292724609375, + 2736.12109375, + 925.4517211914062, + 2843.675048828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6608365774154663, + "bbox": [ + 2022.101806640625, + 2627.602294921875, + 2141.164306640625, + 2744.98046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.551425576210022, + "bbox": [ + 2134.673583984375, + 3041.867919921875, + 2197.433837890625, + 3108.06103515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.42401012778282166, + "bbox": [ + 790.3473510742188, + 2725.0234375, + 935.4253540039062, + 2861.962158203125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357022643089294, + "bbox": [ + 1287.615478515625, + 627.7685546875, + 2196.891357421875, + 2592.86572265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198180437088013, + "bbox": [ + 298.74517822265625, + 643.5359497070312, + 1195.21337890625, + 2302.4326171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9115281701087952, + "bbox": [ + 255.140380859375, + 375.18609619140625, + 1216.0118408203125, + 2847.78173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9038777947425842, + "bbox": [ + 284.9263916015625, + 2293.08251953125, + 1032.755615234375, + 2654.053466796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8992204070091248, + "bbox": [ + 1281.1580810546875, + 2612.266357421875, + 2019.0830078125, + 2947.741455078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.868629515171051, + "bbox": [ + 1257.5802001953125, + 399.0816955566406, + 2218.2685546875, + 2938.5888671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8370141983032227, + "bbox": [ + 1290.6041259765625, + 520.753662109375, + 2202.096923828125, + 637.7318725585938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8265472054481506, + "bbox": [ + 282.6708068847656, + 510.51275634765625, + 1186.576416015625, + 632.8124389648438 + ] + } + ], + "timestamp": "2025-10-15T21:43:26.954636" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 52.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 52.json" new file mode 100644 index 0000000..7b2db88 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 52.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 52.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7662975788116455, + "bbox": [ + 1181.9298095703125, + 418.1208190917969, + 1276.76904296875, + 501.273681640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7651606202125549, + "bbox": [ + 238.84234619140625, + 407.6986389160156, + 335.3639831542969, + 493.5775451660156 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7574838399887085, + "bbox": [ + 223.2606964111328, + 2107.860595703125, + 287.1679382324219, + 2182.319091796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6849161386489868, + "bbox": [ + 1732.557861328125, + 1851.436279296875, + 1840.6265869140625, + 1960.90576171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6094217896461487, + "bbox": [ + 743.2024536132812, + 2415.5263671875, + 845.207763671875, + 2527.278076171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5847049951553345, + "bbox": [ + 215.71961975097656, + 2875.9697265625, + 271.43115234375, + 2935.2841796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5225362777709961, + "bbox": [ + 1172.2532958984375, + 816.0643920898438, + 1249.7344970703125, + 903.9634399414062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5047069191932678, + "bbox": [ + 734.7420654296875, + 2405.249755859375, + 859.104248046875, + 2538.71484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9509910941123962, + "bbox": [ + 1173.77685546875, + 591.7689819335938, + 2047.6138916015625, + 1747.31884765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443930387496948, + "bbox": [ + 213.1787872314453, + 630.439208984375, + 1108.1746826171875, + 1928.7957763671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9433186054229736, + "bbox": [ + 189.13523864746094, + 386.7783203125, + 1135.1199951171875, + 2476.931640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9248924255371094, + "bbox": [ + 218.98199462890625, + 1940.9918212890625, + 901.3555908203125, + 2342.6748046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9082744121551514, + "bbox": [ + 1140.8138427734375, + 417.06158447265625, + 2073.177978515625, + 2025.3173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8433235287666321, + "bbox": [ + 228.4076385498047, + 498.2198486328125, + 1108.6871337890625, + 613.7312622070312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.837347149848938, + "bbox": [ + 1190.2017822265625, + 500.0388488769531, + 1798.352294921875, + 584.0289306640625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7662975788116455, + "bbox": [ + 1181.9298095703125, + 418.1208190917969, + 1276.76904296875, + 501.273681640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7651606202125549, + "bbox": [ + 238.84234619140625, + 407.6986389160156, + 335.3639831542969, + 493.5775451660156 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7574838399887085, + "bbox": [ + 223.2606964111328, + 2107.860595703125, + 287.1679382324219, + 2182.319091796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6849161386489868, + "bbox": [ + 1732.557861328125, + 1851.436279296875, + 1840.6265869140625, + 1960.90576171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6094217896461487, + "bbox": [ + 743.2024536132812, + 2415.5263671875, + 845.207763671875, + 2527.278076171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5847049951553345, + "bbox": [ + 215.71961975097656, + 2875.9697265625, + 271.43115234375, + 2935.2841796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5225362777709961, + "bbox": [ + 1172.2532958984375, + 816.0643920898438, + 1249.7344970703125, + 903.9634399414062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5047069191932678, + "bbox": [ + 734.7420654296875, + 2405.249755859375, + 859.104248046875, + 2538.71484375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9509910941123962, + "bbox": [ + 1173.77685546875, + 591.7689819335938, + 2047.6138916015625, + 1747.31884765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443930387496948, + "bbox": [ + 213.1787872314453, + 630.439208984375, + 1108.1746826171875, + 1928.7957763671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9433186054229736, + "bbox": [ + 189.13523864746094, + 386.7783203125, + 1135.1199951171875, + 2476.931640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9248924255371094, + "bbox": [ + 218.98199462890625, + 1940.9918212890625, + 901.3555908203125, + 2342.6748046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9082744121551514, + "bbox": [ + 1140.8138427734375, + 417.06158447265625, + 2073.177978515625, + 2025.3173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8433235287666321, + "bbox": [ + 228.4076385498047, + 498.2198486328125, + 1108.6871337890625, + 613.7312622070312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.837347149848938, + "bbox": [ + 1190.2017822265625, + 500.0388488769531, + 1798.352294921875, + 584.0289306640625 + ] + } + ], + "timestamp": "2025-10-15T21:43:27.317907" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 53.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 53.json" new file mode 100644 index 0000000..e7ad877 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 53.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 53.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7776870727539062, + "bbox": [ + 277.3514099121094, + 422.8056335449219, + 373.1806335449219, + 505.22857666015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7764809727668762, + "bbox": [ + 1245.8756103515625, + 428.1627197265625, + 1339.373291015625, + 511.60601806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6531369090080261, + "bbox": [ + 988.7063598632812, + 2013.277099609375, + 1096.4603271484375, + 2128.322998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6297010183334351, + "bbox": [ + 1668.37646484375, + 1913.3929443359375, + 1791.078125, + 2040.564697265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6178457140922546, + "bbox": [ + 255.87615966796875, + 2175.26318359375, + 329.344970703125, + 2257.562744140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.613615095615387, + "bbox": [ + 1888.4476318359375, + 1227.1279296875, + 1954.6668701171875, + 1306.857177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5705599188804626, + "bbox": [ + 2042.65283203125, + 2990.894287109375, + 2103.212646484375, + 3056.4130859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2275792807340622, + "bbox": [ + 969.3150634765625, + 2005.765625, + 1111.2447509765625, + 2140.613037109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9468862414360046, + "bbox": [ + 254.73191833496094, + 651.42041015625, + 1171.2901611328125, + 1970.5809326171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9387440085411072, + "bbox": [ + 1232.663818359375, + 604.806884765625, + 2129.69091796875, + 1880.404052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9349392652511597, + "bbox": [ + 231.6981658935547, + 448.2294006347656, + 1183.143798828125, + 2386.577392578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9115840792655945, + "bbox": [ + 253.46728515625, + 1999.3887939453125, + 919.6586303710938, + 2396.5888671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.894453763961792, + "bbox": [ + 1214.1220703125, + 443.4949645996094, + 2143.558837890625, + 2030.9503173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8736072182655334, + "bbox": [ + 1241.4033203125, + 511.8125305175781, + 1883.948486328125, + 601.1817016601562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484728932380676, + "bbox": [ + 260.4945068359375, + 510.651123046875, + 1165.119140625, + 633.6161499023438 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7776870727539062, + "bbox": [ + 277.3514099121094, + 422.8056335449219, + 373.1806335449219, + 505.22857666015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7764809727668762, + "bbox": [ + 1245.8756103515625, + 428.1627197265625, + 1339.373291015625, + 511.60601806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6531369090080261, + "bbox": [ + 988.7063598632812, + 2013.277099609375, + 1096.4603271484375, + 2128.322998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6297010183334351, + "bbox": [ + 1668.37646484375, + 1913.3929443359375, + 1791.078125, + 2040.564697265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6178457140922546, + "bbox": [ + 255.87615966796875, + 2175.26318359375, + 329.344970703125, + 2257.562744140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.613615095615387, + "bbox": [ + 1888.4476318359375, + 1227.1279296875, + 1954.6668701171875, + 1306.857177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5705599188804626, + "bbox": [ + 2042.65283203125, + 2990.894287109375, + 2103.212646484375, + 3056.4130859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2275792807340622, + "bbox": [ + 969.3150634765625, + 2005.765625, + 1111.2447509765625, + 2140.613037109375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9468862414360046, + "bbox": [ + 254.73191833496094, + 651.42041015625, + 1171.2901611328125, + 1970.5809326171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9387440085411072, + "bbox": [ + 1232.663818359375, + 604.806884765625, + 2129.69091796875, + 1880.404052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9349392652511597, + "bbox": [ + 231.6981658935547, + 448.2294006347656, + 1183.143798828125, + 2386.577392578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9115840792655945, + "bbox": [ + 253.46728515625, + 1999.3887939453125, + 919.6586303710938, + 2396.5888671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.894453763961792, + "bbox": [ + 1214.1220703125, + 443.4949645996094, + 2143.558837890625, + 2030.9503173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8736072182655334, + "bbox": [ + 1241.4033203125, + 511.8125305175781, + 1883.948486328125, + 601.1817016601562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484728932380676, + "bbox": [ + 260.4945068359375, + 510.651123046875, + 1165.119140625, + 633.6161499023438 + ] + } + ], + "timestamp": "2025-10-15T21:43:27.673320" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 54.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 54.json" new file mode 100644 index 0000000..f3685b5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 54.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 54.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.78201824426651, + "bbox": [ + 1323.244140625, + 474.7957458496094, + 1431.791259765625, + 566.0184936523438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.774132490158081, + "bbox": [ + 246.69383239746094, + 453.9662780761719, + 353.6776123046875, + 549.9122314453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7423201203346252, + "bbox": [ + 799.26220703125, + 617.6736450195312, + 907.159423828125, + 714.4849853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7159913778305054, + "bbox": [ + 1876.692138671875, + 658.9224853515625, + 2003.4940185546875, + 770.1031494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7040601968765259, + "bbox": [ + 523.4143676757812, + 900.336181640625, + 595.6331176757812, + 989.3965454101562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5410500764846802, + "bbox": [ + 227.0045623779297, + 3252.660888671875, + 288.62469482421875, + 3322.428466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5295572876930237, + "bbox": [ + 1301.65087890625, + 2471.95703125, + 1387.244384765625, + 2562.998291015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443438053131104, + "bbox": [ + 1322.0054931640625, + 696.43115234375, + 2322.208251953125, + 2377.401123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9438110589981079, + "bbox": [ + 216.12615966796875, + 690.2120971679688, + 1230.273193359375, + 2503.69677734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9435372948646545, + "bbox": [ + 1303.927734375, + 438.7765808105469, + 2339.639892578125, + 2850.604248046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9357724785804749, + "bbox": [ + 212.17478942871094, + 468.6466064453125, + 1238.067626953125, + 2528.662109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9306666851043701, + "bbox": [ + 1298.1627197265625, + 2344.998291015625, + 2269.142333984375, + 2783.48291015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8393926620483398, + "bbox": [ + 1309.0, + 568.8095092773438, + 2318.184326171875, + 701.3134765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8303240537643433, + "bbox": [ + 254.0231170654297, + 559.037353515625, + 1235.6661376953125, + 690.0201416015625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.78201824426651, + "bbox": [ + 1323.244140625, + 474.7957458496094, + 1431.791259765625, + 566.0184936523438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.774132490158081, + "bbox": [ + 246.69383239746094, + 453.9662780761719, + 353.6776123046875, + 549.9122314453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7423201203346252, + "bbox": [ + 799.26220703125, + 617.6736450195312, + 907.159423828125, + 714.4849853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7159913778305054, + "bbox": [ + 1876.692138671875, + 658.9224853515625, + 2003.4940185546875, + 770.1031494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7040601968765259, + "bbox": [ + 523.4143676757812, + 900.336181640625, + 595.6331176757812, + 989.3965454101562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5410500764846802, + "bbox": [ + 227.0045623779297, + 3252.660888671875, + 288.62469482421875, + 3322.428466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5295572876930237, + "bbox": [ + 1301.65087890625, + 2471.95703125, + 1387.244384765625, + 2562.998291015625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443438053131104, + "bbox": [ + 1322.0054931640625, + 696.43115234375, + 2322.208251953125, + 2377.401123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9438110589981079, + "bbox": [ + 216.12615966796875, + 690.2120971679688, + 1230.273193359375, + 2503.69677734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9435372948646545, + "bbox": [ + 1303.927734375, + 438.7765808105469, + 2339.639892578125, + 2850.604248046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9357724785804749, + "bbox": [ + 212.17478942871094, + 468.6466064453125, + 1238.067626953125, + 2528.662109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9306666851043701, + "bbox": [ + 1298.1627197265625, + 2344.998291015625, + 2269.142333984375, + 2783.48291015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8393926620483398, + "bbox": [ + 1309.0, + 568.8095092773438, + 2318.184326171875, + 701.3134765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8303240537643433, + "bbox": [ + 254.0231170654297, + 559.037353515625, + 1235.6661376953125, + 690.0201416015625 + ] + } + ], + "timestamp": "2025-10-15T21:43:28.047778" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 55.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 55.json" new file mode 100644 index 0000000..ea5d485 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 55.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 55.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7716618776321411, + "bbox": [ + 1290.8358154296875, + 449.0101013183594, + 1392.3846435546875, + 535.672119140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7703613638877869, + "bbox": [ + 276.9950256347656, + 429.8171691894531, + 377.5768737792969, + 518.9830322265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6826803088188171, + "bbox": [ + 1799.977783203125, + 2197.838623046875, + 1901.07568359375, + 2296.591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6612007021903992, + "bbox": [ + 619.1699829101562, + 2325.635009765625, + 724.9519653320312, + 2440.180419921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6169714331626892, + "bbox": [ + 338.88677978515625, + 1777.6578369140625, + 414.3040771484375, + 1868.0682373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5182663798332214, + "bbox": [ + 1275.2696533203125, + 2479.123779296875, + 1329.752197265625, + 2550.365234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4906849265098572, + "bbox": [ + 2133.081298828125, + 3114.877685546875, + 2195.68408203125, + 3183.533447265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.38651373982429504, + "bbox": [ + 601.76611328125, + 2316.23486328125, + 734.6893310546875, + 2450.95556640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9537068605422974, + "bbox": [ + 1273.3426513671875, + 682.309326171875, + 2215.9482421875, + 2279.011962890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9388247728347778, + "bbox": [ + 276.10015869140625, + 660.271484375, + 1216.425048828125, + 2213.355712890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9375671148300171, + "bbox": [ + 253.34909057617188, + 452.5361022949219, + 1233.920166015625, + 2542.4716796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9307223558425903, + "bbox": [ + 1254.3526611328125, + 411.3973388671875, + 2227.123291015625, + 2747.972412109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9237676858901978, + "bbox": [ + 1290.911865234375, + 2287.94189453125, + 2178.74853515625, + 2726.447509765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8570380806922913, + "bbox": [ + 1277.110595703125, + 540.9954833984375, + 2232.50244140625, + 670.0107421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.851348876953125, + "bbox": [ + 280.9107360839844, + 523.6336059570312, + 1201.949462890625, + 655.3038940429688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7716618776321411, + "bbox": [ + 1290.8358154296875, + 449.0101013183594, + 1392.3846435546875, + 535.672119140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7703613638877869, + "bbox": [ + 276.9950256347656, + 429.8171691894531, + 377.5768737792969, + 518.9830322265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6826803088188171, + "bbox": [ + 1799.977783203125, + 2197.838623046875, + 1901.07568359375, + 2296.591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6612007021903992, + "bbox": [ + 619.1699829101562, + 2325.635009765625, + 724.9519653320312, + 2440.180419921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6169714331626892, + "bbox": [ + 338.88677978515625, + 1777.6578369140625, + 414.3040771484375, + 1868.0682373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5182663798332214, + "bbox": [ + 1275.2696533203125, + 2479.123779296875, + 1329.752197265625, + 2550.365234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4906849265098572, + "bbox": [ + 2133.081298828125, + 3114.877685546875, + 2195.68408203125, + 3183.533447265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.38651373982429504, + "bbox": [ + 601.76611328125, + 2316.23486328125, + 734.6893310546875, + 2450.95556640625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9537068605422974, + "bbox": [ + 1273.3426513671875, + 682.309326171875, + 2215.9482421875, + 2279.011962890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9388247728347778, + "bbox": [ + 276.10015869140625, + 660.271484375, + 1216.425048828125, + 2213.355712890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9375671148300171, + "bbox": [ + 253.34909057617188, + 452.5361022949219, + 1233.920166015625, + 2542.4716796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9307223558425903, + "bbox": [ + 1254.3526611328125, + 411.3973388671875, + 2227.123291015625, + 2747.972412109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9237676858901978, + "bbox": [ + 1290.911865234375, + 2287.94189453125, + 2178.74853515625, + 2726.447509765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8570380806922913, + "bbox": [ + 1277.110595703125, + 540.9954833984375, + 2232.50244140625, + 670.0107421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.851348876953125, + "bbox": [ + 280.9107360839844, + 523.6336059570312, + 1201.949462890625, + 655.3038940429688 + ] + } + ], + "timestamp": "2025-10-15T21:43:28.480345" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 56.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 56.json" new file mode 100644 index 0000000..316a33c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 56.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 56.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7878429293632507, + "bbox": [ + 1248.7259521484375, + 437.1191711425781, + 1351.6226806640625, + 523.3489379882812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7821791768074036, + "bbox": [ + 241.67250061035156, + 424.4669189453125, + 342.28466796875, + 514.49755859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7327080368995667, + "bbox": [ + 723.5433349609375, + 1790.8006591796875, + 825.8709716796875, + 1898.12939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.694329023361206, + "bbox": [ + 231.88723754882812, + 1950.0643310546875, + 299.7809143066406, + 2027.8167724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6586117744445801, + "bbox": [ + 1860.229736328125, + 2234.301513671875, + 1989.147705078125, + 2381.00146484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.524495542049408, + "bbox": [ + 222.86643981933594, + 3078.16650390625, + 281.7267150878906, + 3146.27880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.39756831526756287, + "bbox": [ + 1232.576171875, + 2486.002685546875, + 1293.6368408203125, + 2562.329345703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3281264901161194, + "bbox": [ + 1229.134521484375, + 2476.947265625, + 1304.47021484375, + 2569.721435546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9559857845306396, + "bbox": [ + 230.9691162109375, + 592.2944946289062, + 1177.403564453125, + 1788.7237548828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9303390979766846, + "bbox": [ + 179.50743103027344, + 410.19921875, + 1200.6910400390625, + 2228.29736328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9294762015342712, + "bbox": [ + 1233.1446533203125, + 591.7938842773438, + 2190.725341796875, + 2258.859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9186832308769226, + "bbox": [ + 1234.328125, + 354.5795593261719, + 2237.955810546875, + 2740.6298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8996248841285706, + "bbox": [ + 1226.0301513671875, + 2292.518798828125, + 1764.616943359375, + 2654.072021484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8648650646209717, + "bbox": [ + 1240.8758544921875, + 526.3724365234375, + 1903.0428466796875, + 619.2955322265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8390024304389954, + "bbox": [ + 227.57862854003906, + 1813.0103759765625, + 553.6353759765625, + 2178.764404296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8256607055664062, + "bbox": [ + 241.5628662109375, + 513.5860595703125, + 866.1226196289062, + 599.595703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7878429293632507, + "bbox": [ + 1248.7259521484375, + 437.1191711425781, + 1351.6226806640625, + 523.3489379882812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7821791768074036, + "bbox": [ + 241.67250061035156, + 424.4669189453125, + 342.28466796875, + 514.49755859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7327080368995667, + "bbox": [ + 723.5433349609375, + 1790.8006591796875, + 825.8709716796875, + 1898.12939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.694329023361206, + "bbox": [ + 231.88723754882812, + 1950.0643310546875, + 299.7809143066406, + 2027.8167724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6586117744445801, + "bbox": [ + 1860.229736328125, + 2234.301513671875, + 1989.147705078125, + 2381.00146484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.524495542049408, + "bbox": [ + 222.86643981933594, + 3078.16650390625, + 281.7267150878906, + 3146.27880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.39756831526756287, + "bbox": [ + 1232.576171875, + 2486.002685546875, + 1293.6368408203125, + 2562.329345703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3281264901161194, + "bbox": [ + 1229.134521484375, + 2476.947265625, + 1304.47021484375, + 2569.721435546875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9559857845306396, + "bbox": [ + 230.9691162109375, + 592.2944946289062, + 1177.403564453125, + 1788.7237548828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9303390979766846, + "bbox": [ + 179.50743103027344, + 410.19921875, + 1200.6910400390625, + 2228.29736328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9294762015342712, + "bbox": [ + 1233.1446533203125, + 591.7938842773438, + 2190.725341796875, + 2258.859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9186832308769226, + "bbox": [ + 1234.328125, + 354.5795593261719, + 2237.955810546875, + 2740.6298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8996248841285706, + "bbox": [ + 1226.0301513671875, + 2292.518798828125, + 1764.616943359375, + 2654.072021484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8648650646209717, + "bbox": [ + 1240.8758544921875, + 526.3724365234375, + 1903.0428466796875, + 619.2955322265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8390024304389954, + "bbox": [ + 227.57862854003906, + 1813.0103759765625, + 553.6353759765625, + 2178.764404296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8256607055664062, + "bbox": [ + 241.5628662109375, + 513.5860595703125, + 866.1226196289062, + 599.595703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:28.898973" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 57.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 57.json" new file mode 100644 index 0000000..1b65ee7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 57.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 57.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7989176511764526, + "bbox": [ + 1220.1295166015625, + 429.2672119140625, + 1317.8433837890625, + 511.6912841796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7820753455162048, + "bbox": [ + 236.31141662597656, + 417.27532958984375, + 334.7438049316406, + 505.7097473144531 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7176951766014099, + "bbox": [ + 708.0447998046875, + 1755.4969482421875, + 808.021728515625, + 1860.3759765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7151309251785278, + "bbox": [ + 223.87400817871094, + 1910.3243408203125, + 291.10919189453125, + 1984.423583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6792254447937012, + "bbox": [ + 1813.1103515625, + 2186.65283203125, + 1947.3204345703125, + 2337.239990234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5823143124580383, + "bbox": [ + 212.9134521484375, + 3017.1640625, + 273.11590576171875, + 3083.5830078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.36342400312423706, + "bbox": [ + 1202.8487548828125, + 2428.09814453125, + 1274.7177734375, + 2512.600830078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9415574073791504, + "bbox": [ + 1202.479736328125, + 392.7911376953125, + 2167.0263671875, + 2653.431396484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9382830262184143, + "bbox": [ + 1209.230712890625, + 606.1560668945312, + 2140.428955078125, + 2214.660400390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9305949211120605, + "bbox": [ + 225.9620361328125, + 593.6521606445312, + 1141.7423095703125, + 1782.2159423828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9149758219718933, + "bbox": [ + 203.42527770996094, + 395.560791015625, + 1168.6373291015625, + 2161.176025390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.89565509557724, + "bbox": [ + 1210.9478759765625, + 2246.781005859375, + 1716.321044921875, + 2591.256591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8707748651504517, + "bbox": [ + 217.12245178222656, + 1778.7451171875, + 522.7432861328125, + 2132.5419921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484314680099487, + "bbox": [ + 1216.23291015625, + 517.83544921875, + 1842.0045166015625, + 604.8806762695312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8041062951087952, + "bbox": [ + 237.7939453125, + 513.2341918945312, + 842.8491821289062, + 588.991455078125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7989176511764526, + "bbox": [ + 1220.1295166015625, + 429.2672119140625, + 1317.8433837890625, + 511.6912841796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7820753455162048, + "bbox": [ + 236.31141662597656, + 417.27532958984375, + 334.7438049316406, + 505.7097473144531 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7176951766014099, + "bbox": [ + 708.0447998046875, + 1755.4969482421875, + 808.021728515625, + 1860.3759765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7151309251785278, + "bbox": [ + 223.87400817871094, + 1910.3243408203125, + 291.10919189453125, + 1984.423583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6792254447937012, + "bbox": [ + 1813.1103515625, + 2186.65283203125, + 1947.3204345703125, + 2337.239990234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5823143124580383, + "bbox": [ + 212.9134521484375, + 3017.1640625, + 273.11590576171875, + 3083.5830078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.36342400312423706, + "bbox": [ + 1202.8487548828125, + 2428.09814453125, + 1274.7177734375, + 2512.600830078125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9415574073791504, + "bbox": [ + 1202.479736328125, + 392.7911376953125, + 2167.0263671875, + 2653.431396484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9382830262184143, + "bbox": [ + 1209.230712890625, + 606.1560668945312, + 2140.428955078125, + 2214.660400390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9305949211120605, + "bbox": [ + 225.9620361328125, + 593.6521606445312, + 1141.7423095703125, + 1782.2159423828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9149758219718933, + "bbox": [ + 203.42527770996094, + 395.560791015625, + 1168.6373291015625, + 2161.176025390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.89565509557724, + "bbox": [ + 1210.9478759765625, + 2246.781005859375, + 1716.321044921875, + 2591.256591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8707748651504517, + "bbox": [ + 217.12245178222656, + 1778.7451171875, + 522.7432861328125, + 2132.5419921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484314680099487, + "bbox": [ + 1216.23291015625, + 517.83544921875, + 1842.0045166015625, + 604.8806762695312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8041062951087952, + "bbox": [ + 237.7939453125, + 513.2341918945312, + 842.8491821289062, + 588.991455078125 + ] + } + ], + "timestamp": "2025-10-15T21:43:29.310931" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 58.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 58.json" new file mode 100644 index 0000000..207936f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 58.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 58.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7775489091873169, + "bbox": [ + 283.4914245605469, + 432.0616149902344, + 383.5087585449219, + 518.190185546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7605919241905212, + "bbox": [ + 1301.0791015625, + 442.8301086425781, + 1402.9942626953125, + 530.723876953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6965488791465759, + "bbox": [ + 262.5986328125, + 2475.431884765625, + 330.7027282714844, + 2555.975341796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6868824362754822, + "bbox": [ + 724.7388305664062, + 2361.657470703125, + 845.6329956054688, + 2493.726806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6458823680877686, + "bbox": [ + 2203.141845703125, + 2297.3681640625, + 2348.8603515625, + 2422.44677734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6028180718421936, + "bbox": [ + 1276.532470703125, + 2838.206298828125, + 1364.6307373046875, + 2941.10400390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5103561282157898, + "bbox": [ + 2153.340576171875, + 3163.132080078125, + 2219.638427734375, + 3233.67333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9578820466995239, + "bbox": [ + 229.01243591308594, + 406.07928466796875, + 1243.682861328125, + 2788.1640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.952389121055603, + "bbox": [ + 251.50709533691406, + 610.8395385742188, + 1210.37548828125, + 2336.5439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9346904158592224, + "bbox": [ + 1276.5509033203125, + 2416.17138671875, + 2234.60546875, + 3014.2451171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9226248264312744, + "bbox": [ + 1266.4962158203125, + 611.1201171875, + 2245.092529296875, + 2383.645751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8897944092750549, + "bbox": [ + 279.4750061035156, + 524.4847412109375, + 930.296630859375, + 615.3002319335938 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8862763047218323, + "bbox": [ + 1254.6156005859375, + 486.2048645019531, + 2249.841064453125, + 3103.45556640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8743375539779663, + "bbox": [ + 1297.4068603515625, + 532.4794921875, + 1939.033935546875, + 618.0802612304688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8339842557907104, + "bbox": [ + 254.16476440429688, + 2343.462646484375, + 542.8796997070312, + 2701.673095703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7775489091873169, + "bbox": [ + 283.4914245605469, + 432.0616149902344, + 383.5087585449219, + 518.190185546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7605919241905212, + "bbox": [ + 1301.0791015625, + 442.8301086425781, + 1402.9942626953125, + 530.723876953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6965488791465759, + "bbox": [ + 262.5986328125, + 2475.431884765625, + 330.7027282714844, + 2555.975341796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6868824362754822, + "bbox": [ + 724.7388305664062, + 2361.657470703125, + 845.6329956054688, + 2493.726806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6458823680877686, + "bbox": [ + 2203.141845703125, + 2297.3681640625, + 2348.8603515625, + 2422.44677734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6028180718421936, + "bbox": [ + 1276.532470703125, + 2838.206298828125, + 1364.6307373046875, + 2941.10400390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5103561282157898, + "bbox": [ + 2153.340576171875, + 3163.132080078125, + 2219.638427734375, + 3233.67333984375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9578820466995239, + "bbox": [ + 229.01243591308594, + 406.07928466796875, + 1243.682861328125, + 2788.1640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.952389121055603, + "bbox": [ + 251.50709533691406, + 610.8395385742188, + 1210.37548828125, + 2336.5439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9346904158592224, + "bbox": [ + 1276.5509033203125, + 2416.17138671875, + 2234.60546875, + 3014.2451171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9226248264312744, + "bbox": [ + 1266.4962158203125, + 611.1201171875, + 2245.092529296875, + 2383.645751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8897944092750549, + "bbox": [ + 279.4750061035156, + 524.4847412109375, + 930.296630859375, + 615.3002319335938 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8862763047218323, + "bbox": [ + 1254.6156005859375, + 486.2048645019531, + 2249.841064453125, + 3103.45556640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8743375539779663, + "bbox": [ + 1297.4068603515625, + 532.4794921875, + 1939.033935546875, + 618.0802612304688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8339842557907104, + "bbox": [ + 254.16476440429688, + 2343.462646484375, + 542.8796997070312, + 2701.673095703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:29.745991" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 59.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 59.json" new file mode 100644 index 0000000..bbc67ac --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 59.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 59.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7862241268157959, + "bbox": [ + 1264.2506103515625, + 454.3207092285156, + 1367.503662109375, + 544.4924926757812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7760095596313477, + "bbox": [ + 241.83816528320312, + 441.433837890625, + 343.9618835449219, + 534.6007690429688 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7582188844680786, + "bbox": [ + 1246.122314453125, + 2423.9287109375, + 1313.342529296875, + 2501.473876953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7144309878349304, + "bbox": [ + 224.2533721923828, + 1950.4068603515625, + 300.8932189941406, + 2032.30859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6773825287818909, + "bbox": [ + 1802.351318359375, + 2635.589599609375, + 1923.245361328125, + 2756.16357421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6628341674804688, + "bbox": [ + 608.6179809570312, + 2327.087890625, + 723.0242919921875, + 2447.62646484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4307290315628052, + "bbox": [ + 210.0298614501953, + 3170.98681640625, + 273.76123046875, + 3241.570556640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.24180661141872406, + "bbox": [ + 1788.208984375, + 2627.4677734375, + 1941.4024658203125, + 2770.5634765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9543498158454895, + "bbox": [ + 1246.0457763671875, + 644.0110473632812, + 2190.347412109375, + 2219.230224609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9428220987319946, + "bbox": [ + 201.65757751464844, + 427.23614501953125, + 1203.2548828125, + 2432.7685546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9341171383857727, + "bbox": [ + 1242.8604736328125, + 403.46417236328125, + 2236.38720703125, + 2719.28955078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9323497414588928, + "bbox": [ + 245.5540008544922, + 630.1744995117188, + 1183.1478271484375, + 1887.114501953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9056631326675415, + "bbox": [ + 209.8916015625, + 1885.2369384765625, + 1174.9736328125, + 2245.2138671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8951770067214966, + "bbox": [ + 1248.7861328125, + 2223.74853515625, + 2057.235107421875, + 2581.74658203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8633673787117004, + "bbox": [ + 1260.9390869140625, + 547.5243530273438, + 1886.015625, + 634.9281005859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8011807203292847, + "bbox": [ + 245.7655487060547, + 539.2646484375, + 879.9325561523438, + 617.9425659179688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7862241268157959, + "bbox": [ + 1264.2506103515625, + 454.3207092285156, + 1367.503662109375, + 544.4924926757812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7760095596313477, + "bbox": [ + 241.83816528320312, + 441.433837890625, + 343.9618835449219, + 534.6007690429688 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7582188844680786, + "bbox": [ + 1246.122314453125, + 2423.9287109375, + 1313.342529296875, + 2501.473876953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7144309878349304, + "bbox": [ + 224.2533721923828, + 1950.4068603515625, + 300.8932189941406, + 2032.30859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6773825287818909, + "bbox": [ + 1802.351318359375, + 2635.589599609375, + 1923.245361328125, + 2756.16357421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6628341674804688, + "bbox": [ + 608.6179809570312, + 2327.087890625, + 723.0242919921875, + 2447.62646484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4307290315628052, + "bbox": [ + 210.0298614501953, + 3170.98681640625, + 273.76123046875, + 3241.570556640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.24180661141872406, + "bbox": [ + 1788.208984375, + 2627.4677734375, + 1941.4024658203125, + 2770.5634765625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9543498158454895, + "bbox": [ + 1246.0457763671875, + 644.0110473632812, + 2190.347412109375, + 2219.230224609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9428220987319946, + "bbox": [ + 201.65757751464844, + 427.23614501953125, + 1203.2548828125, + 2432.7685546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9341171383857727, + "bbox": [ + 1242.8604736328125, + 403.46417236328125, + 2236.38720703125, + 2719.28955078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9323497414588928, + "bbox": [ + 245.5540008544922, + 630.1744995117188, + 1183.1478271484375, + 1887.114501953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9056631326675415, + "bbox": [ + 209.8916015625, + 1885.2369384765625, + 1174.9736328125, + 2245.2138671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8951770067214966, + "bbox": [ + 1248.7861328125, + 2223.74853515625, + 2057.235107421875, + 2581.74658203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8633673787117004, + "bbox": [ + 1260.9390869140625, + 547.5243530273438, + 1886.015625, + 634.9281005859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8011807203292847, + "bbox": [ + 245.7655487060547, + 539.2646484375, + 879.9325561523438, + 617.9425659179688 + ] + } + ], + "timestamp": "2025-10-15T21:43:30.193247" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 60.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 60.json" new file mode 100644 index 0000000..75c1ad0 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 60.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 60.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7968915700912476, + "bbox": [ + 1215.6051025390625, + 422.79266357421875, + 1307.812255859375, + 505.1455993652344 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7706426382064819, + "bbox": [ + 256.1319274902344, + 415.9372253417969, + 353.700439453125, + 499.3877868652344 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7501000165939331, + "bbox": [ + 243.63853454589844, + 1960.4239501953125, + 310.301025390625, + 2031.8936767578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6988071799278259, + "bbox": [ + 577.8882446289062, + 2148.407958984375, + 684.1600952148438, + 2255.4853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6069499850273132, + "bbox": [ + 1673.6468505859375, + 2165.28125, + 1800.089111328125, + 2295.8349609375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5202502012252808, + "bbox": [ + 2020.4412841796875, + 2978.691650390625, + 2085.712890625, + 3046.674072265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5010879039764404, + "bbox": [ + 1202.388916015625, + 1765.6617431640625, + 1271.9085693359375, + 1842.583740234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2247111201286316, + "bbox": [ + 1201.8585205078125, + 1756.16162109375, + 1286.620361328125, + 1846.510009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9502419829368591, + "bbox": [ + 245.2679443359375, + 590.2755126953125, + 1136.9891357421875, + 1776.190673828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.943726658821106, + "bbox": [ + 1186.5726318359375, + 417.40478515625, + 2117.782470703125, + 2242.03857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9392086863517761, + "bbox": [ + 1203.2076416015625, + 591.4410400390625, + 2096.302490234375, + 1752.8184814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9381285905838013, + "bbox": [ + 211.78260803222656, + 399.54815673828125, + 1159.265869140625, + 2218.43896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9160510301589966, + "bbox": [ + 1196.935302734375, + 1763.1705322265625, + 2094.54736328125, + 2122.0947265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9103603363037109, + "bbox": [ + 243.33094787597656, + 1768.634033203125, + 1125.4525146484375, + 2103.57177734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8633698225021362, + "bbox": [ + 1212.046630859375, + 510.5813903808594, + 1820.756103515625, + 589.9862060546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8333650827407837, + "bbox": [ + 252.84190368652344, + 499.13507080078125, + 858.7269287109375, + 590.0230102539062 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7968915700912476, + "bbox": [ + 1215.6051025390625, + 422.79266357421875, + 1307.812255859375, + 505.1455993652344 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7706426382064819, + "bbox": [ + 256.1319274902344, + 415.9372253417969, + 353.700439453125, + 499.3877868652344 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7501000165939331, + "bbox": [ + 243.63853454589844, + 1960.4239501953125, + 310.301025390625, + 2031.8936767578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6988071799278259, + "bbox": [ + 577.8882446289062, + 2148.407958984375, + 684.1600952148438, + 2255.4853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6069499850273132, + "bbox": [ + 1673.6468505859375, + 2165.28125, + 1800.089111328125, + 2295.8349609375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5202502012252808, + "bbox": [ + 2020.4412841796875, + 2978.691650390625, + 2085.712890625, + 3046.674072265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5010879039764404, + "bbox": [ + 1202.388916015625, + 1765.6617431640625, + 1271.9085693359375, + 1842.583740234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2247111201286316, + "bbox": [ + 1201.8585205078125, + 1756.16162109375, + 1286.620361328125, + 1846.510009765625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9502419829368591, + "bbox": [ + 245.2679443359375, + 590.2755126953125, + 1136.9891357421875, + 1776.190673828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.943726658821106, + "bbox": [ + 1186.5726318359375, + 417.40478515625, + 2117.782470703125, + 2242.03857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9392086863517761, + "bbox": [ + 1203.2076416015625, + 591.4410400390625, + 2096.302490234375, + 1752.8184814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9381285905838013, + "bbox": [ + 211.78260803222656, + 399.54815673828125, + 1159.265869140625, + 2218.43896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9160510301589966, + "bbox": [ + 1196.935302734375, + 1763.1705322265625, + 2094.54736328125, + 2122.0947265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9103603363037109, + "bbox": [ + 243.33094787597656, + 1768.634033203125, + 1125.4525146484375, + 2103.57177734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8633698225021362, + "bbox": [ + 1212.046630859375, + 510.5813903808594, + 1820.756103515625, + 589.9862060546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8333650827407837, + "bbox": [ + 252.84190368652344, + 499.13507080078125, + 858.7269287109375, + 590.0230102539062 + ] + } + ], + "timestamp": "2025-10-15T21:43:30.627357" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 61.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 61.json" new file mode 100644 index 0000000..226fff9 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 61.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 61.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7867382168769836, + "bbox": [ + 276.9656677246094, + 441.0323181152344, + 379.5300598144531, + 533.2345581054688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7688069343566895, + "bbox": [ + 1313.3463134765625, + 456.1064147949219, + 1421.037353515625, + 546.5509033203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7168067097663879, + "bbox": [ + 238.0077667236328, + 2140.5302734375, + 303.7331848144531, + 2219.7919921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7016903162002563, + "bbox": [ + 687.37158203125, + 2272.18701171875, + 793.736328125, + 2388.3330078125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6155722737312317, + "bbox": [ + 200.73997497558594, + 3177.150390625, + 265.0934143066406, + 3246.44189453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6128831505775452, + "bbox": [ + 1836.9141845703125, + 2757.261962890625, + 1968.0587158203125, + 2883.87939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5308651924133301, + "bbox": [ + 1282.7900390625, + 2196.515380859375, + 1366.3348388671875, + 2300.1376953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9445486068725586, + "bbox": [ + 187.9001007080078, + 447.28253173828125, + 1232.50439453125, + 2355.262451171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9347812533378601, + "bbox": [ + 1276.6390380859375, + 2087.102294921875, + 2260.723388671875, + 2760.3486328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9341485500335693, + "bbox": [ + 235.21253967285156, + 677.480224609375, + 1233.281494140625, + 1828.9210205078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.928979218006134, + "bbox": [ + 1312.326171875, + 692.3761596679688, + 2287.13427734375, + 2047.3121337890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9027610421180725, + "bbox": [ + 1276.2777099609375, + 394.28436279296875, + 2318.14013671875, + 2823.1943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8787819147109985, + "bbox": [ + 244.66494750976562, + 1876.39306640625, + 1156.3612060546875, + 2225.802001953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.868323802947998, + "bbox": [ + 1320.1383056640625, + 557.8253784179688, + 2283.69921875, + 678.583984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8439749479293823, + "bbox": [ + 254.7745361328125, + 532.6582641601562, + 1239.684814453125, + 670.7265625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7867382168769836, + "bbox": [ + 276.9656677246094, + 441.0323181152344, + 379.5300598144531, + 533.2345581054688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7688069343566895, + "bbox": [ + 1313.3463134765625, + 456.1064147949219, + 1421.037353515625, + 546.5509033203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7168067097663879, + "bbox": [ + 238.0077667236328, + 2140.5302734375, + 303.7331848144531, + 2219.7919921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7016903162002563, + "bbox": [ + 687.37158203125, + 2272.18701171875, + 793.736328125, + 2388.3330078125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6155722737312317, + "bbox": [ + 200.73997497558594, + 3177.150390625, + 265.0934143066406, + 3246.44189453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6128831505775452, + "bbox": [ + 1836.9141845703125, + 2757.261962890625, + 1968.0587158203125, + 2883.87939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5308651924133301, + "bbox": [ + 1282.7900390625, + 2196.515380859375, + 1366.3348388671875, + 2300.1376953125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9445486068725586, + "bbox": [ + 187.9001007080078, + 447.28253173828125, + 1232.50439453125, + 2355.262451171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9347812533378601, + "bbox": [ + 1276.6390380859375, + 2087.102294921875, + 2260.723388671875, + 2760.3486328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9341485500335693, + "bbox": [ + 235.21253967285156, + 677.480224609375, + 1233.281494140625, + 1828.9210205078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.928979218006134, + "bbox": [ + 1312.326171875, + 692.3761596679688, + 2287.13427734375, + 2047.3121337890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9027610421180725, + "bbox": [ + 1276.2777099609375, + 394.28436279296875, + 2318.14013671875, + 2823.1943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8787819147109985, + "bbox": [ + 244.66494750976562, + 1876.39306640625, + 1156.3612060546875, + 2225.802001953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.868323802947998, + "bbox": [ + 1320.1383056640625, + 557.8253784179688, + 2283.69921875, + 678.583984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8439749479293823, + "bbox": [ + 254.7745361328125, + 532.6582641601562, + 1239.684814453125, + 670.7265625 + ] + } + ], + "timestamp": "2025-10-15T21:43:31.051602" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 62.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 62.json" new file mode 100644 index 0000000..f4a6588 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 62.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 62.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7847425937652588, + "bbox": [ + 1283.482421875, + 434.8128662109375, + 1381.0645751953125, + 520.3748779296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7667604684829712, + "bbox": [ + 289.5599365234375, + 430.19036865234375, + 388.3841247558594, + 515.5416259765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6667987704277039, + "bbox": [ + 739.6033935546875, + 2669.900634765625, + 853.4111328125, + 2792.088134765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6355686187744141, + "bbox": [ + 1950.318115234375, + 2778.0537109375, + 2067.4013671875, + 2889.158935546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5416995882987976, + "bbox": [ + 2126.7255859375, + 3047.6962890625, + 2188.78173828125, + 3114.974853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5360406041145325, + "bbox": [ + 1271.8721923828125, + 2225.41455078125, + 1365.6734619140625, + 2342.993408203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5064846277236938, + "bbox": [ + 276.5186767578125, + 2478.424560546875, + 342.6667785644531, + 2573.746826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9515276551246643, + "bbox": [ + 1278.9449462890625, + 598.5579833984375, + 2209.611572265625, + 2104.07275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9478847980499268, + "bbox": [ + 1268.4285888671875, + 2140.723876953125, + 2195.18017578125, + 2771.830078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9465190172195435, + "bbox": [ + 271.6744079589844, + 2009.560791015625, + 1196.7437744140625, + 2639.562255859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9302257299423218, + "bbox": [ + 275.0104064941406, + 618.824951171875, + 1207.1348876953125, + 1994.101318359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9264856576919556, + "bbox": [ + 1251.2647705078125, + 374.88958740234375, + 2225.71337890625, + 2851.305419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9257607460021973, + "bbox": [ + 266.25921630859375, + 403.2320251464844, + 1226.078857421875, + 2711.920166015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7191731333732605, + "bbox": [ + 1292.204345703125, + 533.15234375, + 2148.95556640625, + 594.5885009765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6890917420387268, + "bbox": [ + 282.1640319824219, + 521.0567626953125, + 1172.987548828125, + 587.5680541992188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7847425937652588, + "bbox": [ + 1283.482421875, + 434.8128662109375, + 1381.0645751953125, + 520.3748779296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7667604684829712, + "bbox": [ + 289.5599365234375, + 430.19036865234375, + 388.3841247558594, + 515.5416259765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6667987704277039, + "bbox": [ + 739.6033935546875, + 2669.900634765625, + 853.4111328125, + 2792.088134765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6355686187744141, + "bbox": [ + 1950.318115234375, + 2778.0537109375, + 2067.4013671875, + 2889.158935546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5416995882987976, + "bbox": [ + 2126.7255859375, + 3047.6962890625, + 2188.78173828125, + 3114.974853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5360406041145325, + "bbox": [ + 1271.8721923828125, + 2225.41455078125, + 1365.6734619140625, + 2342.993408203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5064846277236938, + "bbox": [ + 276.5186767578125, + 2478.424560546875, + 342.6667785644531, + 2573.746826171875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9515276551246643, + "bbox": [ + 1278.9449462890625, + 598.5579833984375, + 2209.611572265625, + 2104.07275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9478847980499268, + "bbox": [ + 1268.4285888671875, + 2140.723876953125, + 2195.18017578125, + 2771.830078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9465190172195435, + "bbox": [ + 271.6744079589844, + 2009.560791015625, + 1196.7437744140625, + 2639.562255859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9302257299423218, + "bbox": [ + 275.0104064941406, + 618.824951171875, + 1207.1348876953125, + 1994.101318359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9264856576919556, + "bbox": [ + 1251.2647705078125, + 374.88958740234375, + 2225.71337890625, + 2851.305419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9257607460021973, + "bbox": [ + 266.25921630859375, + 403.2320251464844, + 1226.078857421875, + 2711.920166015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7191731333732605, + "bbox": [ + 1292.204345703125, + 533.15234375, + 2148.95556640625, + 594.5885009765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6890917420387268, + "bbox": [ + 282.1640319824219, + 521.0567626953125, + 1172.987548828125, + 587.5680541992188 + ] + } + ], + "timestamp": "2025-10-15T21:43:31.485487" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 63.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 63.json" new file mode 100644 index 0000000..04b525e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 63.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 63.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.779576301574707, + "bbox": [ + 1173.7569580078125, + 436.2480163574219, + 1269.259033203125, + 520.3143310546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7710956335067749, + "bbox": [ + 215.82484436035156, + 417.95367431640625, + 312.8224792480469, + 505.0193786621094 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6789515614509583, + "bbox": [ + 1411.2872314453125, + 1546.7138671875, + 1496.4532470703125, + 1632.8448486328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6213219165802002, + "bbox": [ + 186.31475830078125, + 2981.541748046875, + 244.0559844970703, + 3046.364501953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6160686612129211, + "bbox": [ + 1593.5758056640625, + 2160.564453125, + 1721.7540283203125, + 2288.052490234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5846815705299377, + "bbox": [ + 471.94287109375, + 1818.85400390625, + 593.213623046875, + 1947.9967041015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5674062371253967, + "bbox": [ + 728.553955078125, + 1410.3165283203125, + 795.5034790039062, + 1491.118896484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357914924621582, + "bbox": [ + 196.90151977539062, + 590.5660400390625, + 1099.3720703125, + 1730.4512939453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9281841516494751, + "bbox": [ + 1128.1490478515625, + 368.2048034667969, + 2042.21826171875, + 2160.371826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.926852285861969, + "bbox": [ + 1153.6876220703125, + 610.0641479492188, + 2054.581298828125, + 2061.8779296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9044339656829834, + "bbox": [ + 149.60728454589844, + 421.1939697265625, + 1106.8804931640625, + 2175.231689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8180068731307983, + "bbox": [ + 218.46853637695312, + 510.9898986816406, + 817.6577758789062, + 588.9566040039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7090044021606445, + "bbox": [ + 1176.985107421875, + 534.6043701171875, + 1776.57861328125, + 592.2709350585938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.29838433861732483, + "bbox": [ + 1182.15966796875, + 519.3270874023438, + 1781.587158203125, + 604.19970703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.779576301574707, + "bbox": [ + 1173.7569580078125, + 436.2480163574219, + 1269.259033203125, + 520.3143310546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7710956335067749, + "bbox": [ + 215.82484436035156, + 417.95367431640625, + 312.8224792480469, + 505.0193786621094 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6789515614509583, + "bbox": [ + 1411.2872314453125, + 1546.7138671875, + 1496.4532470703125, + 1632.8448486328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6213219165802002, + "bbox": [ + 186.31475830078125, + 2981.541748046875, + 244.0559844970703, + 3046.364501953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6160686612129211, + "bbox": [ + 1593.5758056640625, + 2160.564453125, + 1721.7540283203125, + 2288.052490234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5846815705299377, + "bbox": [ + 471.94287109375, + 1818.85400390625, + 593.213623046875, + 1947.9967041015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5674062371253967, + "bbox": [ + 728.553955078125, + 1410.3165283203125, + 795.5034790039062, + 1491.118896484375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357914924621582, + "bbox": [ + 196.90151977539062, + 590.5660400390625, + 1099.3720703125, + 1730.4512939453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9281841516494751, + "bbox": [ + 1128.1490478515625, + 368.2048034667969, + 2042.21826171875, + 2160.371826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.926852285861969, + "bbox": [ + 1153.6876220703125, + 610.0641479492188, + 2054.581298828125, + 2061.8779296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9044339656829834, + "bbox": [ + 149.60728454589844, + 421.1939697265625, + 1106.8804931640625, + 2175.231689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8180068731307983, + "bbox": [ + 218.46853637695312, + 510.9898986816406, + 817.6577758789062, + 588.9566040039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7090044021606445, + "bbox": [ + 1176.985107421875, + 534.6043701171875, + 1776.57861328125, + 592.2709350585938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.29838433861732483, + "bbox": [ + 1182.15966796875, + 519.3270874023438, + 1781.587158203125, + 604.19970703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:31.885278" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 64.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 64.json" new file mode 100644 index 0000000..ce1c138 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 64.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 64.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7817879319190979, + "bbox": [ + 284.1883239746094, + 450.6307373046875, + 387.098876953125, + 538.561279296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7713593244552612, + "bbox": [ + 1318.829833984375, + 464.4869689941406, + 1421.1192626953125, + 552.52099609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6589848399162292, + "bbox": [ + 760.4031372070312, + 2204.319580078125, + 877.0477294921875, + 2323.779296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.647266685962677, + "bbox": [ + 2140.60107421875, + 1314.9710693359375, + 2207.15478515625, + 1389.798583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6097150444984436, + "bbox": [ + 1962.0333251953125, + 2190.52978515625, + 2093.16748046875, + 2324.635498046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5674170255661011, + "bbox": [ + 2186.34619140625, + 3205.58447265625, + 2250.600341796875, + 3274.613037109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4246600866317749, + "bbox": [ + 454.37542724609375, + 1720.216552734375, + 527.5523071289062, + 1801.9559326171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9507489204406738, + "bbox": [ + 1302.216552734375, + 644.624267578125, + 2273.93408203125, + 2187.56884765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9395396113395691, + "bbox": [ + 273.6948547363281, + 641.6515502929688, + 1230.7503662109375, + 2060.79345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9329845905303955, + "bbox": [ + 1285.01953125, + 439.359375, + 2294.169921875, + 2335.585205078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9181224703788757, + "bbox": [ + 224.8604278564453, + 463.1475830078125, + 1244.23046875, + 2250.326416015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.892905592918396, + "bbox": [ + 280.97540283203125, + 548.3339233398438, + 931.6777954101562, + 635.7080078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8498175144195557, + "bbox": [ + 1326.6983642578125, + 552.4964599609375, + 1969.9639892578125, + 640.478515625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7817879319190979, + "bbox": [ + 284.1883239746094, + 450.6307373046875, + 387.098876953125, + 538.561279296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7713593244552612, + "bbox": [ + 1318.829833984375, + 464.4869689941406, + 1421.1192626953125, + 552.52099609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6589848399162292, + "bbox": [ + 760.4031372070312, + 2204.319580078125, + 877.0477294921875, + 2323.779296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.647266685962677, + "bbox": [ + 2140.60107421875, + 1314.9710693359375, + 2207.15478515625, + 1389.798583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6097150444984436, + "bbox": [ + 1962.0333251953125, + 2190.52978515625, + 2093.16748046875, + 2324.635498046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5674170255661011, + "bbox": [ + 2186.34619140625, + 3205.58447265625, + 2250.600341796875, + 3274.613037109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4246600866317749, + "bbox": [ + 454.37542724609375, + 1720.216552734375, + 527.5523071289062, + 1801.9559326171875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9507489204406738, + "bbox": [ + 1302.216552734375, + 644.624267578125, + 2273.93408203125, + 2187.56884765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9395396113395691, + "bbox": [ + 273.6948547363281, + 641.6515502929688, + 1230.7503662109375, + 2060.79345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9329845905303955, + "bbox": [ + 1285.01953125, + 439.359375, + 2294.169921875, + 2335.585205078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9181224703788757, + "bbox": [ + 224.8604278564453, + 463.1475830078125, + 1244.23046875, + 2250.326416015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.892905592918396, + "bbox": [ + 280.97540283203125, + 548.3339233398438, + 931.6777954101562, + 635.7080078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8498175144195557, + "bbox": [ + 1326.6983642578125, + 552.4964599609375, + 1969.9639892578125, + 640.478515625 + ] + } + ], + "timestamp": "2025-10-15T21:43:32.241318" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 65.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 65.json" new file mode 100644 index 0000000..bb5bef7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 65.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 65.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7806954979896545, + "bbox": [ + 1202.540771484375, + 429.9014892578125, + 1303.4755859375, + 515.8250122070312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7715578675270081, + "bbox": [ + 226.6529998779297, + 423.1974182128906, + 322.08734130859375, + 510.23504638671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7179463505744934, + "bbox": [ + 1709.1776123046875, + 2669.6787109375, + 1818.6248779296875, + 2778.207763671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7024132609367371, + "bbox": [ + 752.937255859375, + 2514.197265625, + 821.6884765625, + 2591.29443359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6617028117179871, + "bbox": [ + 798.7138671875, + 2619.778076171875, + 927.13330078125, + 2771.136474609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6533079743385315, + "bbox": [ + 1719.684326171875, + 2365.43115234375, + 1812.21728515625, + 2465.368408203125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5899726748466492, + "bbox": [ + 193.22019958496094, + 3024.73046875, + 253.18670654296875, + 3088.51953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9553265571594238, + "bbox": [ + 195.64280700683594, + 593.3401489257812, + 1121.806640625, + 2449.19091796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9336778521537781, + "bbox": [ + 1185.4312744140625, + 593.7222290039062, + 2096.6279296875, + 2393.7392578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9264929294586182, + "bbox": [ + 175.20945739746094, + 393.5173034667969, + 1136.7711181640625, + 2808.006103515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9246057868003845, + "bbox": [ + 1183.1842041015625, + 401.2304382324219, + 2115.785888671875, + 2768.571533203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9092100858688354, + "bbox": [ + 196.54702758789062, + 2439.75048828125, + 1062.7286376953125, + 2661.72509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8777595162391663, + "bbox": [ + 1173.095458984375, + 2381.05322265625, + 2062.173583984375, + 2609.698486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8242934942245483, + "bbox": [ + 1202.2376708984375, + 515.7455444335938, + 1977.3604736328125, + 593.4674072265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7999833822250366, + "bbox": [ + 235.63380432128906, + 505.4225769042969, + 995.5970458984375, + 595.2589721679688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7806954979896545, + "bbox": [ + 1202.540771484375, + 429.9014892578125, + 1303.4755859375, + 515.8250122070312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7715578675270081, + "bbox": [ + 226.6529998779297, + 423.1974182128906, + 322.08734130859375, + 510.23504638671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7179463505744934, + "bbox": [ + 1709.1776123046875, + 2669.6787109375, + 1818.6248779296875, + 2778.207763671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7024132609367371, + "bbox": [ + 752.937255859375, + 2514.197265625, + 821.6884765625, + 2591.29443359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6617028117179871, + "bbox": [ + 798.7138671875, + 2619.778076171875, + 927.13330078125, + 2771.136474609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6533079743385315, + "bbox": [ + 1719.684326171875, + 2365.43115234375, + 1812.21728515625, + 2465.368408203125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5899726748466492, + "bbox": [ + 193.22019958496094, + 3024.73046875, + 253.18670654296875, + 3088.51953125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9553265571594238, + "bbox": [ + 195.64280700683594, + 593.3401489257812, + 1121.806640625, + 2449.19091796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9336778521537781, + "bbox": [ + 1185.4312744140625, + 593.7222290039062, + 2096.6279296875, + 2393.7392578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9264929294586182, + "bbox": [ + 175.20945739746094, + 393.5173034667969, + 1136.7711181640625, + 2808.006103515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9246057868003845, + "bbox": [ + 1183.1842041015625, + 401.2304382324219, + 2115.785888671875, + 2768.571533203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9092100858688354, + "bbox": [ + 196.54702758789062, + 2439.75048828125, + 1062.7286376953125, + 2661.72509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8777595162391663, + "bbox": [ + 1173.095458984375, + 2381.05322265625, + 2062.173583984375, + 2609.698486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8242934942245483, + "bbox": [ + 1202.2376708984375, + 515.7455444335938, + 1977.3604736328125, + 593.4674072265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7999833822250366, + "bbox": [ + 235.63380432128906, + 505.4225769042969, + 995.5970458984375, + 595.2589721679688 + ] + } + ], + "timestamp": "2025-10-15T21:43:32.630096" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 66.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 66.json" new file mode 100644 index 0000000..e06e926 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 66.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 66.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7821287512779236, + "bbox": [ + 272.5928955078125, + 437.3414611816406, + 371.9617004394531, + 522.292236328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7783365249633789, + "bbox": [ + 1275.007568359375, + 442.6730651855469, + 1374.0892333984375, + 530.4382934570312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7125735282897949, + "bbox": [ + 1248.788818359375, + 2838.0205078125, + 1313.9315185546875, + 2913.0341796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7032056450843811, + "bbox": [ + 864.8407592773438, + 2694.222412109375, + 982.3810424804688, + 2810.298583984375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6306340098381042, + "bbox": [ + 796.1435546875, + 2422.20751953125, + 879.0203857421875, + 2522.84228515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6113597750663757, + "bbox": [ + 1757.2359619140625, + 2901.157470703125, + 1882.737060546875, + 3027.486328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5416631102561951, + "bbox": [ + 2124.774658203125, + 3094.76171875, + 2187.39892578125, + 3162.439697265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.30437010526657104, + "bbox": [ + 1744.2119140625, + 2895.444580078125, + 1903.2318115234375, + 3046.27880859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9335023760795593, + "bbox": [ + 258.3420715332031, + 614.9690551757812, + 1191.7557373046875, + 2452.934814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.932094395160675, + "bbox": [ + 1256.91259765625, + 648.4121704101562, + 2201.8359375, + 2691.727783203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9189847111701965, + "bbox": [ + 213.85855102539062, + 407.56158447265625, + 1204.4443359375, + 2852.155517578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9132133722305298, + "bbox": [ + 1235.2750244140625, + 475.879638671875, + 2215.558349609375, + 3054.82275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8989214301109314, + "bbox": [ + 1248.9310302734375, + 2697.6982421875, + 2147.06298828125, + 2937.20068359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.873914897441864, + "bbox": [ + 239.1878204345703, + 2436.740966796875, + 1117.1103515625, + 2686.558349609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8509293794631958, + "bbox": [ + 275.7570495605469, + 519.3045043945312, + 1068.0155029296875, + 616.2587280273438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8066378235816956, + "bbox": [ + 1272.351318359375, + 531.1710815429688, + 2086.957275390625, + 607.885498046875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7821287512779236, + "bbox": [ + 272.5928955078125, + 437.3414611816406, + 371.9617004394531, + 522.292236328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7783365249633789, + "bbox": [ + 1275.007568359375, + 442.6730651855469, + 1374.0892333984375, + 530.4382934570312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7125735282897949, + "bbox": [ + 1248.788818359375, + 2838.0205078125, + 1313.9315185546875, + 2913.0341796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7032056450843811, + "bbox": [ + 864.8407592773438, + 2694.222412109375, + 982.3810424804688, + 2810.298583984375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6306340098381042, + "bbox": [ + 796.1435546875, + 2422.20751953125, + 879.0203857421875, + 2522.84228515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6113597750663757, + "bbox": [ + 1757.2359619140625, + 2901.157470703125, + 1882.737060546875, + 3027.486328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5416631102561951, + "bbox": [ + 2124.774658203125, + 3094.76171875, + 2187.39892578125, + 3162.439697265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.30437010526657104, + "bbox": [ + 1744.2119140625, + 2895.444580078125, + 1903.2318115234375, + 3046.27880859375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9335023760795593, + "bbox": [ + 258.3420715332031, + 614.9690551757812, + 1191.7557373046875, + 2452.934814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.932094395160675, + "bbox": [ + 1256.91259765625, + 648.4121704101562, + 2201.8359375, + 2691.727783203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9189847111701965, + "bbox": [ + 213.85855102539062, + 407.56158447265625, + 1204.4443359375, + 2852.155517578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9132133722305298, + "bbox": [ + 1235.2750244140625, + 475.879638671875, + 2215.558349609375, + 3054.82275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8989214301109314, + "bbox": [ + 1248.9310302734375, + 2697.6982421875, + 2147.06298828125, + 2937.20068359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.873914897441864, + "bbox": [ + 239.1878204345703, + 2436.740966796875, + 1117.1103515625, + 2686.558349609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8509293794631958, + "bbox": [ + 275.7570495605469, + 519.3045043945312, + 1068.0155029296875, + 616.2587280273438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8066378235816956, + "bbox": [ + 1272.351318359375, + 531.1710815429688, + 2086.957275390625, + 607.885498046875 + ] + } + ], + "timestamp": "2025-10-15T21:43:33.018662" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 67.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 67.json" new file mode 100644 index 0000000..3c243c6 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 67.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 67.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7861997485160828, + "bbox": [ + 222.6878204345703, + 412.8216552734375, + 319.5566101074219, + 499.443603515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7628344297409058, + "bbox": [ + 1201.079833984375, + 422.3739318847656, + 1301.17724609375, + 506.72344970703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7113251686096191, + "bbox": [ + 1740.9395751953125, + 1823.8134765625, + 1804.1771240234375, + 1895.53515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6413028240203857, + "bbox": [ + 757.0560913085938, + 2117.21533203125, + 871.0280151367188, + 2240.582275390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5932678580284119, + "bbox": [ + 483.4000244140625, + 1626.243408203125, + 547.6461181640625, + 1700.5057373046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5852173566818237, + "bbox": [ + 1657.142578125, + 2345.413330078125, + 1773.142578125, + 2465.289794921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5670217871665955, + "bbox": [ + 192.81155395507812, + 2989.930908203125, + 257.50408935546875, + 3055.975830078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4918529987335205, + "bbox": [ + 1648.6812744140625, + 2335.846923828125, + 1799.9774169921875, + 2482.189208984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2787882089614868, + "bbox": [ + 763.5647583007812, + 2134.270751953125, + 847.6527709960938, + 2234.4599609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9654228091239929, + "bbox": [ + 198.56202697753906, + 631.50341796875, + 1119.42529296875, + 2118.1728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9366127252578735, + "bbox": [ + 1183.4951171875, + 648.3150024414062, + 2116.135986328125, + 2310.948974609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9284017086029053, + "bbox": [ + 167.55567932128906, + 427.77410888671875, + 1137.0921630859375, + 2182.1396484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9210756421089172, + "bbox": [ + 1177.2353515625, + 410.6089782714844, + 2138.908935546875, + 2427.638427734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8501324653625488, + "bbox": [ + 1191.4552001953125, + 509.5351257324219, + 2106.71630859375, + 631.7449340820312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8309291005134583, + "bbox": [ + 204.948486328125, + 498.94500732421875, + 1128.32568359375, + 625.197509765625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7861997485160828, + "bbox": [ + 222.6878204345703, + 412.8216552734375, + 319.5566101074219, + 499.443603515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7628344297409058, + "bbox": [ + 1201.079833984375, + 422.3739318847656, + 1301.17724609375, + 506.72344970703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7113251686096191, + "bbox": [ + 1740.9395751953125, + 1823.8134765625, + 1804.1771240234375, + 1895.53515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6413028240203857, + "bbox": [ + 757.0560913085938, + 2117.21533203125, + 871.0280151367188, + 2240.582275390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5932678580284119, + "bbox": [ + 483.4000244140625, + 1626.243408203125, + 547.6461181640625, + 1700.5057373046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5852173566818237, + "bbox": [ + 1657.142578125, + 2345.413330078125, + 1773.142578125, + 2465.289794921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5670217871665955, + "bbox": [ + 192.81155395507812, + 2989.930908203125, + 257.50408935546875, + 3055.975830078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4918529987335205, + "bbox": [ + 1648.6812744140625, + 2335.846923828125, + 1799.9774169921875, + 2482.189208984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2787882089614868, + "bbox": [ + 763.5647583007812, + 2134.270751953125, + 847.6527709960938, + 2234.4599609375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9654228091239929, + "bbox": [ + 198.56202697753906, + 631.50341796875, + 1119.42529296875, + 2118.1728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9366127252578735, + "bbox": [ + 1183.4951171875, + 648.3150024414062, + 2116.135986328125, + 2310.948974609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9284017086029053, + "bbox": [ + 167.55567932128906, + 427.77410888671875, + 1137.0921630859375, + 2182.1396484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9210756421089172, + "bbox": [ + 1177.2353515625, + 410.6089782714844, + 2138.908935546875, + 2427.638427734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8501324653625488, + "bbox": [ + 1191.4552001953125, + 509.5351257324219, + 2106.71630859375, + 631.7449340820312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8309291005134583, + "bbox": [ + 204.948486328125, + 498.94500732421875, + 1128.32568359375, + 625.197509765625 + ] + } + ], + "timestamp": "2025-10-15T21:43:33.403457" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 68.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 68.json" new file mode 100644 index 0000000..f35ee22 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 68.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 68.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.756471574306488, + "bbox": [ + 267.1417541503906, + 430.0179748535156, + 367.61956787109375, + 517.0064086914062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7553554773330688, + "bbox": [ + 1266.87353515625, + 430.8829040527344, + 1367.607177734375, + 517.9833374023438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.684646725654602, + "bbox": [ + 724.112060546875, + 2413.634033203125, + 844.1387939453125, + 2544.005126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6337822079658508, + "bbox": [ + 942.1161499023438, + 1341.604736328125, + 1022.1744995117188, + 1428.239013671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.572338879108429, + "bbox": [ + 1633.9580078125, + 2427.914794921875, + 1761.43701171875, + 2568.295654296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5471958518028259, + "bbox": [ + 2110.852294921875, + 3083.074951171875, + 2175.37841796875, + 3149.4189453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5316458344459534, + "bbox": [ + 1445.0625, + 1478.438232421875, + 1513.730712890625, + 1554.445556640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.34981706738471985, + "bbox": [ + 700.6315307617188, + 2403.91650390625, + 859.6141967773438, + 2555.49755859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2819594144821167, + "bbox": [ + 1436.9866943359375, + 1470.1094970703125, + 1524.381591796875, + 1561.7142333984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2684803307056427, + "bbox": [ + 2104.68115234375, + 3075.326416015625, + 2180.008056640625, + 3157.23486328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9487684369087219, + "bbox": [ + 251.02023315429688, + 439.7728271484375, + 1196.609375, + 2585.31982421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.934045672416687, + "bbox": [ + 243.7948455810547, + 646.8696899414062, + 1174.60205078125, + 2392.850341796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.933059811592102, + "bbox": [ + 1250.9134521484375, + 657.0731201171875, + 2199.790771484375, + 2375.08984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9221405982971191, + "bbox": [ + 1234.0147705078125, + 441.8699035644531, + 2226.439697265625, + 2538.660400390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8566531538963318, + "bbox": [ + 1250.804443359375, + 509.8090515136719, + 2191.548828125, + 640.9461669921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8252121806144714, + "bbox": [ + 254.54006958007812, + 514.8320922851562, + 1183.1072998046875, + 643.084228515625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.756471574306488, + "bbox": [ + 267.1417541503906, + 430.0179748535156, + 367.61956787109375, + 517.0064086914062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7553554773330688, + "bbox": [ + 1266.87353515625, + 430.8829040527344, + 1367.607177734375, + 517.9833374023438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.684646725654602, + "bbox": [ + 724.112060546875, + 2413.634033203125, + 844.1387939453125, + 2544.005126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6337822079658508, + "bbox": [ + 942.1161499023438, + 1341.604736328125, + 1022.1744995117188, + 1428.239013671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.572338879108429, + "bbox": [ + 1633.9580078125, + 2427.914794921875, + 1761.43701171875, + 2568.295654296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5471958518028259, + "bbox": [ + 2110.852294921875, + 3083.074951171875, + 2175.37841796875, + 3149.4189453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5316458344459534, + "bbox": [ + 1445.0625, + 1478.438232421875, + 1513.730712890625, + 1554.445556640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.34981706738471985, + "bbox": [ + 700.6315307617188, + 2403.91650390625, + 859.6141967773438, + 2555.49755859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2819594144821167, + "bbox": [ + 1436.9866943359375, + 1470.1094970703125, + 1524.381591796875, + 1561.7142333984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2684803307056427, + "bbox": [ + 2104.68115234375, + 3075.326416015625, + 2180.008056640625, + 3157.23486328125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9487684369087219, + "bbox": [ + 251.02023315429688, + 439.7728271484375, + 1196.609375, + 2585.31982421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.934045672416687, + "bbox": [ + 243.7948455810547, + 646.8696899414062, + 1174.60205078125, + 2392.850341796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.933059811592102, + "bbox": [ + 1250.9134521484375, + 657.0731201171875, + 2199.790771484375, + 2375.08984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9221405982971191, + "bbox": [ + 1234.0147705078125, + 441.8699035644531, + 2226.439697265625, + 2538.660400390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8566531538963318, + "bbox": [ + 1250.804443359375, + 509.8090515136719, + 2191.548828125, + 640.9461669921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8252121806144714, + "bbox": [ + 254.54006958007812, + 514.8320922851562, + 1183.1072998046875, + 643.084228515625 + ] + } + ], + "timestamp": "2025-10-15T21:43:33.774297" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 69.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 69.json" new file mode 100644 index 0000000..226fc83 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 69.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 69.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7858311533927917, + "bbox": [ + 228.86875915527344, + 435.4128112792969, + 330.747802734375, + 526.8451538085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.758439838886261, + "bbox": [ + 1264.1500244140625, + 447.930908203125, + 1370.43798828125, + 537.9575805664062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7353906035423279, + "bbox": [ + 211.80445861816406, + 2726.5478515625, + 281.800048828125, + 2805.97998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6673663854598999, + "bbox": [ + 903.0076904296875, + 2516.05810546875, + 1031.057373046875, + 2648.452880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6465587019920349, + "bbox": [ + 1248.151123046875, + 2800.64599609375, + 1316.958740234375, + 2881.351806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6352947354316711, + "bbox": [ + 2004.99072265625, + 2676.5849609375, + 2131.50732421875, + 2796.837890625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5736376047134399, + "bbox": [ + 209.52272033691406, + 3155.23046875, + 269.5751647949219, + 3220.317626953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9345974922180176, + "bbox": [ + 211.63223266601562, + 665.1795043945312, + 1171.39306640625, + 2517.423095703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9343888759613037, + "bbox": [ + 1237.938720703125, + 684.312255859375, + 2214.5625, + 2692.206787109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9182138442993164, + "bbox": [ + 192.84625244140625, + 433.7027587890625, + 1189.253173828125, + 2948.028076171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9162229895591736, + "bbox": [ + 201.5040283203125, + 2527.480224609375, + 846.0499877929688, + 2972.614990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9110521078109741, + "bbox": [ + 1255.7572021484375, + 2662.73046875, + 1902.78125, + 3120.3447265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8730579614639282, + "bbox": [ + 1228.1419677734375, + 494.77294921875, + 2227.77587890625, + 3134.680908203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.861112654209137, + "bbox": [ + 1266.279052734375, + 545.9535522460938, + 2224.8447265625, + 671.40869140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7963024377822876, + "bbox": [ + 213.53421020507812, + 527.6439208984375, + 1187.793701171875, + 663.2926025390625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7858311533927917, + "bbox": [ + 228.86875915527344, + 435.4128112792969, + 330.747802734375, + 526.8451538085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.758439838886261, + "bbox": [ + 1264.1500244140625, + 447.930908203125, + 1370.43798828125, + 537.9575805664062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7353906035423279, + "bbox": [ + 211.80445861816406, + 2726.5478515625, + 281.800048828125, + 2805.97998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6673663854598999, + "bbox": [ + 903.0076904296875, + 2516.05810546875, + 1031.057373046875, + 2648.452880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6465587019920349, + "bbox": [ + 1248.151123046875, + 2800.64599609375, + 1316.958740234375, + 2881.351806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6352947354316711, + "bbox": [ + 2004.99072265625, + 2676.5849609375, + 2131.50732421875, + 2796.837890625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5736376047134399, + "bbox": [ + 209.52272033691406, + 3155.23046875, + 269.5751647949219, + 3220.317626953125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9345974922180176, + "bbox": [ + 211.63223266601562, + 665.1795043945312, + 1171.39306640625, + 2517.423095703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9343888759613037, + "bbox": [ + 1237.938720703125, + 684.312255859375, + 2214.5625, + 2692.206787109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9182138442993164, + "bbox": [ + 192.84625244140625, + 433.7027587890625, + 1189.253173828125, + 2948.028076171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9162229895591736, + "bbox": [ + 201.5040283203125, + 2527.480224609375, + 846.0499877929688, + 2972.614990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9110521078109741, + "bbox": [ + 1255.7572021484375, + 2662.73046875, + 1902.78125, + 3120.3447265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8730579614639282, + "bbox": [ + 1228.1419677734375, + 494.77294921875, + 2227.77587890625, + 3134.680908203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.861112654209137, + "bbox": [ + 1266.279052734375, + 545.9535522460938, + 2224.8447265625, + 671.40869140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7963024377822876, + "bbox": [ + 213.53421020507812, + 527.6439208984375, + 1187.793701171875, + 663.2926025390625 + ] + } + ], + "timestamp": "2025-10-15T21:43:34.164776" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 70.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 70.json" new file mode 100644 index 0000000..f942e3e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 70.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 70.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7984797358512878, + "bbox": [ + 1275.7530517578125, + 441.538330078125, + 1372.9580078125, + 526.4832153320312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7893118858337402, + "bbox": [ + 1253.797607421875, + 2813.5390625, + 1319.1656494140625, + 2886.271484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7601549625396729, + "bbox": [ + 270.1971740722656, + 430.92913818359375, + 370.1064453125, + 518.2190551757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7146188616752625, + "bbox": [ + 2019.90234375, + 2594.259765625, + 2143.49755859375, + 2724.955078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6861907839775085, + "bbox": [ + 1009.5106811523438, + 2321.123046875, + 1126.5477294921875, + 2438.446533203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6713186502456665, + "bbox": [ + 243.87176513671875, + 2666.5224609375, + 314.60516357421875, + 2746.02978515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5594301223754883, + "bbox": [ + 2122.0888671875, + 3094.227294921875, + 2190.8134765625, + 3163.224853515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9557541012763977, + "bbox": [ + 1249.9798583984375, + 657.5346069335938, + 2195.97705078125, + 2628.7431640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.945822536945343, + "bbox": [ + 238.94027709960938, + 653.7559814453125, + 1186.662353515625, + 2333.781005859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9395791888237, + "bbox": [ + 229.54087829589844, + 405.1367492675781, + 1199.3056640625, + 2726.3125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9209741353988647, + "bbox": [ + 248.98696899414062, + 2344.439697265625, + 1020.5008544921875, + 2745.067626953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9063810110092163, + "bbox": [ + 1251.4110107421875, + 2620.846923828125, + 1863.3201904296875, + 3054.8671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8686098456382751, + "bbox": [ + 1235.3458251953125, + 477.468505859375, + 2210.144287109375, + 3057.85693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8313900828361511, + "bbox": [ + 1264.7049560546875, + 534.9700317382812, + 2194.71630859375, + 653.8171997070312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8293032646179199, + "bbox": [ + 263.8679504394531, + 517.753662109375, + 1204.170654296875, + 647.25390625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7984797358512878, + "bbox": [ + 1275.7530517578125, + 441.538330078125, + 1372.9580078125, + 526.4832153320312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7893118858337402, + "bbox": [ + 1253.797607421875, + 2813.5390625, + 1319.1656494140625, + 2886.271484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7601549625396729, + "bbox": [ + 270.1971740722656, + 430.92913818359375, + 370.1064453125, + 518.2190551757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7146188616752625, + "bbox": [ + 2019.90234375, + 2594.259765625, + 2143.49755859375, + 2724.955078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6861907839775085, + "bbox": [ + 1009.5106811523438, + 2321.123046875, + 1126.5477294921875, + 2438.446533203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6713186502456665, + "bbox": [ + 243.87176513671875, + 2666.5224609375, + 314.60516357421875, + 2746.02978515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5594301223754883, + "bbox": [ + 2122.0888671875, + 3094.227294921875, + 2190.8134765625, + 3163.224853515625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9557541012763977, + "bbox": [ + 1249.9798583984375, + 657.5346069335938, + 2195.97705078125, + 2628.7431640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.945822536945343, + "bbox": [ + 238.94027709960938, + 653.7559814453125, + 1186.662353515625, + 2333.781005859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9395791888237, + "bbox": [ + 229.54087829589844, + 405.1367492675781, + 1199.3056640625, + 2726.3125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9209741353988647, + "bbox": [ + 248.98696899414062, + 2344.439697265625, + 1020.5008544921875, + 2745.067626953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9063810110092163, + "bbox": [ + 1251.4110107421875, + 2620.846923828125, + 1863.3201904296875, + 3054.8671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8686098456382751, + "bbox": [ + 1235.3458251953125, + 477.468505859375, + 2210.144287109375, + 3057.85693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8313900828361511, + "bbox": [ + 1264.7049560546875, + 534.9700317382812, + 2194.71630859375, + 653.8171997070312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8293032646179199, + "bbox": [ + 263.8679504394531, + 517.753662109375, + 1204.170654296875, + 647.25390625 + ] + } + ], + "timestamp": "2025-10-15T21:43:34.563997" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 71.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 71.json" new file mode 100644 index 0000000..0d74ee1 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 71.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 71.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7753919363021851, + "bbox": [ + 1202.753662109375, + 430.31219482421875, + 1300.2139892578125, + 516.8137817382812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7689806222915649, + "bbox": [ + 1195.19873046875, + 1777.8406982421875, + 1294.616943359375, + 1865.1055908203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7112677693367004, + "bbox": [ + 1463.9488525390625, + 2172.897216796875, + 1577.9158935546875, + 2287.234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6874988675117493, + "bbox": [ + 1191.666259765625, + 879.1769409179688, + 1265.029541015625, + 968.8734741210938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6789718866348267, + "bbox": [ + 1698.872802734375, + 1975.801513671875, + 1776.072509765625, + 2072.763916015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6487367749214172, + "bbox": [ + 1447.9337158203125, + 1243.3419189453125, + 1559.9775390625, + 1371.1383056640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5855937600135803, + "bbox": [ + 201.5085906982422, + 2997.157470703125, + 260.3041076660156, + 3061.216796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9500079154968262, + "bbox": [ + 1201.7391357421875, + 594.940673828125, + 2115.483642578125, + 1158.10498046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9249199628829956, + "bbox": [ + 1177.814208984375, + 1754.4095458984375, + 2129.47509765625, + 2114.73193359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9172533750534058, + "bbox": [ + 1173.975830078125, + 401.2607116699219, + 2146.166748046875, + 1259.6495361328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8868899941444397, + "bbox": [ + 195.72731018066406, + 415.29962158203125, + 1136.21630859375, + 2320.716064453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8270283937454224, + "bbox": [ + 1196.8763427734375, + 1875.740478515625, + 2101.91796875, + 1991.0872802734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.814175009727478, + "bbox": [ + 1202.0577392578125, + 516.5905151367188, + 1705.2017822265625, + 595.2514038085938 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7782363295555115, + "bbox": [ + 1186.1722412109375, + 2001.8857421875, + 2001.031982421875, + 2082.2822265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.13193781673908234, + "bbox": [ + 1205.5479736328125, + 1978.3270263671875, + 2047.3922119140625, + 2088.531494140625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7753919363021851, + "bbox": [ + 1202.753662109375, + 430.31219482421875, + 1300.2139892578125, + 516.8137817382812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7689806222915649, + "bbox": [ + 1195.19873046875, + 1777.8406982421875, + 1294.616943359375, + 1865.1055908203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7112677693367004, + "bbox": [ + 1463.9488525390625, + 2172.897216796875, + 1577.9158935546875, + 2287.234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6874988675117493, + "bbox": [ + 1191.666259765625, + 879.1769409179688, + 1265.029541015625, + 968.8734741210938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6789718866348267, + "bbox": [ + 1698.872802734375, + 1975.801513671875, + 1776.072509765625, + 2072.763916015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6487367749214172, + "bbox": [ + 1447.9337158203125, + 1243.3419189453125, + 1559.9775390625, + 1371.1383056640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5855937600135803, + "bbox": [ + 201.5085906982422, + 2997.157470703125, + 260.3041076660156, + 3061.216796875 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9500079154968262, + "bbox": [ + 1201.7391357421875, + 594.940673828125, + 2115.483642578125, + 1158.10498046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9249199628829956, + "bbox": [ + 1177.814208984375, + 1754.4095458984375, + 2129.47509765625, + 2114.73193359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9172533750534058, + "bbox": [ + 1173.975830078125, + 401.2607116699219, + 2146.166748046875, + 1259.6495361328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8868899941444397, + "bbox": [ + 195.72731018066406, + 415.29962158203125, + 1136.21630859375, + 2320.716064453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8270283937454224, + "bbox": [ + 1196.8763427734375, + 1875.740478515625, + 2101.91796875, + 1991.0872802734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.814175009727478, + "bbox": [ + 1202.0577392578125, + 516.5905151367188, + 1705.2017822265625, + 595.2514038085938 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7782363295555115, + "bbox": [ + 1186.1722412109375, + 2001.8857421875, + 2001.031982421875, + 2082.2822265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.13193781673908234, + "bbox": [ + 1205.5479736328125, + 1978.3270263671875, + 2047.3922119140625, + 2088.531494140625 + ] + } + ], + "timestamp": "2025-10-15T21:43:35.004245" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 72.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 72.json" new file mode 100644 index 0000000..99c8b9d --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 72.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 72.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7530669569969177, + "bbox": [ + 1261.422607421875, + 442.5573425292969, + 1360.8525390625, + 527.7227172851562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7499573230743408, + "bbox": [ + 1254.292724609375, + 1823.3267822265625, + 1353.949951171875, + 1909.1358642578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6615809202194214, + "bbox": [ + 1736.3447265625, + 2270.30126953125, + 1855.7537841796875, + 2389.87646484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6355082988739014, + "bbox": [ + 1443.5111083984375, + 1208.2777099609375, + 1569.267578125, + 1333.9794921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6186056137084961, + "bbox": [ + 1252.7120361328125, + 906.2190551757812, + 1321.6058349609375, + 998.1641845703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5764458179473877, + "bbox": [ + 2110.089599609375, + 3074.017333984375, + 2174.28271484375, + 3141.779541015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49348655343055725, + "bbox": [ + 1418.5447998046875, + 2012.5809326171875, + 1501.848876953125, + 2116.060791015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.934943437576294, + "bbox": [ + 238.81539916992188, + 478.1450500488281, + 1195.792236328125, + 2851.943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9326093196868896, + "bbox": [ + 1246.777587890625, + 615.1453247070312, + 2200.024658203125, + 1176.9525146484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9056293368339539, + "bbox": [ + 1240.930908203125, + 411.4196472167969, + 2217.864013671875, + 1319.713623046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8599600195884705, + "bbox": [ + 1244.428466796875, + 2035.16650390625, + 2113.657958984375, + 2137.423828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.859470009803772, + "bbox": [ + 242.3201446533203, + 420.0257873535156, + 904.0890502929688, + 513.5427856445312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8536745309829712, + "bbox": [ + 1249.2247314453125, + 1910.5137939453125, + 2163.693359375, + 2026.052978515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.797603964805603, + "bbox": [ + 1219.8216552734375, + 1787.36376953125, + 2196.340576171875, + 2444.3896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7452623844146729, + "bbox": [ + 1262.1224365234375, + 530.2010498046875, + 1772.923095703125, + 605.125732421875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7530669569969177, + "bbox": [ + 1261.422607421875, + 442.5573425292969, + 1360.8525390625, + 527.7227172851562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7499573230743408, + "bbox": [ + 1254.292724609375, + 1823.3267822265625, + 1353.949951171875, + 1909.1358642578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6615809202194214, + "bbox": [ + 1736.3447265625, + 2270.30126953125, + 1855.7537841796875, + 2389.87646484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6355082988739014, + "bbox": [ + 1443.5111083984375, + 1208.2777099609375, + 1569.267578125, + 1333.9794921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6186056137084961, + "bbox": [ + 1252.7120361328125, + 906.2190551757812, + 1321.6058349609375, + 998.1641845703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5764458179473877, + "bbox": [ + 2110.089599609375, + 3074.017333984375, + 2174.28271484375, + 3141.779541015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49348655343055725, + "bbox": [ + 1418.5447998046875, + 2012.5809326171875, + 1501.848876953125, + 2116.060791015625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.934943437576294, + "bbox": [ + 238.81539916992188, + 478.1450500488281, + 1195.792236328125, + 2851.943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9326093196868896, + "bbox": [ + 1246.777587890625, + 615.1453247070312, + 2200.024658203125, + 1176.9525146484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9056293368339539, + "bbox": [ + 1240.930908203125, + 411.4196472167969, + 2217.864013671875, + 1319.713623046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8599600195884705, + "bbox": [ + 1244.428466796875, + 2035.16650390625, + 2113.657958984375, + 2137.423828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.859470009803772, + "bbox": [ + 242.3201446533203, + 420.0257873535156, + 904.0890502929688, + 513.5427856445312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8536745309829712, + "bbox": [ + 1249.2247314453125, + 1910.5137939453125, + 2163.693359375, + 2026.052978515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.797603964805603, + "bbox": [ + 1219.8216552734375, + 1787.36376953125, + 2196.340576171875, + 2444.3896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7452623844146729, + "bbox": [ + 1262.1224365234375, + 530.2010498046875, + 1772.923095703125, + 605.125732421875 + ] + } + ], + "timestamp": "2025-10-15T21:43:35.407920" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 73.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 73.json" new file mode 100644 index 0000000..57af3d8 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 73.json" @@ -0,0 +1,516 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 73.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7664481401443481, + "bbox": [ + 1246.716552734375, + 2247.074462890625, + 1354.1915283203125, + 2339.601806640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.756467878818512, + "bbox": [ + 1253.3011474609375, + 1752.7437744140625, + 1350.935302734375, + 1841.1649169921875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7517487406730652, + "bbox": [ + 1245.900146484375, + 2609.317138671875, + 1352.0504150390625, + 2697.30517578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6575540900230408, + "bbox": [ + 1571.9647216796875, + 2528.888916015625, + 1712.4647216796875, + 2681.06396484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6525534987449646, + "bbox": [ + 2062.739501953125, + 2871.642333984375, + 2194.771484375, + 2997.202880859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6063077449798584, + "bbox": [ + 1687.5289306640625, + 2101.9580078125, + 1828.6795654296875, + 2242.7412109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6015544533729553, + "bbox": [ + 1249.39599609375, + 2033.5618896484375, + 1324.2894287109375, + 2120.5859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6007958054542542, + "bbox": [ + 1424.882568359375, + 2446.244873046875, + 1507.0909423828125, + 2547.696044921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5738393068313599, + "bbox": [ + 202.9099884033203, + 3151.50146484375, + 269.5949401855469, + 3220.06640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5521044135093689, + "bbox": [ + 1243.2392578125, + 2907.505859375, + 1308.9449462890625, + 2989.304443359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9190278053283691, + "bbox": [ + 1230.3792724609375, + 1747.232421875, + 2234.951416015625, + 2224.91796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.916451632976532, + "bbox": [ + 184.81568908691406, + 532.05615234375, + 1186.4036865234375, + 2970.700927734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9131284356117249, + "bbox": [ + 1257.6309814453125, + 2792.9287109375, + 2080.14306640625, + 3133.519287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8834227919578552, + "bbox": [ + 1235.531005859375, + 2249.30712890625, + 2233.291259765625, + 2542.25732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8759658336639404, + "bbox": [ + 1235.143798828125, + 2595.748779296875, + 2266.68701171875, + 3165.283935546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8145148754119873, + "bbox": [ + 1231.6920166015625, + 1839.4637451171875, + 2203.957275390625, + 1975.19580078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7932111024856567, + "bbox": [ + 1257.33984375, + 2342.94189453125, + 2194.750732421875, + 2458.701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6336739659309387, + "bbox": [ + 1247.0185546875, + 2699.41357421875, + 2049.04833984375, + 2790.702880859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5242316126823425, + "bbox": [ + 1242.0570068359375, + 1991.5416259765625, + 2183.3583984375, + 2192.96923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.4885760247707367, + "bbox": [ + 1247.63330078125, + 408.9120178222656, + 2228.304443359375, + 1691.11572265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.45361119508743286, + "bbox": [ + 1229.5609130859375, + 2461.7890625, + 2111.9716796875, + 2558.1484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.4168507754802704, + "bbox": [ + 1235.3646240234375, + 2709.048095703125, + 2080.164794921875, + 2774.349365234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.38285502791404724, + "bbox": [ + 1248.958740234375, + 0.0, + 2228.95654296875, + 2323.703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7664481401443481, + "bbox": [ + 1246.716552734375, + 2247.074462890625, + 1354.1915283203125, + 2339.601806640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.756467878818512, + "bbox": [ + 1253.3011474609375, + 1752.7437744140625, + 1350.935302734375, + 1841.1649169921875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7517487406730652, + "bbox": [ + 1245.900146484375, + 2609.317138671875, + 1352.0504150390625, + 2697.30517578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6575540900230408, + "bbox": [ + 1571.9647216796875, + 2528.888916015625, + 1712.4647216796875, + 2681.06396484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6525534987449646, + "bbox": [ + 2062.739501953125, + 2871.642333984375, + 2194.771484375, + 2997.202880859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6063077449798584, + "bbox": [ + 1687.5289306640625, + 2101.9580078125, + 1828.6795654296875, + 2242.7412109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6015544533729553, + "bbox": [ + 1249.39599609375, + 2033.5618896484375, + 1324.2894287109375, + 2120.5859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6007958054542542, + "bbox": [ + 1424.882568359375, + 2446.244873046875, + 1507.0909423828125, + 2547.696044921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5738393068313599, + "bbox": [ + 202.9099884033203, + 3151.50146484375, + 269.5949401855469, + 3220.06640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5521044135093689, + "bbox": [ + 1243.2392578125, + 2907.505859375, + 1308.9449462890625, + 2989.304443359375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9190278053283691, + "bbox": [ + 1230.3792724609375, + 1747.232421875, + 2234.951416015625, + 2224.91796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.916451632976532, + "bbox": [ + 184.81568908691406, + 532.05615234375, + 1186.4036865234375, + 2970.700927734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9131284356117249, + "bbox": [ + 1257.6309814453125, + 2792.9287109375, + 2080.14306640625, + 3133.519287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8834227919578552, + "bbox": [ + 1235.531005859375, + 2249.30712890625, + 2233.291259765625, + 2542.25732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8759658336639404, + "bbox": [ + 1235.143798828125, + 2595.748779296875, + 2266.68701171875, + 3165.283935546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8145148754119873, + "bbox": [ + 1231.6920166015625, + 1839.4637451171875, + 2203.957275390625, + 1975.19580078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7932111024856567, + "bbox": [ + 1257.33984375, + 2342.94189453125, + 2194.750732421875, + 2458.701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6336739659309387, + "bbox": [ + 1247.0185546875, + 2699.41357421875, + 2049.04833984375, + 2790.702880859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5242316126823425, + "bbox": [ + 1242.0570068359375, + 1991.5416259765625, + 2183.3583984375, + 2192.96923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.4885760247707367, + "bbox": [ + 1247.63330078125, + 408.9120178222656, + 2228.304443359375, + 1691.11572265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.45361119508743286, + "bbox": [ + 1229.5609130859375, + 2461.7890625, + 2111.9716796875, + 2558.1484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.4168507754802704, + "bbox": [ + 1235.3646240234375, + 2709.048095703125, + 2080.164794921875, + 2774.349365234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.38285502791404724, + "bbox": [ + 1248.958740234375, + 0.0, + 2228.95654296875, + 2323.703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:35.831115" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 74.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 74.json" new file mode 100644 index 0000000..1826098 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \341\204\213\341\205\262\341\204\222\341\205\247\341\206\274\341\204\221\341\205\247\341\206\253 - 74.json" @@ -0,0 +1,538 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 74.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.792370617389679, + "bbox": [ + 1298.730224609375, + 1935.156494140625, + 1403.91650390625, + 2025.9468994140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7882457375526428, + "bbox": [ + 1306.03271484375, + 1096.9365234375, + 1408.3167724609375, + 1185.9906005859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.765673816204071, + "bbox": [ + 1288.41259765625, + 2639.6826171875, + 1393.766845703125, + 2730.700927734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6923834681510925, + "bbox": [ + 1580.841552734375, + 2319.0546875, + 1706.2867431640625, + 2440.045654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6850404739379883, + "bbox": [ + 1482.046875, + 1593.5264892578125, + 1593.6812744140625, + 1706.4853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6532686352729797, + "bbox": [ + 1481.0919189453125, + 2148.535400390625, + 1552.97412109375, + 2245.31005859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6507720351219177, + "bbox": [ + 1304.0699462890625, + 1392.9853515625, + 1373.6934814453125, + 1473.9119873046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6419696807861328, + "bbox": [ + 1287.3687744140625, + 2880.04736328125, + 1358.24462890625, + 2959.064453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.604889988899231, + "bbox": [ + 2119.85205078125, + 2765.466552734375, + 2252.977783203125, + 2905.072509765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5505516529083252, + "bbox": [ + 2195.25634765625, + 3205.020751953125, + 2256.1064453125, + 3273.509521484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3094460070133209, + "bbox": [ + 1487.44189453125, + 2161.918212890625, + 1546.9534912109375, + 2241.971923828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9369469881057739, + "bbox": [ + 1274.59033203125, + 1917.9049072265625, + 2272.65283203125, + 2470.1044921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9195506572723389, + "bbox": [ + 1288.3079833984375, + 2826.788330078125, + 2215.414306640625, + 3172.965087890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9180538654327393, + "bbox": [ + 234.3252716064453, + 580.5828247070312, + 1239.00439453125, + 3141.962158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.909698486328125, + "bbox": [ + 1290.299560546875, + 447.5787658691406, + 2290.232666015625, + 940.0625610351562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8959141373634338, + "bbox": [ + 1296.3541259765625, + 2032.3314208984375, + 2255.595703125, + 2154.242919921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8866969347000122, + "bbox": [ + 1301.962158203125, + 1332.196533203125, + 2239.038330078125, + 1569.4949951171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8834633231163025, + "bbox": [ + 1260.4725341796875, + 2620.889404296875, + 2241.560302734375, + 3181.55859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8637134432792664, + "bbox": [ + 1280.812744140625, + 1056.36181640625, + 2295.263916015625, + 1719.1187744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8477247953414917, + "bbox": [ + 1313.0194091796875, + 1189.440185546875, + 2271.572021484375, + 1319.092529296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.830805242061615, + "bbox": [ + 253.79124450683594, + 437.30523681640625, + 923.0347900390625, + 516.93896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8007912039756775, + "bbox": [ + 1284.6964111328125, + 2156.035400390625, + 2183.310302734375, + 2259.83154296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7454482913017273, + "bbox": [ + 1288.4547119140625, + 2731.65673828125, + 1944.729248046875, + 2817.138427734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.2264460325241089, + "bbox": [ + 181.57862854003906, + 502.8815002441406, + 1243.480712890625, + 3165.079345703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.792370617389679, + "bbox": [ + 1298.730224609375, + 1935.156494140625, + 1403.91650390625, + 2025.9468994140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7882457375526428, + "bbox": [ + 1306.03271484375, + 1096.9365234375, + 1408.3167724609375, + 1185.9906005859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.765673816204071, + "bbox": [ + 1288.41259765625, + 2639.6826171875, + 1393.766845703125, + 2730.700927734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6923834681510925, + "bbox": [ + 1580.841552734375, + 2319.0546875, + 1706.2867431640625, + 2440.045654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6850404739379883, + "bbox": [ + 1482.046875, + 1593.5264892578125, + 1593.6812744140625, + 1706.4853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6532686352729797, + "bbox": [ + 1481.0919189453125, + 2148.535400390625, + 1552.97412109375, + 2245.31005859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6507720351219177, + "bbox": [ + 1304.0699462890625, + 1392.9853515625, + 1373.6934814453125, + 1473.9119873046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6419696807861328, + "bbox": [ + 1287.3687744140625, + 2880.04736328125, + 1358.24462890625, + 2959.064453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.604889988899231, + "bbox": [ + 2119.85205078125, + 2765.466552734375, + 2252.977783203125, + 2905.072509765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5505516529083252, + "bbox": [ + 2195.25634765625, + 3205.020751953125, + 2256.1064453125, + 3273.509521484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3094460070133209, + "bbox": [ + 1487.44189453125, + 2161.918212890625, + 1546.9534912109375, + 2241.971923828125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9369469881057739, + "bbox": [ + 1274.59033203125, + 1917.9049072265625, + 2272.65283203125, + 2470.1044921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9195506572723389, + "bbox": [ + 1288.3079833984375, + 2826.788330078125, + 2215.414306640625, + 3172.965087890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9180538654327393, + "bbox": [ + 234.3252716064453, + 580.5828247070312, + 1239.00439453125, + 3141.962158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.909698486328125, + "bbox": [ + 1290.299560546875, + 447.5787658691406, + 2290.232666015625, + 940.0625610351562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8959141373634338, + "bbox": [ + 1296.3541259765625, + 2032.3314208984375, + 2255.595703125, + 2154.242919921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8866969347000122, + "bbox": [ + 1301.962158203125, + 1332.196533203125, + 2239.038330078125, + 1569.4949951171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8834633231163025, + "bbox": [ + 1260.4725341796875, + 2620.889404296875, + 2241.560302734375, + 3181.55859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8637134432792664, + "bbox": [ + 1280.812744140625, + 1056.36181640625, + 2295.263916015625, + 1719.1187744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8477247953414917, + "bbox": [ + 1313.0194091796875, + 1189.440185546875, + 2271.572021484375, + 1319.092529296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.830805242061615, + "bbox": [ + 253.79124450683594, + 437.30523681640625, + 923.0347900390625, + 516.93896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8007912039756775, + "bbox": [ + 1284.6964111328125, + 2156.035400390625, + 2183.310302734375, + 2259.83154296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7454482913017273, + "bbox": [ + 1288.4547119140625, + 2731.65673828125, + 1944.729248046875, + 2817.138427734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.2264460325241089, + "bbox": [ + 181.57862854003906, + 502.8815002441406, + 1243.480712890625, + 3165.079345703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:36.315035" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 38.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 38.json" new file mode 100644 index 0000000..f6aa4c6 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 38.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 38.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7850658893585205, + "bbox": [ + 1245.004638671875, + 444.0091552734375, + 1349.467529296875, + 531.5126342773438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654370069503784, + "bbox": [ + 214.3993682861328, + 427.22271728515625, + 318.3274230957031, + 516.9413452148438 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6831666231155396, + "bbox": [ + 196.97161865234375, + 2384.95947265625, + 271.91229248046875, + 2470.052978515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6807867884635925, + "bbox": [ + 859.1079711914062, + 478.5378723144531, + 981.0159301757812, + 592.7740478515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6585734486579895, + "bbox": [ + 1744.1968994140625, + 421.41668701171875, + 1868.040771484375, + 539.2625122070312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5486059784889221, + "bbox": [ + 198.19703674316406, + 3122.937744140625, + 262.08868408203125, + 3192.882080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5204101800918579, + "bbox": [ + 1230.80322265625, + 2077.01611328125, + 1313.129638671875, + 2178.70263671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2878696620464325, + "bbox": [ + 1236.32666015625, + 2084.52099609375, + 1299.093505859375, + 2177.623291015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9623130559921265, + "bbox": [ + 207.51609802246094, + 388.75640869140625, + 1174.981201171875, + 2691.782470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9469709992408752, + "bbox": [ + 220.479736328125, + 609.2149658203125, + 1145.5208740234375, + 2318.5673828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9439365863800049, + "bbox": [ + 1239.0762939453125, + 623.738525390625, + 2181.610107421875, + 2075.578857421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9404712915420532, + "bbox": [ + 1214.403076171875, + 385.86895751953125, + 2225.052734375, + 2566.18115234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9193567633628845, + "bbox": [ + 203.88946533203125, + 2331.926025390625, + 916.0518188476562, + 2682.495849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8635926842689514, + "bbox": [ + 1236.4417724609375, + 2086.396240234375, + 1765.524658203125, + 2494.394775390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8282334804534912, + "bbox": [ + 1253.0677490234375, + 534.4161376953125, + 2029.6082763671875, + 632.1238403320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8022109270095825, + "bbox": [ + 219.03334045410156, + 521.4546508789062, + 800.873046875, + 601.1928100585938 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7850658893585205, + "bbox": [ + 1245.004638671875, + 444.0091552734375, + 1349.467529296875, + 531.5126342773438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654370069503784, + "bbox": [ + 214.3993682861328, + 427.22271728515625, + 318.3274230957031, + 516.9413452148438 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6831666231155396, + "bbox": [ + 196.97161865234375, + 2384.95947265625, + 271.91229248046875, + 2470.052978515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6807867884635925, + "bbox": [ + 859.1079711914062, + 478.5378723144531, + 981.0159301757812, + 592.7740478515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6585734486579895, + "bbox": [ + 1744.1968994140625, + 421.41668701171875, + 1868.040771484375, + 539.2625122070312 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5486059784889221, + "bbox": [ + 198.19703674316406, + 3122.937744140625, + 262.08868408203125, + 3192.882080078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5204101800918579, + "bbox": [ + 1230.80322265625, + 2077.01611328125, + 1313.129638671875, + 2178.70263671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2878696620464325, + "bbox": [ + 1236.32666015625, + 2084.52099609375, + 1299.093505859375, + 2177.623291015625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9623130559921265, + "bbox": [ + 207.51609802246094, + 388.75640869140625, + 1174.981201171875, + 2691.782470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9469709992408752, + "bbox": [ + 220.479736328125, + 609.2149658203125, + 1145.5208740234375, + 2318.5673828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9439365863800049, + "bbox": [ + 1239.0762939453125, + 623.738525390625, + 2181.610107421875, + 2075.578857421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9404712915420532, + "bbox": [ + 1214.403076171875, + 385.86895751953125, + 2225.052734375, + 2566.18115234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9193567633628845, + "bbox": [ + 203.88946533203125, + 2331.926025390625, + 916.0518188476562, + 2682.495849609375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8635926842689514, + "bbox": [ + 1236.4417724609375, + 2086.396240234375, + 1765.524658203125, + 2494.394775390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8282334804534912, + "bbox": [ + 1253.0677490234375, + 534.4161376953125, + 2029.6082763671875, + 632.1238403320312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8022109270095825, + "bbox": [ + 219.03334045410156, + 521.4546508789062, + 800.873046875, + 601.1928100585938 + ] + } + ], + "timestamp": "2025-10-15T21:43:22.254768" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 39.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 39.json" new file mode 100644 index 0000000..8a636de --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 39.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 39.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7705318927764893, + "bbox": [ + 1335.5081787109375, + 453.4455261230469, + 1438.02001953125, + 543.862060546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7528239488601685, + "bbox": [ + 272.1936340332031, + 441.65704345703125, + 378.8155517578125, + 531.9685668945312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6945548057556152, + "bbox": [ + 878.6261596679688, + 497.85687255859375, + 991.0343627929688, + 617.134033203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.643441379070282, + "bbox": [ + 241.22537231445312, + 2593.587646484375, + 317.70770263671875, + 2678.981689453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6320832371711731, + "bbox": [ + 1742.81982421875, + 443.4820251464844, + 1867.21533203125, + 555.793701171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5415790677070618, + "bbox": [ + 2218.605224609375, + 3235.1162109375, + 2291.90380859375, + 3310.81982421875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2517617642879486, + "bbox": [ + 2200.31103515625, + 3226.35107421875, + 2298.653076171875, + 3322.5771484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9083693027496338, + "bbox": [ + 1294.9228515625, + 447.8087463378906, + 2355.884765625, + 2303.7451171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9019496440887451, + "bbox": [ + 1321.7520751953125, + 626.2509155273438, + 2311.973388671875, + 1855.4375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9001947641372681, + "bbox": [ + 224.91502380371094, + 2533.6220703125, + 1243.6923828125, + 2913.085693359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.896881103515625, + "bbox": [ + 228.53538513183594, + 408.3642578125, + 1254.3138427734375, + 3113.564208984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8927276134490967, + "bbox": [ + 265.60845947265625, + 624.4931640625, + 1236.8133544921875, + 2506.95458984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8398045897483826, + "bbox": [ + 1314.0621337890625, + 1818.96923828125, + 1849.0626220703125, + 2223.958984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8349809050559998, + "bbox": [ + 271.5494079589844, + 536.8231811523438, + 878.4813842773438, + 615.4722290039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7630285024642944, + "bbox": [ + 1343.740234375, + 540.97216796875, + 2137.949462890625, + 635.5275268554688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7705318927764893, + "bbox": [ + 1335.5081787109375, + 453.4455261230469, + 1438.02001953125, + 543.862060546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7528239488601685, + "bbox": [ + 272.1936340332031, + 441.65704345703125, + 378.8155517578125, + 531.9685668945312 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6945548057556152, + "bbox": [ + 878.6261596679688, + 497.85687255859375, + 991.0343627929688, + 617.134033203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.643441379070282, + "bbox": [ + 241.22537231445312, + 2593.587646484375, + 317.70770263671875, + 2678.981689453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6320832371711731, + "bbox": [ + 1742.81982421875, + 443.4820251464844, + 1867.21533203125, + 555.793701171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5415790677070618, + "bbox": [ + 2218.605224609375, + 3235.1162109375, + 2291.90380859375, + 3310.81982421875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2517617642879486, + "bbox": [ + 2200.31103515625, + 3226.35107421875, + 2298.653076171875, + 3322.5771484375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9083693027496338, + "bbox": [ + 1294.9228515625, + 447.8087463378906, + 2355.884765625, + 2303.7451171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9019496440887451, + "bbox": [ + 1321.7520751953125, + 626.2509155273438, + 2311.973388671875, + 1855.4375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9001947641372681, + "bbox": [ + 224.91502380371094, + 2533.6220703125, + 1243.6923828125, + 2913.085693359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.896881103515625, + "bbox": [ + 228.53538513183594, + 408.3642578125, + 1254.3138427734375, + 3113.564208984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8927276134490967, + "bbox": [ + 265.60845947265625, + 624.4931640625, + 1236.8133544921875, + 2506.95458984375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8398045897483826, + "bbox": [ + 1314.0621337890625, + 1818.96923828125, + 1849.0626220703125, + 2223.958984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8349809050559998, + "bbox": [ + 271.5494079589844, + 536.8231811523438, + 878.4813842773438, + 615.4722290039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7630285024642944, + "bbox": [ + 1343.740234375, + 540.97216796875, + 2137.949462890625, + 635.5275268554688 + ] + } + ], + "timestamp": "2025-10-15T21:43:22.737629" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 40.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 40.json" new file mode 100644 index 0000000..8886a1f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 40.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 40.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654352188110352, + "bbox": [ + 1225.0933837890625, + 429.0877990722656, + 1328.6439208984375, + 514.9036865234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7562647461891174, + "bbox": [ + 226.2820281982422, + 420.0055236816406, + 322.644775390625, + 505.904541015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7214211225509644, + "bbox": [ + 835.6333618164062, + 518.2304077148438, + 927.5881958007812, + 609.849853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6707378029823303, + "bbox": [ + 1711.8406982421875, + 426.275146484375, + 1813.7047119140625, + 513.9613037109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6110719442367554, + "bbox": [ + 206.29953002929688, + 2173.352783203125, + 288.9198303222656, + 2261.854736328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5850449204444885, + "bbox": [ + 213.97677612304688, + 3030.710205078125, + 272.8304138183594, + 3097.380126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5558397769927979, + "bbox": [ + 1218.1103515625, + 1939.59326171875, + 1277.22607421875, + 2008.6546630859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9454506039619446, + "bbox": [ + 1207.9368896484375, + 1878.02197265625, + 2146.3828125, + 2442.2734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9415259957313538, + "bbox": [ + 218.802001953125, + 595.69189453125, + 1134.3333740234375, + 1872.0609130859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9283991456031799, + "bbox": [ + 1222.4478759765625, + 609.94775390625, + 2139.650634765625, + 1838.4598388671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.924217164516449, + "bbox": [ + 1204.2374267578125, + 397.7838439941406, + 2166.80224609375, + 2461.242431640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9125683903694153, + "bbox": [ + 204.62210083007812, + 391.5213928222656, + 1162.757080078125, + 2356.0625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9055758118629456, + "bbox": [ + 231.21624755859375, + 1882.1463623046875, + 1141.70068359375, + 2308.773681640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7925806045532227, + "bbox": [ + 1229.46337890625, + 514.5020751953125, + 1993.301513671875, + 612.98486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7691817283630371, + "bbox": [ + 230.06353759765625, + 508.97686767578125, + 750.6973266601562, + 583.2625122070312 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7654352188110352, + "bbox": [ + 1225.0933837890625, + 429.0877990722656, + 1328.6439208984375, + 514.9036865234375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7562647461891174, + "bbox": [ + 226.2820281982422, + 420.0055236816406, + 322.644775390625, + 505.904541015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7214211225509644, + "bbox": [ + 835.6333618164062, + 518.2304077148438, + 927.5881958007812, + 609.849853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6707378029823303, + "bbox": [ + 1711.8406982421875, + 426.275146484375, + 1813.7047119140625, + 513.9613037109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6110719442367554, + "bbox": [ + 206.29953002929688, + 2173.352783203125, + 288.9198303222656, + 2261.854736328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5850449204444885, + "bbox": [ + 213.97677612304688, + 3030.710205078125, + 272.8304138183594, + 3097.380126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5558397769927979, + "bbox": [ + 1218.1103515625, + 1939.59326171875, + 1277.22607421875, + 2008.6546630859375 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9454506039619446, + "bbox": [ + 1207.9368896484375, + 1878.02197265625, + 2146.3828125, + 2442.2734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9415259957313538, + "bbox": [ + 218.802001953125, + 595.69189453125, + 1134.3333740234375, + 1872.0609130859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9283991456031799, + "bbox": [ + 1222.4478759765625, + 609.94775390625, + 2139.650634765625, + 1838.4598388671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.924217164516449, + "bbox": [ + 1204.2374267578125, + 397.7838439941406, + 2166.80224609375, + 2461.242431640625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9125683903694153, + "bbox": [ + 204.62210083007812, + 391.5213928222656, + 1162.757080078125, + 2356.0625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9055758118629456, + "bbox": [ + 231.21624755859375, + 1882.1463623046875, + 1141.70068359375, + 2308.773681640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7925806045532227, + "bbox": [ + 1229.46337890625, + 514.5020751953125, + 1993.301513671875, + 612.98486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7691817283630371, + "bbox": [ + 230.06353759765625, + 508.97686767578125, + 750.6973266601562, + 583.2625122070312 + ] + } + ], + "timestamp": "2025-10-15T21:43:23.128262" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 41.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 41.json" new file mode 100644 index 0000000..711d2cd --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 41.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 41.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7704930901527405, + "bbox": [ + 1278.50390625, + 428.1532287597656, + 1378.7559814453125, + 516.4186401367188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7660089731216431, + "bbox": [ + 272.17938232421875, + 417.98846435546875, + 373.4778137207031, + 503.37646484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6935708522796631, + "bbox": [ + 1022.9564208984375, + 511.60992431640625, + 1137.188232421875, + 624.1637573242188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6412867903709412, + "bbox": [ + 1560.87841796875, + 396.8089599609375, + 1692.5703125, + 526.0737915039062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6085079312324524, + "bbox": [ + 252.24537658691406, + 2051.8115234375, + 320.007568359375, + 2129.72509765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5714181661605835, + "bbox": [ + 2121.674072265625, + 3071.4169921875, + 2187.406982421875, + 3139.539306640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5603699088096619, + "bbox": [ + 1259.2344970703125, + 2335.939697265625, + 1324.157958984375, + 2410.65771484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9606887102127075, + "bbox": [ + 212.1630096435547, + 374.3209228515625, + 1214.235107421875, + 2447.73291015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9581459164619446, + "bbox": [ + 252.73916625976562, + 590.4154663085938, + 1191.886474609375, + 1924.550048828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9495642185211182, + "bbox": [ + 1226.61181640625, + 384.3192443847656, + 2342.485107421875, + 2732.600341796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9430052638053894, + "bbox": [ + 1264.0965576171875, + 609.1795043945312, + 2210.238037109375, + 2103.279052734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9215652942657471, + "bbox": [ + 1258.311279296875, + 2145.02685546875, + 2219.642822265625, + 2623.100830078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8931517601013184, + "bbox": [ + 246.94166564941406, + 1987.853515625, + 1193.8262939453125, + 2344.37939453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7632874250411987, + "bbox": [ + 278.0298767089844, + 512.6778564453125, + 809.997314453125, + 583.1834106445312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7256768941879272, + "bbox": [ + 1278.171875, + 525.3020629882812, + 2074.1826171875, + 608.5372314453125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7704930901527405, + "bbox": [ + 1278.50390625, + 428.1532287597656, + 1378.7559814453125, + 516.4186401367188 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7660089731216431, + "bbox": [ + 272.17938232421875, + 417.98846435546875, + 373.4778137207031, + 503.37646484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6935708522796631, + "bbox": [ + 1022.9564208984375, + 511.60992431640625, + 1137.188232421875, + 624.1637573242188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6412867903709412, + "bbox": [ + 1560.87841796875, + 396.8089599609375, + 1692.5703125, + 526.0737915039062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6085079312324524, + "bbox": [ + 252.24537658691406, + 2051.8115234375, + 320.007568359375, + 2129.72509765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5714181661605835, + "bbox": [ + 2121.674072265625, + 3071.4169921875, + 2187.406982421875, + 3139.539306640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5603699088096619, + "bbox": [ + 1259.2344970703125, + 2335.939697265625, + 1324.157958984375, + 2410.65771484375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9606887102127075, + "bbox": [ + 212.1630096435547, + 374.3209228515625, + 1214.235107421875, + 2447.73291015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9581459164619446, + "bbox": [ + 252.73916625976562, + 590.4154663085938, + 1191.886474609375, + 1924.550048828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9495642185211182, + "bbox": [ + 1226.61181640625, + 384.3192443847656, + 2342.485107421875, + 2732.600341796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9430052638053894, + "bbox": [ + 1264.0965576171875, + 609.1795043945312, + 2210.238037109375, + 2103.279052734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9215652942657471, + "bbox": [ + 1258.311279296875, + 2145.02685546875, + 2219.642822265625, + 2623.100830078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8931517601013184, + "bbox": [ + 246.94166564941406, + 1987.853515625, + 1193.8262939453125, + 2344.37939453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7632874250411987, + "bbox": [ + 278.0298767089844, + 512.6778564453125, + 809.997314453125, + 583.1834106445312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7256768941879272, + "bbox": [ + 1278.171875, + 525.3020629882812, + 2074.1826171875, + 608.5372314453125 + ] + } + ], + "timestamp": "2025-10-15T21:43:23.574899" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 42.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 42.json" new file mode 100644 index 0000000..710304a --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 42.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 42.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7746860980987549, + "bbox": [ + 1305.7808837890625, + 463.9405212402344, + 1411.87353515625, + 556.7373657226562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7627440094947815, + "bbox": [ + 253.69287109375, + 439.0149230957031, + 361.7425231933594, + 532.6146240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7203215956687927, + "bbox": [ + 233.90243530273438, + 2254.19482421875, + 300.6990051269531, + 2334.261962890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7125086784362793, + "bbox": [ + 851.4931030273438, + 540.1419067382812, + 957.6577758789062, + 650.2022094726562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6795146465301514, + "bbox": [ + 1893.40625, + 542.3942260742188, + 2008.872802734375, + 650.734619140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5904086828231812, + "bbox": [ + 1262.9464111328125, + 2482.47802734375, + 1350.1436767578125, + 2604.143310546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5448732972145081, + "bbox": [ + 220.23251342773438, + 3208.184326171875, + 284.95208740234375, + 3279.4912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9502140283584595, + "bbox": [ + 1289.65869140625, + 651.6404418945312, + 2255.57275390625, + 2115.330078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9488906264305115, + "bbox": [ + 223.61814880371094, + 2123.25341796875, + 1197.5814208984375, + 2667.544189453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9457461833953857, + "bbox": [ + 245.62489318847656, + 628.8764038085938, + 1215.645263671875, + 2108.302978515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9445514678955078, + "bbox": [ + 1278.370361328125, + 2126.092529296875, + 2276.478271484375, + 2815.958740234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.929721474647522, + "bbox": [ + 210.7411346435547, + 454.82073974609375, + 1238.378662109375, + 2681.951416015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9281341433525085, + "bbox": [ + 1273.3570556640625, + 445.7247619628906, + 2294.51416015625, + 2824.548095703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7607080936431885, + "bbox": [ + 1305.3443603515625, + 558.714111328125, + 1858.5296630859375, + 642.2191162109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7370347380638123, + "bbox": [ + 260.9091491699219, + 535.5781860351562, + 806.7699584960938, + 616.169189453125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7746860980987549, + "bbox": [ + 1305.7808837890625, + 463.9405212402344, + 1411.87353515625, + 556.7373657226562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7627440094947815, + "bbox": [ + 253.69287109375, + 439.0149230957031, + 361.7425231933594, + 532.6146240234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7203215956687927, + "bbox": [ + 233.90243530273438, + 2254.19482421875, + 300.6990051269531, + 2334.261962890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7125086784362793, + "bbox": [ + 851.4931030273438, + 540.1419067382812, + 957.6577758789062, + 650.2022094726562 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6795146465301514, + "bbox": [ + 1893.40625, + 542.3942260742188, + 2008.872802734375, + 650.734619140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5904086828231812, + "bbox": [ + 1262.9464111328125, + 2482.47802734375, + 1350.1436767578125, + 2604.143310546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5448732972145081, + "bbox": [ + 220.23251342773438, + 3208.184326171875, + 284.95208740234375, + 3279.4912109375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9502140283584595, + "bbox": [ + 1289.65869140625, + 651.6404418945312, + 2255.57275390625, + 2115.330078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9488906264305115, + "bbox": [ + 223.61814880371094, + 2123.25341796875, + 1197.5814208984375, + 2667.544189453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9457461833953857, + "bbox": [ + 245.62489318847656, + 628.8764038085938, + 1215.645263671875, + 2108.302978515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9445514678955078, + "bbox": [ + 1278.370361328125, + 2126.092529296875, + 2276.478271484375, + 2815.958740234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.929721474647522, + "bbox": [ + 210.7411346435547, + 454.82073974609375, + 1238.378662109375, + 2681.951416015625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9281341433525085, + "bbox": [ + 1273.3570556640625, + 445.7247619628906, + 2294.51416015625, + 2824.548095703125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7607080936431885, + "bbox": [ + 1305.3443603515625, + 558.714111328125, + 1858.5296630859375, + 642.2191162109375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7370347380638123, + "bbox": [ + 260.9091491699219, + 535.5781860351562, + 806.7699584960938, + 616.169189453125 + ] + } + ], + "timestamp": "2025-10-15T21:43:23.269848" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 43.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 43.json" new file mode 100644 index 0000000..280afd6 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 43.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 43.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.8039552569389343, + "bbox": [ + 1288.2667236328125, + 444.808837890625, + 1388.116943359375, + 532.298828125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7848572134971619, + "bbox": [ + 270.17645263671875, + 429.76080322265625, + 370.3000793457031, + 515.5499877929688 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7206164002418518, + "bbox": [ + 236.4505615234375, + 2172.7607421875, + 312.0801086425781, + 2253.761474609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7093446850776672, + "bbox": [ + 922.391845703125, + 527.2451782226562, + 1029.745361328125, + 627.534912109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6879465579986572, + "bbox": [ + 1882.165771484375, + 524.4732666015625, + 1998.200927734375, + 628.2763671875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5427035093307495, + "bbox": [ + 2125.669677734375, + 3136.19189453125, + 2187.322998046875, + 3201.577880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5274348855018616, + "bbox": [ + 1262.73388671875, + 2312.609130859375, + 1320.851318359375, + 2389.0048828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3918744921684265, + "bbox": [ + 2117.759765625, + 3127.5185546875, + 2193.734375, + 3206.89599609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467979669570923, + "bbox": [ + 259.1834716796875, + 611.2193603515625, + 1194.6339111328125, + 2043.5908203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9431027770042419, + "bbox": [ + 231.5713653564453, + 2046.8077392578125, + 1185.7298583984375, + 2710.495361328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.941900908946991, + "bbox": [ + 1250.595703125, + 2301.87841796875, + 2210.11083984375, + 2994.392333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9391692280769348, + "bbox": [ + 216.26011657714844, + 382.04595947265625, + 1217.029541015625, + 2752.213623046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.937053382396698, + "bbox": [ + 1256.363525390625, + 630.2880249023438, + 2206.486328125, + 2283.434814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9227409958839417, + "bbox": [ + 1247.66259765625, + 402.3257141113281, + 2226.161376953125, + 3002.470947265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8329855799674988, + "bbox": [ + 1288.8583984375, + 540.76904296875, + 1827.7896728515625, + 619.51416015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.786961019039154, + "bbox": [ + 269.44342041015625, + 519.3678588867188, + 807.2881469726562, + 598.6730346679688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.8039552569389343, + "bbox": [ + 1288.2667236328125, + 444.808837890625, + 1388.116943359375, + 532.298828125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7848572134971619, + "bbox": [ + 270.17645263671875, + 429.76080322265625, + 370.3000793457031, + 515.5499877929688 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7206164002418518, + "bbox": [ + 236.4505615234375, + 2172.7607421875, + 312.0801086425781, + 2253.761474609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7093446850776672, + "bbox": [ + 922.391845703125, + 527.2451782226562, + 1029.745361328125, + 627.534912109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6879465579986572, + "bbox": [ + 1882.165771484375, + 524.4732666015625, + 1998.200927734375, + 628.2763671875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5427035093307495, + "bbox": [ + 2125.669677734375, + 3136.19189453125, + 2187.322998046875, + 3201.577880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5274348855018616, + "bbox": [ + 1262.73388671875, + 2312.609130859375, + 1320.851318359375, + 2389.0048828125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.3918744921684265, + "bbox": [ + 2117.759765625, + 3127.5185546875, + 2193.734375, + 3206.89599609375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9467979669570923, + "bbox": [ + 259.1834716796875, + 611.2193603515625, + 1194.6339111328125, + 2043.5908203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9431027770042419, + "bbox": [ + 231.5713653564453, + 2046.8077392578125, + 1185.7298583984375, + 2710.495361328125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.941900908946991, + "bbox": [ + 1250.595703125, + 2301.87841796875, + 2210.11083984375, + 2994.392333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9391692280769348, + "bbox": [ + 216.26011657714844, + 382.04595947265625, + 1217.029541015625, + 2752.213623046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.937053382396698, + "bbox": [ + 1256.363525390625, + 630.2880249023438, + 2206.486328125, + 2283.434814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9227409958839417, + "bbox": [ + 1247.66259765625, + 402.3257141113281, + 2226.161376953125, + 3002.470947265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8329855799674988, + "bbox": [ + 1288.8583984375, + 540.76904296875, + 1827.7896728515625, + 619.51416015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.786961019039154, + "bbox": [ + 269.44342041015625, + 519.3678588867188, + 807.2881469726562, + 598.6730346679688 + ] + } + ], + "timestamp": "2025-10-15T21:43:23.713488" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 44.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 44.json" new file mode 100644 index 0000000..e67e1c3 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 44.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 44.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7845910787582397, + "bbox": [ + 245.999267578125, + 445.87652587890625, + 345.4327697753906, + 536.3497924804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7820394039154053, + "bbox": [ + 1294.6217041015625, + 456.06939697265625, + 1399.06005859375, + 545.6227416992188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6507018208503723, + "bbox": [ + 863.2969970703125, + 2590.098876953125, + 987.869140625, + 2712.94482421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6207662224769592, + "bbox": [ + 1852.10986328125, + 2410.89453125, + 1978.6109619140625, + 2541.1328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5552783608436584, + "bbox": [ + 199.14100646972656, + 3208.264404296875, + 264.80889892578125, + 3279.2373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5505495667457581, + "bbox": [ + 1270.28271484375, + 2046.583984375, + 1333.0772705078125, + 2125.27880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4882269501686096, + "bbox": [ + 214.9437255859375, + 2250.5615234375, + 307.1544189453125, + 2379.091064453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9374234676361084, + "bbox": [ + 209.8842315673828, + 1890.6182861328125, + 1179.4910888671875, + 2573.814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9263067245483398, + "bbox": [ + 235.85838317871094, + 626.661376953125, + 1208.9600830078125, + 1908.19873046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9254040122032166, + "bbox": [ + 1256.765869140625, + 445.131591796875, + 2286.751708984375, + 2384.210205078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.924713134765625, + "bbox": [ + 215.1496124267578, + 408.5166015625, + 1213.23828125, + 2603.1298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.922139585018158, + "bbox": [ + 1270.826904296875, + 1921.19091796875, + 2255.972412109375, + 2349.409912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9161280393600464, + "bbox": [ + 1282.2891845703125, + 640.4149169921875, + 2251.07666015625, + 1867.8896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.78031986951828, + "bbox": [ + 1297.1019287109375, + 554.3802490234375, + 1878.3837890625, + 637.9168701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7180740237236023, + "bbox": [ + 246.48385620117188, + 536.1273803710938, + 819.8499755859375, + 613.4973754882812 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7845910787582397, + "bbox": [ + 245.999267578125, + 445.87652587890625, + 345.4327697753906, + 536.3497924804688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7820394039154053, + "bbox": [ + 1294.6217041015625, + 456.06939697265625, + 1399.06005859375, + 545.6227416992188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6507018208503723, + "bbox": [ + 863.2969970703125, + 2590.098876953125, + 987.869140625, + 2712.94482421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6207662224769592, + "bbox": [ + 1852.10986328125, + 2410.89453125, + 1978.6109619140625, + 2541.1328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5552783608436584, + "bbox": [ + 199.14100646972656, + 3208.264404296875, + 264.80889892578125, + 3279.2373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5505495667457581, + "bbox": [ + 1270.28271484375, + 2046.583984375, + 1333.0772705078125, + 2125.27880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4882269501686096, + "bbox": [ + 214.9437255859375, + 2250.5615234375, + 307.1544189453125, + 2379.091064453125 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9374234676361084, + "bbox": [ + 209.8842315673828, + 1890.6182861328125, + 1179.4910888671875, + 2573.814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9263067245483398, + "bbox": [ + 235.85838317871094, + 626.661376953125, + 1208.9600830078125, + 1908.19873046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9254040122032166, + "bbox": [ + 1256.765869140625, + 445.131591796875, + 2286.751708984375, + 2384.210205078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.924713134765625, + "bbox": [ + 215.1496124267578, + 408.5166015625, + 1213.23828125, + 2603.1298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.922139585018158, + "bbox": [ + 1270.826904296875, + 1921.19091796875, + 2255.972412109375, + 2349.409912109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9161280393600464, + "bbox": [ + 1282.2891845703125, + 640.4149169921875, + 2251.07666015625, + 1867.8896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.78031986951828, + "bbox": [ + 1297.1019287109375, + 554.3802490234375, + 1878.3837890625, + 637.9168701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7180740237236023, + "bbox": [ + 246.48385620117188, + 536.1273803710938, + 819.8499755859375, + 613.4973754882812 + ] + } + ], + "timestamp": "2025-10-15T21:43:24.152413" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 45.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 45.json" new file mode 100644 index 0000000..e274c4c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 45.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 45.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7931270599365234, + "bbox": [ + 1311.9981689453125, + 436.4145812988281, + 1407.85888671875, + 521.4217529296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7587273716926575, + "bbox": [ + 316.2994689941406, + 421.86138916015625, + 416.55242919921875, + 508.7156677246094 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6463793516159058, + "bbox": [ + 937.572998046875, + 2624.193115234375, + 1057.8326416015625, + 2742.765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.624078094959259, + "bbox": [ + 1725.593994140625, + 2667.236328125, + 1852.017578125, + 2782.94189453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5799404382705688, + "bbox": [ + 2124.63916015625, + 3055.417236328125, + 2192.68017578125, + 3124.4306640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5614355802536011, + "bbox": [ + 1269.6162109375, + 2240.910400390625, + 1342.140625, + 2329.63330078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4390317499637604, + "bbox": [ + 264.9559020996094, + 2333.263427734375, + 339.5945129394531, + 2441.2021484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.35075685381889343, + "bbox": [ + 1704.2557373046875, + 2650.145751953125, + 1869.216796875, + 2805.676025390625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9529445767402649, + "bbox": [ + 257.5992736816406, + 384.68408203125, + 1220.3992919921875, + 2706.79248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9502235651016235, + "bbox": [ + 268.4039611816406, + 2051.927978515625, + 1199.833251953125, + 2624.282470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9471122026443481, + "bbox": [ + 298.0169372558594, + 596.5098876953125, + 1223.0772705078125, + 2023.62939453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9348850846290588, + "bbox": [ + 1285.727783203125, + 599.9483032226562, + 2221.41259765625, + 2188.06201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9252095818519592, + "bbox": [ + 1270.8231201171875, + 411.1346435546875, + 2251.297607421875, + 2815.730712890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9032801389694214, + "bbox": [ + 1278.500244140625, + 2195.905029296875, + 2214.2451171875, + 2656.06201171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8423024415969849, + "bbox": [ + 1304.7052001953125, + 529.2310180664062, + 1871.400146484375, + 609.80126953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7191998958587646, + "bbox": [ + 311.24237060546875, + 513.063232421875, + 866.3126831054688, + 588.3631591796875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7931270599365234, + "bbox": [ + 1311.9981689453125, + 436.4145812988281, + 1407.85888671875, + 521.4217529296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7587273716926575, + "bbox": [ + 316.2994689941406, + 421.86138916015625, + 416.55242919921875, + 508.7156677246094 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6463793516159058, + "bbox": [ + 937.572998046875, + 2624.193115234375, + 1057.8326416015625, + 2742.765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.624078094959259, + "bbox": [ + 1725.593994140625, + 2667.236328125, + 1852.017578125, + 2782.94189453125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5799404382705688, + "bbox": [ + 2124.63916015625, + 3055.417236328125, + 2192.68017578125, + 3124.4306640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5614355802536011, + "bbox": [ + 1269.6162109375, + 2240.910400390625, + 1342.140625, + 2329.63330078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4390317499637604, + "bbox": [ + 264.9559020996094, + 2333.263427734375, + 339.5945129394531, + 2441.2021484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.35075685381889343, + "bbox": [ + 1704.2557373046875, + 2650.145751953125, + 1869.216796875, + 2805.676025390625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9529445767402649, + "bbox": [ + 257.5992736816406, + 384.68408203125, + 1220.3992919921875, + 2706.79248046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9502235651016235, + "bbox": [ + 268.4039611816406, + 2051.927978515625, + 1199.833251953125, + 2624.282470703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9471122026443481, + "bbox": [ + 298.0169372558594, + 596.5098876953125, + 1223.0772705078125, + 2023.62939453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9348850846290588, + "bbox": [ + 1285.727783203125, + 599.9483032226562, + 2221.41259765625, + 2188.06201171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9252095818519592, + "bbox": [ + 1270.8231201171875, + 411.1346435546875, + 2251.297607421875, + 2815.730712890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9032801389694214, + "bbox": [ + 1278.500244140625, + 2195.905029296875, + 2214.2451171875, + 2656.06201171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8423024415969849, + "bbox": [ + 1304.7052001953125, + 529.2310180664062, + 1871.400146484375, + 609.80126953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7191998958587646, + "bbox": [ + 311.24237060546875, + 513.063232421875, + 866.3126831054688, + 588.3631591796875 + ] + } + ], + "timestamp": "2025-10-15T21:43:24.588446" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 46.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 46.json" new file mode 100644 index 0000000..cca52da --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 46.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 46.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7843865156173706, + "bbox": [ + 1207.572509765625, + 415.8751525878906, + 1308.035400390625, + 502.2336120605469 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7566031813621521, + "bbox": [ + 226.0583953857422, + 399.6450500488281, + 324.3490905761719, + 485.2010192871094 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6890085935592651, + "bbox": [ + 1808.068603515625, + 459.8889465332031, + 1940.491943359375, + 589.8876342773438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6784251928329468, + "bbox": [ + 826.2779541015625, + 434.4393615722656, + 944.7090454101562, + 554.8372192382812 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6009083390235901, + "bbox": [ + 206.2031707763672, + 3002.328857421875, + 265.1278381347656, + 3065.1064453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3886060118675232, + "bbox": [ + 910.659912109375, + 1870.14306640625, + 979.3333740234375, + 1958.6322021484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.35170474648475647, + "bbox": [ + 1611.9703369140625, + 2503.47412109375, + 1703.369873046875, + 2615.57763671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.26060688495635986, + "bbox": [ + 912.573974609375, + 1881.109130859375, + 971.9015502929688, + 1952.630126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22912733256816864, + "bbox": [ + 1615.51953125, + 2521.79345703125, + 1687.4873046875, + 2604.911865234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.933727502822876, + "bbox": [ + 174.71627807617188, + 393.9068603515625, + 1133.452880859375, + 2354.1494140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9207546710968018, + "bbox": [ + 1170.7996826171875, + 380.8194885253906, + 2101.07568359375, + 2811.97705078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9101459980010986, + "bbox": [ + 188.31361389160156, + 597.335205078125, + 1109.9005126953125, + 2330.333740234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8943648338317871, + "bbox": [ + 1185.260009765625, + 601.4429931640625, + 2085.86865234375, + 2775.410400390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7673927545547485, + "bbox": [ + 1197.0540771484375, + 504.17291259765625, + 1756.362060546875, + 590.1963500976562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6961699724197388, + "bbox": [ + 245.38504028320312, + 488.6070556640625, + 800.1921997070312, + 559.661376953125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7843865156173706, + "bbox": [ + 1207.572509765625, + 415.8751525878906, + 1308.035400390625, + 502.2336120605469 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7566031813621521, + "bbox": [ + 226.0583953857422, + 399.6450500488281, + 324.3490905761719, + 485.2010192871094 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6890085935592651, + "bbox": [ + 1808.068603515625, + 459.8889465332031, + 1940.491943359375, + 589.8876342773438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6784251928329468, + "bbox": [ + 826.2779541015625, + 434.4393615722656, + 944.7090454101562, + 554.8372192382812 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6009083390235901, + "bbox": [ + 206.2031707763672, + 3002.328857421875, + 265.1278381347656, + 3065.1064453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3886060118675232, + "bbox": [ + 910.659912109375, + 1870.14306640625, + 979.3333740234375, + 1958.6322021484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.35170474648475647, + "bbox": [ + 1611.9703369140625, + 2503.47412109375, + 1703.369873046875, + 2615.57763671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.26060688495635986, + "bbox": [ + 912.573974609375, + 1881.109130859375, + 971.9015502929688, + 1952.630126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22912733256816864, + "bbox": [ + 1615.51953125, + 2521.79345703125, + 1687.4873046875, + 2604.911865234375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.933727502822876, + "bbox": [ + 174.71627807617188, + 393.9068603515625, + 1133.452880859375, + 2354.1494140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9207546710968018, + "bbox": [ + 1170.7996826171875, + 380.8194885253906, + 2101.07568359375, + 2811.97705078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9101459980010986, + "bbox": [ + 188.31361389160156, + 597.335205078125, + 1109.9005126953125, + 2330.333740234375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8943648338317871, + "bbox": [ + 1185.260009765625, + 601.4429931640625, + 2085.86865234375, + 2775.410400390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7673927545547485, + "bbox": [ + 1197.0540771484375, + 504.17291259765625, + 1756.362060546875, + 590.1963500976562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6961699724197388, + "bbox": [ + 245.38504028320312, + 488.6070556640625, + 800.1921997070312, + 559.661376953125 + ] + } + ], + "timestamp": "2025-10-15T21:43:25.006462" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 47.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 47.json" new file mode 100644 index 0000000..100a91c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 47.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 47.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7637745141983032, + "bbox": [ + 1281.3331298828125, + 431.3254699707031, + 1382.662109375, + 518.2401123046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7615582346916199, + "bbox": [ + 268.7275390625, + 417.9487609863281, + 370.343994140625, + 505.3556213378906 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.700963020324707, + "bbox": [ + 902.0318603515625, + 500.62420654296875, + 1018.945556640625, + 615.0596923828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6734440326690674, + "bbox": [ + 1860.009521484375, + 480.6521911621094, + 1980.3133544921875, + 592.3084716796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6073032021522522, + "bbox": [ + 1380.986083984375, + 1583.1798095703125, + 1476.1507568359375, + 1692.702880859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5591750741004944, + "bbox": [ + 2115.88623046875, + 3100.304443359375, + 2179.758544921875, + 3167.580322265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48304539918899536, + "bbox": [ + 817.1116333007812, + 1908.6402587890625, + 920.1727905273438, + 2031.4873046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.23558421432971954, + "bbox": [ + 2108.99072265625, + 3092.55517578125, + 2185.157470703125, + 3175.589111328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22681589424610138, + "bbox": [ + 821.4630737304688, + 1920.0452880859375, + 899.2451171875, + 2024.4661865234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9371247887611389, + "bbox": [ + 1250.2119140625, + 394.1856994628906, + 2216.448974609375, + 2530.40185546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9193915128707886, + "bbox": [ + 241.201904296875, + 451.201416015625, + 1214.4248046875, + 2637.3427734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9149619340896606, + "bbox": [ + 1258.4056396484375, + 613.6257934570312, + 2198.619140625, + 2501.471923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.895502507686615, + "bbox": [ + 257.1153869628906, + 601.7205200195312, + 1192.04345703125, + 2638.293212890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8659393191337585, + "bbox": [ + 269.3448486328125, + 508.31427001953125, + 867.6799926757812, + 593.4024047851562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7746074795722961, + "bbox": [ + 1276.8433837890625, + 523.4634399414062, + 1831.685791015625, + 597.4881591796875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7637745141983032, + "bbox": [ + 1281.3331298828125, + 431.3254699707031, + 1382.662109375, + 518.2401123046875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7615582346916199, + "bbox": [ + 268.7275390625, + 417.9487609863281, + 370.343994140625, + 505.3556213378906 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.700963020324707, + "bbox": [ + 902.0318603515625, + 500.62420654296875, + 1018.945556640625, + 615.0596923828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6734440326690674, + "bbox": [ + 1860.009521484375, + 480.6521911621094, + 1980.3133544921875, + 592.3084716796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6073032021522522, + "bbox": [ + 1380.986083984375, + 1583.1798095703125, + 1476.1507568359375, + 1692.702880859375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5591750741004944, + "bbox": [ + 2115.88623046875, + 3100.304443359375, + 2179.758544921875, + 3167.580322265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.48304539918899536, + "bbox": [ + 817.1116333007812, + 1908.6402587890625, + 920.1727905273438, + 2031.4873046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.23558421432971954, + "bbox": [ + 2108.99072265625, + 3092.55517578125, + 2185.157470703125, + 3175.589111328125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.22681589424610138, + "bbox": [ + 821.4630737304688, + 1920.0452880859375, + 899.2451171875, + 2024.4661865234375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9371247887611389, + "bbox": [ + 1250.2119140625, + 394.1856994628906, + 2216.448974609375, + 2530.40185546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9193915128707886, + "bbox": [ + 241.201904296875, + 451.201416015625, + 1214.4248046875, + 2637.3427734375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9149619340896606, + "bbox": [ + 1258.4056396484375, + 613.6257934570312, + 2198.619140625, + 2501.471923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.895502507686615, + "bbox": [ + 257.1153869628906, + 601.7205200195312, + 1192.04345703125, + 2638.293212890625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8659393191337585, + "bbox": [ + 269.3448486328125, + 508.31427001953125, + 867.6799926757812, + 593.4024047851562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7746074795722961, + "bbox": [ + 1276.8433837890625, + 523.4634399414062, + 1831.685791015625, + 597.4881591796875 + ] + } + ], + "timestamp": "2025-10-15T21:43:25.399830" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 48.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 48.json" new file mode 100644 index 0000000..8b96a81 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 48.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 48.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.761832594871521, + "bbox": [ + 1194.5025634765625, + 426.0437927246094, + 1294.8182373046875, + 513.5643920898438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7558843493461609, + "bbox": [ + 217.1937713623047, + 421.4517517089844, + 317.0434875488281, + 509.03997802734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6906967759132385, + "bbox": [ + 766.6115112304688, + 2271.959716796875, + 879.8487548828125, + 2390.0087890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5859882235527039, + "bbox": [ + 1611.577392578125, + 2178.003173828125, + 1733.277099609375, + 2301.035888671875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5273987650871277, + "bbox": [ + 220.9464569091797, + 2976.860107421875, + 283.26971435546875, + 3043.1962890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5247274041175842, + "bbox": [ + 222.21620178222656, + 2126.157958984375, + 281.7179870605469, + 2200.72412109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3841470181941986, + "bbox": [ + 1595.612060546875, + 2172.345947265625, + 1747.837158203125, + 2315.735595703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3773598372936249, + "bbox": [ + 1186.9813232421875, + 1777.7135009765625, + 1257.454833984375, + 1863.5328369140625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9491549730300903, + "bbox": [ + 197.5543975830078, + 419.8193664550781, + 1135.0311279296875, + 2313.736083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9441031813621521, + "bbox": [ + 213.30897521972656, + 654.7716064453125, + 1122.309326171875, + 1899.614990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.938422441482544, + "bbox": [ + 1191.224365234375, + 1727.22412109375, + 2086.506103515625, + 2171.40869140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9156239628791809, + "bbox": [ + 1183.12451171875, + 603.550537109375, + 2094.80810546875, + 1739.456787109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.914038360118866, + "bbox": [ + 1177.0543212890625, + 418.02117919921875, + 2119.41650390625, + 2233.0517578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9041059613227844, + "bbox": [ + 226.46212768554688, + 1946.5125732421875, + 1031.5899658203125, + 2272.9189453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8196301460266113, + "bbox": [ + 212.6968231201172, + 506.2052001953125, + 1110.7606201171875, + 632.6334838867188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.686562180519104, + "bbox": [ + 1190.712890625, + 520.4950561523438, + 2061.48388671875, + 583.3331909179688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.761832594871521, + "bbox": [ + 1194.5025634765625, + 426.0437927246094, + 1294.8182373046875, + 513.5643920898438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7558843493461609, + "bbox": [ + 217.1937713623047, + 421.4517517089844, + 317.0434875488281, + 509.03997802734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6906967759132385, + "bbox": [ + 766.6115112304688, + 2271.959716796875, + 879.8487548828125, + 2390.0087890625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5859882235527039, + "bbox": [ + 1611.577392578125, + 2178.003173828125, + 1733.277099609375, + 2301.035888671875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5273987650871277, + "bbox": [ + 220.9464569091797, + 2976.860107421875, + 283.26971435546875, + 3043.1962890625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5247274041175842, + "bbox": [ + 222.21620178222656, + 2126.157958984375, + 281.7179870605469, + 2200.72412109375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.3841470181941986, + "bbox": [ + 1595.612060546875, + 2172.345947265625, + 1747.837158203125, + 2315.735595703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3773598372936249, + "bbox": [ + 1186.9813232421875, + 1777.7135009765625, + 1257.454833984375, + 1863.5328369140625 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9491549730300903, + "bbox": [ + 197.5543975830078, + 419.8193664550781, + 1135.0311279296875, + 2313.736083984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9441031813621521, + "bbox": [ + 213.30897521972656, + 654.7716064453125, + 1122.309326171875, + 1899.614990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.938422441482544, + "bbox": [ + 1191.224365234375, + 1727.22412109375, + 2086.506103515625, + 2171.40869140625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9156239628791809, + "bbox": [ + 1183.12451171875, + 603.550537109375, + 2094.80810546875, + 1739.456787109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.914038360118866, + "bbox": [ + 1177.0543212890625, + 418.02117919921875, + 2119.41650390625, + 2233.0517578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9041059613227844, + "bbox": [ + 226.46212768554688, + 1946.5125732421875, + 1031.5899658203125, + 2272.9189453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8196301460266113, + "bbox": [ + 212.6968231201172, + 506.2052001953125, + 1110.7606201171875, + 632.6334838867188 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.686562180519104, + "bbox": [ + 1190.712890625, + 520.4950561523438, + 2061.48388671875, + 583.3331909179688 + ] + } + ], + "timestamp": "2025-10-15T21:43:25.783379" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 49.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 49.json" new file mode 100644 index 0000000..2806cd7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 49.json" @@ -0,0 +1,384 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 49.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.780134916305542, + "bbox": [ + 256.15020751953125, + 434.1932067871094, + 354.1650695800781, + 519.278076171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7795239686965942, + "bbox": [ + 1252.0650634765625, + 438.5823974609375, + 1348.4190673828125, + 524.1647338867188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7196395993232727, + "bbox": [ + 848.813232421875, + 2407.525634765625, + 954.1893920898438, + 2511.158935546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5952417254447937, + "bbox": [ + 1658.5916748046875, + 2422.9990234375, + 1790.88720703125, + 2557.6962890625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5826197266578674, + "bbox": [ + 2081.43798828125, + 3065.691162109375, + 2148.2568359375, + 3136.514892578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5644999146461487, + "bbox": [ + 1244.0379638671875, + 2074.459228515625, + 1308.9884033203125, + 2153.791015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4584798514842987, + "bbox": [ + 258.18878173828125, + 1936.684326171875, + 318.6199951171875, + 2011.361083984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.25767257809638977, + "bbox": [ + 1643.815673828125, + 2413.978271484375, + 1810.749267578125, + 2571.27783203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23458905518054962, + "bbox": [ + 1238.3782958984375, + 2060.038330078125, + 1321.0302734375, + 2162.014404296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9619943499565125, + "bbox": [ + 233.8098907470703, + 435.261962890625, + 1196.7174072265625, + 2478.4482421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9512573480606079, + "bbox": [ + 251.65020751953125, + 659.0870361328125, + 1168.5526123046875, + 1916.99609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9458175301551819, + "bbox": [ + 1240.2913818359375, + 618.889892578125, + 2155.150634765625, + 1860.6180419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9365116953849792, + "bbox": [ + 1222.9481201171875, + 431.4078674316406, + 2173.12548828125, + 2549.2587890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9321571588516235, + "bbox": [ + 1242.382568359375, + 1898.4298095703125, + 2160.006103515625, + 2353.427978515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8854532837867737, + "bbox": [ + 262.89263916015625, + 1914.3111572265625, + 1145.04052734375, + 2293.63525390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484488725662231, + "bbox": [ + 253.18734741210938, + 523.8699951171875, + 1163.755126953125, + 646.6802368164062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6665724515914917, + "bbox": [ + 1255.01318359375, + 530.4454956054688, + 2061.2529296875, + 598.1119995117188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.780134916305542, + "bbox": [ + 256.15020751953125, + 434.1932067871094, + 354.1650695800781, + 519.278076171875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7795239686965942, + "bbox": [ + 1252.0650634765625, + 438.5823974609375, + 1348.4190673828125, + 524.1647338867188 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7196395993232727, + "bbox": [ + 848.813232421875, + 2407.525634765625, + 954.1893920898438, + 2511.158935546875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5952417254447937, + "bbox": [ + 1658.5916748046875, + 2422.9990234375, + 1790.88720703125, + 2557.6962890625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5826197266578674, + "bbox": [ + 2081.43798828125, + 3065.691162109375, + 2148.2568359375, + 3136.514892578125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5644999146461487, + "bbox": [ + 1244.0379638671875, + 2074.459228515625, + 1308.9884033203125, + 2153.791015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4584798514842987, + "bbox": [ + 258.18878173828125, + 1936.684326171875, + 318.6199951171875, + 2011.361083984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.25767257809638977, + "bbox": [ + 1643.815673828125, + 2413.978271484375, + 1810.749267578125, + 2571.27783203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.23458905518054962, + "bbox": [ + 1238.3782958984375, + 2060.038330078125, + 1321.0302734375, + 2162.014404296875 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9619943499565125, + "bbox": [ + 233.8098907470703, + 435.261962890625, + 1196.7174072265625, + 2478.4482421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9512573480606079, + "bbox": [ + 251.65020751953125, + 659.0870361328125, + 1168.5526123046875, + 1916.99609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9458175301551819, + "bbox": [ + 1240.2913818359375, + 618.889892578125, + 2155.150634765625, + 1860.6180419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9365116953849792, + "bbox": [ + 1222.9481201171875, + 431.4078674316406, + 2173.12548828125, + 2549.2587890625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9321571588516235, + "bbox": [ + 1242.382568359375, + 1898.4298095703125, + 2160.006103515625, + 2353.427978515625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8854532837867737, + "bbox": [ + 262.89263916015625, + 1914.3111572265625, + 1145.04052734375, + 2293.63525390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484488725662231, + "bbox": [ + 253.18734741210938, + 523.8699951171875, + 1163.755126953125, + 646.6802368164062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6665724515914917, + "bbox": [ + 1255.01318359375, + 530.4454956054688, + 2061.2529296875, + 598.1119995117188 + ] + } + ], + "timestamp": "2025-10-15T21:43:26.165593" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 50.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 50.json" new file mode 100644 index 0000000..eff9059 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 50.json" @@ -0,0 +1,384 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 50.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7904474139213562, + "bbox": [ + 1305.9730224609375, + 454.6781005859375, + 1411.0693359375, + 544.9685668945312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7630218863487244, + "bbox": [ + 262.91156005859375, + 436.4554138183594, + 368.8863830566406, + 529.860107421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6920769214630127, + "bbox": [ + 1632.2176513671875, + 433.8262023925781, + 1750.3948974609375, + 545.2208862304688 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.690771222114563, + "bbox": [ + 843.9723510742188, + 427.2707824707031, + 955.9827270507812, + 537.5853881835938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6154984831809998, + "bbox": [ + 1289.9635009765625, + 2731.99072265625, + 1354.92236328125, + 2809.833984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5829889178276062, + "bbox": [ + 249.4376678466797, + 3182.93896484375, + 311.1623229980469, + 3248.7451171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3711366057395935, + "bbox": [ + 254.37771606445312, + 2672.283935546875, + 322.44378662109375, + 2751.8310546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3064165711402893, + "bbox": [ + 253.32247924804688, + 2638.01953125, + 333.4209899902344, + 2756.7998046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2254997342824936, + "bbox": [ + 240.2407989501953, + 3173.567138671875, + 318.4705810546875, + 3259.79931640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9421749711036682, + "bbox": [ + 1284.8690185546875, + 680.3593139648438, + 2261.192138671875, + 2588.590576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9301369786262512, + "bbox": [ + 255.45822143554688, + 2468.455078125, + 1138.59619140625, + 2827.376708984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9293893575668335, + "bbox": [ + 243.26011657714844, + 665.6390991210938, + 1212.5750732421875, + 2456.0751953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9261131882667542, + "bbox": [ + 229.2140350341797, + 374.9838562011719, + 1237.4315185546875, + 2898.684326171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9104871153831482, + "bbox": [ + 1297.6397705078125, + 2601.8232421875, + 2172.830078125, + 2952.422607421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9095256924629211, + "bbox": [ + 1289.8665771484375, + 412.5694885253906, + 2283.015869140625, + 3025.748046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8420007824897766, + "bbox": [ + 260.91064453125, + 528.5440063476562, + 1229.6417236328125, + 668.8494873046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8399321436882019, + "bbox": [ + 1298.3521728515625, + 549.59326171875, + 2259.93115234375, + 679.4110107421875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7904474139213562, + "bbox": [ + 1305.9730224609375, + 454.6781005859375, + 1411.0693359375, + 544.9685668945312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7630218863487244, + "bbox": [ + 262.91156005859375, + 436.4554138183594, + 368.8863830566406, + 529.860107421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6920769214630127, + "bbox": [ + 1632.2176513671875, + 433.8262023925781, + 1750.3948974609375, + 545.2208862304688 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.690771222114563, + "bbox": [ + 843.9723510742188, + 427.2707824707031, + 955.9827270507812, + 537.5853881835938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6154984831809998, + "bbox": [ + 1289.9635009765625, + 2731.99072265625, + 1354.92236328125, + 2809.833984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5829889178276062, + "bbox": [ + 249.4376678466797, + 3182.93896484375, + 311.1623229980469, + 3248.7451171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3711366057395935, + "bbox": [ + 254.37771606445312, + 2672.283935546875, + 322.44378662109375, + 2751.8310546875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3064165711402893, + "bbox": [ + 253.32247924804688, + 2638.01953125, + 333.4209899902344, + 2756.7998046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2254997342824936, + "bbox": [ + 240.2407989501953, + 3173.567138671875, + 318.4705810546875, + 3259.79931640625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9421749711036682, + "bbox": [ + 1284.8690185546875, + 680.3593139648438, + 2261.192138671875, + 2588.590576171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9301369786262512, + "bbox": [ + 255.45822143554688, + 2468.455078125, + 1138.59619140625, + 2827.376708984375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9293893575668335, + "bbox": [ + 243.26011657714844, + 665.6390991210938, + 1212.5750732421875, + 2456.0751953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9261131882667542, + "bbox": [ + 229.2140350341797, + 374.9838562011719, + 1237.4315185546875, + 2898.684326171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9104871153831482, + "bbox": [ + 1297.6397705078125, + 2601.8232421875, + 2172.830078125, + 2952.422607421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9095256924629211, + "bbox": [ + 1289.8665771484375, + 412.5694885253906, + 2283.015869140625, + 3025.748046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8420007824897766, + "bbox": [ + 260.91064453125, + 528.5440063476562, + 1229.6417236328125, + 668.8494873046875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8399321436882019, + "bbox": [ + 1298.3521728515625, + 549.59326171875, + 2259.93115234375, + 679.4110107421875 + ] + } + ], + "timestamp": "2025-10-15T21:43:26.560093" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 51.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 51.json" new file mode 100644 index 0000000..2574723 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 51.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 51.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7854154706001282, + "bbox": [ + 290.4771423339844, + 417.18902587890625, + 390.0992431640625, + 501.3641357421875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7761234045028687, + "bbox": [ + 1289.3033447265625, + 423.1119384765625, + 1388.7099609375, + 510.2628479003906 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7106432318687439, + "bbox": [ + 1285.0648193359375, + 2797.974609375, + 1343.6654052734375, + 2871.871826171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6930999755859375, + "bbox": [ + 287.39227294921875, + 2351.132080078125, + 351.663330078125, + 2428.945068359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6618533134460449, + "bbox": [ + 807.1292724609375, + 2736.12109375, + 925.4517211914062, + 2843.675048828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6608365774154663, + "bbox": [ + 2022.101806640625, + 2627.602294921875, + 2141.164306640625, + 2744.98046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.551425576210022, + "bbox": [ + 2134.673583984375, + 3041.867919921875, + 2197.433837890625, + 3108.06103515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.42401012778282166, + "bbox": [ + 790.3473510742188, + 2725.0234375, + 935.4253540039062, + 2861.962158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357022643089294, + "bbox": [ + 1287.615478515625, + 627.7685546875, + 2196.891357421875, + 2592.86572265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198180437088013, + "bbox": [ + 298.74517822265625, + 643.5359497070312, + 1195.21337890625, + 2302.4326171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9115281701087952, + "bbox": [ + 255.140380859375, + 375.18609619140625, + 1216.0118408203125, + 2847.78173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9038777947425842, + "bbox": [ + 284.9263916015625, + 2293.08251953125, + 1032.755615234375, + 2654.053466796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8992204070091248, + "bbox": [ + 1281.1580810546875, + 2612.266357421875, + 2019.0830078125, + 2947.741455078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.868629515171051, + "bbox": [ + 1257.5802001953125, + 399.0816955566406, + 2218.2685546875, + 2938.5888671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8370141983032227, + "bbox": [ + 1290.6041259765625, + 520.753662109375, + 2202.096923828125, + 637.7318725585938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8265472054481506, + "bbox": [ + 282.6708068847656, + 510.51275634765625, + 1186.576416015625, + 632.8124389648438 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7854154706001282, + "bbox": [ + 290.4771423339844, + 417.18902587890625, + 390.0992431640625, + 501.3641357421875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7761234045028687, + "bbox": [ + 1289.3033447265625, + 423.1119384765625, + 1388.7099609375, + 510.2628479003906 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7106432318687439, + "bbox": [ + 1285.0648193359375, + 2797.974609375, + 1343.6654052734375, + 2871.871826171875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6930999755859375, + "bbox": [ + 287.39227294921875, + 2351.132080078125, + 351.663330078125, + 2428.945068359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6618533134460449, + "bbox": [ + 807.1292724609375, + 2736.12109375, + 925.4517211914062, + 2843.675048828125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6608365774154663, + "bbox": [ + 2022.101806640625, + 2627.602294921875, + 2141.164306640625, + 2744.98046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.551425576210022, + "bbox": [ + 2134.673583984375, + 3041.867919921875, + 2197.433837890625, + 3108.06103515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.42401012778282166, + "bbox": [ + 790.3473510742188, + 2725.0234375, + 935.4253540039062, + 2861.962158203125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357022643089294, + "bbox": [ + 1287.615478515625, + 627.7685546875, + 2196.891357421875, + 2592.86572265625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9198180437088013, + "bbox": [ + 298.74517822265625, + 643.5359497070312, + 1195.21337890625, + 2302.4326171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9115281701087952, + "bbox": [ + 255.140380859375, + 375.18609619140625, + 1216.0118408203125, + 2847.78173828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9038777947425842, + "bbox": [ + 284.9263916015625, + 2293.08251953125, + 1032.755615234375, + 2654.053466796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8992204070091248, + "bbox": [ + 1281.1580810546875, + 2612.266357421875, + 2019.0830078125, + 2947.741455078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.868629515171051, + "bbox": [ + 1257.5802001953125, + 399.0816955566406, + 2218.2685546875, + 2938.5888671875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8370141983032227, + "bbox": [ + 1290.6041259765625, + 520.753662109375, + 2202.096923828125, + 637.7318725585938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8265472054481506, + "bbox": [ + 282.6708068847656, + 510.51275634765625, + 1186.576416015625, + 632.8124389648438 + ] + } + ], + "timestamp": "2025-10-15T21:43:26.954636" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 52.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 52.json" new file mode 100644 index 0000000..7b2db88 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 52.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 52.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7662975788116455, + "bbox": [ + 1181.9298095703125, + 418.1208190917969, + 1276.76904296875, + 501.273681640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7651606202125549, + "bbox": [ + 238.84234619140625, + 407.6986389160156, + 335.3639831542969, + 493.5775451660156 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7574838399887085, + "bbox": [ + 223.2606964111328, + 2107.860595703125, + 287.1679382324219, + 2182.319091796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6849161386489868, + "bbox": [ + 1732.557861328125, + 1851.436279296875, + 1840.6265869140625, + 1960.90576171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6094217896461487, + "bbox": [ + 743.2024536132812, + 2415.5263671875, + 845.207763671875, + 2527.278076171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5847049951553345, + "bbox": [ + 215.71961975097656, + 2875.9697265625, + 271.43115234375, + 2935.2841796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5225362777709961, + "bbox": [ + 1172.2532958984375, + 816.0643920898438, + 1249.7344970703125, + 903.9634399414062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5047069191932678, + "bbox": [ + 734.7420654296875, + 2405.249755859375, + 859.104248046875, + 2538.71484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9509910941123962, + "bbox": [ + 1173.77685546875, + 591.7689819335938, + 2047.6138916015625, + 1747.31884765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443930387496948, + "bbox": [ + 213.1787872314453, + 630.439208984375, + 1108.1746826171875, + 1928.7957763671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9433186054229736, + "bbox": [ + 189.13523864746094, + 386.7783203125, + 1135.1199951171875, + 2476.931640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9248924255371094, + "bbox": [ + 218.98199462890625, + 1940.9918212890625, + 901.3555908203125, + 2342.6748046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9082744121551514, + "bbox": [ + 1140.8138427734375, + 417.06158447265625, + 2073.177978515625, + 2025.3173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8433235287666321, + "bbox": [ + 228.4076385498047, + 498.2198486328125, + 1108.6871337890625, + 613.7312622070312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.837347149848938, + "bbox": [ + 1190.2017822265625, + 500.0388488769531, + 1798.352294921875, + 584.0289306640625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7662975788116455, + "bbox": [ + 1181.9298095703125, + 418.1208190917969, + 1276.76904296875, + 501.273681640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7651606202125549, + "bbox": [ + 238.84234619140625, + 407.6986389160156, + 335.3639831542969, + 493.5775451660156 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7574838399887085, + "bbox": [ + 223.2606964111328, + 2107.860595703125, + 287.1679382324219, + 2182.319091796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6849161386489868, + "bbox": [ + 1732.557861328125, + 1851.436279296875, + 1840.6265869140625, + 1960.90576171875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6094217896461487, + "bbox": [ + 743.2024536132812, + 2415.5263671875, + 845.207763671875, + 2527.278076171875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5847049951553345, + "bbox": [ + 215.71961975097656, + 2875.9697265625, + 271.43115234375, + 2935.2841796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5225362777709961, + "bbox": [ + 1172.2532958984375, + 816.0643920898438, + 1249.7344970703125, + 903.9634399414062 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5047069191932678, + "bbox": [ + 734.7420654296875, + 2405.249755859375, + 859.104248046875, + 2538.71484375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9509910941123962, + "bbox": [ + 1173.77685546875, + 591.7689819335938, + 2047.6138916015625, + 1747.31884765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443930387496948, + "bbox": [ + 213.1787872314453, + 630.439208984375, + 1108.1746826171875, + 1928.7957763671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9433186054229736, + "bbox": [ + 189.13523864746094, + 386.7783203125, + 1135.1199951171875, + 2476.931640625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9248924255371094, + "bbox": [ + 218.98199462890625, + 1940.9918212890625, + 901.3555908203125, + 2342.6748046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9082744121551514, + "bbox": [ + 1140.8138427734375, + 417.06158447265625, + 2073.177978515625, + 2025.3173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8433235287666321, + "bbox": [ + 228.4076385498047, + 498.2198486328125, + 1108.6871337890625, + 613.7312622070312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.837347149848938, + "bbox": [ + 1190.2017822265625, + 500.0388488769531, + 1798.352294921875, + 584.0289306640625 + ] + } + ], + "timestamp": "2025-10-15T21:43:27.317907" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 53.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 53.json" new file mode 100644 index 0000000..e7ad877 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 53.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 53.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7776870727539062, + "bbox": [ + 277.3514099121094, + 422.8056335449219, + 373.1806335449219, + 505.22857666015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7764809727668762, + "bbox": [ + 1245.8756103515625, + 428.1627197265625, + 1339.373291015625, + 511.60601806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6531369090080261, + "bbox": [ + 988.7063598632812, + 2013.277099609375, + 1096.4603271484375, + 2128.322998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6297010183334351, + "bbox": [ + 1668.37646484375, + 1913.3929443359375, + 1791.078125, + 2040.564697265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6178457140922546, + "bbox": [ + 255.87615966796875, + 2175.26318359375, + 329.344970703125, + 2257.562744140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.613615095615387, + "bbox": [ + 1888.4476318359375, + 1227.1279296875, + 1954.6668701171875, + 1306.857177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5705599188804626, + "bbox": [ + 2042.65283203125, + 2990.894287109375, + 2103.212646484375, + 3056.4130859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2275792807340622, + "bbox": [ + 969.3150634765625, + 2005.765625, + 1111.2447509765625, + 2140.613037109375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9468862414360046, + "bbox": [ + 254.73191833496094, + 651.42041015625, + 1171.2901611328125, + 1970.5809326171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9387440085411072, + "bbox": [ + 1232.663818359375, + 604.806884765625, + 2129.69091796875, + 1880.404052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9349392652511597, + "bbox": [ + 231.6981658935547, + 448.2294006347656, + 1183.143798828125, + 2386.577392578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9115840792655945, + "bbox": [ + 253.46728515625, + 1999.3887939453125, + 919.6586303710938, + 2396.5888671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.894453763961792, + "bbox": [ + 1214.1220703125, + 443.4949645996094, + 2143.558837890625, + 2030.9503173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8736072182655334, + "bbox": [ + 1241.4033203125, + 511.8125305175781, + 1883.948486328125, + 601.1817016601562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484728932380676, + "bbox": [ + 260.4945068359375, + 510.651123046875, + 1165.119140625, + 633.6161499023438 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7776870727539062, + "bbox": [ + 277.3514099121094, + 422.8056335449219, + 373.1806335449219, + 505.22857666015625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7764809727668762, + "bbox": [ + 1245.8756103515625, + 428.1627197265625, + 1339.373291015625, + 511.60601806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6531369090080261, + "bbox": [ + 988.7063598632812, + 2013.277099609375, + 1096.4603271484375, + 2128.322998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6297010183334351, + "bbox": [ + 1668.37646484375, + 1913.3929443359375, + 1791.078125, + 2040.564697265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6178457140922546, + "bbox": [ + 255.87615966796875, + 2175.26318359375, + 329.344970703125, + 2257.562744140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.613615095615387, + "bbox": [ + 1888.4476318359375, + 1227.1279296875, + 1954.6668701171875, + 1306.857177734375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5705599188804626, + "bbox": [ + 2042.65283203125, + 2990.894287109375, + 2103.212646484375, + 3056.4130859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2275792807340622, + "bbox": [ + 969.3150634765625, + 2005.765625, + 1111.2447509765625, + 2140.613037109375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9468862414360046, + "bbox": [ + 254.73191833496094, + 651.42041015625, + 1171.2901611328125, + 1970.5809326171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9387440085411072, + "bbox": [ + 1232.663818359375, + 604.806884765625, + 2129.69091796875, + 1880.404052734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9349392652511597, + "bbox": [ + 231.6981658935547, + 448.2294006347656, + 1183.143798828125, + 2386.577392578125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9115840792655945, + "bbox": [ + 253.46728515625, + 1999.3887939453125, + 919.6586303710938, + 2396.5888671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.894453763961792, + "bbox": [ + 1214.1220703125, + 443.4949645996094, + 2143.558837890625, + 2030.9503173828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8736072182655334, + "bbox": [ + 1241.4033203125, + 511.8125305175781, + 1883.948486328125, + 601.1817016601562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484728932380676, + "bbox": [ + 260.4945068359375, + 510.651123046875, + 1165.119140625, + 633.6161499023438 + ] + } + ], + "timestamp": "2025-10-15T21:43:27.673320" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 54.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 54.json" new file mode 100644 index 0000000..f3685b5 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 54.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 54.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.78201824426651, + "bbox": [ + 1323.244140625, + 474.7957458496094, + 1431.791259765625, + 566.0184936523438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.774132490158081, + "bbox": [ + 246.69383239746094, + 453.9662780761719, + 353.6776123046875, + 549.9122314453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7423201203346252, + "bbox": [ + 799.26220703125, + 617.6736450195312, + 907.159423828125, + 714.4849853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7159913778305054, + "bbox": [ + 1876.692138671875, + 658.9224853515625, + 2003.4940185546875, + 770.1031494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7040601968765259, + "bbox": [ + 523.4143676757812, + 900.336181640625, + 595.6331176757812, + 989.3965454101562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5410500764846802, + "bbox": [ + 227.0045623779297, + 3252.660888671875, + 288.62469482421875, + 3322.428466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5295572876930237, + "bbox": [ + 1301.65087890625, + 2471.95703125, + 1387.244384765625, + 2562.998291015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443438053131104, + "bbox": [ + 1322.0054931640625, + 696.43115234375, + 2322.208251953125, + 2377.401123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9438110589981079, + "bbox": [ + 216.12615966796875, + 690.2120971679688, + 1230.273193359375, + 2503.69677734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9435372948646545, + "bbox": [ + 1303.927734375, + 438.7765808105469, + 2339.639892578125, + 2850.604248046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9357724785804749, + "bbox": [ + 212.17478942871094, + 468.6466064453125, + 1238.067626953125, + 2528.662109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9306666851043701, + "bbox": [ + 1298.1627197265625, + 2344.998291015625, + 2269.142333984375, + 2783.48291015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8393926620483398, + "bbox": [ + 1309.0, + 568.8095092773438, + 2318.184326171875, + 701.3134765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8303240537643433, + "bbox": [ + 254.0231170654297, + 559.037353515625, + 1235.6661376953125, + 690.0201416015625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.78201824426651, + "bbox": [ + 1323.244140625, + 474.7957458496094, + 1431.791259765625, + 566.0184936523438 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.774132490158081, + "bbox": [ + 246.69383239746094, + 453.9662780761719, + 353.6776123046875, + 549.9122314453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7423201203346252, + "bbox": [ + 799.26220703125, + 617.6736450195312, + 907.159423828125, + 714.4849853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7159913778305054, + "bbox": [ + 1876.692138671875, + 658.9224853515625, + 2003.4940185546875, + 770.1031494140625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7040601968765259, + "bbox": [ + 523.4143676757812, + 900.336181640625, + 595.6331176757812, + 989.3965454101562 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5410500764846802, + "bbox": [ + 227.0045623779297, + 3252.660888671875, + 288.62469482421875, + 3322.428466796875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5295572876930237, + "bbox": [ + 1301.65087890625, + 2471.95703125, + 1387.244384765625, + 2562.998291015625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9443438053131104, + "bbox": [ + 1322.0054931640625, + 696.43115234375, + 2322.208251953125, + 2377.401123046875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9438110589981079, + "bbox": [ + 216.12615966796875, + 690.2120971679688, + 1230.273193359375, + 2503.69677734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9435372948646545, + "bbox": [ + 1303.927734375, + 438.7765808105469, + 2339.639892578125, + 2850.604248046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9357724785804749, + "bbox": [ + 212.17478942871094, + 468.6466064453125, + 1238.067626953125, + 2528.662109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9306666851043701, + "bbox": [ + 1298.1627197265625, + 2344.998291015625, + 2269.142333984375, + 2783.48291015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8393926620483398, + "bbox": [ + 1309.0, + 568.8095092773438, + 2318.184326171875, + 701.3134765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8303240537643433, + "bbox": [ + 254.0231170654297, + 559.037353515625, + 1235.6661376953125, + 690.0201416015625 + ] + } + ], + "timestamp": "2025-10-15T21:43:28.047778" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 55.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 55.json" new file mode 100644 index 0000000..ea5d485 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 55.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 55.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7716618776321411, + "bbox": [ + 1290.8358154296875, + 449.0101013183594, + 1392.3846435546875, + 535.672119140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7703613638877869, + "bbox": [ + 276.9950256347656, + 429.8171691894531, + 377.5768737792969, + 518.9830322265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6826803088188171, + "bbox": [ + 1799.977783203125, + 2197.838623046875, + 1901.07568359375, + 2296.591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6612007021903992, + "bbox": [ + 619.1699829101562, + 2325.635009765625, + 724.9519653320312, + 2440.180419921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6169714331626892, + "bbox": [ + 338.88677978515625, + 1777.6578369140625, + 414.3040771484375, + 1868.0682373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5182663798332214, + "bbox": [ + 1275.2696533203125, + 2479.123779296875, + 1329.752197265625, + 2550.365234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4906849265098572, + "bbox": [ + 2133.081298828125, + 3114.877685546875, + 2195.68408203125, + 3183.533447265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.38651373982429504, + "bbox": [ + 601.76611328125, + 2316.23486328125, + 734.6893310546875, + 2450.95556640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9537068605422974, + "bbox": [ + 1273.3426513671875, + 682.309326171875, + 2215.9482421875, + 2279.011962890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9388247728347778, + "bbox": [ + 276.10015869140625, + 660.271484375, + 1216.425048828125, + 2213.355712890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9375671148300171, + "bbox": [ + 253.34909057617188, + 452.5361022949219, + 1233.920166015625, + 2542.4716796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9307223558425903, + "bbox": [ + 1254.3526611328125, + 411.3973388671875, + 2227.123291015625, + 2747.972412109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9237676858901978, + "bbox": [ + 1290.911865234375, + 2287.94189453125, + 2178.74853515625, + 2726.447509765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8570380806922913, + "bbox": [ + 1277.110595703125, + 540.9954833984375, + 2232.50244140625, + 670.0107421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.851348876953125, + "bbox": [ + 280.9107360839844, + 523.6336059570312, + 1201.949462890625, + 655.3038940429688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7716618776321411, + "bbox": [ + 1290.8358154296875, + 449.0101013183594, + 1392.3846435546875, + 535.672119140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7703613638877869, + "bbox": [ + 276.9950256347656, + 429.8171691894531, + 377.5768737792969, + 518.9830322265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6826803088188171, + "bbox": [ + 1799.977783203125, + 2197.838623046875, + 1901.07568359375, + 2296.591796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6612007021903992, + "bbox": [ + 619.1699829101562, + 2325.635009765625, + 724.9519653320312, + 2440.180419921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6169714331626892, + "bbox": [ + 338.88677978515625, + 1777.6578369140625, + 414.3040771484375, + 1868.0682373046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5182663798332214, + "bbox": [ + 1275.2696533203125, + 2479.123779296875, + 1329.752197265625, + 2550.365234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4906849265098572, + "bbox": [ + 2133.081298828125, + 3114.877685546875, + 2195.68408203125, + 3183.533447265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.38651373982429504, + "bbox": [ + 601.76611328125, + 2316.23486328125, + 734.6893310546875, + 2450.95556640625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9537068605422974, + "bbox": [ + 1273.3426513671875, + 682.309326171875, + 2215.9482421875, + 2279.011962890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9388247728347778, + "bbox": [ + 276.10015869140625, + 660.271484375, + 1216.425048828125, + 2213.355712890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9375671148300171, + "bbox": [ + 253.34909057617188, + 452.5361022949219, + 1233.920166015625, + 2542.4716796875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9307223558425903, + "bbox": [ + 1254.3526611328125, + 411.3973388671875, + 2227.123291015625, + 2747.972412109375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9237676858901978, + "bbox": [ + 1290.911865234375, + 2287.94189453125, + 2178.74853515625, + 2726.447509765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8570380806922913, + "bbox": [ + 1277.110595703125, + 540.9954833984375, + 2232.50244140625, + 670.0107421875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.851348876953125, + "bbox": [ + 280.9107360839844, + 523.6336059570312, + 1201.949462890625, + 655.3038940429688 + ] + } + ], + "timestamp": "2025-10-15T21:43:28.480345" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 56.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 56.json" new file mode 100644 index 0000000..316a33c --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 56.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 56.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7878429293632507, + "bbox": [ + 1248.7259521484375, + 437.1191711425781, + 1351.6226806640625, + 523.3489379882812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7821791768074036, + "bbox": [ + 241.67250061035156, + 424.4669189453125, + 342.28466796875, + 514.49755859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7327080368995667, + "bbox": [ + 723.5433349609375, + 1790.8006591796875, + 825.8709716796875, + 1898.12939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.694329023361206, + "bbox": [ + 231.88723754882812, + 1950.0643310546875, + 299.7809143066406, + 2027.8167724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6586117744445801, + "bbox": [ + 1860.229736328125, + 2234.301513671875, + 1989.147705078125, + 2381.00146484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.524495542049408, + "bbox": [ + 222.86643981933594, + 3078.16650390625, + 281.7267150878906, + 3146.27880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.39756831526756287, + "bbox": [ + 1232.576171875, + 2486.002685546875, + 1293.6368408203125, + 2562.329345703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3281264901161194, + "bbox": [ + 1229.134521484375, + 2476.947265625, + 1304.47021484375, + 2569.721435546875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9559857845306396, + "bbox": [ + 230.9691162109375, + 592.2944946289062, + 1177.403564453125, + 1788.7237548828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9303390979766846, + "bbox": [ + 179.50743103027344, + 410.19921875, + 1200.6910400390625, + 2228.29736328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9294762015342712, + "bbox": [ + 1233.1446533203125, + 591.7938842773438, + 2190.725341796875, + 2258.859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9186832308769226, + "bbox": [ + 1234.328125, + 354.5795593261719, + 2237.955810546875, + 2740.6298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8996248841285706, + "bbox": [ + 1226.0301513671875, + 2292.518798828125, + 1764.616943359375, + 2654.072021484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8648650646209717, + "bbox": [ + 1240.8758544921875, + 526.3724365234375, + 1903.0428466796875, + 619.2955322265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8390024304389954, + "bbox": [ + 227.57862854003906, + 1813.0103759765625, + 553.6353759765625, + 2178.764404296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8256607055664062, + "bbox": [ + 241.5628662109375, + 513.5860595703125, + 866.1226196289062, + 599.595703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7878429293632507, + "bbox": [ + 1248.7259521484375, + 437.1191711425781, + 1351.6226806640625, + 523.3489379882812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7821791768074036, + "bbox": [ + 241.67250061035156, + 424.4669189453125, + 342.28466796875, + 514.49755859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7327080368995667, + "bbox": [ + 723.5433349609375, + 1790.8006591796875, + 825.8709716796875, + 1898.12939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.694329023361206, + "bbox": [ + 231.88723754882812, + 1950.0643310546875, + 299.7809143066406, + 2027.8167724609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6586117744445801, + "bbox": [ + 1860.229736328125, + 2234.301513671875, + 1989.147705078125, + 2381.00146484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.524495542049408, + "bbox": [ + 222.86643981933594, + 3078.16650390625, + 281.7267150878906, + 3146.27880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.39756831526756287, + "bbox": [ + 1232.576171875, + 2486.002685546875, + 1293.6368408203125, + 2562.329345703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3281264901161194, + "bbox": [ + 1229.134521484375, + 2476.947265625, + 1304.47021484375, + 2569.721435546875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9559857845306396, + "bbox": [ + 230.9691162109375, + 592.2944946289062, + 1177.403564453125, + 1788.7237548828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9303390979766846, + "bbox": [ + 179.50743103027344, + 410.19921875, + 1200.6910400390625, + 2228.29736328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9294762015342712, + "bbox": [ + 1233.1446533203125, + 591.7938842773438, + 2190.725341796875, + 2258.859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9186832308769226, + "bbox": [ + 1234.328125, + 354.5795593261719, + 2237.955810546875, + 2740.6298828125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8996248841285706, + "bbox": [ + 1226.0301513671875, + 2292.518798828125, + 1764.616943359375, + 2654.072021484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8648650646209717, + "bbox": [ + 1240.8758544921875, + 526.3724365234375, + 1903.0428466796875, + 619.2955322265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8390024304389954, + "bbox": [ + 227.57862854003906, + 1813.0103759765625, + 553.6353759765625, + 2178.764404296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8256607055664062, + "bbox": [ + 241.5628662109375, + 513.5860595703125, + 866.1226196289062, + 599.595703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:28.898973" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 57.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 57.json" new file mode 100644 index 0000000..1b65ee7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 57.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 57.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7989176511764526, + "bbox": [ + 1220.1295166015625, + 429.2672119140625, + 1317.8433837890625, + 511.6912841796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7820753455162048, + "bbox": [ + 236.31141662597656, + 417.27532958984375, + 334.7438049316406, + 505.7097473144531 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7176951766014099, + "bbox": [ + 708.0447998046875, + 1755.4969482421875, + 808.021728515625, + 1860.3759765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7151309251785278, + "bbox": [ + 223.87400817871094, + 1910.3243408203125, + 291.10919189453125, + 1984.423583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6792254447937012, + "bbox": [ + 1813.1103515625, + 2186.65283203125, + 1947.3204345703125, + 2337.239990234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5823143124580383, + "bbox": [ + 212.9134521484375, + 3017.1640625, + 273.11590576171875, + 3083.5830078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.36342400312423706, + "bbox": [ + 1202.8487548828125, + 2428.09814453125, + 1274.7177734375, + 2512.600830078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9415574073791504, + "bbox": [ + 1202.479736328125, + 392.7911376953125, + 2167.0263671875, + 2653.431396484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9382830262184143, + "bbox": [ + 1209.230712890625, + 606.1560668945312, + 2140.428955078125, + 2214.660400390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9305949211120605, + "bbox": [ + 225.9620361328125, + 593.6521606445312, + 1141.7423095703125, + 1782.2159423828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9149758219718933, + "bbox": [ + 203.42527770996094, + 395.560791015625, + 1168.6373291015625, + 2161.176025390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.89565509557724, + "bbox": [ + 1210.9478759765625, + 2246.781005859375, + 1716.321044921875, + 2591.256591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8707748651504517, + "bbox": [ + 217.12245178222656, + 1778.7451171875, + 522.7432861328125, + 2132.5419921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484314680099487, + "bbox": [ + 1216.23291015625, + 517.83544921875, + 1842.0045166015625, + 604.8806762695312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8041062951087952, + "bbox": [ + 237.7939453125, + 513.2341918945312, + 842.8491821289062, + 588.991455078125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7989176511764526, + "bbox": [ + 1220.1295166015625, + 429.2672119140625, + 1317.8433837890625, + 511.6912841796875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7820753455162048, + "bbox": [ + 236.31141662597656, + 417.27532958984375, + 334.7438049316406, + 505.7097473144531 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7176951766014099, + "bbox": [ + 708.0447998046875, + 1755.4969482421875, + 808.021728515625, + 1860.3759765625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7151309251785278, + "bbox": [ + 223.87400817871094, + 1910.3243408203125, + 291.10919189453125, + 1984.423583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6792254447937012, + "bbox": [ + 1813.1103515625, + 2186.65283203125, + 1947.3204345703125, + 2337.239990234375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5823143124580383, + "bbox": [ + 212.9134521484375, + 3017.1640625, + 273.11590576171875, + 3083.5830078125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.36342400312423706, + "bbox": [ + 1202.8487548828125, + 2428.09814453125, + 1274.7177734375, + 2512.600830078125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9415574073791504, + "bbox": [ + 1202.479736328125, + 392.7911376953125, + 2167.0263671875, + 2653.431396484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9382830262184143, + "bbox": [ + 1209.230712890625, + 606.1560668945312, + 2140.428955078125, + 2214.660400390625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9305949211120605, + "bbox": [ + 225.9620361328125, + 593.6521606445312, + 1141.7423095703125, + 1782.2159423828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9149758219718933, + "bbox": [ + 203.42527770996094, + 395.560791015625, + 1168.6373291015625, + 2161.176025390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.89565509557724, + "bbox": [ + 1210.9478759765625, + 2246.781005859375, + 1716.321044921875, + 2591.256591796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8707748651504517, + "bbox": [ + 217.12245178222656, + 1778.7451171875, + 522.7432861328125, + 2132.5419921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8484314680099487, + "bbox": [ + 1216.23291015625, + 517.83544921875, + 1842.0045166015625, + 604.8806762695312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8041062951087952, + "bbox": [ + 237.7939453125, + 513.2341918945312, + 842.8491821289062, + 588.991455078125 + ] + } + ], + "timestamp": "2025-10-15T21:43:29.310931" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 58.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 58.json" new file mode 100644 index 0000000..207936f --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 58.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 58.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7775489091873169, + "bbox": [ + 283.4914245605469, + 432.0616149902344, + 383.5087585449219, + 518.190185546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7605919241905212, + "bbox": [ + 1301.0791015625, + 442.8301086425781, + 1402.9942626953125, + 530.723876953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6965488791465759, + "bbox": [ + 262.5986328125, + 2475.431884765625, + 330.7027282714844, + 2555.975341796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6868824362754822, + "bbox": [ + 724.7388305664062, + 2361.657470703125, + 845.6329956054688, + 2493.726806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6458823680877686, + "bbox": [ + 2203.141845703125, + 2297.3681640625, + 2348.8603515625, + 2422.44677734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6028180718421936, + "bbox": [ + 1276.532470703125, + 2838.206298828125, + 1364.6307373046875, + 2941.10400390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5103561282157898, + "bbox": [ + 2153.340576171875, + 3163.132080078125, + 2219.638427734375, + 3233.67333984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9578820466995239, + "bbox": [ + 229.01243591308594, + 406.07928466796875, + 1243.682861328125, + 2788.1640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.952389121055603, + "bbox": [ + 251.50709533691406, + 610.8395385742188, + 1210.37548828125, + 2336.5439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9346904158592224, + "bbox": [ + 1276.5509033203125, + 2416.17138671875, + 2234.60546875, + 3014.2451171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9226248264312744, + "bbox": [ + 1266.4962158203125, + 611.1201171875, + 2245.092529296875, + 2383.645751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8897944092750549, + "bbox": [ + 279.4750061035156, + 524.4847412109375, + 930.296630859375, + 615.3002319335938 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8862763047218323, + "bbox": [ + 1254.6156005859375, + 486.2048645019531, + 2249.841064453125, + 3103.45556640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8743375539779663, + "bbox": [ + 1297.4068603515625, + 532.4794921875, + 1939.033935546875, + 618.0802612304688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8339842557907104, + "bbox": [ + 254.16476440429688, + 2343.462646484375, + 542.8796997070312, + 2701.673095703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7775489091873169, + "bbox": [ + 283.4914245605469, + 432.0616149902344, + 383.5087585449219, + 518.190185546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7605919241905212, + "bbox": [ + 1301.0791015625, + 442.8301086425781, + 1402.9942626953125, + 530.723876953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6965488791465759, + "bbox": [ + 262.5986328125, + 2475.431884765625, + 330.7027282714844, + 2555.975341796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6868824362754822, + "bbox": [ + 724.7388305664062, + 2361.657470703125, + 845.6329956054688, + 2493.726806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6458823680877686, + "bbox": [ + 2203.141845703125, + 2297.3681640625, + 2348.8603515625, + 2422.44677734375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6028180718421936, + "bbox": [ + 1276.532470703125, + 2838.206298828125, + 1364.6307373046875, + 2941.10400390625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5103561282157898, + "bbox": [ + 2153.340576171875, + 3163.132080078125, + 2219.638427734375, + 3233.67333984375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9578820466995239, + "bbox": [ + 229.01243591308594, + 406.07928466796875, + 1243.682861328125, + 2788.1640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.952389121055603, + "bbox": [ + 251.50709533691406, + 610.8395385742188, + 1210.37548828125, + 2336.5439453125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9346904158592224, + "bbox": [ + 1276.5509033203125, + 2416.17138671875, + 2234.60546875, + 3014.2451171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9226248264312744, + "bbox": [ + 1266.4962158203125, + 611.1201171875, + 2245.092529296875, + 2383.645751953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8897944092750549, + "bbox": [ + 279.4750061035156, + 524.4847412109375, + 930.296630859375, + 615.3002319335938 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8862763047218323, + "bbox": [ + 1254.6156005859375, + 486.2048645019531, + 2249.841064453125, + 3103.45556640625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8743375539779663, + "bbox": [ + 1297.4068603515625, + 532.4794921875, + 1939.033935546875, + 618.0802612304688 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8339842557907104, + "bbox": [ + 254.16476440429688, + 2343.462646484375, + 542.8796997070312, + 2701.673095703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:29.745991" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 59.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 59.json" new file mode 100644 index 0000000..bbc67ac --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 59.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 59.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7862241268157959, + "bbox": [ + 1264.2506103515625, + 454.3207092285156, + 1367.503662109375, + 544.4924926757812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7760095596313477, + "bbox": [ + 241.83816528320312, + 441.433837890625, + 343.9618835449219, + 534.6007690429688 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7582188844680786, + "bbox": [ + 1246.122314453125, + 2423.9287109375, + 1313.342529296875, + 2501.473876953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7144309878349304, + "bbox": [ + 224.2533721923828, + 1950.4068603515625, + 300.8932189941406, + 2032.30859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6773825287818909, + "bbox": [ + 1802.351318359375, + 2635.589599609375, + 1923.245361328125, + 2756.16357421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6628341674804688, + "bbox": [ + 608.6179809570312, + 2327.087890625, + 723.0242919921875, + 2447.62646484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4307290315628052, + "bbox": [ + 210.0298614501953, + 3170.98681640625, + 273.76123046875, + 3241.570556640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.24180661141872406, + "bbox": [ + 1788.208984375, + 2627.4677734375, + 1941.4024658203125, + 2770.5634765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9543498158454895, + "bbox": [ + 1246.0457763671875, + 644.0110473632812, + 2190.347412109375, + 2219.230224609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9428220987319946, + "bbox": [ + 201.65757751464844, + 427.23614501953125, + 1203.2548828125, + 2432.7685546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9341171383857727, + "bbox": [ + 1242.8604736328125, + 403.46417236328125, + 2236.38720703125, + 2719.28955078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9323497414588928, + "bbox": [ + 245.5540008544922, + 630.1744995117188, + 1183.1478271484375, + 1887.114501953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9056631326675415, + "bbox": [ + 209.8916015625, + 1885.2369384765625, + 1174.9736328125, + 2245.2138671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8951770067214966, + "bbox": [ + 1248.7861328125, + 2223.74853515625, + 2057.235107421875, + 2581.74658203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8633673787117004, + "bbox": [ + 1260.9390869140625, + 547.5243530273438, + 1886.015625, + 634.9281005859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8011807203292847, + "bbox": [ + 245.7655487060547, + 539.2646484375, + 879.9325561523438, + 617.9425659179688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7862241268157959, + "bbox": [ + 1264.2506103515625, + 454.3207092285156, + 1367.503662109375, + 544.4924926757812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7760095596313477, + "bbox": [ + 241.83816528320312, + 441.433837890625, + 343.9618835449219, + 534.6007690429688 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7582188844680786, + "bbox": [ + 1246.122314453125, + 2423.9287109375, + 1313.342529296875, + 2501.473876953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7144309878349304, + "bbox": [ + 224.2533721923828, + 1950.4068603515625, + 300.8932189941406, + 2032.30859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6773825287818909, + "bbox": [ + 1802.351318359375, + 2635.589599609375, + 1923.245361328125, + 2756.16357421875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6628341674804688, + "bbox": [ + 608.6179809570312, + 2327.087890625, + 723.0242919921875, + 2447.62646484375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.4307290315628052, + "bbox": [ + 210.0298614501953, + 3170.98681640625, + 273.76123046875, + 3241.570556640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.24180661141872406, + "bbox": [ + 1788.208984375, + 2627.4677734375, + 1941.4024658203125, + 2770.5634765625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9543498158454895, + "bbox": [ + 1246.0457763671875, + 644.0110473632812, + 2190.347412109375, + 2219.230224609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9428220987319946, + "bbox": [ + 201.65757751464844, + 427.23614501953125, + 1203.2548828125, + 2432.7685546875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9341171383857727, + "bbox": [ + 1242.8604736328125, + 403.46417236328125, + 2236.38720703125, + 2719.28955078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9323497414588928, + "bbox": [ + 245.5540008544922, + 630.1744995117188, + 1183.1478271484375, + 1887.114501953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9056631326675415, + "bbox": [ + 209.8916015625, + 1885.2369384765625, + 1174.9736328125, + 2245.2138671875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8951770067214966, + "bbox": [ + 1248.7861328125, + 2223.74853515625, + 2057.235107421875, + 2581.74658203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8633673787117004, + "bbox": [ + 1260.9390869140625, + 547.5243530273438, + 1886.015625, + 634.9281005859375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8011807203292847, + "bbox": [ + 245.7655487060547, + 539.2646484375, + 879.9325561523438, + 617.9425659179688 + ] + } + ], + "timestamp": "2025-10-15T21:43:30.193247" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 60.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 60.json" new file mode 100644 index 0000000..75c1ad0 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 60.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 60.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7968915700912476, + "bbox": [ + 1215.6051025390625, + 422.79266357421875, + 1307.812255859375, + 505.1455993652344 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7706426382064819, + "bbox": [ + 256.1319274902344, + 415.9372253417969, + 353.700439453125, + 499.3877868652344 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7501000165939331, + "bbox": [ + 243.63853454589844, + 1960.4239501953125, + 310.301025390625, + 2031.8936767578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6988071799278259, + "bbox": [ + 577.8882446289062, + 2148.407958984375, + 684.1600952148438, + 2255.4853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6069499850273132, + "bbox": [ + 1673.6468505859375, + 2165.28125, + 1800.089111328125, + 2295.8349609375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5202502012252808, + "bbox": [ + 2020.4412841796875, + 2978.691650390625, + 2085.712890625, + 3046.674072265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5010879039764404, + "bbox": [ + 1202.388916015625, + 1765.6617431640625, + 1271.9085693359375, + 1842.583740234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2247111201286316, + "bbox": [ + 1201.8585205078125, + 1756.16162109375, + 1286.620361328125, + 1846.510009765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9502419829368591, + "bbox": [ + 245.2679443359375, + 590.2755126953125, + 1136.9891357421875, + 1776.190673828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.943726658821106, + "bbox": [ + 1186.5726318359375, + 417.40478515625, + 2117.782470703125, + 2242.03857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9392086863517761, + "bbox": [ + 1203.2076416015625, + 591.4410400390625, + 2096.302490234375, + 1752.8184814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9381285905838013, + "bbox": [ + 211.78260803222656, + 399.54815673828125, + 1159.265869140625, + 2218.43896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9160510301589966, + "bbox": [ + 1196.935302734375, + 1763.1705322265625, + 2094.54736328125, + 2122.0947265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9103603363037109, + "bbox": [ + 243.33094787597656, + 1768.634033203125, + 1125.4525146484375, + 2103.57177734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8633698225021362, + "bbox": [ + 1212.046630859375, + 510.5813903808594, + 1820.756103515625, + 589.9862060546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8333650827407837, + "bbox": [ + 252.84190368652344, + 499.13507080078125, + 858.7269287109375, + 590.0230102539062 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7968915700912476, + "bbox": [ + 1215.6051025390625, + 422.79266357421875, + 1307.812255859375, + 505.1455993652344 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7706426382064819, + "bbox": [ + 256.1319274902344, + 415.9372253417969, + 353.700439453125, + 499.3877868652344 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7501000165939331, + "bbox": [ + 243.63853454589844, + 1960.4239501953125, + 310.301025390625, + 2031.8936767578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6988071799278259, + "bbox": [ + 577.8882446289062, + 2148.407958984375, + 684.1600952148438, + 2255.4853515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6069499850273132, + "bbox": [ + 1673.6468505859375, + 2165.28125, + 1800.089111328125, + 2295.8349609375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5202502012252808, + "bbox": [ + 2020.4412841796875, + 2978.691650390625, + 2085.712890625, + 3046.674072265625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5010879039764404, + "bbox": [ + 1202.388916015625, + 1765.6617431640625, + 1271.9085693359375, + 1842.583740234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2247111201286316, + "bbox": [ + 1201.8585205078125, + 1756.16162109375, + 1286.620361328125, + 1846.510009765625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9502419829368591, + "bbox": [ + 245.2679443359375, + 590.2755126953125, + 1136.9891357421875, + 1776.190673828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.943726658821106, + "bbox": [ + 1186.5726318359375, + 417.40478515625, + 2117.782470703125, + 2242.03857421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9392086863517761, + "bbox": [ + 1203.2076416015625, + 591.4410400390625, + 2096.302490234375, + 1752.8184814453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9381285905838013, + "bbox": [ + 211.78260803222656, + 399.54815673828125, + 1159.265869140625, + 2218.43896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9160510301589966, + "bbox": [ + 1196.935302734375, + 1763.1705322265625, + 2094.54736328125, + 2122.0947265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9103603363037109, + "bbox": [ + 243.33094787597656, + 1768.634033203125, + 1125.4525146484375, + 2103.57177734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8633698225021362, + "bbox": [ + 1212.046630859375, + 510.5813903808594, + 1820.756103515625, + 589.9862060546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8333650827407837, + "bbox": [ + 252.84190368652344, + 499.13507080078125, + 858.7269287109375, + 590.0230102539062 + ] + } + ], + "timestamp": "2025-10-15T21:43:30.627357" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 61.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 61.json" new file mode 100644 index 0000000..226fff9 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 61.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 61.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7867382168769836, + "bbox": [ + 276.9656677246094, + 441.0323181152344, + 379.5300598144531, + 533.2345581054688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7688069343566895, + "bbox": [ + 1313.3463134765625, + 456.1064147949219, + 1421.037353515625, + 546.5509033203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7168067097663879, + "bbox": [ + 238.0077667236328, + 2140.5302734375, + 303.7331848144531, + 2219.7919921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7016903162002563, + "bbox": [ + 687.37158203125, + 2272.18701171875, + 793.736328125, + 2388.3330078125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6155722737312317, + "bbox": [ + 200.73997497558594, + 3177.150390625, + 265.0934143066406, + 3246.44189453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6128831505775452, + "bbox": [ + 1836.9141845703125, + 2757.261962890625, + 1968.0587158203125, + 2883.87939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5308651924133301, + "bbox": [ + 1282.7900390625, + 2196.515380859375, + 1366.3348388671875, + 2300.1376953125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9445486068725586, + "bbox": [ + 187.9001007080078, + 447.28253173828125, + 1232.50439453125, + 2355.262451171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9347812533378601, + "bbox": [ + 1276.6390380859375, + 2087.102294921875, + 2260.723388671875, + 2760.3486328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9341485500335693, + "bbox": [ + 235.21253967285156, + 677.480224609375, + 1233.281494140625, + 1828.9210205078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.928979218006134, + "bbox": [ + 1312.326171875, + 692.3761596679688, + 2287.13427734375, + 2047.3121337890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9027610421180725, + "bbox": [ + 1276.2777099609375, + 394.28436279296875, + 2318.14013671875, + 2823.1943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8787819147109985, + "bbox": [ + 244.66494750976562, + 1876.39306640625, + 1156.3612060546875, + 2225.802001953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.868323802947998, + "bbox": [ + 1320.1383056640625, + 557.8253784179688, + 2283.69921875, + 678.583984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8439749479293823, + "bbox": [ + 254.7745361328125, + 532.6582641601562, + 1239.684814453125, + 670.7265625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7867382168769836, + "bbox": [ + 276.9656677246094, + 441.0323181152344, + 379.5300598144531, + 533.2345581054688 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7688069343566895, + "bbox": [ + 1313.3463134765625, + 456.1064147949219, + 1421.037353515625, + 546.5509033203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7168067097663879, + "bbox": [ + 238.0077667236328, + 2140.5302734375, + 303.7331848144531, + 2219.7919921875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7016903162002563, + "bbox": [ + 687.37158203125, + 2272.18701171875, + 793.736328125, + 2388.3330078125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6155722737312317, + "bbox": [ + 200.73997497558594, + 3177.150390625, + 265.0934143066406, + 3246.44189453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6128831505775452, + "bbox": [ + 1836.9141845703125, + 2757.261962890625, + 1968.0587158203125, + 2883.87939453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5308651924133301, + "bbox": [ + 1282.7900390625, + 2196.515380859375, + 1366.3348388671875, + 2300.1376953125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9445486068725586, + "bbox": [ + 187.9001007080078, + 447.28253173828125, + 1232.50439453125, + 2355.262451171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9347812533378601, + "bbox": [ + 1276.6390380859375, + 2087.102294921875, + 2260.723388671875, + 2760.3486328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9341485500335693, + "bbox": [ + 235.21253967285156, + 677.480224609375, + 1233.281494140625, + 1828.9210205078125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.928979218006134, + "bbox": [ + 1312.326171875, + 692.3761596679688, + 2287.13427734375, + 2047.3121337890625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9027610421180725, + "bbox": [ + 1276.2777099609375, + 394.28436279296875, + 2318.14013671875, + 2823.1943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8787819147109985, + "bbox": [ + 244.66494750976562, + 1876.39306640625, + 1156.3612060546875, + 2225.802001953125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.868323802947998, + "bbox": [ + 1320.1383056640625, + 557.8253784179688, + 2283.69921875, + 678.583984375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8439749479293823, + "bbox": [ + 254.7745361328125, + 532.6582641601562, + 1239.684814453125, + 670.7265625 + ] + } + ], + "timestamp": "2025-10-15T21:43:31.051602" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 62.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 62.json" new file mode 100644 index 0000000..f4a6588 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 62.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 62.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7847425937652588, + "bbox": [ + 1283.482421875, + 434.8128662109375, + 1381.0645751953125, + 520.3748779296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7667604684829712, + "bbox": [ + 289.5599365234375, + 430.19036865234375, + 388.3841247558594, + 515.5416259765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6667987704277039, + "bbox": [ + 739.6033935546875, + 2669.900634765625, + 853.4111328125, + 2792.088134765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6355686187744141, + "bbox": [ + 1950.318115234375, + 2778.0537109375, + 2067.4013671875, + 2889.158935546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5416995882987976, + "bbox": [ + 2126.7255859375, + 3047.6962890625, + 2188.78173828125, + 3114.974853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5360406041145325, + "bbox": [ + 1271.8721923828125, + 2225.41455078125, + 1365.6734619140625, + 2342.993408203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5064846277236938, + "bbox": [ + 276.5186767578125, + 2478.424560546875, + 342.6667785644531, + 2573.746826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9515276551246643, + "bbox": [ + 1278.9449462890625, + 598.5579833984375, + 2209.611572265625, + 2104.07275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9478847980499268, + "bbox": [ + 1268.4285888671875, + 2140.723876953125, + 2195.18017578125, + 2771.830078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9465190172195435, + "bbox": [ + 271.6744079589844, + 2009.560791015625, + 1196.7437744140625, + 2639.562255859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9302257299423218, + "bbox": [ + 275.0104064941406, + 618.824951171875, + 1207.1348876953125, + 1994.101318359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9264856576919556, + "bbox": [ + 1251.2647705078125, + 374.88958740234375, + 2225.71337890625, + 2851.305419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9257607460021973, + "bbox": [ + 266.25921630859375, + 403.2320251464844, + 1226.078857421875, + 2711.920166015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7191731333732605, + "bbox": [ + 1292.204345703125, + 533.15234375, + 2148.95556640625, + 594.5885009765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6890917420387268, + "bbox": [ + 282.1640319824219, + 521.0567626953125, + 1172.987548828125, + 587.5680541992188 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7847425937652588, + "bbox": [ + 1283.482421875, + 434.8128662109375, + 1381.0645751953125, + 520.3748779296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7667604684829712, + "bbox": [ + 289.5599365234375, + 430.19036865234375, + 388.3841247558594, + 515.5416259765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6667987704277039, + "bbox": [ + 739.6033935546875, + 2669.900634765625, + 853.4111328125, + 2792.088134765625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6355686187744141, + "bbox": [ + 1950.318115234375, + 2778.0537109375, + 2067.4013671875, + 2889.158935546875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5416995882987976, + "bbox": [ + 2126.7255859375, + 3047.6962890625, + 2188.78173828125, + 3114.974853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5360406041145325, + "bbox": [ + 1271.8721923828125, + 2225.41455078125, + 1365.6734619140625, + 2342.993408203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5064846277236938, + "bbox": [ + 276.5186767578125, + 2478.424560546875, + 342.6667785644531, + 2573.746826171875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9515276551246643, + "bbox": [ + 1278.9449462890625, + 598.5579833984375, + 2209.611572265625, + 2104.07275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9478847980499268, + "bbox": [ + 1268.4285888671875, + 2140.723876953125, + 2195.18017578125, + 2771.830078125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9465190172195435, + "bbox": [ + 271.6744079589844, + 2009.560791015625, + 1196.7437744140625, + 2639.562255859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9302257299423218, + "bbox": [ + 275.0104064941406, + 618.824951171875, + 1207.1348876953125, + 1994.101318359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9264856576919556, + "bbox": [ + 1251.2647705078125, + 374.88958740234375, + 2225.71337890625, + 2851.305419921875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9257607460021973, + "bbox": [ + 266.25921630859375, + 403.2320251464844, + 1226.078857421875, + 2711.920166015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7191731333732605, + "bbox": [ + 1292.204345703125, + 533.15234375, + 2148.95556640625, + 594.5885009765625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6890917420387268, + "bbox": [ + 282.1640319824219, + 521.0567626953125, + 1172.987548828125, + 587.5680541992188 + ] + } + ], + "timestamp": "2025-10-15T21:43:31.485487" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 63.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 63.json" new file mode 100644 index 0000000..04b525e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 63.json" @@ -0,0 +1,318 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 63.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.779576301574707, + "bbox": [ + 1173.7569580078125, + 436.2480163574219, + 1269.259033203125, + 520.3143310546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7710956335067749, + "bbox": [ + 215.82484436035156, + 417.95367431640625, + 312.8224792480469, + 505.0193786621094 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6789515614509583, + "bbox": [ + 1411.2872314453125, + 1546.7138671875, + 1496.4532470703125, + 1632.8448486328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6213219165802002, + "bbox": [ + 186.31475830078125, + 2981.541748046875, + 244.0559844970703, + 3046.364501953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6160686612129211, + "bbox": [ + 1593.5758056640625, + 2160.564453125, + 1721.7540283203125, + 2288.052490234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5846815705299377, + "bbox": [ + 471.94287109375, + 1818.85400390625, + 593.213623046875, + 1947.9967041015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5674062371253967, + "bbox": [ + 728.553955078125, + 1410.3165283203125, + 795.5034790039062, + 1491.118896484375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357914924621582, + "bbox": [ + 196.90151977539062, + 590.5660400390625, + 1099.3720703125, + 1730.4512939453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9281841516494751, + "bbox": [ + 1128.1490478515625, + 368.2048034667969, + 2042.21826171875, + 2160.371826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.926852285861969, + "bbox": [ + 1153.6876220703125, + 610.0641479492188, + 2054.581298828125, + 2061.8779296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9044339656829834, + "bbox": [ + 149.60728454589844, + 421.1939697265625, + 1106.8804931640625, + 2175.231689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8180068731307983, + "bbox": [ + 218.46853637695312, + 510.9898986816406, + 817.6577758789062, + 588.9566040039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7090044021606445, + "bbox": [ + 1176.985107421875, + 534.6043701171875, + 1776.57861328125, + 592.2709350585938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.29838433861732483, + "bbox": [ + 1182.15966796875, + 519.3270874023438, + 1781.587158203125, + 604.19970703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.779576301574707, + "bbox": [ + 1173.7569580078125, + 436.2480163574219, + 1269.259033203125, + 520.3143310546875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7710956335067749, + "bbox": [ + 215.82484436035156, + 417.95367431640625, + 312.8224792480469, + 505.0193786621094 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6789515614509583, + "bbox": [ + 1411.2872314453125, + 1546.7138671875, + 1496.4532470703125, + 1632.8448486328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.6213219165802002, + "bbox": [ + 186.31475830078125, + 2981.541748046875, + 244.0559844970703, + 3046.364501953125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6160686612129211, + "bbox": [ + 1593.5758056640625, + 2160.564453125, + 1721.7540283203125, + 2288.052490234375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5846815705299377, + "bbox": [ + 471.94287109375, + 1818.85400390625, + 593.213623046875, + 1947.9967041015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5674062371253967, + "bbox": [ + 728.553955078125, + 1410.3165283203125, + 795.5034790039062, + 1491.118896484375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9357914924621582, + "bbox": [ + 196.90151977539062, + 590.5660400390625, + 1099.3720703125, + 1730.4512939453125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9281841516494751, + "bbox": [ + 1128.1490478515625, + 368.2048034667969, + 2042.21826171875, + 2160.371826171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.926852285861969, + "bbox": [ + 1153.6876220703125, + 610.0641479492188, + 2054.581298828125, + 2061.8779296875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9044339656829834, + "bbox": [ + 149.60728454589844, + 421.1939697265625, + 1106.8804931640625, + 2175.231689453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8180068731307983, + "bbox": [ + 218.46853637695312, + 510.9898986816406, + 817.6577758789062, + 588.9566040039062 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7090044021606445, + "bbox": [ + 1176.985107421875, + 534.6043701171875, + 1776.57861328125, + 592.2709350585938 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.29838433861732483, + "bbox": [ + 1182.15966796875, + 519.3270874023438, + 1781.587158203125, + 604.19970703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:31.885278" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 64.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 64.json" new file mode 100644 index 0000000..ce1c138 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 64.json" @@ -0,0 +1,296 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 64.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7817879319190979, + "bbox": [ + 284.1883239746094, + 450.6307373046875, + 387.098876953125, + 538.561279296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7713593244552612, + "bbox": [ + 1318.829833984375, + 464.4869689941406, + 1421.1192626953125, + 552.52099609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6589848399162292, + "bbox": [ + 760.4031372070312, + 2204.319580078125, + 877.0477294921875, + 2323.779296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.647266685962677, + "bbox": [ + 2140.60107421875, + 1314.9710693359375, + 2207.15478515625, + 1389.798583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6097150444984436, + "bbox": [ + 1962.0333251953125, + 2190.52978515625, + 2093.16748046875, + 2324.635498046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5674170255661011, + "bbox": [ + 2186.34619140625, + 3205.58447265625, + 2250.600341796875, + 3274.613037109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4246600866317749, + "bbox": [ + 454.37542724609375, + 1720.216552734375, + 527.5523071289062, + 1801.9559326171875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9507489204406738, + "bbox": [ + 1302.216552734375, + 644.624267578125, + 2273.93408203125, + 2187.56884765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9395396113395691, + "bbox": [ + 273.6948547363281, + 641.6515502929688, + 1230.7503662109375, + 2060.79345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9329845905303955, + "bbox": [ + 1285.01953125, + 439.359375, + 2294.169921875, + 2335.585205078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9181224703788757, + "bbox": [ + 224.8604278564453, + 463.1475830078125, + 1244.23046875, + 2250.326416015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.892905592918396, + "bbox": [ + 280.97540283203125, + 548.3339233398438, + 931.6777954101562, + 635.7080078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8498175144195557, + "bbox": [ + 1326.6983642578125, + 552.4964599609375, + 1969.9639892578125, + 640.478515625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7817879319190979, + "bbox": [ + 284.1883239746094, + 450.6307373046875, + 387.098876953125, + 538.561279296875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7713593244552612, + "bbox": [ + 1318.829833984375, + 464.4869689941406, + 1421.1192626953125, + 552.52099609375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6589848399162292, + "bbox": [ + 760.4031372070312, + 2204.319580078125, + 877.0477294921875, + 2323.779296875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.647266685962677, + "bbox": [ + 2140.60107421875, + 1314.9710693359375, + 2207.15478515625, + 1389.798583984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6097150444984436, + "bbox": [ + 1962.0333251953125, + 2190.52978515625, + 2093.16748046875, + 2324.635498046875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5674170255661011, + "bbox": [ + 2186.34619140625, + 3205.58447265625, + 2250.600341796875, + 3274.613037109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.4246600866317749, + "bbox": [ + 454.37542724609375, + 1720.216552734375, + 527.5523071289062, + 1801.9559326171875 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9507489204406738, + "bbox": [ + 1302.216552734375, + 644.624267578125, + 2273.93408203125, + 2187.56884765625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9395396113395691, + "bbox": [ + 273.6948547363281, + 641.6515502929688, + 1230.7503662109375, + 2060.79345703125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9329845905303955, + "bbox": [ + 1285.01953125, + 439.359375, + 2294.169921875, + 2335.585205078125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9181224703788757, + "bbox": [ + 224.8604278564453, + 463.1475830078125, + 1244.23046875, + 2250.326416015625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.892905592918396, + "bbox": [ + 280.97540283203125, + 548.3339233398438, + 931.6777954101562, + 635.7080078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8498175144195557, + "bbox": [ + 1326.6983642578125, + 552.4964599609375, + 1969.9639892578125, + 640.478515625 + ] + } + ], + "timestamp": "2025-10-15T21:43:32.241318" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 65.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 65.json" new file mode 100644 index 0000000..bb5bef7 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 65.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 65.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7806954979896545, + "bbox": [ + 1202.540771484375, + 429.9014892578125, + 1303.4755859375, + 515.8250122070312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7715578675270081, + "bbox": [ + 226.6529998779297, + 423.1974182128906, + 322.08734130859375, + 510.23504638671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7179463505744934, + "bbox": [ + 1709.1776123046875, + 2669.6787109375, + 1818.6248779296875, + 2778.207763671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7024132609367371, + "bbox": [ + 752.937255859375, + 2514.197265625, + 821.6884765625, + 2591.29443359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6617028117179871, + "bbox": [ + 798.7138671875, + 2619.778076171875, + 927.13330078125, + 2771.136474609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6533079743385315, + "bbox": [ + 1719.684326171875, + 2365.43115234375, + 1812.21728515625, + 2465.368408203125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5899726748466492, + "bbox": [ + 193.22019958496094, + 3024.73046875, + 253.18670654296875, + 3088.51953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9553265571594238, + "bbox": [ + 195.64280700683594, + 593.3401489257812, + 1121.806640625, + 2449.19091796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9336778521537781, + "bbox": [ + 1185.4312744140625, + 593.7222290039062, + 2096.6279296875, + 2393.7392578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9264929294586182, + "bbox": [ + 175.20945739746094, + 393.5173034667969, + 1136.7711181640625, + 2808.006103515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9246057868003845, + "bbox": [ + 1183.1842041015625, + 401.2304382324219, + 2115.785888671875, + 2768.571533203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9092100858688354, + "bbox": [ + 196.54702758789062, + 2439.75048828125, + 1062.7286376953125, + 2661.72509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8777595162391663, + "bbox": [ + 1173.095458984375, + 2381.05322265625, + 2062.173583984375, + 2609.698486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8242934942245483, + "bbox": [ + 1202.2376708984375, + 515.7455444335938, + 1977.3604736328125, + 593.4674072265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7999833822250366, + "bbox": [ + 235.63380432128906, + 505.4225769042969, + 995.5970458984375, + 595.2589721679688 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7806954979896545, + "bbox": [ + 1202.540771484375, + 429.9014892578125, + 1303.4755859375, + 515.8250122070312 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7715578675270081, + "bbox": [ + 226.6529998779297, + 423.1974182128906, + 322.08734130859375, + 510.23504638671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7179463505744934, + "bbox": [ + 1709.1776123046875, + 2669.6787109375, + 1818.6248779296875, + 2778.207763671875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7024132609367371, + "bbox": [ + 752.937255859375, + 2514.197265625, + 821.6884765625, + 2591.29443359375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6617028117179871, + "bbox": [ + 798.7138671875, + 2619.778076171875, + 927.13330078125, + 2771.136474609375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6533079743385315, + "bbox": [ + 1719.684326171875, + 2365.43115234375, + 1812.21728515625, + 2465.368408203125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5899726748466492, + "bbox": [ + 193.22019958496094, + 3024.73046875, + 253.18670654296875, + 3088.51953125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9553265571594238, + "bbox": [ + 195.64280700683594, + 593.3401489257812, + 1121.806640625, + 2449.19091796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9336778521537781, + "bbox": [ + 1185.4312744140625, + 593.7222290039062, + 2096.6279296875, + 2393.7392578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9264929294586182, + "bbox": [ + 175.20945739746094, + 393.5173034667969, + 1136.7711181640625, + 2808.006103515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9246057868003845, + "bbox": [ + 1183.1842041015625, + 401.2304382324219, + 2115.785888671875, + 2768.571533203125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9092100858688354, + "bbox": [ + 196.54702758789062, + 2439.75048828125, + 1062.7286376953125, + 2661.72509765625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8777595162391663, + "bbox": [ + 1173.095458984375, + 2381.05322265625, + 2062.173583984375, + 2609.698486328125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8242934942245483, + "bbox": [ + 1202.2376708984375, + 515.7455444335938, + 1977.3604736328125, + 593.4674072265625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7999833822250366, + "bbox": [ + 235.63380432128906, + 505.4225769042969, + 995.5970458984375, + 595.2589721679688 + ] + } + ], + "timestamp": "2025-10-15T21:43:32.630096" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 66.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 66.json" new file mode 100644 index 0000000..e06e926 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 66.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 66.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7821287512779236, + "bbox": [ + 272.5928955078125, + 437.3414611816406, + 371.9617004394531, + 522.292236328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7783365249633789, + "bbox": [ + 1275.007568359375, + 442.6730651855469, + 1374.0892333984375, + 530.4382934570312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7125735282897949, + "bbox": [ + 1248.788818359375, + 2838.0205078125, + 1313.9315185546875, + 2913.0341796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7032056450843811, + "bbox": [ + 864.8407592773438, + 2694.222412109375, + 982.3810424804688, + 2810.298583984375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6306340098381042, + "bbox": [ + 796.1435546875, + 2422.20751953125, + 879.0203857421875, + 2522.84228515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6113597750663757, + "bbox": [ + 1757.2359619140625, + 2901.157470703125, + 1882.737060546875, + 3027.486328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5416631102561951, + "bbox": [ + 2124.774658203125, + 3094.76171875, + 2187.39892578125, + 3162.439697265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.30437010526657104, + "bbox": [ + 1744.2119140625, + 2895.444580078125, + 1903.2318115234375, + 3046.27880859375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9335023760795593, + "bbox": [ + 258.3420715332031, + 614.9690551757812, + 1191.7557373046875, + 2452.934814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.932094395160675, + "bbox": [ + 1256.91259765625, + 648.4121704101562, + 2201.8359375, + 2691.727783203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9189847111701965, + "bbox": [ + 213.85855102539062, + 407.56158447265625, + 1204.4443359375, + 2852.155517578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9132133722305298, + "bbox": [ + 1235.2750244140625, + 475.879638671875, + 2215.558349609375, + 3054.82275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8989214301109314, + "bbox": [ + 1248.9310302734375, + 2697.6982421875, + 2147.06298828125, + 2937.20068359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.873914897441864, + "bbox": [ + 239.1878204345703, + 2436.740966796875, + 1117.1103515625, + 2686.558349609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8509293794631958, + "bbox": [ + 275.7570495605469, + 519.3045043945312, + 1068.0155029296875, + 616.2587280273438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8066378235816956, + "bbox": [ + 1272.351318359375, + 531.1710815429688, + 2086.957275390625, + 607.885498046875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7821287512779236, + "bbox": [ + 272.5928955078125, + 437.3414611816406, + 371.9617004394531, + 522.292236328125 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7783365249633789, + "bbox": [ + 1275.007568359375, + 442.6730651855469, + 1374.0892333984375, + 530.4382934570312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7125735282897949, + "bbox": [ + 1248.788818359375, + 2838.0205078125, + 1313.9315185546875, + 2913.0341796875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7032056450843811, + "bbox": [ + 864.8407592773438, + 2694.222412109375, + 982.3810424804688, + 2810.298583984375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6306340098381042, + "bbox": [ + 796.1435546875, + 2422.20751953125, + 879.0203857421875, + 2522.84228515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6113597750663757, + "bbox": [ + 1757.2359619140625, + 2901.157470703125, + 1882.737060546875, + 3027.486328125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5416631102561951, + "bbox": [ + 2124.774658203125, + 3094.76171875, + 2187.39892578125, + 3162.439697265625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.30437010526657104, + "bbox": [ + 1744.2119140625, + 2895.444580078125, + 1903.2318115234375, + 3046.27880859375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9335023760795593, + "bbox": [ + 258.3420715332031, + 614.9690551757812, + 1191.7557373046875, + 2452.934814453125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.932094395160675, + "bbox": [ + 1256.91259765625, + 648.4121704101562, + 2201.8359375, + 2691.727783203125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9189847111701965, + "bbox": [ + 213.85855102539062, + 407.56158447265625, + 1204.4443359375, + 2852.155517578125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9132133722305298, + "bbox": [ + 1235.2750244140625, + 475.879638671875, + 2215.558349609375, + 3054.82275390625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8989214301109314, + "bbox": [ + 1248.9310302734375, + 2697.6982421875, + 2147.06298828125, + 2937.20068359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.873914897441864, + "bbox": [ + 239.1878204345703, + 2436.740966796875, + 1117.1103515625, + 2686.558349609375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8509293794631958, + "bbox": [ + 275.7570495605469, + 519.3045043945312, + 1068.0155029296875, + 616.2587280273438 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8066378235816956, + "bbox": [ + 1272.351318359375, + 531.1710815429688, + 2086.957275390625, + 607.885498046875 + ] + } + ], + "timestamp": "2025-10-15T21:43:33.018662" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 67.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 67.json" new file mode 100644 index 0000000..3c243c6 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 67.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 67.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7861997485160828, + "bbox": [ + 222.6878204345703, + 412.8216552734375, + 319.5566101074219, + 499.443603515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7628344297409058, + "bbox": [ + 1201.079833984375, + 422.3739318847656, + 1301.17724609375, + 506.72344970703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7113251686096191, + "bbox": [ + 1740.9395751953125, + 1823.8134765625, + 1804.1771240234375, + 1895.53515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6413028240203857, + "bbox": [ + 757.0560913085938, + 2117.21533203125, + 871.0280151367188, + 2240.582275390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5932678580284119, + "bbox": [ + 483.4000244140625, + 1626.243408203125, + 547.6461181640625, + 1700.5057373046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5852173566818237, + "bbox": [ + 1657.142578125, + 2345.413330078125, + 1773.142578125, + 2465.289794921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5670217871665955, + "bbox": [ + 192.81155395507812, + 2989.930908203125, + 257.50408935546875, + 3055.975830078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4918529987335205, + "bbox": [ + 1648.6812744140625, + 2335.846923828125, + 1799.9774169921875, + 2482.189208984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2787882089614868, + "bbox": [ + 763.5647583007812, + 2134.270751953125, + 847.6527709960938, + 2234.4599609375 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9654228091239929, + "bbox": [ + 198.56202697753906, + 631.50341796875, + 1119.42529296875, + 2118.1728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9366127252578735, + "bbox": [ + 1183.4951171875, + 648.3150024414062, + 2116.135986328125, + 2310.948974609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9284017086029053, + "bbox": [ + 167.55567932128906, + 427.77410888671875, + 1137.0921630859375, + 2182.1396484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9210756421089172, + "bbox": [ + 1177.2353515625, + 410.6089782714844, + 2138.908935546875, + 2427.638427734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8501324653625488, + "bbox": [ + 1191.4552001953125, + 509.5351257324219, + 2106.71630859375, + 631.7449340820312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8309291005134583, + "bbox": [ + 204.948486328125, + 498.94500732421875, + 1128.32568359375, + 625.197509765625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7861997485160828, + "bbox": [ + 222.6878204345703, + 412.8216552734375, + 319.5566101074219, + 499.443603515625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7628344297409058, + "bbox": [ + 1201.079833984375, + 422.3739318847656, + 1301.17724609375, + 506.72344970703125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7113251686096191, + "bbox": [ + 1740.9395751953125, + 1823.8134765625, + 1804.1771240234375, + 1895.53515625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6413028240203857, + "bbox": [ + 757.0560913085938, + 2117.21533203125, + 871.0280151367188, + 2240.582275390625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5932678580284119, + "bbox": [ + 483.4000244140625, + 1626.243408203125, + 547.6461181640625, + 1700.5057373046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.5852173566818237, + "bbox": [ + 1657.142578125, + 2345.413330078125, + 1773.142578125, + 2465.289794921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5670217871665955, + "bbox": [ + 192.81155395507812, + 2989.930908203125, + 257.50408935546875, + 3055.975830078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.4918529987335205, + "bbox": [ + 1648.6812744140625, + 2335.846923828125, + 1799.9774169921875, + 2482.189208984375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.2787882089614868, + "bbox": [ + 763.5647583007812, + 2134.270751953125, + 847.6527709960938, + 2234.4599609375 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9654228091239929, + "bbox": [ + 198.56202697753906, + 631.50341796875, + 1119.42529296875, + 2118.1728515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9366127252578735, + "bbox": [ + 1183.4951171875, + 648.3150024414062, + 2116.135986328125, + 2310.948974609375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9284017086029053, + "bbox": [ + 167.55567932128906, + 427.77410888671875, + 1137.0921630859375, + 2182.1396484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9210756421089172, + "bbox": [ + 1177.2353515625, + 410.6089782714844, + 2138.908935546875, + 2427.638427734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8501324653625488, + "bbox": [ + 1191.4552001953125, + 509.5351257324219, + 2106.71630859375, + 631.7449340820312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8309291005134583, + "bbox": [ + 204.948486328125, + 498.94500732421875, + 1128.32568359375, + 625.197509765625 + ] + } + ], + "timestamp": "2025-10-15T21:43:33.403457" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 68.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 68.json" new file mode 100644 index 0000000..f35ee22 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 68.json" @@ -0,0 +1,362 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 68.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.756471574306488, + "bbox": [ + 267.1417541503906, + 430.0179748535156, + 367.61956787109375, + 517.0064086914062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7553554773330688, + "bbox": [ + 1266.87353515625, + 430.8829040527344, + 1367.607177734375, + 517.9833374023438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.684646725654602, + "bbox": [ + 724.112060546875, + 2413.634033203125, + 844.1387939453125, + 2544.005126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6337822079658508, + "bbox": [ + 942.1161499023438, + 1341.604736328125, + 1022.1744995117188, + 1428.239013671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.572338879108429, + "bbox": [ + 1633.9580078125, + 2427.914794921875, + 1761.43701171875, + 2568.295654296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5471958518028259, + "bbox": [ + 2110.852294921875, + 3083.074951171875, + 2175.37841796875, + 3149.4189453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5316458344459534, + "bbox": [ + 1445.0625, + 1478.438232421875, + 1513.730712890625, + 1554.445556640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.34981706738471985, + "bbox": [ + 700.6315307617188, + 2403.91650390625, + 859.6141967773438, + 2555.49755859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2819594144821167, + "bbox": [ + 1436.9866943359375, + 1470.1094970703125, + 1524.381591796875, + 1561.7142333984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2684803307056427, + "bbox": [ + 2104.68115234375, + 3075.326416015625, + 2180.008056640625, + 3157.23486328125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9487684369087219, + "bbox": [ + 251.02023315429688, + 439.7728271484375, + 1196.609375, + 2585.31982421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.934045672416687, + "bbox": [ + 243.7948455810547, + 646.8696899414062, + 1174.60205078125, + 2392.850341796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.933059811592102, + "bbox": [ + 1250.9134521484375, + 657.0731201171875, + 2199.790771484375, + 2375.08984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9221405982971191, + "bbox": [ + 1234.0147705078125, + 441.8699035644531, + 2226.439697265625, + 2538.660400390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8566531538963318, + "bbox": [ + 1250.804443359375, + 509.8090515136719, + 2191.548828125, + 640.9461669921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8252121806144714, + "bbox": [ + 254.54006958007812, + 514.8320922851562, + 1183.1072998046875, + 643.084228515625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.756471574306488, + "bbox": [ + 267.1417541503906, + 430.0179748535156, + 367.61956787109375, + 517.0064086914062 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7553554773330688, + "bbox": [ + 1266.87353515625, + 430.8829040527344, + 1367.607177734375, + 517.9833374023438 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.684646725654602, + "bbox": [ + 724.112060546875, + 2413.634033203125, + 844.1387939453125, + 2544.005126953125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6337822079658508, + "bbox": [ + 942.1161499023438, + 1341.604736328125, + 1022.1744995117188, + 1428.239013671875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.572338879108429, + "bbox": [ + 1633.9580078125, + 2427.914794921875, + 1761.43701171875, + 2568.295654296875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5471958518028259, + "bbox": [ + 2110.852294921875, + 3083.074951171875, + 2175.37841796875, + 3149.4189453125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5316458344459534, + "bbox": [ + 1445.0625, + 1478.438232421875, + 1513.730712890625, + 1554.445556640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.34981706738471985, + "bbox": [ + 700.6315307617188, + 2403.91650390625, + 859.6141967773438, + 2555.49755859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.2819594144821167, + "bbox": [ + 1436.9866943359375, + 1470.1094970703125, + 1524.381591796875, + 1561.7142333984375 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.2684803307056427, + "bbox": [ + 2104.68115234375, + 3075.326416015625, + 2180.008056640625, + 3157.23486328125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9487684369087219, + "bbox": [ + 251.02023315429688, + 439.7728271484375, + 1196.609375, + 2585.31982421875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.934045672416687, + "bbox": [ + 243.7948455810547, + 646.8696899414062, + 1174.60205078125, + 2392.850341796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.933059811592102, + "bbox": [ + 1250.9134521484375, + 657.0731201171875, + 2199.790771484375, + 2375.08984375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9221405982971191, + "bbox": [ + 1234.0147705078125, + 441.8699035644531, + 2226.439697265625, + 2538.660400390625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8566531538963318, + "bbox": [ + 1250.804443359375, + 509.8090515136719, + 2191.548828125, + 640.9461669921875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8252121806144714, + "bbox": [ + 254.54006958007812, + 514.8320922851562, + 1183.1072998046875, + 643.084228515625 + ] + } + ], + "timestamp": "2025-10-15T21:43:33.774297" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 69.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 69.json" new file mode 100644 index 0000000..226fc83 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 69.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 69.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7858311533927917, + "bbox": [ + 228.86875915527344, + 435.4128112792969, + 330.747802734375, + 526.8451538085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.758439838886261, + "bbox": [ + 1264.1500244140625, + 447.930908203125, + 1370.43798828125, + 537.9575805664062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7353906035423279, + "bbox": [ + 211.80445861816406, + 2726.5478515625, + 281.800048828125, + 2805.97998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6673663854598999, + "bbox": [ + 903.0076904296875, + 2516.05810546875, + 1031.057373046875, + 2648.452880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6465587019920349, + "bbox": [ + 1248.151123046875, + 2800.64599609375, + 1316.958740234375, + 2881.351806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6352947354316711, + "bbox": [ + 2004.99072265625, + 2676.5849609375, + 2131.50732421875, + 2796.837890625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5736376047134399, + "bbox": [ + 209.52272033691406, + 3155.23046875, + 269.5751647949219, + 3220.317626953125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9345974922180176, + "bbox": [ + 211.63223266601562, + 665.1795043945312, + 1171.39306640625, + 2517.423095703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9343888759613037, + "bbox": [ + 1237.938720703125, + 684.312255859375, + 2214.5625, + 2692.206787109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9182138442993164, + "bbox": [ + 192.84625244140625, + 433.7027587890625, + 1189.253173828125, + 2948.028076171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9162229895591736, + "bbox": [ + 201.5040283203125, + 2527.480224609375, + 846.0499877929688, + 2972.614990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9110521078109741, + "bbox": [ + 1255.7572021484375, + 2662.73046875, + 1902.78125, + 3120.3447265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8730579614639282, + "bbox": [ + 1228.1419677734375, + 494.77294921875, + 2227.77587890625, + 3134.680908203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.861112654209137, + "bbox": [ + 1266.279052734375, + 545.9535522460938, + 2224.8447265625, + 671.40869140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7963024377822876, + "bbox": [ + 213.53421020507812, + 527.6439208984375, + 1187.793701171875, + 663.2926025390625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7858311533927917, + "bbox": [ + 228.86875915527344, + 435.4128112792969, + 330.747802734375, + 526.8451538085938 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.758439838886261, + "bbox": [ + 1264.1500244140625, + 447.930908203125, + 1370.43798828125, + 537.9575805664062 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7353906035423279, + "bbox": [ + 211.80445861816406, + 2726.5478515625, + 281.800048828125, + 2805.97998046875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6673663854598999, + "bbox": [ + 903.0076904296875, + 2516.05810546875, + 1031.057373046875, + 2648.452880859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6465587019920349, + "bbox": [ + 1248.151123046875, + 2800.64599609375, + 1316.958740234375, + 2881.351806640625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6352947354316711, + "bbox": [ + 2004.99072265625, + 2676.5849609375, + 2131.50732421875, + 2796.837890625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5736376047134399, + "bbox": [ + 209.52272033691406, + 3155.23046875, + 269.5751647949219, + 3220.317626953125 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9345974922180176, + "bbox": [ + 211.63223266601562, + 665.1795043945312, + 1171.39306640625, + 2517.423095703125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9343888759613037, + "bbox": [ + 1237.938720703125, + 684.312255859375, + 2214.5625, + 2692.206787109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9182138442993164, + "bbox": [ + 192.84625244140625, + 433.7027587890625, + 1189.253173828125, + 2948.028076171875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9162229895591736, + "bbox": [ + 201.5040283203125, + 2527.480224609375, + 846.0499877929688, + 2972.614990234375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9110521078109741, + "bbox": [ + 1255.7572021484375, + 2662.73046875, + 1902.78125, + 3120.3447265625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8730579614639282, + "bbox": [ + 1228.1419677734375, + 494.77294921875, + 2227.77587890625, + 3134.680908203125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.861112654209137, + "bbox": [ + 1266.279052734375, + 545.9535522460938, + 2224.8447265625, + 671.40869140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7963024377822876, + "bbox": [ + 213.53421020507812, + 527.6439208984375, + 1187.793701171875, + 663.2926025390625 + ] + } + ], + "timestamp": "2025-10-15T21:43:34.164776" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 70.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 70.json" new file mode 100644 index 0000000..f942e3e --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 70.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 70.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7984797358512878, + "bbox": [ + 1275.7530517578125, + 441.538330078125, + 1372.9580078125, + 526.4832153320312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7893118858337402, + "bbox": [ + 1253.797607421875, + 2813.5390625, + 1319.1656494140625, + 2886.271484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7601549625396729, + "bbox": [ + 270.1971740722656, + 430.92913818359375, + 370.1064453125, + 518.2190551757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7146188616752625, + "bbox": [ + 2019.90234375, + 2594.259765625, + 2143.49755859375, + 2724.955078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6861907839775085, + "bbox": [ + 1009.5106811523438, + 2321.123046875, + 1126.5477294921875, + 2438.446533203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6713186502456665, + "bbox": [ + 243.87176513671875, + 2666.5224609375, + 314.60516357421875, + 2746.02978515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5594301223754883, + "bbox": [ + 2122.0888671875, + 3094.227294921875, + 2190.8134765625, + 3163.224853515625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9557541012763977, + "bbox": [ + 1249.9798583984375, + 657.5346069335938, + 2195.97705078125, + 2628.7431640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.945822536945343, + "bbox": [ + 238.94027709960938, + 653.7559814453125, + 1186.662353515625, + 2333.781005859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9395791888237, + "bbox": [ + 229.54087829589844, + 405.1367492675781, + 1199.3056640625, + 2726.3125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9209741353988647, + "bbox": [ + 248.98696899414062, + 2344.439697265625, + 1020.5008544921875, + 2745.067626953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9063810110092163, + "bbox": [ + 1251.4110107421875, + 2620.846923828125, + 1863.3201904296875, + 3054.8671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8686098456382751, + "bbox": [ + 1235.3458251953125, + 477.468505859375, + 2210.144287109375, + 3057.85693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8313900828361511, + "bbox": [ + 1264.7049560546875, + 534.9700317382812, + 2194.71630859375, + 653.8171997070312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8293032646179199, + "bbox": [ + 263.8679504394531, + 517.753662109375, + 1204.170654296875, + 647.25390625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7984797358512878, + "bbox": [ + 1275.7530517578125, + 441.538330078125, + 1372.9580078125, + 526.4832153320312 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.7893118858337402, + "bbox": [ + 1253.797607421875, + 2813.5390625, + 1319.1656494140625, + 2886.271484375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7601549625396729, + "bbox": [ + 270.1971740722656, + 430.92913818359375, + 370.1064453125, + 518.2190551757812 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7146188616752625, + "bbox": [ + 2019.90234375, + 2594.259765625, + 2143.49755859375, + 2724.955078125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6861907839775085, + "bbox": [ + 1009.5106811523438, + 2321.123046875, + 1126.5477294921875, + 2438.446533203125 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6713186502456665, + "bbox": [ + 243.87176513671875, + 2666.5224609375, + 314.60516357421875, + 2746.02978515625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5594301223754883, + "bbox": [ + 2122.0888671875, + 3094.227294921875, + 2190.8134765625, + 3163.224853515625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9557541012763977, + "bbox": [ + 1249.9798583984375, + 657.5346069335938, + 2195.97705078125, + 2628.7431640625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.945822536945343, + "bbox": [ + 238.94027709960938, + 653.7559814453125, + 1186.662353515625, + 2333.781005859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9395791888237, + "bbox": [ + 229.54087829589844, + 405.1367492675781, + 1199.3056640625, + 2726.3125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9209741353988647, + "bbox": [ + 248.98696899414062, + 2344.439697265625, + 1020.5008544921875, + 2745.067626953125 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9063810110092163, + "bbox": [ + 1251.4110107421875, + 2620.846923828125, + 1863.3201904296875, + 3054.8671875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8686098456382751, + "bbox": [ + 1235.3458251953125, + 477.468505859375, + 2210.144287109375, + 3057.85693359375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8313900828361511, + "bbox": [ + 1264.7049560546875, + 534.9700317382812, + 2194.71630859375, + 653.8171997070312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8293032646179199, + "bbox": [ + 263.8679504394531, + 517.753662109375, + 1204.170654296875, + 647.25390625 + ] + } + ], + "timestamp": "2025-10-15T21:43:34.563997" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 71.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 71.json" new file mode 100644 index 0000000..0d74ee1 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 71.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 71.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7753919363021851, + "bbox": [ + 1202.753662109375, + 430.31219482421875, + 1300.2139892578125, + 516.8137817382812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7689806222915649, + "bbox": [ + 1195.19873046875, + 1777.8406982421875, + 1294.616943359375, + 1865.1055908203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7112677693367004, + "bbox": [ + 1463.9488525390625, + 2172.897216796875, + 1577.9158935546875, + 2287.234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6874988675117493, + "bbox": [ + 1191.666259765625, + 879.1769409179688, + 1265.029541015625, + 968.8734741210938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6789718866348267, + "bbox": [ + 1698.872802734375, + 1975.801513671875, + 1776.072509765625, + 2072.763916015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6487367749214172, + "bbox": [ + 1447.9337158203125, + 1243.3419189453125, + 1559.9775390625, + 1371.1383056640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5855937600135803, + "bbox": [ + 201.5085906982422, + 2997.157470703125, + 260.3041076660156, + 3061.216796875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9500079154968262, + "bbox": [ + 1201.7391357421875, + 594.940673828125, + 2115.483642578125, + 1158.10498046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9249199628829956, + "bbox": [ + 1177.814208984375, + 1754.4095458984375, + 2129.47509765625, + 2114.73193359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9172533750534058, + "bbox": [ + 1173.975830078125, + 401.2607116699219, + 2146.166748046875, + 1259.6495361328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8868899941444397, + "bbox": [ + 195.72731018066406, + 415.29962158203125, + 1136.21630859375, + 2320.716064453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8270283937454224, + "bbox": [ + 1196.8763427734375, + 1875.740478515625, + 2101.91796875, + 1991.0872802734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.814175009727478, + "bbox": [ + 1202.0577392578125, + 516.5905151367188, + 1705.2017822265625, + 595.2514038085938 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7782363295555115, + "bbox": [ + 1186.1722412109375, + 2001.8857421875, + 2001.031982421875, + 2082.2822265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.13193781673908234, + "bbox": [ + 1205.5479736328125, + 1978.3270263671875, + 2047.3922119140625, + 2088.531494140625 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7753919363021851, + "bbox": [ + 1202.753662109375, + 430.31219482421875, + 1300.2139892578125, + 516.8137817382812 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7689806222915649, + "bbox": [ + 1195.19873046875, + 1777.8406982421875, + 1294.616943359375, + 1865.1055908203125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.7112677693367004, + "bbox": [ + 1463.9488525390625, + 2172.897216796875, + 1577.9158935546875, + 2287.234375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6874988675117493, + "bbox": [ + 1191.666259765625, + 879.1769409179688, + 1265.029541015625, + 968.8734741210938 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6789718866348267, + "bbox": [ + 1698.872802734375, + 1975.801513671875, + 1776.072509765625, + 2072.763916015625 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6487367749214172, + "bbox": [ + 1447.9337158203125, + 1243.3419189453125, + 1559.9775390625, + 1371.1383056640625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5855937600135803, + "bbox": [ + 201.5085906982422, + 2997.157470703125, + 260.3041076660156, + 3061.216796875 + ] + } + ], + "large_detections": [ + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9500079154968262, + "bbox": [ + 1201.7391357421875, + 594.940673828125, + 2115.483642578125, + 1158.10498046875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9249199628829956, + "bbox": [ + 1177.814208984375, + 1754.4095458984375, + 2129.47509765625, + 2114.73193359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9172533750534058, + "bbox": [ + 1173.975830078125, + 401.2607116699219, + 2146.166748046875, + 1259.6495361328125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.8868899941444397, + "bbox": [ + 195.72731018066406, + 415.29962158203125, + 1136.21630859375, + 2320.716064453125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8270283937454224, + "bbox": [ + 1196.8763427734375, + 1875.740478515625, + 2101.91796875, + 1991.0872802734375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.814175009727478, + "bbox": [ + 1202.0577392578125, + 516.5905151367188, + 1705.2017822265625, + 595.2514038085938 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.7782363295555115, + "bbox": [ + 1186.1722412109375, + 2001.8857421875, + 2001.031982421875, + 2082.2822265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.13193781673908234, + "bbox": [ + 1205.5479736328125, + 1978.3270263671875, + 2047.3922119140625, + 2088.531494140625 + ] + } + ], + "timestamp": "2025-10-15T21:43:35.004245" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 72.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 72.json" new file mode 100644 index 0000000..99c8b9d --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 72.json" @@ -0,0 +1,340 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 72.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7530669569969177, + "bbox": [ + 1261.422607421875, + 442.5573425292969, + 1360.8525390625, + 527.7227172851562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7499573230743408, + "bbox": [ + 1254.292724609375, + 1823.3267822265625, + 1353.949951171875, + 1909.1358642578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6615809202194214, + "bbox": [ + 1736.3447265625, + 2270.30126953125, + 1855.7537841796875, + 2389.87646484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6355082988739014, + "bbox": [ + 1443.5111083984375, + 1208.2777099609375, + 1569.267578125, + 1333.9794921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6186056137084961, + "bbox": [ + 1252.7120361328125, + 906.2190551757812, + 1321.6058349609375, + 998.1641845703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5764458179473877, + "bbox": [ + 2110.089599609375, + 3074.017333984375, + 2174.28271484375, + 3141.779541015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49348655343055725, + "bbox": [ + 1418.5447998046875, + 2012.5809326171875, + 1501.848876953125, + 2116.060791015625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.934943437576294, + "bbox": [ + 238.81539916992188, + 478.1450500488281, + 1195.792236328125, + 2851.943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9326093196868896, + "bbox": [ + 1246.777587890625, + 615.1453247070312, + 2200.024658203125, + 1176.9525146484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9056293368339539, + "bbox": [ + 1240.930908203125, + 411.4196472167969, + 2217.864013671875, + 1319.713623046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8599600195884705, + "bbox": [ + 1244.428466796875, + 2035.16650390625, + 2113.657958984375, + 2137.423828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.859470009803772, + "bbox": [ + 242.3201446533203, + 420.0257873535156, + 904.0890502929688, + 513.5427856445312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8536745309829712, + "bbox": [ + 1249.2247314453125, + 1910.5137939453125, + 2163.693359375, + 2026.052978515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.797603964805603, + "bbox": [ + 1219.8216552734375, + 1787.36376953125, + 2196.340576171875, + 2444.3896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7452623844146729, + "bbox": [ + 1262.1224365234375, + 530.2010498046875, + 1772.923095703125, + 605.125732421875 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7530669569969177, + "bbox": [ + 1261.422607421875, + 442.5573425292969, + 1360.8525390625, + 527.7227172851562 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7499573230743408, + "bbox": [ + 1254.292724609375, + 1823.3267822265625, + 1353.949951171875, + 1909.1358642578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6615809202194214, + "bbox": [ + 1736.3447265625, + 2270.30126953125, + 1855.7537841796875, + 2389.87646484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6355082988739014, + "bbox": [ + 1443.5111083984375, + 1208.2777099609375, + 1569.267578125, + 1333.9794921875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6186056137084961, + "bbox": [ + 1252.7120361328125, + 906.2190551757812, + 1321.6058349609375, + 998.1641845703125 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5764458179473877, + "bbox": [ + 2110.089599609375, + 3074.017333984375, + 2174.28271484375, + 3141.779541015625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.49348655343055725, + "bbox": [ + 1418.5447998046875, + 2012.5809326171875, + 1501.848876953125, + 2116.060791015625 + ] + } + ], + "large_detections": [ + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.934943437576294, + "bbox": [ + 238.81539916992188, + 478.1450500488281, + 1195.792236328125, + 2851.943359375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9326093196868896, + "bbox": [ + 1246.777587890625, + 615.1453247070312, + 2200.024658203125, + 1176.9525146484375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9056293368339539, + "bbox": [ + 1240.930908203125, + 411.4196472167969, + 2217.864013671875, + 1319.713623046875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8599600195884705, + "bbox": [ + 1244.428466796875, + 2035.16650390625, + 2113.657958984375, + 2137.423828125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.859470009803772, + "bbox": [ + 242.3201446533203, + 420.0257873535156, + 904.0890502929688, + 513.5427856445312 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8536745309829712, + "bbox": [ + 1249.2247314453125, + 1910.5137939453125, + 2163.693359375, + 2026.052978515625 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.797603964805603, + "bbox": [ + 1219.8216552734375, + 1787.36376953125, + 2196.340576171875, + 2444.3896484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7452623844146729, + "bbox": [ + 1262.1224365234375, + 530.2010498046875, + 1772.923095703125, + 605.125732421875 + ] + } + ], + "timestamp": "2025-10-15T21:43:35.407920" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 73.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 73.json" new file mode 100644 index 0000000..57af3d8 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 73.json" @@ -0,0 +1,516 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 73.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7664481401443481, + "bbox": [ + 1246.716552734375, + 2247.074462890625, + 1354.1915283203125, + 2339.601806640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.756467878818512, + "bbox": [ + 1253.3011474609375, + 1752.7437744140625, + 1350.935302734375, + 1841.1649169921875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7517487406730652, + "bbox": [ + 1245.900146484375, + 2609.317138671875, + 1352.0504150390625, + 2697.30517578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6575540900230408, + "bbox": [ + 1571.9647216796875, + 2528.888916015625, + 1712.4647216796875, + 2681.06396484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6525534987449646, + "bbox": [ + 2062.739501953125, + 2871.642333984375, + 2194.771484375, + 2997.202880859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6063077449798584, + "bbox": [ + 1687.5289306640625, + 2101.9580078125, + 1828.6795654296875, + 2242.7412109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6015544533729553, + "bbox": [ + 1249.39599609375, + 2033.5618896484375, + 1324.2894287109375, + 2120.5859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6007958054542542, + "bbox": [ + 1424.882568359375, + 2446.244873046875, + 1507.0909423828125, + 2547.696044921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5738393068313599, + "bbox": [ + 202.9099884033203, + 3151.50146484375, + 269.5949401855469, + 3220.06640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5521044135093689, + "bbox": [ + 1243.2392578125, + 2907.505859375, + 1308.9449462890625, + 2989.304443359375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9190278053283691, + "bbox": [ + 1230.3792724609375, + 1747.232421875, + 2234.951416015625, + 2224.91796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.916451632976532, + "bbox": [ + 184.81568908691406, + 532.05615234375, + 1186.4036865234375, + 2970.700927734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9131284356117249, + "bbox": [ + 1257.6309814453125, + 2792.9287109375, + 2080.14306640625, + 3133.519287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8834227919578552, + "bbox": [ + 1235.531005859375, + 2249.30712890625, + 2233.291259765625, + 2542.25732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8759658336639404, + "bbox": [ + 1235.143798828125, + 2595.748779296875, + 2266.68701171875, + 3165.283935546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8145148754119873, + "bbox": [ + 1231.6920166015625, + 1839.4637451171875, + 2203.957275390625, + 1975.19580078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7932111024856567, + "bbox": [ + 1257.33984375, + 2342.94189453125, + 2194.750732421875, + 2458.701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6336739659309387, + "bbox": [ + 1247.0185546875, + 2699.41357421875, + 2049.04833984375, + 2790.702880859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5242316126823425, + "bbox": [ + 1242.0570068359375, + 1991.5416259765625, + 2183.3583984375, + 2192.96923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.4885760247707367, + "bbox": [ + 1247.63330078125, + 408.9120178222656, + 2228.304443359375, + 1691.11572265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.45361119508743286, + "bbox": [ + 1229.5609130859375, + 2461.7890625, + 2111.9716796875, + 2558.1484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.4168507754802704, + "bbox": [ + 1235.3646240234375, + 2709.048095703125, + 2080.164794921875, + 2774.349365234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.38285502791404724, + "bbox": [ + 1248.958740234375, + 0.0, + 2228.95654296875, + 2323.703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7664481401443481, + "bbox": [ + 1246.716552734375, + 2247.074462890625, + 1354.1915283203125, + 2339.601806640625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.756467878818512, + "bbox": [ + 1253.3011474609375, + 1752.7437744140625, + 1350.935302734375, + 1841.1649169921875 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7517487406730652, + "bbox": [ + 1245.900146484375, + 2609.317138671875, + 1352.0504150390625, + 2697.30517578125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6575540900230408, + "bbox": [ + 1571.9647216796875, + 2528.888916015625, + 1712.4647216796875, + 2681.06396484375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6525534987449646, + "bbox": [ + 2062.739501953125, + 2871.642333984375, + 2194.771484375, + 2997.202880859375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6063077449798584, + "bbox": [ + 1687.5289306640625, + 2101.9580078125, + 1828.6795654296875, + 2242.7412109375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6015544533729553, + "bbox": [ + 1249.39599609375, + 2033.5618896484375, + 1324.2894287109375, + 2120.5859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6007958054542542, + "bbox": [ + 1424.882568359375, + 2446.244873046875, + 1507.0909423828125, + 2547.696044921875 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5738393068313599, + "bbox": [ + 202.9099884033203, + 3151.50146484375, + 269.5949401855469, + 3220.06640625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.5521044135093689, + "bbox": [ + 1243.2392578125, + 2907.505859375, + 1308.9449462890625, + 2989.304443359375 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9190278053283691, + "bbox": [ + 1230.3792724609375, + 1747.232421875, + 2234.951416015625, + 2224.91796875 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.916451632976532, + "bbox": [ + 184.81568908691406, + 532.05615234375, + 1186.4036865234375, + 2970.700927734375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9131284356117249, + "bbox": [ + 1257.6309814453125, + 2792.9287109375, + 2080.14306640625, + 3133.519287109375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8834227919578552, + "bbox": [ + 1235.531005859375, + 2249.30712890625, + 2233.291259765625, + 2542.25732421875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8759658336639404, + "bbox": [ + 1235.143798828125, + 2595.748779296875, + 2266.68701171875, + 3165.283935546875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8145148754119873, + "bbox": [ + 1231.6920166015625, + 1839.4637451171875, + 2203.957275390625, + 1975.19580078125 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7932111024856567, + "bbox": [ + 1257.33984375, + 2342.94189453125, + 2194.750732421875, + 2458.701171875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.6336739659309387, + "bbox": [ + 1247.0185546875, + 2699.41357421875, + 2049.04833984375, + 2790.702880859375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.5242316126823425, + "bbox": [ + 1242.0570068359375, + 1991.5416259765625, + 2183.3583984375, + 2192.96923828125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.4885760247707367, + "bbox": [ + 1247.63330078125, + 408.9120178222656, + 2228.304443359375, + 1691.11572265625 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.45361119508743286, + "bbox": [ + 1229.5609130859375, + 2461.7890625, + 2111.9716796875, + 2558.1484375 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.4168507754802704, + "bbox": [ + 1235.3646240234375, + 2709.048095703125, + 2080.164794921875, + 2774.349365234375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.38285502791404724, + "bbox": [ + 1248.958740234375, + 0.0, + 2228.95654296875, + 2323.703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:35.831115" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 74.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 74.json" new file mode 100644 index 0000000..1826098 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/annotations/routed_result_2022 \354\234\240\355\230\225\355\216\270 - 74.json" @@ -0,0 +1,538 @@ +{ + "image_path": "/home/yerim/workspace/Gradi_25Fall/ai-service/models/Recognition/exp_images/2022_์œ ํ˜•ํŽธ/2022 แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ - 74.jpg", + "detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.792370617389679, + "bbox": [ + 1298.730224609375, + 1935.156494140625, + 1403.91650390625, + 2025.9468994140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7882457375526428, + "bbox": [ + 1306.03271484375, + 1096.9365234375, + 1408.3167724609375, + 1185.9906005859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.765673816204071, + "bbox": [ + 1288.41259765625, + 2639.6826171875, + 1393.766845703125, + 2730.700927734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6923834681510925, + "bbox": [ + 1580.841552734375, + 2319.0546875, + 1706.2867431640625, + 2440.045654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6850404739379883, + "bbox": [ + 1482.046875, + 1593.5264892578125, + 1593.6812744140625, + 1706.4853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6532686352729797, + "bbox": [ + 1481.0919189453125, + 2148.535400390625, + 1552.97412109375, + 2245.31005859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6507720351219177, + "bbox": [ + 1304.0699462890625, + 1392.9853515625, + 1373.6934814453125, + 1473.9119873046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6419696807861328, + "bbox": [ + 1287.3687744140625, + 2880.04736328125, + 1358.24462890625, + 2959.064453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.604889988899231, + "bbox": [ + 2119.85205078125, + 2765.466552734375, + 2252.977783203125, + 2905.072509765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5505516529083252, + "bbox": [ + 2195.25634765625, + 3205.020751953125, + 2256.1064453125, + 3273.509521484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3094460070133209, + "bbox": [ + 1487.44189453125, + 2161.918212890625, + 1546.9534912109375, + 2241.971923828125 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9369469881057739, + "bbox": [ + 1274.59033203125, + 1917.9049072265625, + 2272.65283203125, + 2470.1044921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9195506572723389, + "bbox": [ + 1288.3079833984375, + 2826.788330078125, + 2215.414306640625, + 3172.965087890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9180538654327393, + "bbox": [ + 234.3252716064453, + 580.5828247070312, + 1239.00439453125, + 3141.962158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.909698486328125, + "bbox": [ + 1290.299560546875, + 447.5787658691406, + 2290.232666015625, + 940.0625610351562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8959141373634338, + "bbox": [ + 1296.3541259765625, + 2032.3314208984375, + 2255.595703125, + 2154.242919921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8866969347000122, + "bbox": [ + 1301.962158203125, + 1332.196533203125, + 2239.038330078125, + 1569.4949951171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8834633231163025, + "bbox": [ + 1260.4725341796875, + 2620.889404296875, + 2241.560302734375, + 3181.55859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8637134432792664, + "bbox": [ + 1280.812744140625, + 1056.36181640625, + 2295.263916015625, + 1719.1187744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8477247953414917, + "bbox": [ + 1313.0194091796875, + 1189.440185546875, + 2271.572021484375, + 1319.092529296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.830805242061615, + "bbox": [ + 253.79124450683594, + 437.30523681640625, + 923.0347900390625, + 516.93896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8007912039756775, + "bbox": [ + 1284.6964111328125, + 2156.035400390625, + 2183.310302734375, + 2259.83154296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7454482913017273, + "bbox": [ + 1288.4547119140625, + 2731.65673828125, + 1944.729248046875, + 2817.138427734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.2264460325241089, + "bbox": [ + 181.57862854003906, + 502.8815002441406, + 1243.480712890625, + 3165.079345703125 + ] + } + ], + "small_detections": [ + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.792370617389679, + "bbox": [ + 1298.730224609375, + 1935.156494140625, + 1403.91650390625, + 2025.9468994140625 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.7882457375526428, + "bbox": [ + 1306.03271484375, + 1096.9365234375, + 1408.3167724609375, + 1185.9906005859375 + ] + }, + { + "class_name": "problem_number", + "class_id": 1, + "confidence": 0.765673816204071, + "bbox": [ + 1288.41259765625, + 2639.6826171875, + 1393.766845703125, + 2730.700927734375 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6923834681510925, + "bbox": [ + 1580.841552734375, + 2319.0546875, + 1706.2867431640625, + 2440.045654296875 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.6850404739379883, + "bbox": [ + 1482.046875, + 1593.5264892578125, + 1593.6812744140625, + 1706.4853515625 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6532686352729797, + "bbox": [ + 1481.0919189453125, + 2148.535400390625, + 1552.97412109375, + 2245.31005859375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6507720351219177, + "bbox": [ + 1304.0699462890625, + 1392.9853515625, + 1373.6934814453125, + 1473.9119873046875 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.6419696807861328, + "bbox": [ + 1287.3687744140625, + 2880.04736328125, + 1358.24462890625, + 2959.064453125 + ] + }, + { + "class_name": "answer_2", + "class_id": 3, + "confidence": 0.604889988899231, + "bbox": [ + 2119.85205078125, + 2765.466552734375, + 2252.977783203125, + 2905.072509765625 + ] + }, + { + "class_name": "page_number", + "class_id": 0, + "confidence": 0.5505516529083252, + "bbox": [ + 2195.25634765625, + 3205.020751953125, + 2256.1064453125, + 3273.509521484375 + ] + }, + { + "class_name": "answer_1", + "class_id": 2, + "confidence": 0.3094460070133209, + "bbox": [ + 1487.44189453125, + 2161.918212890625, + 1546.9534912109375, + 2241.971923828125 + ] + } + ], + "large_detections": [ + { + "class_name": "section", + "class_id": 3, + "confidence": 0.9369469881057739, + "bbox": [ + 1274.59033203125, + 1917.9049072265625, + 2272.65283203125, + 2470.1044921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.9195506572723389, + "bbox": [ + 1288.3079833984375, + 2826.788330078125, + 2215.414306640625, + 3172.965087890625 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.9180538654327393, + "bbox": [ + 234.3252716064453, + 580.5828247070312, + 1239.00439453125, + 3141.962158203125 + ] + }, + { + "class_name": "english_content", + "class_id": 1, + "confidence": 0.909698486328125, + "bbox": [ + 1290.299560546875, + 447.5787658691406, + 2290.232666015625, + 940.0625610351562 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8959141373634338, + "bbox": [ + 1296.3541259765625, + 2032.3314208984375, + 2255.595703125, + 2154.242919921875 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8866969347000122, + "bbox": [ + 1301.962158203125, + 1332.196533203125, + 2239.038330078125, + 1569.4949951171875 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8834633231163025, + "bbox": [ + 1260.4725341796875, + 2620.889404296875, + 2241.560302734375, + 3181.55859375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.8637134432792664, + "bbox": [ + 1280.812744140625, + 1056.36181640625, + 2295.263916015625, + 1719.1187744140625 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.8477247953414917, + "bbox": [ + 1313.0194091796875, + 1189.440185546875, + 2271.572021484375, + 1319.092529296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.830805242061615, + "bbox": [ + 253.79124450683594, + 437.30523681640625, + 923.0347900390625, + 516.93896484375 + ] + }, + { + "class_name": "answer_option", + "class_id": 0, + "confidence": 0.8007912039756775, + "bbox": [ + 1284.6964111328125, + 2156.035400390625, + 2183.310302734375, + 2259.83154296875 + ] + }, + { + "class_name": "korean_content", + "class_id": 2, + "confidence": 0.7454482913017273, + "bbox": [ + 1288.4547119140625, + 2731.65673828125, + 1944.729248046875, + 2817.138427734375 + ] + }, + { + "class_name": "section", + "class_id": 3, + "confidence": 0.2264460325241089, + "bbox": [ + 181.57862854003906, + 502.8815002441406, + 1243.480712890625, + 3165.079345703125 + ] + } + ], + "timestamp": "2025-10-15T21:43:36.315035" +} \ No newline at end of file diff --git "a/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/routing_results_summary.json" "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/routing_results_summary.json" new file mode 100644 index 0000000..5f4a1f1 --- /dev/null +++ "b/ai-service/models/Detection/routed_temp_results/2022_\354\234\240\355\230\225\355\216\270/routing_results_summary.json" @@ -0,0 +1,33 @@ +{ + "total_images": 37, + "processed_images": 37, + "total_detections": 582, + "average_detections_per_image": 15.72972972972973, + "class_counts": { + "answer_option": 61, + "english_content": 72, + "korean_content": 80, + "section": 78, + "page_number": 42, + "problem_number": 76, + "answer_1": 85, + "answer_2": 88 + }, + "average_confidence": 0.7525663866415057, + "routing_strategy": { + "small_objects": [ + "answer_2", + "problem_number", + "page_number", + "answer_1" + ], + "large_objects": [ + "korean_content", + "section", + "english_content", + "answer_option" + ], + "small_model_conf": 0.22, + "large_model_conf": 0.12 + } +} \ No newline at end of file diff --git "a/ai-service/models/Detection/section_crop \354\275\224\353\223\234 \354\264\210\352\260\204\353\213\250 \354\204\244\353\252\205.md" "b/ai-service/models/Detection/section_crop \354\275\224\353\223\234 \354\264\210\352\260\204\353\213\250 \354\204\244\353\252\205.md" new file mode 100644 index 0000000..ef47ebc --- /dev/null +++ "b/ai-service/models/Detection/section_crop \354\275\224\353\223\234 \354\264\210\352\260\204\353\213\250 \354\204\244\353\252\205.md" @@ -0,0 +1,32 @@ +# Section Crop ์‚ฌ์šฉ ์„ค๋ช…์„œ + +## ์‚ฌ์šฉ ๋ฐฉ๋ฒ• + +```bash +python section_crop.py +``` + +## ์ž…๋ ฅ ๋ฐ์ดํ„ฐ + +- **์œ„์น˜**: `ai-service/models/recognition/exp_images/` ํด๋” +- **ํŒŒ์ผ ํ˜•์‹**: `.jpg`, `.jpeg`, `.png`, `.bmp` ์ด๋ฏธ์ง€ ํŒŒ์ผ + +## ์‚ฌ์šฉ ๋ชจ๋ธ + +- **๋ชจ๋ธ ํŒŒ์ผ**: `yolov8l_best_0904.pt` (๊ฐ™์€ ํด๋”์— ์œ„์น˜) +- **๋ชจ๋ธ ํƒ€์ž…**: YOLOv8 ๊ฐ์ฒด ๊ฒ€์ถœ ๋ชจ๋ธ + +## ์ถœ๋ ฅ ๊ฒฐ๊ณผ + +1. **์˜ˆ์ธก ์‹œ๊ฐํ™”**: `ai-service/models/Detection/predictions_visualization/` + + - ๊ฒ€์ถœ ๊ฒฐ๊ณผ๊ฐ€ ํ‘œ์‹œ๋œ ์ด๋ฏธ์ง€๋“ค + +2. **ํฌ๋กญ๋œ Section ์ด๋ฏธ์ง€**: `ai-service/models/Detection/sections/` + - ๊ฒ€์ถœ๋œ ๊ฐ section์ด ๊ฐœ๋ณ„ ์ด๋ฏธ์ง€๋กœ ํฌ๋กญ๋˜์–ด ์ €์žฅ + - ํŒŒ์ผ๋ช… ํ˜•์‹: `์›๋ณธํŒŒ์ผ๋ช…_section_๋ฒˆํ˜ธ_conf์‹ ๋ขฐ๋„.jpg` + +## ์‹คํ–‰ ์ „ ํ™•์ธ์‚ฌํ•ญ + +- `exp_images/` ํด๋”์— ์ฒ˜๋ฆฌํ•  ์ด๋ฏธ์ง€๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ +- `yolov8l_best_0904.pt` ๋ชจ๋ธ ํŒŒ์ผ์ด ๊ฐ™์€ ํด๋”์— ์žˆ๋Š”์ง€ ํ™•์ธ diff --git a/ai-service/models/Detection/section_crop.py b/ai-service/models/Detection/section_crop.py new file mode 100644 index 0000000..a808148 --- /dev/null +++ b/ai-service/models/Detection/section_crop.py @@ -0,0 +1,141 @@ +# section_crop.py +""" +๋ผ์šฐํŒ… ์ถ”๋ก  ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ Section ํด๋ž˜์Šค ํฌ๋กญ ์Šคํฌ๋ฆฝํŠธ + +- run_routed_inference.py ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ ์ด๋ฏธ์ง€ ํฌ๋กญ +- ํŽ˜์ด์ง€๋ณ„ + ํด๋ž˜์Šค๋ณ„ ํด๋” ๊ตฌ์กฐ๋กœ ์ €์žฅ +""" + +from __future__ import annotations +import logging +from pathlib import Path +from typing import Dict, List +import cv2 +import numpy as np + +# ๋กœ๊น… ์„ค์ • +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +class SectionPredictor: + """๋ผ์šฐํŒ… ์ถ”๋ก  ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ด๋ฏธ์ง€ ํฌ๋กญ ์ˆ˜ํ–‰""" + + def __init__(self, class_names: List[str]): + """ + Args: + class_names: ํด๋ž˜์Šค ์ด๋ฆ„ ๋ฆฌ์ŠคํŠธ + """ + self.class_names = class_names + self.class_ids = {name: idx for idx, name in enumerate(class_names)} + logger.info(f"SectionPredictor ์ดˆ๊ธฐํ™” ์™„๋ฃŒ. ํด๋ž˜์Šค: {self.class_ids}") + + def load_predictions(self, routed_results: List[Dict]) -> Dict[str, Dict]: + """ + run_routed_inference.py ๊ฒฐ๊ณผ๋ฅผ crop_sections()์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ + """ + predictions = {} + + for res in routed_results: + image_path = res['image_path'] + boxes = [] + scores = [] + classes = [] + + for det in res['detections']: + cls_name = det['class_name'] + if cls_name in self.class_ids: + boxes.append(det['bbox']) + scores.append(det['confidence']) + classes.append(self.class_ids[cls_name]) + + predictions[image_path] = { + 'boxes': np.array(boxes), + 'scores': np.array(scores), + 'classes': np.array(classes), + 'image_path': image_path + } + + logger.info(f"์ด {len(predictions)}๊ฐœ ์ด๋ฏธ์ง€ ์˜ˆ์ธก ๊ฒฐ๊ณผ ๋กœ๋“œ ์™„๋ฃŒ") + return predictions + + def crop_sections(self, predictions: Dict[str, Dict], output_dir: Path) -> None: + """ + ๋ชจ๋“  ํด๋ž˜์Šค ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ํฌ๋กญ. + ํŽ˜์ด์ง€๋ณ„ + ํด๋ž˜์Šค๋ณ„ ํด๋” ๊ตฌ์กฐ ์ƒ์„ฑ. + """ + output_dir.mkdir(parents=True, exist_ok=True) + total_crops = 0 + processed_images = 0 + + for image_path_str, pred_data in predictions.items(): + image_path = Path(image_path_str) + image = cv2.imread(str(image_path)) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + continue + + page_dir = output_dir / image_path.stem + page_dir.mkdir(parents=True, exist_ok=True) + + for label, class_id in self.class_ids.items(): + mask = pred_data['classes'] == class_id + boxes = pred_data['boxes'][mask] + scores = pred_data['scores'][mask] + + if len(boxes) == 0: + continue + + class_dir = page_dir / label + class_dir.mkdir(exist_ok=True, parents=True) + + for j, (box, score) in enumerate(zip(boxes, scores)): + x1, y1, x2, y2 = map(int, box) + + h, w = image.shape[:2] + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + if x2 <= x1 or y2 <= y1: + logger.warning(f"์ž˜๋ชป๋œ ๋ฐ•์Šค ์ขŒํ‘œ: {box}") + continue + + cropped = image[y1:y2, x1:x2] + crop_filename = f"{label}_{j:02d}_conf{score:.2f}.jpg" + cv2.imwrite(str(class_dir / crop_filename), cropped) + total_crops += 1 + + processed_images += 1 + + logger.info(f"ํฌ๋กญ ์™„๋ฃŒ: {processed_images}๊ฐœ ์ด๋ฏธ์ง€์—์„œ ์ด {total_crops}๊ฐœ ๊ฐ์ฒด ์ถ”์ถœ") + + +def main(): + from Model_routing_1004.run_routed_inference import RoutedInference + + current_dir = Path(__file__).parent + raws_dir = current_dir.parent / "recognition" / "exp_images" + + predictions_output_dir = current_dir / "predictions_visualization" + sections_output_dir = current_dir / "sections" + + class_names = ['answer_1', 'answer_2', 'answer_option', 'english_content', + 'korean_content', 'page_number', 'problem_number', 'section'] + + # 1๏ธโƒฃ ๋ผ์šฐํŒ… ์ถ”๋ก  ์ˆ˜ํ–‰ + router = RoutedInference(str(current_dir / "Model_routing_1004")) + routed_results = router.process_test_images(str(raws_dir), str(current_dir / "routed_temp_results")) + + # 2๏ธโƒฃ SectionPredictor ์ดˆ๊ธฐํ™” ๋ฐ ์˜ˆ์ธก ๊ฒฐ๊ณผ ๋กœ๋“œ + predictor = SectionPredictor(class_names) + predictions = predictor.load_predictions(routed_results) + + # 3๏ธโƒฃ ํฌ๋กญ ์‹คํ–‰ + predictor.crop_sections(predictions, sections_output_dir) + logger.info("=== ๋ชจ๋“  ์ž‘์—… ์™„๋ฃŒ ===") + logger.info(f"ํฌ๋กญ๋œ ์ด๋ฏธ์ง€ ์ €์žฅ ์œ„์น˜: {sections_output_dir}") + + +if __name__ == "__main__": + main() diff --git a/ai-service/models/Recognition/__pycache__/ocr.cpython-311.pyc b/ai-service/models/Recognition/__pycache__/ocr.cpython-311.pyc new file mode 100644 index 0000000..3c91f05 Binary files /dev/null and b/ai-service/models/Recognition/__pycache__/ocr.cpython-311.pyc differ diff --git a/ai-service/models/Recognition/__pycache__/ocr.cpython-312.pyc b/ai-service/models/Recognition/__pycache__/ocr.cpython-312.pyc new file mode 100644 index 0000000..a3c30d5 Binary files /dev/null and b/ai-service/models/Recognition/__pycache__/ocr.cpython-312.pyc differ diff --git a/ai-service/models/Recognition/__pycache__/resnetClassifier.cpython-311.pyc b/ai-service/models/Recognition/__pycache__/resnetClassifier.cpython-311.pyc new file mode 100644 index 0000000..e4fb1bf Binary files /dev/null and b/ai-service/models/Recognition/__pycache__/resnetClassifier.cpython-311.pyc differ diff --git a/ai-service/models/Recognition/__pycache__/resnetClassifier.cpython-312.pyc b/ai-service/models/Recognition/__pycache__/resnetClassifier.cpython-312.pyc new file mode 100644 index 0000000..4f03a8f Binary files /dev/null and b/ai-service/models/Recognition/__pycache__/resnetClassifier.cpython-312.pyc differ diff --git a/ai-service/models/Recognition/models/answer_1_efficientnet.pth b/ai-service/models/Recognition/models/answer_1_efficientnet.pth new file mode 100644 index 0000000..6b880df Binary files /dev/null and b/ai-service/models/Recognition/models/answer_1_efficientnet.pth differ diff --git a/ai-service/models/Recognition/models/answer_1_mobilenet.pth b/ai-service/models/Recognition/models/answer_1_mobilenet.pth new file mode 100644 index 0000000..2126a28 Binary files /dev/null and b/ai-service/models/Recognition/models/answer_1_mobilenet.pth differ diff --git a/ai-service/models/Recognition/models/answer_1_resnet.pth b/ai-service/models/Recognition/models/answer_1_resnet.pth new file mode 100644 index 0000000..eff1a8e Binary files /dev/null and b/ai-service/models/Recognition/models/answer_1_resnet.pth differ diff --git a/ai-service/models/Recognition/models/answer_2_efficientnet.pth b/ai-service/models/Recognition/models/answer_2_efficientnet.pth new file mode 100644 index 0000000..08d0e83 Binary files /dev/null and b/ai-service/models/Recognition/models/answer_2_efficientnet.pth differ diff --git a/ai-service/models/Recognition/models/answer_2_mobilenet.pth b/ai-service/models/Recognition/models/answer_2_mobilenet.pth new file mode 100644 index 0000000..6ace207 Binary files /dev/null and b/ai-service/models/Recognition/models/answer_2_mobilenet.pth differ diff --git a/ai-service/models/Recognition/models/answer_2_resnet.pth b/ai-service/models/Recognition/models/answer_2_resnet.pth new file mode 100644 index 0000000..b52495b Binary files /dev/null and b/ai-service/models/Recognition/models/answer_2_resnet.pth differ diff --git a/ai-service/models/Recognition/ocr.py b/ai-service/models/Recognition/ocr.py new file mode 100644 index 0000000..54bfa51 --- /dev/null +++ b/ai-service/models/Recognition/ocr.py @@ -0,0 +1,21 @@ +import easyocr +import re + +class OCRModel: + def __init__(self): + self.reader = easyocr.Reader(['en'], gpu=False) + + def extract_number(self, image_path): + """์ด๋ฏธ์ง€์—์„œ ์ˆซ์ž๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.""" + try: + results = self.reader.readtext(image_path) + # ๋ชจ๋“  ํ…์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ํ•ฉ์นจ + text = ' '.join([result[1] for result in results]) + # ์ˆซ์ž๋งŒ ์ถ”์ถœ + numbers = re.findall(r'\d+', text) + if numbers: + return numbers[0] # ์ฒซ ๋ฒˆ์งธ ์ˆซ์ž ๋ฐ˜ํ™˜ + return "" + except Exception as e: + print(f"EasyOCR Error processing {image_path}: {e}") + return "" \ No newline at end of file diff --git a/ai-service/models/Recognition/resnetClassifier.py b/ai-service/models/Recognition/resnetClassifier.py new file mode 100644 index 0000000..0f0125a --- /dev/null +++ b/ai-service/models/Recognition/resnetClassifier.py @@ -0,0 +1,156 @@ +from typing import Tuple, Optional +import cv2 +import torch +import torch.nn as nn +from torchvision import transforms + +class ResNetClassifier: + """ResNet ๊ธฐ๋ฐ˜ ๋‹ต์•ˆ ๋ถ„๋ฅ˜ ๋ชจ๋ธ (1-5 ๋ถ„๋ฅ˜)""" + + def __init__(self, model_path: str, model_type: str = 'answer', device: str = 'cuda'): + """ + Args: + model_path: ResNet ๋ชจ๋ธ ๊ฐ€์ค‘์น˜ ํŒŒ์ผ ๊ฒฝ๋กœ (.pth) + model_type: ๋ชจ๋ธ ํƒ€์ž… ('answer_1' ๋˜๋Š” 'answer_2') + device: 'cuda' ๋˜๋Š” 'cpu' + """ + self.device = torch.device(device if torch.cuda.is_available() else 'cpu') + self.model_type = model_type + self.model = self._load_model(model_path) + self.transform = self._get_transform() + + + def _load_model(self, model_path: str): + """ResNet ๋ชจ๋ธ ๋กœ๋“œ - ์ปค์Šคํ…€ ๊ตฌ์กฐ""" + # ์ปค์Šคํ…€ ResNet18 ๊ตฌ์กฐ (shortcut ์‚ฌ์šฉ, grayscale ์ž…๋ ฅ) + class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, in_channels, out_channels, stride=1): + super(BasicBlock, self).__init__() + self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(out_channels) + self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(out_channels) + + self.shortcut = nn.Sequential() + if stride != 1 or in_channels != out_channels: + self.shortcut = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(out_channels) + ) + + def forward(self, x): + out = torch.relu(self.bn1(self.conv1(x))) + out = self.bn2(self.conv2(out)) + out += self.shortcut(x) + out = torch.relu(out) + return out + + class CustomResNet18(nn.Module): + def __init__(self, num_classes=5): + super(CustomResNet18, self).__init__() + # Grayscale ์ž…๋ ฅ (1 ์ฑ„๋„) + self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(64) + + # ResNet18 ๊ตฌ์กฐ + self.layer1 = self._make_layer(64, 64, 2, stride=1) + self.layer2 = self._make_layer(64, 128, 2, stride=2) + self.layer3 = self._make_layer(128, 256, 2, stride=2) + self.layer4 = self._make_layer(256, 512, 2, stride=2) + + self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(512, num_classes) + + def _make_layer(self, in_channels, out_channels, num_blocks, stride): + layers = [] + layers.append(BasicBlock(in_channels, out_channels, stride)) + for _ in range(1, num_blocks): + layers.append(BasicBlock(out_channels, out_channels, 1)) + return nn.Sequential(*layers) + + def forward(self, x): + out = torch.relu(self.bn1(self.conv1(x))) + out = self.layer1(out) + out = self.layer2(out) + out = self.layer3(out) + out = self.layer4(out) + out = self.avgpool(out) + out = out.view(out.size(0), -1) + out = self.fc(out) + return out + + # ๋ชจ๋ธ ์ƒ์„ฑ + model = CustomResNet18(num_classes=5) + + # ๊ฐ€์ค‘์น˜ ๋กœ๋“œ (PyTorch 2.6+ ํ˜ธํ™˜) + try: + checkpoint = torch.load(model_path, map_location=self.device, weights_only=False) + except TypeError: + checkpoint = torch.load(model_path, map_location=self.device) + + # state_dict ์ถ”์ถœ + if isinstance(checkpoint, dict): + if 'model_state_dict' in checkpoint: + state_dict = checkpoint['model_state_dict'] + elif 'state_dict' in checkpoint: + state_dict = checkpoint['state_dict'] + else: + state_dict = checkpoint + else: + state_dict = checkpoint + + model.load_state_dict(state_dict) + model.to(self.device) + model.eval() + + return model + + def _get_transform(self): + """์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ ๋ณ€ํ™˜ - MNIST ์Šคํƒ€์ผ""" + return transforms.Compose([ + transforms.ToPILImage(), + transforms.Grayscale(num_output_channels=1), # Grayscale ๋ณ€ํ™˜ + transforms.Resize((28, 28)), # MNIST ํฌ๊ธฐ + transforms.ToTensor(), + transforms.Normalize(mean=[0.1307], std=[0.3081]) # MNIST ์ •๊ทœํ™” + ]) + + def predict(self, image_path: str) -> Tuple[Optional[str], float]: + """ + ์ด๋ฏธ์ง€์—์„œ ๋‹ต์•ˆ ๋ฒˆํ˜ธ ์˜ˆ์ธก + + Args: + image_path: ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ + + Returns: + Tuple[Optional[str], float]: (์˜ˆ์ธก๋œ ๋‹ต์•ˆ ๋ฒˆํ˜ธ '1'-'5', ์‹ ๋ขฐ๋„) + """ + try: + # ์ด๋ฏธ์ง€ ๋กœ๋“œ (BGR) + image = cv2.imread(image_path) + if image is None: + return None, 0.0 + + # RGB๋กœ ๋ณ€ํ™˜ (PIL์€ RGB๋ฅผ ๊ธฐ๋Œ€) + image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + + # ์ „์ฒ˜๋ฆฌ (Grayscale ๋ณ€ํ™˜ ํฌํ•จ) + input_tensor = self.transform(image_rgb).unsqueeze(0).to(self.device) + + # ์ถ”๋ก  + with torch.no_grad(): + outputs = self.model(input_tensor) + probabilities = torch.softmax(outputs, dim=1) + confidence, predicted = torch.max(probabilities, 1) + + # ๊ฒฐ๊ณผ ๋ณ€ํ™˜ (0-4 โ†’ 1-5) + answer = str(predicted.item() + 1) + conf = confidence.item() + + + return answer, conf + + except Exception as e: + return None, 0.0 \ No newline at end of file diff --git a/ai-service/models/__init__.py b/ai-service/models/__init__.py new file mode 100644 index 0000000..2529813 --- /dev/null +++ b/ai-service/models/__init__.py @@ -0,0 +1 @@ +# ๋ชจ๋ธ ํŒจํ‚ค์ง€ diff --git a/ai-service/models/__pycache__/__init__.cpython-311.pyc b/ai-service/models/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..879538a Binary files /dev/null and b/ai-service/models/__pycache__/__init__.cpython-311.pyc differ diff --git a/ai-service/models/__pycache__/__init__.cpython-312.pyc b/ai-service/models/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..447e97d Binary files /dev/null and b/ai-service/models/__pycache__/__init__.cpython-312.pyc differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 10_section_00_conf0.50.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 10_section_00_conf0.50.jpg" new file mode 100644 index 0000000..952961d Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 10_section_00_conf0.50.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 10_section_01_conf0.34.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 10_section_01_conf0.34.jpg" new file mode 100644 index 0000000..117720d Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 10_section_01_conf0.34.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 10_section_02_conf0.31.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 10_section_02_conf0.31.jpg" new file mode 100644 index 0000000..8b1145b Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 10_section_02_conf0.31.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_00_conf0.55.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_00_conf0.55.jpg" new file mode 100644 index 0000000..893962c Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_00_conf0.55.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_01_conf0.52.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_01_conf0.52.jpg" new file mode 100644 index 0000000..e009e8b Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_01_conf0.52.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_02_conf0.51.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_02_conf0.51.jpg" new file mode 100644 index 0000000..64b9033 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_02_conf0.51.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_03_conf0.50.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_03_conf0.50.jpg" new file mode 100644 index 0000000..0cc807a Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_03_conf0.50.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_04_conf0.45.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_04_conf0.45.jpg" new file mode 100644 index 0000000..0fdcc2a Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_04_conf0.45.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_05_conf0.36.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_05_conf0.36.jpg" new file mode 100644 index 0000000..f0c5427 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_05_conf0.36.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_06_conf0.31.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_06_conf0.31.jpg" new file mode 100644 index 0000000..8760733 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 11_section_06_conf0.31.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_00_conf0.75.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_00_conf0.75.jpg" new file mode 100644 index 0000000..2d173df Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_00_conf0.75.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_01_conf0.71.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_01_conf0.71.jpg" new file mode 100644 index 0000000..09062f7 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_01_conf0.71.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_02_conf0.62.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_02_conf0.62.jpg" new file mode 100644 index 0000000..bd13228 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_02_conf0.62.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_03_conf0.55.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_03_conf0.55.jpg" new file mode 100644 index 0000000..22abf14 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_03_conf0.55.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_04_conf0.52.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_04_conf0.52.jpg" new file mode 100644 index 0000000..ec708f7 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_04_conf0.52.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_05_conf0.49.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_05_conf0.49.jpg" new file mode 100644 index 0000000..8e27a93 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_05_conf0.49.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_06_conf0.45.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_06_conf0.45.jpg" new file mode 100644 index 0000000..3bf5b1d Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 12_section_06_conf0.45.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_00_conf0.73.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_00_conf0.73.jpg" new file mode 100644 index 0000000..a35e53a Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_00_conf0.73.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_01_conf0.72.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_01_conf0.72.jpg" new file mode 100644 index 0000000..b07a9af Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_01_conf0.72.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_02_conf0.72.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_02_conf0.72.jpg" new file mode 100644 index 0000000..a6d7960 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_02_conf0.72.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_03_conf0.68.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_03_conf0.68.jpg" new file mode 100644 index 0000000..4c2d14a Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_03_conf0.68.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_04_conf0.67.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_04_conf0.67.jpg" new file mode 100644 index 0000000..89b01c6 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_04_conf0.67.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_05_conf0.60.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_05_conf0.60.jpg" new file mode 100644 index 0000000..a75a2aa Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_05_conf0.60.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_06_conf0.45.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_06_conf0.45.jpg" new file mode 100644 index 0000000..6ef4fa8 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_06_conf0.45.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_07_conf0.42.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_07_conf0.42.jpg" new file mode 100644 index 0000000..2b1f148 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_07_conf0.42.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_08_conf0.31.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_08_conf0.31.jpg" new file mode 100644 index 0000000..45c2f54 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 13_section_08_conf0.31.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_00_conf0.73.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_00_conf0.73.jpg" new file mode 100644 index 0000000..ba02a07 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_00_conf0.73.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_01_conf0.66.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_01_conf0.66.jpg" new file mode 100644 index 0000000..4224fb6 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_01_conf0.66.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_02_conf0.63.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_02_conf0.63.jpg" new file mode 100644 index 0000000..5aa2993 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_02_conf0.63.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_03_conf0.55.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_03_conf0.55.jpg" new file mode 100644 index 0000000..a447337 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_03_conf0.55.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_04_conf0.51.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_04_conf0.51.jpg" new file mode 100644 index 0000000..4439389 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_04_conf0.51.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_05_conf0.50.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_05_conf0.50.jpg" new file mode 100644 index 0000000..c6e1355 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_05_conf0.50.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_06_conf0.35.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_06_conf0.35.jpg" new file mode 100644 index 0000000..a95d192 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 14_section_06_conf0.35.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_00_conf0.75.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_00_conf0.75.jpg" new file mode 100644 index 0000000..083d2db Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_00_conf0.75.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_01_conf0.72.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_01_conf0.72.jpg" new file mode 100644 index 0000000..fbac37b Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_01_conf0.72.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_02_conf0.69.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_02_conf0.69.jpg" new file mode 100644 index 0000000..12c75b9 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_02_conf0.69.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_03_conf0.67.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_03_conf0.67.jpg" new file mode 100644 index 0000000..e5c3ab5 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_03_conf0.67.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_04_conf0.66.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_04_conf0.66.jpg" new file mode 100644 index 0000000..0e02293 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_04_conf0.66.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_05_conf0.58.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_05_conf0.58.jpg" new file mode 100644 index 0000000..e147335 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_05_conf0.58.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_06_conf0.52.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_06_conf0.52.jpg" new file mode 100644 index 0000000..f0d9267 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_06_conf0.52.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_07_conf0.28.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_07_conf0.28.jpg" new file mode 100644 index 0000000..0c3c91b Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 15_section_07_conf0.28.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_00_conf0.64.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_00_conf0.64.jpg" new file mode 100644 index 0000000..4895289 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_00_conf0.64.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_01_conf0.62.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_01_conf0.62.jpg" new file mode 100644 index 0000000..01a3508 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_01_conf0.62.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_02_conf0.50.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_02_conf0.50.jpg" new file mode 100644 index 0000000..8ba3f61 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_02_conf0.50.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_03_conf0.43.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_03_conf0.43.jpg" new file mode 100644 index 0000000..603ef97 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 16_section_03_conf0.43.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_00_conf0.61.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_00_conf0.61.jpg" new file mode 100644 index 0000000..cee5b35 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_00_conf0.61.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_01_conf0.55.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_01_conf0.55.jpg" new file mode 100644 index 0000000..3f2bf71 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_01_conf0.55.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_02_conf0.51.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_02_conf0.51.jpg" new file mode 100644 index 0000000..12fbe0f Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_02_conf0.51.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_03_conf0.46.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_03_conf0.46.jpg" new file mode 100644 index 0000000..c1c5de8 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_03_conf0.46.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_04_conf0.44.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_04_conf0.44.jpg" new file mode 100644 index 0000000..cff0e5c Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 1_section_04_conf0.44.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_00_conf0.71.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_00_conf0.71.jpg" new file mode 100644 index 0000000..bb3ef15 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_00_conf0.71.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_01_conf0.64.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_01_conf0.64.jpg" new file mode 100644 index 0000000..89723ea Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_01_conf0.64.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_02_conf0.62.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_02_conf0.62.jpg" new file mode 100644 index 0000000..9aae8b9 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_02_conf0.62.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_03_conf0.44.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_03_conf0.44.jpg" new file mode 100644 index 0000000..78d16b8 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 2_section_03_conf0.44.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_00_conf0.71.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_00_conf0.71.jpg" new file mode 100644 index 0000000..c1beeaf Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_00_conf0.71.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_01_conf0.63.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_01_conf0.63.jpg" new file mode 100644 index 0000000..66ad771 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_01_conf0.63.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_02_conf0.52.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_02_conf0.52.jpg" new file mode 100644 index 0000000..324778b Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_02_conf0.52.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_03_conf0.50.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_03_conf0.50.jpg" new file mode 100644 index 0000000..ecb0a25 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_03_conf0.50.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_04_conf0.47.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_04_conf0.47.jpg" new file mode 100644 index 0000000..e7b0338 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_04_conf0.47.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_05_conf0.32.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_05_conf0.32.jpg" new file mode 100644 index 0000000..f051ed9 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_05_conf0.32.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_06_conf0.30.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_06_conf0.30.jpg" new file mode 100644 index 0000000..8548567 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_06_conf0.30.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_07_conf0.28.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_07_conf0.28.jpg" new file mode 100644 index 0000000..86f6b87 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 3_section_07_conf0.28.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_00_conf0.79.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_00_conf0.79.jpg" new file mode 100644 index 0000000..219a514 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_00_conf0.79.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_01_conf0.62.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_01_conf0.62.jpg" new file mode 100644 index 0000000..89a53be Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_01_conf0.62.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_02_conf0.61.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_02_conf0.61.jpg" new file mode 100644 index 0000000..ae0237c Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_02_conf0.61.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_03_conf0.57.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_03_conf0.57.jpg" new file mode 100644 index 0000000..df6a13d Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_03_conf0.57.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_04_conf0.44.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_04_conf0.44.jpg" new file mode 100644 index 0000000..fc44ea7 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_04_conf0.44.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_05_conf0.38.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_05_conf0.38.jpg" new file mode 100644 index 0000000..8f2484a Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 4_section_05_conf0.38.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_00_conf0.70.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_00_conf0.70.jpg" new file mode 100644 index 0000000..016acf6 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_00_conf0.70.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_01_conf0.70.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_01_conf0.70.jpg" new file mode 100644 index 0000000..1af845c Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_01_conf0.70.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_02_conf0.66.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_02_conf0.66.jpg" new file mode 100644 index 0000000..f56d0c9 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_02_conf0.66.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_03_conf0.60.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_03_conf0.60.jpg" new file mode 100644 index 0000000..b7f4822 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_03_conf0.60.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_04_conf0.59.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_04_conf0.59.jpg" new file mode 100644 index 0000000..3b361a5 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_04_conf0.59.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_06_conf0.36.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_06_conf0.36.jpg" new file mode 100644 index 0000000..8fdf829 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_06_conf0.36.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_07_conf0.29.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_07_conf0.29.jpg" new file mode 100644 index 0000000..68422b2 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 5_section_07_conf0.29.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_00_conf0.72.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_00_conf0.72.jpg" new file mode 100644 index 0000000..5743a78 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_00_conf0.72.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_01_conf0.63.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_01_conf0.63.jpg" new file mode 100644 index 0000000..054c683 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_01_conf0.63.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_02_conf0.48.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_02_conf0.48.jpg" new file mode 100644 index 0000000..c8297be Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_02_conf0.48.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_03_conf0.47.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_03_conf0.47.jpg" new file mode 100644 index 0000000..14d8f0e Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_03_conf0.47.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_04_conf0.27.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_04_conf0.27.jpg" new file mode 100644 index 0000000..b5b2d13 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 6_section_04_conf0.27.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_00_conf0.60.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_00_conf0.60.jpg" new file mode 100644 index 0000000..c6bbb73 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_00_conf0.60.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_01_conf0.60.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_01_conf0.60.jpg" new file mode 100644 index 0000000..1b0eb54 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_01_conf0.60.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_02_conf0.54.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_02_conf0.54.jpg" new file mode 100644 index 0000000..4aaebf9 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_02_conf0.54.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_03_conf0.48.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_03_conf0.48.jpg" new file mode 100644 index 0000000..95b76ad Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_03_conf0.48.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_04_conf0.43.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_04_conf0.43.jpg" new file mode 100644 index 0000000..a6d3cdd Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_04_conf0.43.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_05_conf0.43.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_05_conf0.43.jpg" new file mode 100644 index 0000000..9ed2d27 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_05_conf0.43.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_06_conf0.36.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_06_conf0.36.jpg" new file mode 100644 index 0000000..fe123e9 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 7_section_06_conf0.36.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_00_conf0.78.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_00_conf0.78.jpg" new file mode 100644 index 0000000..14e55bd Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_00_conf0.78.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_01_conf0.71.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_01_conf0.71.jpg" new file mode 100644 index 0000000..026c1ea Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_01_conf0.71.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_02_conf0.68.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_02_conf0.68.jpg" new file mode 100644 index 0000000..5cada42 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_02_conf0.68.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_03_conf0.61.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_03_conf0.61.jpg" new file mode 100644 index 0000000..a3bbf25 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_03_conf0.61.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_04_conf0.48.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_04_conf0.48.jpg" new file mode 100644 index 0000000..34b354e Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_04_conf0.48.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_05_conf0.44.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_05_conf0.44.jpg" new file mode 100644 index 0000000..c8501d9 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_05_conf0.44.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_06_conf0.43.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_06_conf0.43.jpg" new file mode 100644 index 0000000..dfa41e2 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_06_conf0.43.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_07_conf0.29.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_07_conf0.29.jpg" new file mode 100644 index 0000000..c10571d Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 8_section_07_conf0.29.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_00_conf0.54.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_00_conf0.54.jpg" new file mode 100644 index 0000000..cc2ee8b Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_00_conf0.54.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_01_conf0.52.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_01_conf0.52.jpg" new file mode 100644 index 0000000..40e1758 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_01_conf0.52.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_02_conf0.45.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_02_conf0.45.jpg" new file mode 100644 index 0000000..512b61c Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_02_conf0.45.jpg" differ diff --git "a/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_03_conf0.44.jpg" "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_03_conf0.44.jpg" new file mode 100644 index 0000000..637dc64 Binary files /dev/null and "b/ai-service/models/recognition/exp_images/\354\210\230\355\225\231\353\254\270\354\240\234/\353\235\274\354\235\264\355\212\270\354\216\210 \354\244\221\353\223\261\354\210\230\355\225\231 1-1 - 9_section_03_conf0.44.jpg" differ diff --git a/ai-service/requirements.txt b/ai-service/requirements.txt index d8e98fa..48f8156 100644 --- a/ai-service/requirements.txt +++ b/ai-service/requirements.txt @@ -1,18 +1,19 @@ -fastapi==0.104.1 -uvicorn[standard]==0.24.0 -pydantic==2.5.0 -numpy==1.24.3 -pandas==2.0.3 -scikit-learn==1.3.0 -tensorflow==2.15.0 -torch==2.1.0 -transformers==4.35.0 -python-multipart==0.0.6 -python-jose[cryptography]==3.3.0 -passlib[bcrypt]==1.7.4 -pymongo==4.6.0 -redis==5.0.1 -boto3==1.34.0 -python-dotenv==1.0.0 -pytest==7.4.3 -pytest-asyncio==0.21.1 +# requirements.txt (๋ฒ„์ „ ์œ ์—ฐํ•˜๊ฒŒ) +fastapi>=0.100.0 +uvicorn>=0.20.0 +pydantic>=2.0.0 +aiokafka>=0.8.0 +aiohttp>=3.8.0 +openai>=1.0.0 +torch>=2.0.0 +torchvision>=0.15.0 +ultralytics>=8.0.0 +opencv-python>=4.8.0 +pillow>=10.0.0 +easyocr>=1.7.0 +numpy>=1.24.0 +pandas>=2.0.0 +python-dotenv>=1.0.0 +PyYAML>=6.0 +tqdm>=4.65.0 +requests>=2.28.0 \ No newline at end of file diff --git a/ai-service/services/__init__.py b/ai-service/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-service/services/__pycache__/__init__.cpython-311.pyc b/ai-service/services/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..79e5791 Binary files /dev/null and b/ai-service/services/__pycache__/__init__.cpython-311.pyc differ diff --git a/ai-service/services/__pycache__/__init__.cpython-312.pyc b/ai-service/services/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..dafc84a Binary files /dev/null and b/ai-service/services/__pycache__/__init__.cpython-312.pyc differ diff --git a/ai-service/services/__pycache__/chapter_mapper.cpython-311.pyc b/ai-service/services/__pycache__/chapter_mapper.cpython-311.pyc new file mode 100644 index 0000000..574a9ff Binary files /dev/null and b/ai-service/services/__pycache__/chapter_mapper.cpython-311.pyc differ diff --git a/ai-service/services/__pycache__/chapter_mapper.cpython-312.pyc b/ai-service/services/__pycache__/chapter_mapper.cpython-312.pyc new file mode 100644 index 0000000..f325e71 Binary files /dev/null and b/ai-service/services/__pycache__/chapter_mapper.cpython-312.pyc differ diff --git a/ai-service/services/__pycache__/hierarchical_crop.cpython-311.pyc b/ai-service/services/__pycache__/hierarchical_crop.cpython-311.pyc new file mode 100644 index 0000000..4116360 Binary files /dev/null and b/ai-service/services/__pycache__/hierarchical_crop.cpython-311.pyc differ diff --git a/ai-service/services/__pycache__/hierarchical_crop.cpython-312.pyc b/ai-service/services/__pycache__/hierarchical_crop.cpython-312.pyc new file mode 100644 index 0000000..2c562ef Binary files /dev/null and b/ai-service/services/__pycache__/hierarchical_crop.cpython-312.pyc differ diff --git a/ai-service/services/__pycache__/solution_llms.cpython-311.pyc b/ai-service/services/__pycache__/solution_llms.cpython-311.pyc new file mode 100644 index 0000000..a716e51 Binary files /dev/null and b/ai-service/services/__pycache__/solution_llms.cpython-311.pyc differ diff --git a/ai-service/services/__pycache__/solution_llms.cpython-312.pyc b/ai-service/services/__pycache__/solution_llms.cpython-312.pyc new file mode 100644 index 0000000..eacdac7 Binary files /dev/null and b/ai-service/services/__pycache__/solution_llms.cpython-312.pyc differ diff --git a/ai-service/services/chapter_mapper.py b/ai-service/services/chapter_mapper.py new file mode 100644 index 0000000..c3015a5 --- /dev/null +++ b/ai-service/services/chapter_mapper.py @@ -0,0 +1,162 @@ +# services/chapter_mapper.py +""" +์ฑ•ํ„ฐ ๋งคํ•‘ ์œ ํ‹ธ๋ฆฌํ‹ฐ +- chapter.txt ํŒŒ์ผ์—์„œ ์ฑ•ํ„ฐ ์ •๋ณด ๋กœ๋“œ +- ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋กœ ํ•ด๋‹น chapter_id ์กฐํšŒ +""" + +import logging +import os +from typing import Dict, List, Optional, Tuple + +logger = logging.getLogger(__name__) + + +class ChapterMapper: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ chapter_id๋กœ ๋งคํ•‘ํ•˜๋Š” ํด๋ž˜์Šค""" + + def __init__(self, chapter_file_path: str = "DB/chapter.txt"): + """ + Args: + chapter_file_path: chapter.txt ํŒŒ์ผ ๊ฒฝ๋กœ + """ + self.chapter_file_path = chapter_file_path + self.chapters: List[Dict] = [] # [{'chapter_id': '001', 'start_page': 9, 'end_page': 13}, ...] + + self._load_chapters() + + def _load_chapters(self) -> None: + """chapter.txt ํŒŒ์ผ์—์„œ ์ฑ•ํ„ฐ ์ •๋ณด ๋กœ๋“œ + + ํŒŒ์ผ ํ˜•์‹: {chapter_id}, {์‹œ์ž‘ ํŽ˜์ด์ง€}, {๋งˆ์ง€๋ง‰ ํŽ˜์ด์ง€} + ์˜ˆ: 001, 9, 13 + """ + if not os.path.exists(self.chapter_file_path): + logger.warning(f"์ฑ•ํ„ฐ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {self.chapter_file_path}") + return + + try: + with open(self.chapter_file_path, 'r', encoding='utf-8') as f: + for line_num, line in enumerate(f, 1): + line = line.strip() + + # ๋นˆ ์ค„ ์Šคํ‚ต + if not line: + continue + + # ์ฃผ์„ ์Šคํ‚ต (์„ ํƒ์ ) + if line.startswith('#'): + continue + + parts = [p.strip() for p in line.split(',')] + + if len(parts) < 3: + logger.warning(f"์ฑ•ํ„ฐ ํŒŒ์ผ {line_num}๋ฒˆ์งธ ์ค„ ํ˜•์‹ ์˜ค๋ฅ˜: {line}") + continue + + try: + chapter_id = parts[0] + start_page = int(parts[1]) + end_page = int(parts[2]) + + self.chapters.append({ + 'chapter_id': chapter_id, + 'start_page': start_page, + 'end_page': end_page + }) + + except ValueError as e: + logger.warning(f"์ฑ•ํ„ฐ ํŒŒ์ผ {line_num}๋ฒˆ์งธ ์ค„ ํŒŒ์‹ฑ ์˜ค๋ฅ˜: {line} - {e}") + continue + + logger.info(f"โœ… ์ฑ•ํ„ฐ ์ •๋ณด ๋กœ๋“œ ์™„๋ฃŒ: {len(self.chapters)}๊ฐœ ์ฑ•ํ„ฐ") + for ch in self.chapters: + logger.debug(f" - ์ฑ•ํ„ฐ {ch['chapter_id']}: ํŽ˜์ด์ง€ {ch['start_page']}-{ch['end_page']}") + + except Exception as e: + logger.error(f"์ฑ•ํ„ฐ ํŒŒ์ผ ๋กœ๋“œ ์‹คํŒจ: {e}") + + def get_chapter_id(self, page_number: int) -> Optional[str]: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์— ํ•ด๋‹นํ•˜๋Š” chapter_id ๋ฐ˜ํ™˜ + + Args: + page_number: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (์ •์ˆ˜) + + Returns: + chapter_id ๋ฌธ์ž์—ด ๋˜๋Š” None (ํ•ด๋‹น ์ฑ•ํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ) + """ + for chapter in self.chapters: + if chapter['start_page'] <= page_number <= chapter['end_page']: + return chapter['chapter_id'] + + return None + + def get_chapter_id_from_str(self, page_number_str: Optional[str]) -> Optional[str]: + """๋ฌธ์ž์—ด ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์— ํ•ด๋‹นํ•˜๋Š” chapter_id ๋ฐ˜ํ™˜ + + Args: + page_number_str: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฌธ์ž์—ด + + Returns: + chapter_id ๋ฌธ์ž์—ด ๋˜๋Š” None + """ + if not page_number_str: + return None + + try: + page_number = int(page_number_str) + return self.get_chapter_id(page_number) + except ValueError: + logger.warning(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ณ€ํ™˜ ์‹คํŒจ: {page_number_str}") + return None + + def get_chapter_id_as_int(self, page_number: int) -> int: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์— ํ•ด๋‹นํ•˜๋Š” chapter_id๋ฅผ ์ •์ˆ˜๋กœ ๋ฐ˜ํ™˜ + + Args: + page_number: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (์ •์ˆ˜) + + Returns: + chapter_id ์ •์ˆ˜ ๋˜๋Š” 0 (ํ•ด๋‹น ์ฑ•ํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ) + """ + chapter_id_str = self.get_chapter_id(page_number) + + if chapter_id_str is None: + return 0 + + try: + return int(chapter_id_str) + except ValueError: + logger.warning(f"chapter_id๋ฅผ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์—†์Œ: {chapter_id_str}") + return 0 + + def get_chapter_id_as_int_from_str(self, page_number_str: Optional[str]) -> int: + """๋ฌธ์ž์—ด ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์— ํ•ด๋‹นํ•˜๋Š” chapter_id๋ฅผ ์ •์ˆ˜๋กœ ๋ฐ˜ํ™˜ + + Args: + page_number_str: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฌธ์ž์—ด + + Returns: + chapter_id ์ •์ˆ˜ ๋˜๋Š” 0 + """ + if not page_number_str: + return 0 + + try: + page_number = int(page_number_str) + return self.get_chapter_id_as_int(page_number) + except ValueError: + logger.warning(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ณ€ํ™˜ ์‹คํŒจ: {page_number_str}") + return 0 + + def reload(self) -> None: + """์ฑ•ํ„ฐ ์ •๋ณด ๋‹ค์‹œ ๋กœ๋“œ""" + self.chapters = [] + self._load_chapters() + + def __len__(self) -> int: + """๋กœ๋“œ๋œ ์ฑ•ํ„ฐ ๊ฐœ์ˆ˜ ๋ฐ˜ํ™˜""" + return len(self.chapters) + + def __repr__(self) -> str: + return f"ChapterMapper(chapters={len(self.chapters)}, file='{self.chapter_file_path}')" \ No newline at end of file diff --git a/ai-service/services/hierarchical_crop.py b/ai-service/services/hierarchical_crop.py new file mode 100644 index 0000000..a58aedb --- /dev/null +++ b/ai-service/services/hierarchical_crop.py @@ -0,0 +1,859 @@ +# services/hierarchical_crop.py +import logging +import time +import os +from pathlib import Path +from typing import Dict, List, Tuple, Optional +import cv2 +import numpy as np +import torch +import torch.nn as nn +from torchvision import transforms +from models.Detection.legacy.Model_routing_1104.run_routed_inference import RoutedInference as RoutedInference_1104 +from models.Detection.legacy.Model_routing_1004.run_routed_inference import RoutedInference as RoutedInference_1004 +from models.Recognition.resnetClassifier import ResNetClassifier +from models.Recognition.ocr import OCRModel + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + + +class HierarchicalCropPipeline: + """๊ณ„์ธต์  ํฌ๋กญ ํŒŒ์ดํ”„๋ผ์ธ: ํŽ˜์ด์ง€ โ†’ Section โ†’ ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ ์ •๋‹ต (answer_2 ์šฐ์„ , answer_1 fallback)""" + + def __init__(self, model_dir_1104: str, model_dir_1004: str, + section_padding: int = 50, + answer_key_path: Optional[str] = None, + resnet_answer_1_path: Optional[str] = None, + resnet_answer_2_path: Optional[str] = None): + """ + Args: + model_dir_1104: 1104 ๋ชจ๋ธ ๊ฒฝ๋กœ + model_dir_1004: 1004 ๋ชจ๋ธ ๊ฒฝ๋กœ + section_padding: Section crop ์‹œ ์ถ”๊ฐ€ํ•  ์—ฌ๋ฐฑ (ํ”ฝ์…€). ๊ธฐ๋ณธ๊ฐ’ 50 + answer_key_path: ๋‹ต์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ (txt ํŒŒ์ผ) + resnet_answer_1_path: answer_1์šฉ ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ (.pth ํŒŒ์ผ) + resnet_answer_2_path: answer_2์šฉ ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ (.pth ํŒŒ์ผ) + """ + self.router_1104 = RoutedInference_1104(model_dir_1104) # ๋‹ต์•ˆ ์ถ”๋ก ์šฉ + self.router_1004 = RoutedInference_1004(model_dir_1004) # ํฌ๋กญ์šฉ (ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section) + self.ocr = OCRModel() + self.section_padding = section_padding + + # โœจ answer_1๊ณผ answer_2์šฉ ResNet ๋ชจ๋ธ ์ดˆ๊ธฐํ™” + self.resnet_answer_1 = None + self.resnet_answer_2 = None + + # answer_1 ResNet ๋กœ๋“œ + if resnet_answer_1_path and os.path.exists(resnet_answer_1_path): + try: + self.resnet_answer_1 = ResNetClassifier(resnet_answer_1_path, model_type='answer_1') + logger.info("โœ… answer_1 ResNet ๋ถ„๋ฅ˜ ๋ชจ๋ธ ๋กœ๋“œ ์„ฑ๊ณต") + except Exception as e: + logger.error(f"โŒ answer_1 ResNet ๋ชจ๋ธ ๋กœ๋“œ ์‹คํŒจ: {e}") + logger.warning("answer_1 ResNet ๋ถ„๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + else: + if resnet_answer_1_path: + logger.warning(f"answer_1 ResNet ๋ชจ๋ธ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {resnet_answer_1_path}") + logger.info("answer_1 ResNet ๋ถ„๋ฅ˜ ์—†์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.") + + # answer_2 ResNet ๋กœ๋“œ + if resnet_answer_2_path and os.path.exists(resnet_answer_2_path): + try: + self.resnet_answer_2 = ResNetClassifier(resnet_answer_2_path, model_type='answer_2') + logger.info("โœ… answer_2 ResNet ๋ถ„๋ฅ˜ ๋ชจ๋ธ ๋กœ๋“œ ์„ฑ๊ณต") + except Exception as e: + logger.error(f"โŒ answer_2 ResNet ๋ชจ๋ธ ๋กœ๋“œ ์‹คํŒจ: {e}") + logger.warning("answer_2 ResNet ๋ถ„๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + else: + if resnet_answer_2_path: + logger.warning(f"answer_2 ResNet ๋ชจ๋ธ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {resnet_answer_2_path}") + logger.info("answer_2 ResNet ๋ถ„๋ฅ˜ ์—†์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.") + + # ๋‹ต์ง€ ๋กœ๋“œ + self.answer_key = self._load_answer_key(answer_key_path) if answer_key_path else None + + logger.info("HierarchicalCropPipeline ์ดˆ๊ธฐํ™” (๋‘ ๊ฐœ์˜ ๋ชจ๋ธ + OCR ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ)") + logger.info(" - 1104 ๋ชจ๋ธ: ๋‹ต์•ˆ ์ถ”๋ก ์šฉ (answer_1, answer_2 ๊ฒ€์ถœ)") + logger.info(" - 1004 ๋ชจ๋ธ: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ํฌ๋กญ์šฉ") + logger.info(f" - Section padding: {section_padding}px") + logger.info(f" - answer_1 ResNet: {'์‚ฌ์šฉ ๊ฐ€๋Šฅ' if self.resnet_answer_1 else '์‚ฌ์šฉ ๋ถˆ๊ฐ€'}") + logger.info(f" - answer_2 ResNet: {'์‚ฌ์šฉ ๊ฐ€๋Šฅ' if self.resnet_answer_2 else '์‚ฌ์šฉ ๋ถˆ๊ฐ€'}") + if self.answer_key: + logger.info(f" - ๋‹ต์ง€ ๋กœ๋“œ ์™„๋ฃŒ: {len(self.answer_key)}๊ฐœ ํŽ˜์ด์ง€") + + def _normalize_number(self, number_str: Optional[str]) -> Optional[str]: + """ + ์ˆซ์ž ๋ฌธ์ž์—ด ์ •๊ทœํ™”: ์•ž์˜ 0 ์ œ๊ฑฐ (01 -> 1, 001 -> 1) + + Args: + number_str: OCR๋กœ ์ธ์‹๋œ ์ˆซ์ž ๋ฌธ์ž์—ด + + Returns: + ์ •๊ทœํ™”๋œ ์ˆซ์ž ๋ฌธ์ž์—ด + """ + if number_str is None: + return None + + number_str = number_str.strip() + + if not number_str: + return None + + # ์ˆซ์ž๋กœ๋งŒ ์ด๋ฃจ์–ด์ง„ ๊ฒฝ์šฐ ์•ž์˜ 0 ์ œ๊ฑฐ + if number_str.isdigit(): + return str(int(number_str)) # "01" -> "1", "001" -> "1" + + return number_str + + def _load_answer_key(self, answer_key_path: str) -> Dict[str, List[Dict]]: + """๋‹ต์ง€ ํŒŒ์ผ ๋กœ๋“œ + + ํŒŒ์ผ ํ˜•์‹: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต + ์˜ˆ: 1, 1, 3 + + Returns: + Dict[str, List[Dict]]: {ํŽ˜์ด์ง€๋ฒˆํ˜ธ: [{'problem': ๋ฌธ์ œ๋ฒˆํ˜ธ, 'answer': ์ •๋‹ต}, ...]} + """ + answer_key = {} + try: + with open(answer_key_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line: + continue + + parts = [p.strip() for p in line.split(',')] + if len(parts) >= 3: + page_num = self._normalize_number(parts[0]) + problem_num = self._normalize_number(parts[1]) + answer = parts[2] + + if page_num not in answer_key: + answer_key[page_num] = [] + + answer_key[page_num].append({ + 'problem': problem_num, + 'answer': answer + }) + + logger.info(f"๋‹ต์ง€ ๋กœ๋“œ ์™„๋ฃŒ: {answer_key_path}") + for page, problems in answer_key.items(): + logger.info(f" ํŽ˜์ด์ง€ {page}: {len(problems)}๊ฐœ ๋ฌธ์ œ") + + except Exception as e: + logger.error(f"๋‹ต์ง€ ๋กœ๋“œ ์‹คํŒจ: {e}") + return {} + + return answer_key + + def is_valid_page(self, page_number: Optional[str]) -> bool: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๊ฐ€ ๋‹ต์ง€์— ์žˆ๋Š”์ง€ ํ™•์ธ""" + if self.answer_key is None: + return True + + if page_number is None: + logger.warning("ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + return False + + page_number_normalized = self._normalize_number(page_number) + is_valid = page_number_normalized in self.answer_key + + if not is_valid: + logger.warning(f"ํŽ˜์ด์ง€ {page_number_normalized}๋Š” ๋‹ต์ง€์— ์—†์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + else: + logger.info(f"ํŽ˜์ด์ง€ {page_number_normalized}๋Š” ๋‹ต์ง€์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜๋ฆฌ๋ฅผ ๊ณ„์†ํ•ฉ๋‹ˆ๋‹ค.") + + return is_valid + + def get_missing_problem_number(self, page_number: Optional[str], + recognized_numbers: set) -> Optional[str]: + """๋‹ต์ง€ ๊ธฐ๋ฐ˜์œผ๋กœ ํŽ˜์ด์ง€์—์„œ ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ค‘ ๊ฐ€์žฅ ์ž‘์€ ๊ฒƒ์„ ๋ฐ˜ํ™˜""" + if self.answer_key is None or page_number is None: + return None + + page_number_normalized = self._normalize_number(page_number) + + if page_number_normalized not in self.answer_key: + return None + + expected_problems = {item['problem'] for item in self.answer_key[page_number_normalized]} + # recognized_numbers๋„ ์ •๊ทœํ™”ํ•˜์—ฌ ๋น„๊ต + recognized_normalized = {self._normalize_number(n) for n in recognized_numbers if n} + missing = expected_problems - recognized_normalized + + if not missing: + return None + + try: + missing_sorted = sorted(missing, key=lambda x: int(x) if x and x.isdigit() else float('inf')) + smallest_missing = missing_sorted[0] + logger.info(f"๐Ÿ“‹ ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ค‘ ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’: {smallest_missing}") + return smallest_missing + except Exception as e: + logger.error(f"๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ •๋ ฌ ์‹คํŒจ: {e}") + return None + + def calculate_iou(self, bbox1: List[float], bbox2: List[float]) -> float: + """๋‘ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค์˜ IoU ๊ณ„์‚ฐ""" + x1_1, y1_1, x2_1, y2_1 = bbox1 + x1_2, y1_2, x2_2, y2_2 = bbox2 + + x1_i = max(x1_1, x1_2) + y1_i = max(y1_1, y1_2) + x2_i = min(x2_1, x2_2) + y2_i = min(y2_1, y2_2) + + if x2_i <= x1_i or y2_i <= y1_i: + return 0.0 + + intersection = (x2_i - x1_i) * (y2_i - y1_i) + area1 = (x2_1 - x1_1) * (y2_1 - y1_1) + area2 = (x2_2 - x1_2) * (y2_2 - y1_2) + union = area1 + area2 - intersection + + if union == 0: + return 0.0 + + return intersection / union + + def expand_bbox_with_padding(self, bbox: List[float], padding: int, img_width: int, img_height: int) -> List[int]: + """๋ฐ”์šด๋”ฉ ๋ฐ•์Šค์— padding์„ ์ถ”๊ฐ€""" + x1, y1, x2, y2 = bbox + + x1_expanded = max(0, int(x1 - padding)) + y1_expanded = max(0, int(y1 - padding)) + x2_expanded = min(img_width, int(x2 + padding)) + y2_expanded = min(img_height, int(y2 + padding)) + + return [x1_expanded, y1_expanded, x2_expanded, y2_expanded] + + def is_bbox_near_section_boundary(self, bbox: List[float], section_bbox: List[float], threshold: int = 30) -> bool: + """๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ•์Šค๊ฐ€ section ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์žˆ๋Š”์ง€ ํ™•์ธ""" + bx1, by1, bx2, by2 = bbox + sx1, sy1, sx2, sy2 = section_bbox + + dist_top = abs(by1 - sy1) + dist_bottom = abs(by2 - sy2) + dist_left = abs(bx1 - sx1) + dist_right = abs(bx2 - sx2) + + return min(dist_top, dist_bottom, dist_left, dist_right) < threshold + + def crop_page_number(self, image_path: str, detections_1004: List[Dict], output_dir: Path) -> Tuple[Optional[str], Optional[str]]: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ํฌ๋กญํ•˜๊ณ  OCR๋กœ ์ธ์‹ (์ด๋ฏธ์ง€ ์ €์žฅ ์—†์ด)""" + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return None, None + + page_num_detections = [d for d in detections_1004 if d['class_name'] == 'page_number'] + + if not page_num_detections: + logger.warning(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ: {image_path}") + return None, None + + best_det = max(page_num_detections, key=lambda x: x['confidence']) + x1, y1, x2, y2 = map(int, best_det['bbox']) + + h, w = image.shape[:2] + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 <= x1 or y2 <= y1: + logger.warning(f"์ž˜๋ชป๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐ•์Šค: {best_det['bbox']}") + return None, None + + cropped = image[y1:y2, x1:x2] + + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=True) as tmp: + cv2.imwrite(tmp.name, cropped) + recognized_number = self.ocr.extract_number(tmp.name) + # ์•ž์˜ 0 ์ œ๊ฑฐ + recognized_number = self._normalize_number(recognized_number) + + return None, recognized_number + + def classify_answer_with_resnet(self, answer_crop_path: str, section_idx: int, + answer_type: str = "answer_1") -> Tuple[Optional[str], float, bool]: + """answer crop ์ด๋ฏธ์ง€๋ฅผ ํ•ด๋‹น ํƒ€์ž…์˜ ResNet์œผ๋กœ ๋ถ„๋ฅ˜""" + if answer_type == 'answer_2': + resnet_model = self.resnet_answer_2 + else: + resnet_model = self.resnet_answer_1 + + if resnet_model is None: + logger.warning(f"Section {section_idx}: {answer_type} ResNet ๋ชจ๋ธ์ด ์—†์–ด ๋ถ„๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + return None, 0.0, True + + if not os.path.exists(answer_crop_path): + logger.error(f"Section {section_idx}: {answer_type} ์ด๋ฏธ์ง€๊ฐ€ ์—†์–ด ResNet์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {answer_crop_path}") + return None, 0.0, True + + try: + answer, confidence = resnet_model.predict(answer_crop_path) + + if answer is None: + logger.warning(f"Section {section_idx}: {answer_type} ResNet ์˜ˆ์ธก ์‹คํŒจ") + return None, 0.0, True + + return answer, confidence, False + + except Exception as e: + logger.error(f"Section {section_idx}: {answer_type} ResNet ์˜ˆ์ธก ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ: {e}") + return None, 0.0, True + + def _construct_section_path(self, output_dir: Path, page_number: str, problem_number: str) -> Path: + """ + Section ์ด๋ฏธ์ง€ ์ €์žฅ ๊ฒฝ๋กœ ์ƒ์„ฑ + + ํ˜•์‹: {output_dir}/{page_number}/{problem_number}/{page_number}_{problem_number}_section.jpg + + Args: + output_dir: ๊ธฐ๋ณธ ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ + page_number: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ + problem_number: ๋ฌธ์ œ ๋ฒˆํ˜ธ + + Returns: + Path: ์ „์ฒด ํŒŒ์ผ ๊ฒฝ๋กœ + """ + # ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ: {output_dir}/{page_number}/{problem_number}/ + section_dir = output_dir / str(page_number) / str(problem_number) + section_dir.mkdir(parents=True, exist_ok=True) + + # ํŒŒ์ผ๋ช…: {page_number}_{problem_number}_section.jpg + filename = f"{page_number}_{problem_number}_section.jpg" + + return section_dir / filename + + def process_single_section(self, original_image_path: str, section_idx: int, + page_name: str, output_dir: Path, + section_bbox: List[float], detections_1004: List[Dict], + detections_1104: List[Dict], page_number_ocr: Optional[str] = None, + recognized_problem_numbers: Optional[set] = None) -> Dict: + """์„น์…˜ ๋‚ด์˜ ๋ฌธ์ œ๋ฒˆํ˜ธ์™€ ์ •๋‹ต์„ ์ถ”๋ก  + + โœจ Section ์ด๋ฏธ์ง€ ์ €์žฅ ๊ฒฝ๋กœ: + {output_dir}/{page_number}/{problem_number}/{page_number}_{problem_number}_section.jpg + + Args: + original_image_path: ์›๋ณธ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + section_idx: Section ์ธ๋ฑ์Šค + page_name: ํŽ˜์ด์ง€ ์ด๋ฆ„ + output_dir: ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ + section_bbox: Section ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค + detections_1004: 1004 ๋ชจ๋ธ ๊ฒ€์ถœ ๊ฒฐ๊ณผ + detections_1104: 1104 ๋ชจ๋ธ ๊ฒ€์ถœ ๊ฒฐ๊ณผ + page_number_ocr: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (OCR ์ธ์‹ ๊ฒฐ๊ณผ) + recognized_problem_numbers: ์ด๋ฏธ ์ธ์‹๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ๋“ค์˜ ์ง‘ํ•ฉ + + Returns: + Dict: ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ + """ + if recognized_problem_numbers is None: + recognized_problem_numbers = set() + + sx1, sy1, sx2, sy2 = section_bbox + image = cv2.imread(original_image_path) + h, w = image.shape[:2] + + # Section bbox ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if sx2 <= sx1 or sy2 <= sy1: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ์ž˜๋ชป๋œ bbox") + return self._create_failure_result(section_idx, 'invalid_bbox', section_bbox, w, h) + + # Section ์ด๋ฏธ์ง€ ํฌ๋กญ ์‹œ padding ์ถ”๊ฐ€ + expanded_section_bbox = self.expand_bbox_with_padding( + [sx1, sy1, sx2, sy2], + self.section_padding, + w, h + ) + sx1_exp, sy1_exp, sx2_exp, sy2_exp = expanded_section_bbox + + if sx2_exp <= sx1_exp or sy2_exp <= sy1_exp: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ์ž˜๋ชป๋œ ํ™•์žฅ bbox") + return self._create_failure_result(section_idx, 'invalid_expanded_bbox', section_bbox, w, h, expanded_section_bbox) + + # Section ์ด๋ฏธ์ง€ ํฌ๋กญ + try: + section_cropped = image[sy1_exp:sy2_exp, sx1_exp:sx2_exp] + crop_h, crop_w = section_cropped.shape[:2] + + if crop_h == 0 or crop_w == 0: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ํฌ๋กญ๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ๊ฐ€ 0") + return self._create_failure_result(section_idx, 'zero_size_crop', section_bbox, w, h, expanded_section_bbox) + + except Exception as e: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: {e}") + return self._create_failure_result(section_idx, f'exception: {str(e)}', section_bbox, w, h) + + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + # ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ๋จผ์ € ์ˆ˜ํ–‰ (ํŒŒ์ผ ์ €์žฅ ๊ฒฝ๋กœ ๊ฒฐ์ •์— ํ•„์š”) + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + + # 1004 ๋ชจ๋ธ์—์„œ ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ + section_dets_1004 = [] + for det in detections_1004: + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + if det['class_name'] == 'problem_number': + section_dets_1004.append(det) + + # ๋ฌธ์ œ๋ฒˆํ˜ธ OCR + problem_ocr = None + problem_ocr_override = False + + if section_dets_1004: + if len(section_dets_1004) == 2: + logger.warning(f"โš ๏ธ Section {section_idx}: ๋ฌธ์ œ๋ฒˆํ˜ธ 2๊ฐœ ๊ฒ€์ถœ๋จ!") + missing_number = self.get_missing_problem_number(page_number_ocr, recognized_problem_numbers) + + if missing_number: + problem_ocr = missing_number + problem_ocr_override = True + logger.info(f"โœ… Section {section_idx}: ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ํ• ๋‹น โ†’ {problem_ocr}") + else: + best_det = max(section_dets_1004, key=lambda x: x['confidence']) + else: + best_det = max(section_dets_1004, key=lambda x: x['confidence']) + + if not problem_ocr_override: + x1, y1, x2, y2 = map(int, best_det['bbox']) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped = image[y1:y2, x1:x2] + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=True) as tmp: + cv2.imwrite(tmp.name, cropped) + problem_ocr = self.ocr.extract_number(tmp.name) + # ์•ž์˜ 0 ์ œ๊ฑฐ (01 -> 1, 001 -> 1) + problem_ocr = self._normalize_number(problem_ocr) + else: + logger.warning(f"Section {section_idx}: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ") + + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + # Section ์ด๋ฏธ์ง€ ์ €์žฅ (์˜ฌ๋ฐ”๋ฅธ ๊ฒฝ๋กœ๋กœ) + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + + section_crop_path = None + + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์™€ ๋ฌธ์ œ ๋ฒˆํ˜ธ๊ฐ€ ์žˆ์–ด์•ผ ์˜ฌ๋ฐ”๋ฅธ ๊ฒฝ๋กœ์— ์ €์žฅ ๊ฐ€๋Šฅ + if page_number_ocr and problem_ocr: + section_crop_path = self._construct_section_path(output_dir, page_number_ocr, problem_ocr) + + try: + write_success = cv2.imwrite(str(section_crop_path), section_cropped) + + if not write_success or not section_crop_path.exists(): + logger.error(f"โŒ Section {section_idx} ํŒŒ์ผ ์ €์žฅ ์‹คํŒจ: {section_crop_path}") + section_crop_path = None + else: + logger.info(f"โœ… Section ์ด๋ฏธ์ง€ ์ €์žฅ: {section_crop_path}") + except Exception as e: + logger.error(f"โŒ Section {section_idx} ํŒŒ์ผ ์ €์žฅ ์ค‘ ์˜ค๋ฅ˜: {e}") + section_crop_path = None + else: + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋‚˜ ๋ฌธ์ œ ๋ฒˆํ˜ธ๊ฐ€ ์—†์œผ๋ฉด ์ž„์‹œ ๊ฒฝ๋กœ์— ์ €์žฅ + fallback_dir = output_dir / "unknown" + fallback_dir.mkdir(parents=True, exist_ok=True) + fallback_path = fallback_dir / f"section_{section_idx:02d}.jpg" + + try: + cv2.imwrite(str(fallback_path), section_cropped) + section_crop_path = fallback_path + logger.warning(f"โš ๏ธ Section {section_idx}: ํŽ˜์ด์ง€/๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธํ™•์ธ, ์ž„์‹œ ๊ฒฝ๋กœ์— ์ €์žฅ: {fallback_path}") + except Exception as e: + logger.error(f"โŒ Section {section_idx} fallback ์ €์žฅ ์‹คํŒจ: {e}") + + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + # 1104 ๋ชจ๋ธ์—์„œ answer_1, answer_2, ์ˆซ์ž(1-5) ๊ฒ€์ถœ + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + + section_dets_1104 = [] + for det in detections_1104: + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + if det['class_name'] in ['answer_1', 'answer_2', '1', '2', '3', '4', '5']: + section_dets_1104.append(det) + + answer_1_dets = [d for d in section_dets_1104 if d['class_name'] == 'answer_1'] + answer_2_dets = [d for d in section_dets_1104 if d['class_name'] == 'answer_2'] + + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + # ๋‹ต์•ˆ ์ธ์‹ ๋กœ์ง + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + + best_answer = None + used_resnet = False + resnet_confidence = 0.0 + resnet_failed = False + answer_source = None + yolo_iou_verification = None + + # 1๋‹จ๊ณ„: YOLO๋กœ answer_2 ๊ฒ€์ถœ ์—ฌ๋ถ€ ํ™•์ธ + if answer_2_dets: + best_det = max(answer_2_dets, key=lambda x: x['confidence']) + answer_2_bbox = best_det['bbox'] + x1, y1, x2, y2 = map(int, answer_2_bbox) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped_answer_2 = image[y1:y2, x1:x2] + + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmp: + cv2.imwrite(tmp.name, cropped_answer_2) + answer_2_temp_path = tmp.name + + try: + answer, conf, failed = self.classify_answer_with_resnet(answer_2_temp_path, section_idx, "answer_2") + + if not failed and answer is not None: + best_answer = answer + resnet_confidence = conf + used_resnet = True + answer_source = 'answer_2_resnet' + else: + resnet_failed = True + used_resnet = True + answer_source = 'answer_2_failed' + finally: + os.unlink(answer_2_temp_path) + else: + answer_source = 'answer_2_invalid_bbox' + + # 2๋‹จ๊ณ„: answer_2๊ฐ€ ์—†๊ฑฐ๋‚˜ ์‹คํŒจ โ†’ answer_1 ์ฒ˜๋ฆฌ + if best_answer is None: + if answer_1_dets: + best_det = max(answer_1_dets, key=lambda x: x['confidence']) + answer_1_bbox = best_det['bbox'] + x1, y1, x2, y2 = map(int, answer_1_bbox) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped_answer_1 = image[y1:y2, x1:x2] + + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmp: + cv2.imwrite(tmp.name, cropped_answer_1) + answer_1_temp_path = tmp.name + + try: + answer, conf, failed = self.classify_answer_with_resnet(answer_1_temp_path, section_idx, "answer_1") + + if not failed and answer is not None: + # YOLO IoU๋กœ ๊ฒ€์ฆ + number_dets = [d for d in section_dets_1104 if d['class_name'] in ['1', '2', '3', '4', '5']] + + if number_dets: + iou_results = [] + for det in number_dets: + iou = self.calculate_iou(answer_1_bbox, det['bbox']) + iou_results.append({ + 'number': det['class_name'], + 'iou': iou, + 'confidence': det['confidence'] + }) + + best_iou_result = max(iou_results, key=lambda x: x['iou']) + yolo_best_number = best_iou_result['number'] + yolo_best_iou = best_iou_result['iou'] + + yolo_iou_verification = { + 'yolo_best': yolo_best_number, + 'yolo_iou': yolo_best_iou, + 'resnet_pred': answer, + 'resnet_conf': conf, + 'all_ious': iou_results + } + + if answer != yolo_best_number: + logger.warning(f"โš ๏ธ Section {section_idx}: ResNet({answer}) โ‰  YOLO IoU({yolo_best_number})") + + if conf < 0.70 and yolo_best_iou > 0.3: + best_answer = yolo_best_number + answer_source = 'answer_1_yolo' + else: + best_answer = answer + answer_source = 'answer_1_resnet' + else: + best_answer = answer + answer_source = 'answer_1_resnet' + else: + best_answer = answer + answer_source = 'answer_1_resnet' + + resnet_confidence = conf + used_resnet = True + resnet_failed = False + else: + resnet_failed = True + used_resnet = True + answer_source = 'answer_1_failed' + finally: + os.unlink(answer_1_temp_path) + else: + resnet_failed = True + answer_source = 'answer_1_invalid_bbox' + else: + resnet_failed = True + answer_source = 'no_answer_detected' + + # ์ •๋‹ต ์—ฌ๋ถ€ ํŒ๋‹จ + correction = None + if self.answer_key and page_number_ocr and problem_ocr and best_answer: + page_number_normalized = self._normalize_number(page_number_ocr) + if page_number_normalized in self.answer_key: + for item in self.answer_key[page_number_normalized]: + if item['problem'] == problem_ocr: + correct_answer = item['answer'] + correction = (best_answer == correct_answer) + break + + return { + 'section_idx': section_idx, + 'problem_number_ocr': problem_ocr, + 'problem_number_override': problem_ocr_override, + 'answer_number': best_answer, + 'correction': correction, + 'section_crop_path': str(section_crop_path) if section_crop_path else None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'answer_2_crop_path': None, + 'crop_success': section_crop_path is not None, + 'is_boundary_issue': len(section_dets_1004) > 0 and any( + self.is_bbox_near_section_boundary(d['bbox'], [sx1, sy1, sx2, sy2]) + for d in section_dets_1004 + ), + 'used_resnet': used_resnet, + 'resnet_confidence': resnet_confidence, + 'resnet_failed': resnet_failed, + 'answer_source': answer_source, + 'yolo_iou_verification': yolo_iou_verification, + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h), + 'answer_1_count': len(answer_1_dets), + 'answer_2_count': len(answer_2_dets), + 'problem_number_count': len(section_dets_1004) + } + } + + def _create_failure_result(self, section_idx: int, reason: str, + section_bbox: List[float], w: int, h: int, + expanded_bbox: List[int] = None) -> Dict: + """์‹คํŒจ ๊ฒฐ๊ณผ ์ƒ์„ฑ ํ—ฌํผ ๋ฉ”์„œ๋“œ""" + debug_info = { + 'original_bbox': section_bbox, + 'bbox_width': section_bbox[2] - section_bbox[0], + 'bbox_height': section_bbox[3] - section_bbox[1], + 'image_size': (w, h) + } + if expanded_bbox: + debug_info['expanded_bbox'] = expanded_bbox + + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'correction': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'answer_2_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': reason, + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False, + 'answer_source': None, + 'debug_info': debug_info + } + + def filter_duplicate_sections(self, image_path: str, section_detections: List[Dict], + detections_1004: List[Dict]) -> List[Dict]: + """์ค‘๋ณต๋œ section์„ ํ•„ํ„ฐ๋ง""" + if len(section_detections) <= 1: + return section_detections + + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return section_detections + + h, w = image.shape[:2] + + section_with_problem = [] + + for idx, section in enumerate(section_detections): + sx1, sy1, sx2, sy2 = section['bbox'] + section_area = (sx2 - sx1) * (sy2 - sy1) + + problem_numbers = [] + for det in detections_1004: + if det['class_name'] != 'problem_number': + continue + + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + + if sx1 <= cx <= sx2 and sy1 <= cy <= sy2: + problem_numbers.append(det) + + if problem_numbers: + best_problem = max(problem_numbers, key=lambda x: x['confidence']) + + x1, y1, x2, y2 = map(int, best_problem['bbox']) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped = image[y1:y2, x1:x2] + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=True) as tmp: + cv2.imwrite(tmp.name, cropped) + problem_ocr = self.ocr.extract_number(tmp.name) + # ์•ž์˜ 0 ์ œ๊ฑฐ + problem_ocr = self._normalize_number(problem_ocr) + else: + problem_ocr = None + else: + problem_ocr = None + + section_with_problem.append({ + 'section': section, + 'original_index': idx, + 'problem_number_ocr': problem_ocr, + 'section_area': section_area, + 'bbox': section['bbox'] + }) + + problem_groups = {} + no_problem_sections = [] + + for item in section_with_problem: + problem_num = item['problem_number_ocr'] + + if problem_num is None or problem_num == '': + no_problem_sections.append(item) + else: + if problem_num not in problem_groups: + problem_groups[problem_num] = [] + problem_groups[problem_num].append(item) + + filtered_sections = [] + removed_count = 0 + + for problem_num, items in problem_groups.items(): + if len(items) > 1: + largest = max(items, key=lambda x: x['section_area']) + filtered_sections.append(largest['section']) + removed_count += len(items) - 1 + else: + filtered_sections.append(items[0]['section']) + + for item in no_problem_sections: + filtered_sections.append(item['section']) + + if removed_count > 0: + logger.info(f"โœ‚๏ธ ์ค‘๋ณต ํ•„ํ„ฐ๋ง: {removed_count}๊ฐœ section ์ œ๊ฑฐ๋จ") + + filtered_sections = sorted(filtered_sections, key=lambda x: x['bbox'][1]) + + return filtered_sections + + def process_page(self, image_path: str, output_dir: Path) -> Optional[Dict]: + """ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ ๋ฉ”์ธ ํ•จ์ˆ˜ + + Args: + image_path: ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + output_dir: ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ (S3 uploadUrl์— ํ•ด๋‹น) + + Returns: + Optional[Dict]: ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ + + ์ถœ๋ ฅ ๊ตฌ์กฐ: + {output_dir}/ + โ””โ”€โ”€ {page_number}/ + โ””โ”€โ”€ {problem_number}/ + โ””โ”€โ”€ {page_number}_{problem_number}_section.jpg + """ + start_time = time.time() + + # 1004 ๋ชจ๋ธ: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ๊ฒ€์ถœ + logger.info("1004 ๋ชจ๋ธ ์‹คํ–‰ ์ค‘...") + result_1004 = self.router_1004.route_infer_single_image(image_path) + detections_1004 = result_1004['detections'] + + section_detections = [d for d in detections_1004 if d['class_name'] == 'section'] + logger.info(f"1004 ๋ชจ๋ธ Section ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {len(section_detections)}") + + if not section_detections: + logger.error(f"โŒ Section์ด ํ•˜๋‚˜๋„ ๊ฒ€์ถœ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค!") + return None + + page_name = Path(image_path).stem + + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ OCR + _, page_num_ocr = self.crop_page_number(image_path, detections_1004, output_dir) + + # ๋‹ต์ง€ ํ•„ํ„ฐ๋ง + if not self.is_valid_page(page_num_ocr): + logger.info(f"ํŽ˜์ด์ง€ '{page_name}' (ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ: {page_num_ocr})๋Š” ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") + return None + + # 1104 ๋ชจ๋ธ: answer_1, answer_2 ๊ฒ€์ถœ + logger.info("1104 ๋ชจ๋ธ ์‹คํ–‰ ์ค‘...") + result_1104 = self.router_1104.route_infer_single_image(image_path) + detections_1104 = result_1104['detections'] + + # ์ค‘๋ณต section ํ•„ํ„ฐ๋ง + section_detections = self.filter_duplicate_sections(image_path, section_detections, detections_1004) + section_detections = sorted(section_detections, key=lambda x: x['bbox'][1]) + + logger.info(f"ํŽ˜์ด์ง€ '{page_name}': {len(section_detections)}๊ฐœ Section ์ฒ˜๋ฆฌ") + + recognized_problem_numbers = set() + page_result = [] + crop_failure_count = 0 + + for idx, det in enumerate(section_detections): + section_bbox = det['bbox'] + section_result = self.process_single_section( + image_path, idx, page_name, output_dir, section_bbox, + detections_1004, detections_1104, page_num_ocr, recognized_problem_numbers + ) + page_result.append(section_result) + + if section_result.get('problem_number_ocr'): + recognized_problem_numbers.add(section_result['problem_number_ocr']) + + if not section_result.get('crop_success', True): + crop_failure_count += 1 + + end_time = time.time() + + if crop_failure_count > 0: + logger.warning(f"โš ๏ธ ํŽ˜์ด์ง€ '{page_name}': {crop_failure_count}๊ฐœ Section crop ์‹คํŒจ") + + return { + "image_path": image_path, + "page_name": page_name, + "page_number_ocr": page_num_ocr, + "sections": page_result, + "processing_time": end_time - start_time, + "total_sections": len(section_detections), + "crop_failure_count": crop_failure_count + } \ No newline at end of file diff --git a/ai-service/services/solution_llms.py b/ai-service/services/solution_llms.py new file mode 100644 index 0000000..221493a --- /dev/null +++ b/ai-service/services/solution_llms.py @@ -0,0 +1,274 @@ +# services/solution_llms.py +""" +LLM ๊ธฐ๋ฐ˜ ์ˆ˜๋Šฅ ์˜์–ด ๋ฌธ์ œ ํ•ด์„ค ์ƒ์„ฑ + +- ์ง€๋ฌธ ๋ถ„์„ +- ์ •๋‹ต๊ณผ ํ•™์ƒ ๋‹ต์•ˆ ๋น„๊ต +- ์˜ค๋‹ต์ธ ๊ฒฝ์šฐ ์ƒ์„ธ ํ•ด์„ค ์ƒ์„ฑ + +์ด ํŒŒ์ผ์€ services/llm_explanation.py์— ๋ฐฐ์น˜ํ•˜์„ธ์š”. +""" + +import json +import re +import glob +import os +from typing import Optional +from openai import OpenAI +from dotenv import load_dotenv + +load_dotenv() + +client = OpenAI( + api_key=os.getenv('UPSTAGE_API_KEY'), + base_url="https://api.upstage.ai/v1" +) + +# ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ +SYSTEM_PROMPT = """ +๋‹น์‹ ์€ 20๋…„ ๊ฒฝ๋ ฅ์˜ ํ•œ๊ตญ ์ˆ˜๋Šฅ ์˜์–ด ํ•ด์„ค ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค. +์•„๋ž˜ ๊ทœ์น™์„ ์ค€์ฃผํ•˜์—ฌ ํ•™์ƒ ๋‹ต์•ˆ์— ๋Œ€ํ•œ ํ•ด์„ค์„ ์ž‘์„ฑํ•˜์‹ญ์‹œ์˜ค. + +[๊ธฐ๋ณธ ๊ทœ์น™] +1) ์ •๋‹ต(answer)๊ณผ ํ•™์ƒ ๋‹ต์•ˆ(user_answer)์„ ๋จผ์ € ๋น„๊ตํ•œ๋‹ค. +2) ํ•™์ƒ ๋‹ต์•ˆ์ด ์ •๋‹ต์ด๋ฉด ํ•ด์„ค์€ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค. +3) ํ•™์ƒ ๋‹ต์•ˆ์ด ํ‹€๋ฆด ๊ฒฝ์šฐ: + - ๋ฐ˜๋“œ์‹œ ํ•ด์„ค์„ ์ œ๊ณตํ•œ๋‹ค. + - ๋จผ์ € ๋ฌธ์ œ ๋ฌธํ•ญ(korean_content)์„ ์ฝ์–ด, ๋ฌธ์ œ์˜ ์š”๊ตฌ ์‚ฌํ•ญ์„ ํŒŒ์•…ํ•œ๋‹ค. + - ์ดํ›„ ์ง€๋ฌธ(script ๋˜๋Š” english_content)์˜ ๋‚ด์šฉ์„ ๊ทผ๊ฑฐ๋กœ ํ•˜์—ฌ ํ•ด์„ค์„ ์ž‘์„ฑํ•œ๋‹ค. + - ์™ธ๋ถ€ ์ง€์‹์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ง€๋ฌธ๊ณผ ๋ฌธ์ œ์—๋งŒ ๊ทผ๊ฑฐํ•œ๋‹ค. +4) ํ•ด์„ค์€ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•˜๋ฉฐ, + - ์ƒ์„ธ ํ•ด์„ค์€ 8~10๋ฌธ์žฅ ๋ถ„๋Ÿ‰์œผ๋กœ ์ž‘์„ฑํ•œ๋‹ค. + - ํ•ด์„ค ์š”์•ฝ์€ 3~4๋ฌธ์žฅ ๋ถ„๋Ÿ‰์œผ๋กœ ์ž‘์„ฑํ•œ๋‹ค. + +[๋ฌธ์ œ ์˜์—ญ] +๋ฌธ์ œ๋Š” ๋‹ค์Œ ๋‘ ์˜์—ญ ์ค‘ ํ•˜๋‚˜์— ์†ํ•ฉ๋‹ˆ๋‹ค: + +1) ๋งฅ๋ฝ(context) ์˜์—ญ: + - ๋ฌธ๋ฒ• ๋ฌธ์ œ๋ฅผ ์ œ์™ธํ•œ ์œ ํ˜• + - ํ•ด์„ค์€ ๋‹ค์Œ ์ˆœ์„œ๋ฅผ ๋”ฐ๋ฅธ๋‹ค: + 1) ์ง€๋ฌธ์˜ ํ•ต์‹ฌ ํ๋ฆ„๊ณผ ์ฃผ์žฅยท๋‚ด์šฉ์„ 3๋ฌธ์žฅ ์ด๋‚ด๋กœ ์š”์•ฝ + 2) ๋ฌธ์ œ ๋ฌธํ•ญ์ด ๋ฌด์—‡์„ ๋ฌป๋Š”์ง€ ์„ค๋ช… + 3) ์ง€๋ฌธ์„ ๊ทผ๊ฑฐ๋กœ ํ•™์ƒ ๋‹ต์•ˆ์ด ์™œ ํ‹€๋ ธ๋Š”์ง€ ์˜๋ฏธ์ ยท๋…ผ๋ฆฌ์ ์œผ๋กœ ์„ค๋ช… + +2) ๋ฌธ๋ฒ•(grammar) ์˜์—ญ: + - ๋ฌธ๋ฒ•, ์–ด๋ฒ•, ๊ตฌ๋ฌธ ๋ฌธ์ œ + - ํ•ด์„ค์€ ๋‹ค์Œ ์ˆœ์„œ๋ฅผ ๋”ฐ๋ฅธ๋‹ค: + 1) ๋ฌธ์ œ ๋ฌธํ•ญ์ด ์š”๊ตฌํ•˜๋Š” ๋ฌธ๋ฒ• ์š”์†Œ๋ฅผ ํŒŒ์•… + 2) ํ•ด๋‹น ๋ฌธ๋ฒ• ์š”์†Œ์˜ ๊ทœ์น™์„ ๊ฐ„๋‹จํžˆ ์„ค๋ช… + 3) ์ง€๋ฌธ์„ ๊ทผ๊ฑฐ๋กœ ํ•™์ƒ ๋‹ต์•ˆ์ด ์™œ ํ‹€๋ ธ๋Š”์ง€ ๋ฌธ๋ฒ•์ ์œผ๋กœ ์„ค๋ช… + + +์ถœ๋ ฅ ํ˜•์‹์€ ์•„๋ž˜ ํ˜•์‹์„ ์œ ์ง€ํ•˜์‹ญ์‹œ์˜ค. +[์ถœ๋ ฅ ํ˜•์‹]: +------------------------------------ +## ๋ฌธ์ œ {problem_number} (p.{page_number}) +## ์ •๋‹ต: {answer} +## ์‚ฌ์šฉ์ž์˜ ์„ ํƒ: {user_answer} + +## ์ƒ์„ธ ํ•ด์„ค +- (ํ•™์ƒ ๋‹ต์•ˆ์ด ์˜ค๋‹ต์ผ ๊ฒฝ์šฐ) 8~10๋ฌธ์žฅ์˜ ์ƒ์„ธํ•œ ํ•œ๊ตญ์–ด ํ•ด์„ค + +## ํ•ด์„ค ์š”์•ฝ +- 3~4๋ฌธ์žฅ์œผ๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์š”์•ฝ +------------------------------------ +""" + +# ์œ ์ € ํ”„๋กฌํ”„ํŠธ +USER_PROMPT_TEMPLATE = """ +์•„๋ž˜๋Š” ๋ฌธ์ œ JSON ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค. ๊ฐ JSON ๊ฐ์ฒด์—๋Š” ๋‹ค์Œ ํ•„๋“œ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: +page_number, problem_number, korean_content, english_content, script, answer_option, answer, user_answer + +๊ฐ ๋ฌธ์ œ๋Š” ๋‹ค์Œ ๊ธฐ์ค€์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌํ•˜์‹ญ์‹œ์˜ค: + +1) ์ •๋‹ต(answer)๊ณผ ํ•™์ƒ ๋‹ต์•ˆ(user_answer)์„ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค. +2) ํ•™์ƒ ๋‹ต์•ˆ์ด ์ •๋‹ต์ผ ๊ฒฝ์šฐ: + - ์ •๋‹ต๊ณผ ํ•™์ƒ ๋‹ต์•ˆ๋งŒ ์ถœ๋ ฅํ•˜๋ฉฐ, ํ•ด์„ค์€ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +3) ํ•™์ƒ ๋‹ต์•ˆ์ด ํ‹€๋ฆด ๊ฒฝ์šฐ: + - ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด ํ•ด์„ค์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. + - ํ•ด์„ค ์ž‘์„ฑ ์‹œ ๋ฌธ์ œ ์ง€๋ฌธ(script ๋˜๋Š” english_content)๋งŒ์„ ๊ทผ๊ฑฐ๋กœ ์‚ผ์Šต๋‹ˆ๋‹ค. + - ์™ธ๋ถ€ ์ง€์‹์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + - ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ ๊ทœ์น™์— ๋”ฐ๋ผ ๋ฌธ์ œ ์˜์—ญ์— ๋งž๋Š” ํ•ด์„ค์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค: + - ๋งฅ๋ฝ(context) ์˜์—ญ โ†’ ์ง€๋ฌธ ์š”์•ฝ, ๋ฌธ์ œ ์š”๊ตฌ ์‚ฌํ•ญ, ์˜๋ฏธยท๋…ผ๋ฆฌ์  ๊ทผ๊ฑฐ ์ค‘์‹ฌ ํ•ด์„ค + - ๋ฌธ๋ฒ•(grammar) ์˜์—ญ โ†’ ๋ฌธ๋ฒ• ์š”์†Œ ์„ค๋ช…, ๊ทœ์น™ ์ œ์‹œ, ๋ฌธ๋ฒ•์  ๊ทผ๊ฑฐ ์ค‘์‹ฌ ํ•ด์„ค +4) ๋ฌธ์ œ ์˜์—ญ์€ ๋งฅ๋ฝ(context) ์˜์—ญ๊ณผ ๋ฌธ๋ฒ•(grammar) ์˜์—ญ ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ, + ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ์˜ ๊ทœ์น™์— ๋”ฐ๋ผ ํ•ด๋‹น ์˜์—ญ ๋ฐฉ์‹์œผ๋กœ ํ•ด์„ค์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. +5) ์ƒ์„ธ ํ•ด์„ค์€ 8~10๋ฌธ์žฅ, ํ•ด์„ค ์š”์•ฝ์€ 3~4 ๋ฌธ์žฅ์œผ๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. +6) ์ถœ๋ ฅ ํ˜•์‹์€ ์•„๋ž˜ ํ˜•์‹์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. + +[์ถœ๋ ฅ ํ˜•์‹]: +------------------------------------ +๐Ÿ”Ž ๋ฌธ์ œ {problem_number} (p.{page_number}) + +โœ… ์ •๋‹ต: {answer} +โœ๏ธ ์‚ฌ์šฉ์ž์˜ ์„ ํƒ: {user_answer} + +๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค +- ํ•™์ƒ ๋‹ต์•ˆ์ด ํ‹€๋ฆฐ ๊ฒฝ์šฐ 8~10๋ฌธ์žฅ ๋ถ„๋Ÿ‰์˜ ์ƒ์„ธํ•œ ํ•œ๊ตญ์–ด ํ•ด์„ค ์ œ๊ณต + +๐Ÿ”น ํ•ด์„ค ์š”์•ฝ +- 3~4๋ฌธ์žฅ์œผ๋กœ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์š”์•ฝ +------------------------------------ + +์•„๋ž˜ JSON ๋ฐฐ์—ด์„ ์ˆœ์„œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•˜์„ธ์š”: +""" + + +def safe_int(value, default=0) -> int: + """ + ๋ฌธ์ž์—ด์ด๋‚˜ ์ˆซ์ž๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜ + "01" -> 1, "102" -> 102, 1 -> 1 + """ + if value is None: + return default + try: + return int(value) + except (ValueError, TypeError): + return default + + +def load_answers(answer_file: str = "DB/answer.txt") -> dict: + """ + ์ •๋‹ต ํŒŒ์ผ(answer.txt)์„ ๋กœ๋“œํ•˜์—ฌ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ๋ฐ˜ํ™˜ + ํ‚ค๋Š” (ํŽ˜์ด์ง€๋ฒˆํ˜ธ int, ๋ฌธ์ œ๋ฒˆํ˜ธ int) ํŠœํ”Œ๋กœ ์ €์žฅ + + Args: + answer_file (str): ์ •๋‹ต ํŒŒ์ผ ๊ฒฝ๋กœ + + Returns: + dict: {(ํŽ˜์ด์ง€ int, ๋ฌธ์ œ๋ฒˆํ˜ธ int): ์ •๋‹ต} ํ˜•ํƒœ์˜ ๋”•์…”๋„ˆ๋ฆฌ + """ + mapping = {} + + if not os.path.exists(answer_file): + return mapping + + with open(answer_file, encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line: + continue + parts = [x.strip() for x in line.split(",")] + if len(parts) >= 3: + page_str, num_str, ans = parts[0], parts[1], parts[2] + # ๋ฌธ์ž์—ด์„ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ €์žฅ ("88", "01", "1") -> (88, 1, "1") + page_int = safe_int(page_str) + num_int = safe_int(num_str) + mapping[(page_int, num_int)] = ans + return mapping + + +def load_problems(folder_path: str = "DB/files") -> list: + """ + database_file ํด๋”์˜ ๋ชจ๋“  JSON ํŒŒ์ผ์„ ๋กœ๋“œํ•˜์—ฌ ๋ฌธ์ œ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜ + + Returns: + list: ๋ชจ๋“  ๋ฌธ์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ด๊ธด ๋ฆฌ์ŠคํŠธ + """ + all_problems = [] + + if not os.path.exists(folder_path): + return all_problems + + json_files = glob.glob(os.path.join(folder_path, "*.json")) + + if not json_files: + return all_problems + + for json_file in json_files: + with open(json_file, encoding="utf-8") as f: + try: + data = json.load(f) + if isinstance(data, list): + all_problems.extend(data) + else: + all_problems.append(data) + except json.JSONDecodeError as e: + print(f"JSON ํŒŒ์‹ฑ ์‹คํŒจ: {json_file}, Error: {e}") + + return all_problems + + +def generate_explanation( + page_number: int, + problem_number: int, + user_answer: int, + answer_file: str = "DB/answer.txt", + problems_folder: str = "DB/files" +) -> Optional[str]: + """ + ํ•™์ƒ์˜ ๋‹ต์•ˆ์„ ๋ถ„์„ํ•˜๊ณ  LLM์„ ํ†ตํ•ด ํ•ด์„ค์„ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์ธ ํ•จ์ˆ˜ + + Args: + page_number (int or str): ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (์˜ˆ: 102) + problem_number (int or str): ๋ฌธ์ œ ๋ฒˆํ˜ธ (์˜ˆ: 40 ๋˜๋Š” 1) + user_answer (int or str): ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ๋‹ต์•ˆ ๋ฒˆํ˜ธ (์˜ˆ: 5) + answer_file (str): ์ •๋‹ต ํŒŒ์ผ ๊ฒฝ๋กœ + problems_folder (str): ๋ฌธ์ œ JSON ํด๋” ๊ฒฝ๋กœ + + Returns: + str: LLM์ด ์ƒ์„ฑํ•œ ํ•ด์„ค ํ…์ŠคํŠธ + - ์ •๋‹ต์ธ ๊ฒฝ์šฐ: ์ •๋‹ต ํ™•์ธ ๋ฉ”์‹œ์ง€๋งŒ ํฌํ•จ + - ์˜ค๋‹ต์ธ ๊ฒฝ์šฐ: ์ƒ์„ธ ํ•ด์„ค + ํ•ด์„ค ์š”์•ฝ ํฌํ•จ + - ์—๋Ÿฌ์ธ ๊ฒฝ์šฐ: ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ๋ฌธ์ž์—ด + """ + problems = load_problems(problems_folder) + real_answers = load_answers(answer_file) + + # ์ž…๋ ฅ๊ฐ’์„ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜ (๋ฐฑ์—”๋“œ์—์„œ int๋กœ ์ „๋‹ฌ๋˜๋ฏ€๋กœ) + page_int = safe_int(page_number) + num_int = safe_int(problem_number) + user_ans = str(user_answer) + + # ํ•ด๋‹น ๋ฌธ์ œ ๊ฒ€์ƒ‰ (์ •์ˆ˜ ๋น„๊ต) + target = None + for prob in problems: + prob_page = safe_int(prob.get("page_number", "")) + prob_num = safe_int(prob.get("problem_number", 0)) + + if prob_page == page_int and prob_num == num_int: + target = prob.copy() + break + + if not target: + return f"ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (ํŽ˜์ด์ง€: {page_int}, ๋ฌธ์ œ๋ฒˆํ˜ธ: {num_int})" + + # ์‹ค์ œ ์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ (์ •์ˆ˜ ํŠœํ”Œ๋กœ ์กฐํšŒ) + real_ans = real_answers.get((page_int, num_int)) + + if not real_ans: + return f"ํ•ด๋‹น ๋ฌธ์ œ์˜ ์ •๋‹ต์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (ํŽ˜์ด์ง€: {page_int}, ๋ฌธ์ œ๋ฒˆํ˜ธ: {num_int})" + + # ์ •๋‹ต์ธ ๊ฒฝ์šฐ ํ•ด์„ค ์ƒ์„ฑ ์Šคํ‚ต + if str(user_ans) == str(real_ans): + return f"์ •๋‹ต์ž…๋‹ˆ๋‹ค! (๋ฌธ์ œ {num_int}, ํŽ˜์ด์ง€ {page_int})" + + # ๋ฌธ์ œ ๋ฐ์ดํ„ฐ์— ์ •๋‹ต๊ณผ ์‚ฌ์šฉ์ž ๋‹ต์•ˆ ์ถ”๊ฐ€ + target["answer"] = real_ans + target["user_answer"] = user_ans + + # ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ๋ž˜ํ•‘ ํ›„ JSON ๋ฌธ์ž์—ด ์ƒ์„ฑ + problem_json_array = json.dumps([target], ensure_ascii=False, indent=2) + user_prompt = USER_PROMPT_TEMPLATE + problem_json_array + + # OpenAI API ํ˜ธ์ถœ + try: + response = client.chat.completions.create( + model="solar-mini", + messages=[ + {"role": "system", "content": SYSTEM_PROMPT}, + {"role": "user", "content": user_prompt} + ], + temperature=0.2, + max_tokens=2000, + ) + return response.choices[0].message.content + + except Exception as e: + return f"LLM API ํ˜ธ์ถœ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}" + + +# if __name__ == "__main__": +# # ํ…Œ์ŠคํŠธ ์˜ˆ์‹œ +# result = generate_explanation(page_number=102, problem_number=40, user_answer=5) +# print(result) \ No newline at end of file diff --git a/ai-service/test/Classification/__init__.py b/ai-service/test/Classification/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-service/test/Classification/answer_classifier.ipynb b/ai-service/test/Classification/answer_classifier.ipynb new file mode 100644 index 0000000..9aa4b8c --- /dev/null +++ b/ai-service/test/Classification/answer_classifier.ipynb @@ -0,0 +1,24363 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "af858b0e", + "metadata": {}, + "source": [ + "'answer_classifier.ipynb'๋Š” ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ํ•ด๋‹น README.md๋ฅผ ์ฝ์–ด์ฃผ์„ธ์š”" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "cb44d5da", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-10-19 12:04:17,694 - INFO - \n", + "============================================================\n", + "2025-10-19 12:04:17,695 - INFO - ============================================================\n", + "2025-10-19 12:04:17,695 - INFO - Device: cpu\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "answer_1 Fine-tuning with RESNET (K=5 Cross Validation)\n", + " ํด๋ž˜์Šค 1: 189๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 2: 208๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 3: 193๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 4: 214๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 5: 228๊ฐœ ์ด๋ฏธ์ง€\n", + " ์ด 1032๊ฐœ ์ด๋ฏธ์ง€ ๋กœ๋“œ\n", + "\n", + "########################################\n", + "Starting Fold 1/5\n", + "########################################\n", + " Fold 1: Train samples = 825, Validation samples = 207\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6043, Train Acc: 25.94%\n", + " Val Loss: 1.5219, Val Acc: 30.92%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 30.92%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4694, Train Acc: 38.42%\n", + " Val Loss: 1.3765, Val Acc: 43.00%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 43.00%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3494, Train Acc: 43.15%\n", + " Val Loss: 1.1385, Val Acc: 56.52%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 56.52%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0977, Train Acc: 56.36%\n", + " Val Loss: 0.9121, Val Acc: 66.67%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 66.67%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9229, Train Acc: 63.88%\n", + " Val Loss: 0.7894, Val Acc: 67.63%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 67.63%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7999, Train Acc: 68.61%\n", + " Val Loss: 0.6979, Val Acc: 71.98%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 71.98%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6770, Train Acc: 74.79%\n", + " Val Loss: 0.6297, Val Acc: 74.40%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 74.40%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6220, Train Acc: 75.39%\n", + " Val Loss: 0.5478, Val Acc: 77.78%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 77.78%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5505, Train Acc: 78.06%\n", + " Val Loss: 0.5089, Val Acc: 78.26%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 78.26%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5135, Train Acc: 81.94%\n", + " Val Loss: 0.5137, Val Acc: 78.26%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4863, Train Acc: 81.94%\n", + " Val Loss: 0.4216, Val Acc: 83.57%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 83.57%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4402, Train Acc: 82.79%\n", + " Val Loss: 0.3974, Val Acc: 84.54%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 84.54%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4381, Train Acc: 83.64%\n", + " Val Loss: 0.4371, Val Acc: 84.54%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3885, Train Acc: 85.70%\n", + " Val Loss: 0.3826, Val Acc: 84.06%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2959, Train Acc: 89.94%\n", + " Val Loss: 0.3552, Val Acc: 87.44%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 87.44%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3149, Train Acc: 88.73%\n", + " Val Loss: 0.3774, Val Acc: 84.54%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3224, Train Acc: 89.21%\n", + " Val Loss: 0.4162, Val Acc: 85.02%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2676, Train Acc: 91.03%\n", + " Val Loss: 0.3767, Val Acc: 84.54%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2332, Train Acc: 91.76%\n", + " Val Loss: 0.3683, Val Acc: 85.99%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2753, Train Acc: 90.67%\n", + " Val Loss: 0.3190, Val Acc: 87.92%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 87.92%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2229, Train Acc: 92.12%\n", + " Val Loss: 0.3314, Val Acc: 85.99%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2425, Train Acc: 92.00%\n", + " Val Loss: 0.3123, Val Acc: 90.82%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 90.82%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2078, Train Acc: 92.36%\n", + " Val Loss: 0.3137, Val Acc: 89.37%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2064, Train Acc: 93.09%\n", + " Val Loss: 0.2913, Val Acc: 89.37%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2240, Train Acc: 92.36%\n", + " Val Loss: 0.3371, Val Acc: 89.86%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1714, Train Acc: 94.30%\n", + " Val Loss: 0.3090, Val Acc: 89.86%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1677, Train Acc: 94.55%\n", + " Val Loss: 0.3038, Val Acc: 88.89%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1776, Train Acc: 93.58%\n", + " Val Loss: 0.3035, Val Acc: 88.89%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1650, Train Acc: 94.30%\n", + " Val Loss: 0.3003, Val Acc: 89.37%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1662, Train Acc: 94.55%\n", + " Val Loss: 0.2893, Val Acc: 88.89%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1477, Train Acc: 95.03%\n", + " Val Loss: 0.2864, Val Acc: 88.89%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1754, Train Acc: 94.30%\n", + " Val Loss: 0.2869, Val Acc: 90.34%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1310, Train Acc: 95.52%\n", + " Val Loss: 0.2804, Val Acc: 89.37%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1159, Train Acc: 96.73%\n", + " Val Loss: 0.2756, Val Acc: 91.30%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 91.30%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1610, Train Acc: 94.06%\n", + " Val Loss: 0.2808, Val Acc: 88.89%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1414, Train Acc: 95.64%\n", + " Val Loss: 0.2973, Val Acc: 87.44%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1587, Train Acc: 95.03%\n", + " Val Loss: 0.2913, Val Acc: 88.41%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1324, Train Acc: 94.79%\n", + " Val Loss: 0.2840, Val Acc: 88.41%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1128, Train Acc: 96.73%\n", + " Val Loss: 0.2800, Val Acc: 89.37%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1647, Train Acc: 95.03%\n", + " Val Loss: 0.2844, Val Acc: 88.89%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1359, Train Acc: 95.52%\n", + " Val Loss: 0.2843, Val Acc: 89.37%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1372, Train Acc: 94.91%\n", + " Val Loss: 0.2807, Val Acc: 89.86%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1716, Train Acc: 95.03%\n", + " Val Loss: 0.2833, Val Acc: 88.89%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1223, Train Acc: 95.64%\n", + " Val Loss: 0.2767, Val Acc: 89.86%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1126, Train Acc: 96.61%\n", + " Val Loss: 0.2805, Val Acc: 88.41%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1525, Train Acc: 94.18%\n", + " Val Loss: 0.2775, Val Acc: 90.34%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1428, Train Acc: 94.55%\n", + " Val Loss: 0.2795, Val Acc: 89.37%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1269, Train Acc: 95.64%\n", + " Val Loss: 0.2755, Val Acc: 89.86%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1311, Train Acc: 96.12%\n", + " Val Loss: 0.2743, Val Acc: 89.37%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1399, Train Acc: 95.27%\n", + " Val Loss: 0.2840, Val Acc: 87.92%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1181, Train Acc: 95.88%\n", + " Val Loss: 0.2786, Val Acc: 88.41%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1131, Train Acc: 96.36%\n", + " Val Loss: 0.2762, Val Acc: 89.86%\n", + " Early Stopping Counter: 18/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1355, Train Acc: 95.64%\n", + " Val Loss: 0.2840, Val Acc: 88.89%\n", + " Early Stopping Counter: 19/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1625, Train Acc: 94.18%\n", + " Val Loss: 0.2798, Val Acc: 88.41%\n", + " Early Stopping Counter: 20/20\n", + " Early Stopping at epoch 54 for Fold 1\n", + "\n", + "Fold 1 finished. Best Validation Accuracy: 91.30%\n", + " Fold 1 Detailed Metrics:\n", + " Accuracy: 91.30%\n", + " Precision: 0.9165\n", + " Recall: 0.9130\n", + " F1-Score: 0.9131\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_resnet/confusion_matrices/fold_1_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 2/5\n", + "########################################\n", + " Fold 2: Train samples = 825, Validation samples = 207\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6179, Train Acc: 23.39%\n", + " Val Loss: 1.5233, Val Acc: 31.88%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 31.88%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5309, Train Acc: 30.30%\n", + " Val Loss: 1.4173, Val Acc: 36.71%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 36.71%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3715, Train Acc: 40.97%\n", + " Val Loss: 1.1372, Val Acc: 57.97%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 57.97%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1797, Train Acc: 50.42%\n", + " Val Loss: 0.8841, Val Acc: 61.35%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 61.35%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9498, Train Acc: 59.64%\n", + " Val Loss: 0.6560, Val Acc: 75.36%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 75.36%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8462, Train Acc: 65.33%\n", + " Val Loss: 0.5654, Val Acc: 76.33%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 76.33%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7552, Train Acc: 68.61%\n", + " Val Loss: 0.5375, Val Acc: 77.78%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 77.78%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6601, Train Acc: 73.45%\n", + " Val Loss: 0.4746, Val Acc: 79.71%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 79.71%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5995, Train Acc: 75.27%\n", + " Val Loss: 0.4817, Val Acc: 76.81%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5453, Train Acc: 78.42%\n", + " Val Loss: 0.3777, Val Acc: 87.44%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 87.44%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5001, Train Acc: 81.58%\n", + " Val Loss: 0.3205, Val Acc: 88.89%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 88.89%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5048, Train Acc: 80.61%\n", + " Val Loss: 0.3153, Val Acc: 87.92%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4375, Train Acc: 83.39%\n", + " Val Loss: 0.3009, Val Acc: 88.41%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3846, Train Acc: 86.55%\n", + " Val Loss: 0.3420, Val Acc: 84.06%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3964, Train Acc: 85.33%\n", + " Val Loss: 0.2608, Val Acc: 91.30%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 91.30%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3605, Train Acc: 86.30%\n", + " Val Loss: 0.2705, Val Acc: 88.89%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3018, Train Acc: 88.85%\n", + " Val Loss: 0.2283, Val Acc: 89.86%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3182, Train Acc: 88.24%\n", + " Val Loss: 0.1957, Val Acc: 93.72%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 93.72%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2986, Train Acc: 90.79%\n", + " Val Loss: 0.2561, Val Acc: 90.82%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2840, Train Acc: 89.82%\n", + " Val Loss: 0.2859, Val Acc: 90.34%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2764, Train Acc: 89.94%\n", + " Val Loss: 0.1923, Val Acc: 94.20%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 94.20%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2113, Train Acc: 92.73%\n", + " Val Loss: 0.2353, Val Acc: 89.37%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2348, Train Acc: 91.15%\n", + " Val Loss: 0.2318, Val Acc: 93.72%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2211, Train Acc: 92.73%\n", + " Val Loss: 0.2121, Val Acc: 93.72%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2259, Train Acc: 92.36%\n", + " Val Loss: 0.2655, Val Acc: 92.75%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2105, Train Acc: 93.70%\n", + " Val Loss: 0.2434, Val Acc: 93.24%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1739, Train Acc: 93.70%\n", + " Val Loss: 0.2496, Val Acc: 91.30%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1867, Train Acc: 93.33%\n", + " Val Loss: 0.2561, Val Acc: 91.30%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1795, Train Acc: 92.85%\n", + " Val Loss: 0.2274, Val Acc: 91.79%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1666, Train Acc: 94.30%\n", + " Val Loss: 0.1969, Val Acc: 93.72%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1502, Train Acc: 96.00%\n", + " Val Loss: 0.2038, Val Acc: 93.24%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1351, Train Acc: 95.39%\n", + " Val Loss: 0.2121, Val Acc: 92.27%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1381, Train Acc: 95.88%\n", + " Val Loss: 0.2182, Val Acc: 93.24%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1615, Train Acc: 95.39%\n", + " Val Loss: 0.2225, Val Acc: 92.75%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1464, Train Acc: 95.27%\n", + " Val Loss: 0.2176, Val Acc: 93.24%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1483, Train Acc: 94.91%\n", + " Val Loss: 0.2038, Val Acc: 93.72%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1511, Train Acc: 94.79%\n", + " Val Loss: 0.2001, Val Acc: 93.72%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1177, Train Acc: 96.12%\n", + " Val Loss: 0.2012, Val Acc: 93.72%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1132, Train Acc: 95.64%\n", + " Val Loss: 0.2066, Val Acc: 93.72%\n", + " Early Stopping Counter: 18/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1512, Train Acc: 94.55%\n", + " Val Loss: 0.2046, Val Acc: 93.72%\n", + " Early Stopping Counter: 19/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1122, Train Acc: 96.61%\n", + " Val Loss: 0.1984, Val Acc: 93.72%\n", + " Early Stopping Counter: 20/20\n", + " Early Stopping at epoch 41 for Fold 2\n", + "\n", + "Fold 2 finished. Best Validation Accuracy: 94.20%\n", + " Fold 2 Detailed Metrics:\n", + " Accuracy: 94.20%\n", + " Precision: 0.9478\n", + " Recall: 0.9420\n", + " F1-Score: 0.9427\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_resnet/confusion_matrices/fold_2_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 3/5\n", + "########################################\n", + " Fold 3: Train samples = 826, Validation samples = 206\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6120, Train Acc: 26.15%\n", + " Val Loss: 1.5340, Val Acc: 30.58%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 30.58%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5085, Train Acc: 34.50%\n", + " Val Loss: 1.3831, Val Acc: 40.78%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 40.78%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3849, Train Acc: 39.47%\n", + " Val Loss: 1.1721, Val Acc: 57.77%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 57.77%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1471, Train Acc: 56.54%\n", + " Val Loss: 0.9581, Val Acc: 61.65%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 61.65%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9644, Train Acc: 61.14%\n", + " Val Loss: 0.8380, Val Acc: 62.14%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 62.14%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8171, Train Acc: 69.61%\n", + " Val Loss: 0.7140, Val Acc: 70.39%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 70.39%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7399, Train Acc: 72.64%\n", + " Val Loss: 0.6501, Val Acc: 73.30%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 73.30%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6422, Train Acc: 75.79%\n", + " Val Loss: 0.6045, Val Acc: 73.30%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5394, Train Acc: 79.90%\n", + " Val Loss: 0.5404, Val Acc: 77.67%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 77.67%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5171, Train Acc: 81.36%\n", + " Val Loss: 0.5109, Val Acc: 76.70%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4693, Train Acc: 82.81%\n", + " Val Loss: 0.5257, Val Acc: 76.21%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4431, Train Acc: 84.99%\n", + " Val Loss: 0.5672, Val Acc: 76.21%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4189, Train Acc: 83.90%\n", + " Val Loss: 0.5455, Val Acc: 77.67%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3772, Train Acc: 86.32%\n", + " Val Loss: 0.4451, Val Acc: 83.50%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 83.50%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3314, Train Acc: 87.65%\n", + " Val Loss: 0.4349, Val Acc: 81.07%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3068, Train Acc: 89.71%\n", + " Val Loss: 0.3923, Val Acc: 83.98%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 83.98%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3372, Train Acc: 87.41%\n", + " Val Loss: 0.4224, Val Acc: 80.58%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3056, Train Acc: 89.23%\n", + " Val Loss: 0.4212, Val Acc: 83.01%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2878, Train Acc: 90.31%\n", + " Val Loss: 0.4060, Val Acc: 80.10%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2640, Train Acc: 91.65%\n", + " Val Loss: 0.3795, Val Acc: 85.44%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 85.44%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2445, Train Acc: 91.65%\n", + " Val Loss: 0.3791, Val Acc: 85.92%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 85.92%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2629, Train Acc: 90.31%\n", + " Val Loss: 0.3835, Val Acc: 85.44%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2176, Train Acc: 92.98%\n", + " Val Loss: 0.3891, Val Acc: 86.41%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 86.41%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2248, Train Acc: 92.25%\n", + " Val Loss: 0.3966, Val Acc: 84.47%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2255, Train Acc: 92.86%\n", + " Val Loss: 0.4043, Val Acc: 86.89%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 86.89%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1861, Train Acc: 93.58%\n", + " Val Loss: 0.3839, Val Acc: 85.44%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2032, Train Acc: 91.77%\n", + " Val Loss: 0.3524, Val Acc: 85.92%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2455, Train Acc: 91.40%\n", + " Val Loss: 0.3786, Val Acc: 85.44%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2337, Train Acc: 92.62%\n", + " Val Loss: 0.3838, Val Acc: 83.01%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1826, Train Acc: 94.07%\n", + " Val Loss: 0.3673, Val Acc: 83.98%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2014, Train Acc: 92.98%\n", + " Val Loss: 0.3620, Val Acc: 85.92%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2093, Train Acc: 93.22%\n", + " Val Loss: 0.3668, Val Acc: 86.89%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1894, Train Acc: 92.62%\n", + " Val Loss: 0.3522, Val Acc: 87.38%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 87.38%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2087, Train Acc: 92.74%\n", + " Val Loss: 0.3629, Val Acc: 84.95%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1672, Train Acc: 94.31%\n", + " Val Loss: 0.3577, Val Acc: 85.44%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1579, Train Acc: 94.67%\n", + " Val Loss: 0.3578, Val Acc: 85.44%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1636, Train Acc: 94.55%\n", + " Val Loss: 0.3488, Val Acc: 87.38%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1390, Train Acc: 95.76%\n", + " Val Loss: 0.3512, Val Acc: 87.38%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1769, Train Acc: 93.95%\n", + " Val Loss: 0.3564, Val Acc: 87.86%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 87.86%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1567, Train Acc: 94.67%\n", + " Val Loss: 0.3524, Val Acc: 85.92%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1453, Train Acc: 95.76%\n", + " Val Loss: 0.3411, Val Acc: 86.41%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1486, Train Acc: 94.67%\n", + " Val Loss: 0.3476, Val Acc: 86.89%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1733, Train Acc: 94.07%\n", + " Val Loss: 0.3495, Val Acc: 85.44%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1352, Train Acc: 95.76%\n", + " Val Loss: 0.3592, Val Acc: 86.41%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1317, Train Acc: 95.88%\n", + " Val Loss: 0.3421, Val Acc: 87.38%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1327, Train Acc: 95.76%\n", + " Val Loss: 0.3385, Val Acc: 88.35%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 88.35%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1470, Train Acc: 94.92%\n", + " Val Loss: 0.3419, Val Acc: 87.86%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1396, Train Acc: 95.04%\n", + " Val Loss: 0.3337, Val Acc: 87.86%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1562, Train Acc: 94.92%\n", + " Val Loss: 0.3433, Val Acc: 87.38%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1466, Train Acc: 94.67%\n", + " Val Loss: 0.3497, Val Acc: 87.86%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1636, Train Acc: 95.04%\n", + " Val Loss: 0.3315, Val Acc: 86.89%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1389, Train Acc: 95.64%\n", + " Val Loss: 0.3364, Val Acc: 87.86%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1871, Train Acc: 93.95%\n", + " Val Loss: 0.3479, Val Acc: 87.86%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1428, Train Acc: 94.79%\n", + " Val Loss: 0.3358, Val Acc: 89.32%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 89.32%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 55/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1260, Train Acc: 96.00%\n", + " Val Loss: 0.3307, Val Acc: 86.89%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 56/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1279, Train Acc: 96.73%\n", + " Val Loss: 0.3357, Val Acc: 87.38%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 57/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1255, Train Acc: 96.00%\n", + " Val Loss: 0.3386, Val Acc: 87.86%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 58/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1393, Train Acc: 96.00%\n", + " Val Loss: 0.3316, Val Acc: 88.35%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 59/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1516, Train Acc: 95.16%\n", + " Val Loss: 0.3365, Val Acc: 88.83%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 60/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1586, Train Acc: 94.55%\n", + " Val Loss: 0.3429, Val Acc: 88.35%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "Fold 3 finished. Best Validation Accuracy: 89.32%\n", + " Fold 3 Detailed Metrics:\n", + " Accuracy: 89.32%\n", + " Precision: 0.8936\n", + " Recall: 0.8932\n", + " F1-Score: 0.8922\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_resnet/confusion_matrices/fold_3_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 4/5\n", + "########################################\n", + " Fold 4: Train samples = 826, Validation samples = 206\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6304, Train Acc: 20.70%\n", + " Val Loss: 1.5139, Val Acc: 34.47%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 34.47%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4999, Train Acc: 33.78%\n", + " Val Loss: 1.3771, Val Acc: 48.54%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 48.54%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3729, Train Acc: 42.74%\n", + " Val Loss: 1.2133, Val Acc: 51.46%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 51.46%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2148, Train Acc: 54.24%\n", + " Val Loss: 0.9704, Val Acc: 65.53%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 65.53%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0216, Train Acc: 59.08%\n", + " Val Loss: 0.8204, Val Acc: 67.96%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 67.96%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8672, Train Acc: 67.19%\n", + " Val Loss: 0.6256, Val Acc: 73.79%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 73.79%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7641, Train Acc: 70.82%\n", + " Val Loss: 0.6172, Val Acc: 76.21%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 76.21%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6789, Train Acc: 74.58%\n", + " Val Loss: 0.5209, Val Acc: 79.61%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 79.61%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5830, Train Acc: 79.18%\n", + " Val Loss: 0.4820, Val Acc: 81.55%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 81.55%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5243, Train Acc: 79.66%\n", + " Val Loss: 0.4365, Val Acc: 83.01%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 83.01%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4621, Train Acc: 83.41%\n", + " Val Loss: 0.4403, Val Acc: 83.50%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 83.50%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4443, Train Acc: 83.78%\n", + " Val Loss: 0.4476, Val Acc: 82.52%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3943, Train Acc: 85.35%\n", + " Val Loss: 0.4503, Val Acc: 84.47%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 84.47%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3853, Train Acc: 86.20%\n", + " Val Loss: 0.3276, Val Acc: 86.89%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 86.89%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4003, Train Acc: 84.62%\n", + " Val Loss: 0.4002, Val Acc: 85.92%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3182, Train Acc: 87.77%\n", + " Val Loss: 0.3027, Val Acc: 89.32%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 89.32%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3080, Train Acc: 89.23%\n", + " Val Loss: 0.2848, Val Acc: 90.29%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 90.29%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2891, Train Acc: 89.23%\n", + " Val Loss: 0.2938, Val Acc: 90.29%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2861, Train Acc: 89.23%\n", + " Val Loss: 0.3116, Val Acc: 89.32%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2460, Train Acc: 91.65%\n", + " Val Loss: 0.3381, Val Acc: 88.83%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2256, Train Acc: 92.01%\n", + " Val Loss: 0.2745, Val Acc: 89.32%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2330, Train Acc: 91.53%\n", + " Val Loss: 0.2345, Val Acc: 91.75%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 91.75%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2263, Train Acc: 91.53%\n", + " Val Loss: 0.2437, Val Acc: 89.32%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2072, Train Acc: 92.74%\n", + " Val Loss: 0.2482, Val Acc: 90.78%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1820, Train Acc: 93.46%\n", + " Val Loss: 0.2423, Val Acc: 91.26%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1729, Train Acc: 94.07%\n", + " Val Loss: 0.2412, Val Acc: 90.29%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1523, Train Acc: 94.79%\n", + " Val Loss: 0.2197, Val Acc: 91.75%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1602, Train Acc: 94.92%\n", + " Val Loss: 0.2210, Val Acc: 92.23%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 92.23%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1983, Train Acc: 92.37%\n", + " Val Loss: 0.2229, Val Acc: 92.23%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1580, Train Acc: 94.92%\n", + " Val Loss: 0.2164, Val Acc: 91.75%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1742, Train Acc: 93.34%\n", + " Val Loss: 0.2138, Val Acc: 93.20%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 93.20%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1741, Train Acc: 94.07%\n", + " Val Loss: 0.2071, Val Acc: 91.75%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1517, Train Acc: 94.67%\n", + " Val Loss: 0.2030, Val Acc: 91.75%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1497, Train Acc: 95.04%\n", + " Val Loss: 0.1987, Val Acc: 92.23%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1318, Train Acc: 96.61%\n", + " Val Loss: 0.2000, Val Acc: 92.23%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1454, Train Acc: 95.04%\n", + " Val Loss: 0.1952, Val Acc: 93.20%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1598, Train Acc: 94.79%\n", + " Val Loss: 0.1890, Val Acc: 93.69%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 93.69%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1493, Train Acc: 95.28%\n", + " Val Loss: 0.2007, Val Acc: 92.23%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1549, Train Acc: 94.79%\n", + " Val Loss: 0.1976, Val Acc: 92.23%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1684, Train Acc: 94.92%\n", + " Val Loss: 0.2036, Val Acc: 93.20%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1351, Train Acc: 95.40%\n", + " Val Loss: 0.1916, Val Acc: 92.23%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1754, Train Acc: 94.92%\n", + " Val Loss: 0.1972, Val Acc: 91.75%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1406, Train Acc: 94.92%\n", + " Val Loss: 0.1922, Val Acc: 92.23%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1594, Train Acc: 94.31%\n", + " Val Loss: 0.1948, Val Acc: 93.20%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1208, Train Acc: 96.00%\n", + " Val Loss: 0.1872, Val Acc: 92.72%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1271, Train Acc: 95.88%\n", + " Val Loss: 0.1906, Val Acc: 92.23%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1336, Train Acc: 96.00%\n", + " Val Loss: 0.1940, Val Acc: 92.72%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1065, Train Acc: 97.09%\n", + " Val Loss: 0.1920, Val Acc: 92.72%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1280, Train Acc: 95.76%\n", + " Val Loss: 0.1871, Val Acc: 92.72%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1123, Train Acc: 95.64%\n", + " Val Loss: 0.1884, Val Acc: 92.72%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1332, Train Acc: 95.64%\n", + " Val Loss: 0.1944, Val Acc: 92.23%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1391, Train Acc: 95.52%\n", + " Val Loss: 0.1909, Val Acc: 92.72%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1276, Train Acc: 95.52%\n", + " Val Loss: 0.1880, Val Acc: 93.20%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1372, Train Acc: 96.13%\n", + " Val Loss: 0.1924, Val Acc: 92.72%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 55/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1306, Train Acc: 95.88%\n", + " Val Loss: 0.1893, Val Acc: 92.72%\n", + " Early Stopping Counter: 18/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 56/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1063, Train Acc: 96.61%\n", + " Val Loss: 0.1922, Val Acc: 92.72%\n", + " Early Stopping Counter: 19/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 57/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1364, Train Acc: 95.76%\n", + " Val Loss: 0.1928, Val Acc: 92.72%\n", + " Early Stopping Counter: 20/20\n", + " Early Stopping at epoch 57 for Fold 4\n", + "\n", + "Fold 4 finished. Best Validation Accuracy: 93.69%\n", + " Fold 4 Detailed Metrics:\n", + " Accuracy: 93.69%\n", + " Precision: 0.9369\n", + " Recall: 0.9369\n", + " F1-Score: 0.9367\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_resnet/confusion_matrices/fold_4_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 5/5\n", + "########################################\n", + " Fold 5: Train samples = 826, Validation samples = 206\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6302, Train Acc: 20.94%\n", + " Val Loss: 1.5456, Val Acc: 29.13%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 29.13%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4963, Train Acc: 36.32%\n", + " Val Loss: 1.4228, Val Acc: 38.35%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 38.35%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3571, Train Acc: 43.95%\n", + " Val Loss: 1.1778, Val Acc: 51.46%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 51.46%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1914, Train Acc: 50.36%\n", + " Val Loss: 1.0057, Val Acc: 54.37%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 54.37%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9699, Train Acc: 62.95%\n", + " Val Loss: 0.7943, Val Acc: 64.08%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 64.08%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8615, Train Acc: 65.98%\n", + " Val Loss: 0.6876, Val Acc: 66.02%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 66.02%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7240, Train Acc: 72.28%\n", + " Val Loss: 0.6086, Val Acc: 73.79%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 73.79%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6681, Train Acc: 74.33%\n", + " Val Loss: 0.5593, Val Acc: 78.64%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 78.64%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5686, Train Acc: 78.21%\n", + " Val Loss: 0.4830, Val Acc: 79.13%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 79.13%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5419, Train Acc: 79.90%\n", + " Val Loss: 0.4563, Val Acc: 82.52%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 82.52%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4739, Train Acc: 81.23%\n", + " Val Loss: 0.4209, Val Acc: 82.04%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4847, Train Acc: 82.45%\n", + " Val Loss: 0.3931, Val Acc: 82.52%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4357, Train Acc: 85.59%\n", + " Val Loss: 0.3992, Val Acc: 84.95%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 84.95%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4155, Train Acc: 84.62%\n", + " Val Loss: 0.3813, Val Acc: 88.35%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 88.35%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3709, Train Acc: 85.96%\n", + " Val Loss: 0.3293, Val Acc: 87.86%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3440, Train Acc: 88.26%\n", + " Val Loss: 0.3793, Val Acc: 85.92%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2868, Train Acc: 90.07%\n", + " Val Loss: 0.3927, Val Acc: 85.92%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2762, Train Acc: 89.71%\n", + " Val Loss: 0.3148, Val Acc: 89.81%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 89.81%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2890, Train Acc: 89.47%\n", + " Val Loss: 0.2815, Val Acc: 89.32%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2805, Train Acc: 91.40%\n", + " Val Loss: 0.3029, Val Acc: 89.81%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2862, Train Acc: 89.47%\n", + " Val Loss: 0.3402, Val Acc: 87.86%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2546, Train Acc: 91.40%\n", + " Val Loss: 0.3610, Val Acc: 87.38%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2238, Train Acc: 92.74%\n", + " Val Loss: 0.2814, Val Acc: 88.83%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2217, Train Acc: 91.89%\n", + " Val Loss: 0.2784, Val Acc: 91.26%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 91.26%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2201, Train Acc: 92.13%\n", + " Val Loss: 0.2757, Val Acc: 92.23%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 92.23%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1970, Train Acc: 92.74%\n", + " Val Loss: 0.2707, Val Acc: 91.26%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1851, Train Acc: 93.83%\n", + " Val Loss: 0.2708, Val Acc: 90.78%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1890, Train Acc: 94.43%\n", + " Val Loss: 0.2637, Val Acc: 91.26%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1813, Train Acc: 94.67%\n", + " Val Loss: 0.2834, Val Acc: 91.26%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1457, Train Acc: 95.64%\n", + " Val Loss: 0.2494, Val Acc: 92.72%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 92.72%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1572, Train Acc: 94.19%\n", + " Val Loss: 0.2557, Val Acc: 92.72%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1756, Train Acc: 94.55%\n", + " Val Loss: 0.2688, Val Acc: 91.75%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1466, Train Acc: 95.76%\n", + " Val Loss: 0.2545, Val Acc: 92.72%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1322, Train Acc: 95.28%\n", + " Val Loss: 0.2443, Val Acc: 93.20%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 93.20%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1567, Train Acc: 94.43%\n", + " Val Loss: 0.2520, Val Acc: 92.72%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1667, Train Acc: 93.83%\n", + " Val Loss: 0.2575, Val Acc: 91.75%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1358, Train Acc: 95.64%\n", + " Val Loss: 0.2363, Val Acc: 92.23%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1489, Train Acc: 95.28%\n", + " Val Loss: 0.2514, Val Acc: 93.20%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1362, Train Acc: 95.88%\n", + " Val Loss: 0.2552, Val Acc: 92.72%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1289, Train Acc: 96.13%\n", + " Val Loss: 0.2623, Val Acc: 93.20%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1262, Train Acc: 95.88%\n", + " Val Loss: 0.2549, Val Acc: 92.23%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1431, Train Acc: 95.16%\n", + " Val Loss: 0.2371, Val Acc: 92.23%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1201, Train Acc: 96.00%\n", + " Val Loss: 0.2322, Val Acc: 93.20%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1210, Train Acc: 95.52%\n", + " Val Loss: 0.2364, Val Acc: 92.23%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1539, Train Acc: 95.88%\n", + " Val Loss: 0.2405, Val Acc: 93.20%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1365, Train Acc: 95.88%\n", + " Val Loss: 0.2405, Val Acc: 92.23%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1267, Train Acc: 96.13%\n", + " Val Loss: 0.2408, Val Acc: 93.69%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 93.69%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1396, Train Acc: 95.16%\n", + " Val Loss: 0.2380, Val Acc: 92.72%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1065, Train Acc: 96.61%\n", + " Val Loss: 0.2423, Val Acc: 91.75%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1038, Train Acc: 96.49%\n", + " Val Loss: 0.2429, Val Acc: 91.75%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1548, Train Acc: 94.55%\n", + " Val Loss: 0.2472, Val Acc: 92.23%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1210, Train Acc: 96.00%\n", + " Val Loss: 0.2323, Val Acc: 92.72%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1197, Train Acc: 96.00%\n", + " Val Loss: 0.2321, Val Acc: 93.20%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1124, Train Acc: 96.00%\n", + " Val Loss: 0.2373, Val Acc: 93.20%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 55/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1391, Train Acc: 95.52%\n", + " Val Loss: 0.2385, Val Acc: 92.72%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 56/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1257, Train Acc: 95.88%\n", + " Val Loss: 0.2412, Val Acc: 92.23%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 57/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1512, Train Acc: 94.67%\n", + " Val Loss: 0.2422, Val Acc: 91.75%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 58/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1477, Train Acc: 94.19%\n", + " Val Loss: 0.2375, Val Acc: 92.23%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 59/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1148, Train Acc: 96.13%\n", + " Val Loss: 0.2436, Val Acc: 93.69%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 60/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1143, Train Acc: 96.00%\n", + " Val Loss: 0.2475, Val Acc: 93.69%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "Fold 5 finished. Best Validation Accuracy: 93.69%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-10-19 13:13:36,161 - INFO - \n", + "============================================================\n", + "2025-10-19 13:13:36,162 - INFO - ============================================================\n", + "2025-10-19 13:13:36,162 - INFO - Device: cpu\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Fold 5 Detailed Metrics:\n", + " Accuracy: 93.69%\n", + " Precision: 0.9373\n", + " Recall: 0.9369\n", + " F1-Score: 0.9366\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_resnet/confusion_matrices/fold_5_confusion_matrix.png\n", + "\n", + "============================================================\n", + "answer_1 / RESNET Cross Validation Results (K=5)\n", + "============================================================\n", + "Average Validation Accuracy: 92.44% ยฑ 1.86%\n", + "Individual Fold Accuracies: [91.30434782608695, 94.20289855072464, 89.32038834951457, 93.68932038834951, 93.68932038834951]\n", + "\n", + "๐Ÿ† Best model across all folds saved! Validation Acc: 94.20%\n", + " Model saved to: answer_models_cv_results/answer_1_resnet/best_model_overall_cv.pth\n", + "\n", + "RESNET - answer_1 Cross Validation ์™„๋ฃŒ\n", + "answer_2 Fine-tuning with RESNET (K=5 Cross Validation)\n", + " ํด๋ž˜์Šค 1: 165๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 2: 196๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 3: 188๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 4: 210๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 5: 168๊ฐœ ์ด๋ฏธ์ง€\n", + " ์ด 927๊ฐœ ์ด๋ฏธ์ง€ ๋กœ๋“œ\n", + "\n", + "########################################\n", + "Starting Fold 1/5\n", + "########################################\n", + " Fold 1: Train samples = 741, Validation samples = 186\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8461, Train Acc: 67.07%\n", + " Val Loss: 0.2805, Val Acc: 90.86%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 90.86%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2776, Train Acc: 90.69%\n", + " Val Loss: 0.2920, Val Acc: 90.32%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1511, Train Acc: 94.60%\n", + " Val Loss: 0.1178, Val Acc: 95.16%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 95.16%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0915, Train Acc: 96.90%\n", + " Val Loss: 0.0560, Val Acc: 98.39%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 98.39%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1119, Train Acc: 96.36%\n", + " Val Loss: 0.1005, Val Acc: 97.31%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0801, Train Acc: 97.71%\n", + " Val Loss: 0.0503, Val Acc: 97.85%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1185, Train Acc: 97.03%\n", + " Val Loss: 0.0602, Val Acc: 96.77%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1031, Train Acc: 97.44%\n", + " Val Loss: 0.0675, Val Acc: 97.31%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0610, Train Acc: 98.11%\n", + " Val Loss: 0.0436, Val Acc: 98.39%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0230, Train Acc: 99.33%\n", + " Val Loss: 0.0368, Val Acc: 98.39%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0198, Train Acc: 99.33%\n", + " Val Loss: 0.0387, Val Acc: 98.39%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0147, Train Acc: 99.73%\n", + " Val Loss: 0.0185, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0451, Train Acc: 98.79%\n", + " Val Loss: 0.0303, Val Acc: 98.39%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0411, Train Acc: 98.92%\n", + " Val Loss: 0.0246, Val Acc: 98.39%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0251, Train Acc: 99.19%\n", + " Val Loss: 0.0180, Val Acc: 99.46%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 99.46%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0139, Train Acc: 99.60%\n", + " Val Loss: 0.0259, Val Acc: 98.39%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0161, Train Acc: 99.33%\n", + " Val Loss: 0.0501, Val Acc: 98.39%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0238, Train Acc: 99.06%\n", + " Val Loss: 0.0333, Val Acc: 98.92%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0261, Train Acc: 99.06%\n", + " Val Loss: 0.0150, Val Acc: 99.46%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0130, Train Acc: 99.87%\n", + " Val Loss: 0.0108, Val Acc: 99.46%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0132, Train Acc: 99.33%\n", + " Val Loss: 0.0046, Val Acc: 100.00%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 100.00%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0103, Train Acc: 99.73%\n", + " Val Loss: 0.0045, Val Acc: 100.00%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0136, Train Acc: 99.73%\n", + " Val Loss: 0.0053, Val Acc: 100.00%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0085, Train Acc: 99.60%\n", + " Val Loss: 0.0220, Val Acc: 99.46%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0311, Train Acc: 99.19%\n", + " Val Loss: 0.0107, Val Acc: 99.46%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "Fold 1 finished. Best Validation Accuracy: 100.00%\n", + " Fold 1 Detailed Metrics:\n", + " Accuracy: 100.00%\n", + " Precision: 1.0000\n", + " Recall: 1.0000\n", + " F1-Score: 1.0000\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_resnet/confusion_matrices/fold_1_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 2/5\n", + "########################################\n", + " Fold 2: Train samples = 741, Validation samples = 186\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9068, Train Acc: 61.94%\n", + " Val Loss: 0.1701, Val Acc: 94.62%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 94.62%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2367, Train Acc: 92.17%\n", + " Val Loss: 0.0736, Val Acc: 97.85%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 97.85%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1494, Train Acc: 95.55%\n", + " Val Loss: 0.0644, Val Acc: 97.85%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1654, Train Acc: 94.87%\n", + " Val Loss: 0.0594, Val Acc: 97.85%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0723, Train Acc: 98.11%\n", + " Val Loss: 0.0348, Val Acc: 98.39%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 98.39%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0467, Train Acc: 98.52%\n", + " Val Loss: 0.0377, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0847, Train Acc: 96.76%\n", + " Val Loss: 0.0420, Val Acc: 97.85%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0619, Train Acc: 97.98%\n", + " Val Loss: 0.0242, Val Acc: 98.92%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0601, Train Acc: 98.11%\n", + " Val Loss: 0.0513, Val Acc: 97.85%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0774, Train Acc: 97.98%\n", + " Val Loss: 0.0796, Val Acc: 98.92%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0675, Train Acc: 97.57%\n", + " Val Loss: 0.0614, Val Acc: 98.92%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0183, Train Acc: 99.46%\n", + " Val Loss: 0.0488, Val Acc: 98.92%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0175, Train Acc: 99.33%\n", + " Val Loss: 0.0173, Val Acc: 99.46%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 99.46%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0347, Train Acc: 99.06%\n", + " Val Loss: 0.0198, Val Acc: 98.92%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0503, Train Acc: 98.38%\n", + " Val Loss: 0.0439, Val Acc: 98.39%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0252, Train Acc: 98.92%\n", + " Val Loss: 0.0747, Val Acc: 98.92%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0286, Train Acc: 99.46%\n", + " Val Loss: 0.1085, Val Acc: 98.39%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0111, Train Acc: 99.87%\n", + " Val Loss: 0.1019, Val Acc: 98.39%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0127, Train Acc: 99.73%\n", + " Val Loss: 0.0963, Val Acc: 98.39%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0035, Train Acc: 100.00%\n", + " Val Loss: 0.0914, Val Acc: 98.92%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0064, Train Acc: 99.87%\n", + " Val Loss: 0.0880, Val Acc: 98.92%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0089, Train Acc: 99.87%\n", + " Val Loss: 0.0793, Val Acc: 98.39%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0092, Train Acc: 99.87%\n", + " Val Loss: 0.0807, Val Acc: 98.39%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0026, Train Acc: 100.00%\n", + " Val Loss: 0.0835, Val Acc: 98.39%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0048, Train Acc: 99.87%\n", + " Val Loss: 0.0988, Val Acc: 98.92%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "Fold 2 finished. Best Validation Accuracy: 99.46%\n", + " Fold 2 Detailed Metrics:\n", + " Accuracy: 99.46%\n", + " Precision: 0.9948\n", + " Recall: 0.9946\n", + " F1-Score: 0.9946\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_resnet/confusion_matrices/fold_2_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 3/5\n", + "########################################\n", + " Fold 3: Train samples = 742, Validation samples = 185\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8072, Train Acc: 68.87%\n", + " Val Loss: 0.4487, Val Acc: 82.16%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 82.16%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2845, Train Acc: 90.43%\n", + " Val Loss: 0.0879, Val Acc: 97.84%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 97.84%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1694, Train Acc: 94.07%\n", + " Val Loss: 0.2314, Val Acc: 91.35%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1302, Train Acc: 96.36%\n", + " Val Loss: 0.0579, Val Acc: 98.38%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 98.38%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1373, Train Acc: 95.28%\n", + " Val Loss: 0.0619, Val Acc: 98.38%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0971, Train Acc: 96.63%\n", + " Val Loss: 0.1039, Val Acc: 96.76%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1272, Train Acc: 95.96%\n", + " Val Loss: 0.0770, Val Acc: 96.76%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0980, Train Acc: 97.71%\n", + " Val Loss: 0.0277, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0717, Train Acc: 97.57%\n", + " Val Loss: 0.0473, Val Acc: 98.92%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0990, Train Acc: 96.77%\n", + " Val Loss: 0.0308, Val Acc: 98.92%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0974, Train Acc: 96.50%\n", + " Val Loss: 0.0213, Val Acc: 98.92%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0694, Train Acc: 97.71%\n", + " Val Loss: 0.0309, Val Acc: 98.92%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0391, Train Acc: 98.65%\n", + " Val Loss: 0.0120, Val Acc: 99.46%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 99.46%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0219, Train Acc: 99.33%\n", + " Val Loss: 0.0356, Val Acc: 98.92%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0135, Train Acc: 99.87%\n", + " Val Loss: 0.0258, Val Acc: 98.92%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0201, Train Acc: 99.33%\n", + " Val Loss: 0.0357, Val Acc: 98.92%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0104, Train Acc: 99.73%\n", + " Val Loss: 0.0102, Val Acc: 99.46%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0137, Train Acc: 99.73%\n", + " Val Loss: 0.0242, Val Acc: 98.92%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0054, Train Acc: 99.87%\n", + " Val Loss: 0.0205, Val Acc: 98.92%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0052, Train Acc: 100.00%\n", + " Val Loss: 0.0289, Val Acc: 98.92%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0173, Train Acc: 99.60%\n", + " Val Loss: 0.0347, Val Acc: 98.92%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0129, Train Acc: 99.73%\n", + " Val Loss: 0.0213, Val Acc: 98.92%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0030, Train Acc: 100.00%\n", + " Val Loss: 0.0212, Val Acc: 98.92%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0097, Train Acc: 99.46%\n", + " Val Loss: 0.0230, Val Acc: 98.92%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0099, Train Acc: 99.60%\n", + " Val Loss: 0.0199, Val Acc: 99.46%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "Fold 3 finished. Best Validation Accuracy: 99.46%\n", + " Fold 3 Detailed Metrics:\n", + " Accuracy: 99.46%\n", + " Precision: 0.9948\n", + " Recall: 0.9946\n", + " F1-Score: 0.9946\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_resnet/confusion_matrices/fold_3_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 4/5\n", + "########################################\n", + " Fold 4: Train samples = 742, Validation samples = 185\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8715, Train Acc: 65.77%\n", + " Val Loss: 0.2715, Val Acc: 90.27%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 90.27%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2554, Train Acc: 92.05%\n", + " Val Loss: 0.4580, Val Acc: 83.24%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2464, Train Acc: 91.91%\n", + " Val Loss: 0.5767, Val Acc: 77.84%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1034, Train Acc: 96.50%\n", + " Val Loss: 0.1264, Val Acc: 95.68%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 95.68%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0769, Train Acc: 97.71%\n", + " Val Loss: 0.1020, Val Acc: 95.68%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1074, Train Acc: 96.36%\n", + " Val Loss: 0.0426, Val Acc: 97.84%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 97.84%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1115, Train Acc: 96.50%\n", + " Val Loss: 0.0459, Val Acc: 98.38%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 98.38%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0736, Train Acc: 98.11%\n", + " Val Loss: 0.0275, Val Acc: 99.46%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 99.46%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0553, Train Acc: 98.11%\n", + " Val Loss: 0.0497, Val Acc: 97.30%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0810, Train Acc: 97.30%\n", + " Val Loss: 0.0289, Val Acc: 99.46%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0565, Train Acc: 98.38%\n", + " Val Loss: 0.0537, Val Acc: 97.30%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0517, Train Acc: 97.84%\n", + " Val Loss: 0.0448, Val Acc: 98.92%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0238, Train Acc: 99.46%\n", + " Val Loss: 0.0180, Val Acc: 99.46%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0132, Train Acc: 99.46%\n", + " Val Loss: 0.0192, Val Acc: 98.92%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0087, Train Acc: 99.87%\n", + " Val Loss: 0.0172, Val Acc: 98.92%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0157, Train Acc: 99.46%\n", + " Val Loss: 0.0169, Val Acc: 99.46%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0105, Train Acc: 99.46%\n", + " Val Loss: 0.0228, Val Acc: 98.92%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0183, Train Acc: 99.73%\n", + " Val Loss: 0.0192, Val Acc: 98.92%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0053, Train Acc: 100.00%\n", + " Val Loss: 0.0130, Val Acc: 98.92%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0164, Train Acc: 99.73%\n", + " Val Loss: 0.0407, Val Acc: 98.38%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0090, Train Acc: 99.87%\n", + " Val Loss: 0.0163, Val Acc: 99.46%\n", + " Early Stopping Counter: 13/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0110, Train Acc: 99.46%\n", + " Val Loss: 0.0106, Val Acc: 100.00%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 100.00%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0040, Train Acc: 99.87%\n", + " Val Loss: 0.0138, Val Acc: 99.46%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0059, Train Acc: 99.87%\n", + " Val Loss: 0.0121, Val Acc: 99.46%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0136, Train Acc: 99.73%\n", + " Val Loss: 0.0123, Val Acc: 99.46%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "Fold 4 finished. Best Validation Accuracy: 100.00%\n", + " Fold 4 Detailed Metrics:\n", + " Accuracy: 100.00%\n", + " Precision: 1.0000\n", + " Recall: 1.0000\n", + " F1-Score: 1.0000\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_resnet/confusion_matrices/fold_4_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 5/5\n", + "########################################\n", + " Fold 5: Train samples = 742, Validation samples = 185\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_resnet_mnist_model.pth\n", + "Loaded pretrained resnet model.\n", + " MNIST Test Acc: 99.69%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8803, Train Acc: 64.42%\n", + " Val Loss: 0.3526, Val Acc: 83.24%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 83.24%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2345, Train Acc: 93.13%\n", + " Val Loss: 0.1536, Val Acc: 95.68%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 95.68%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1802, Train Acc: 94.07%\n", + " Val Loss: 0.1063, Val Acc: 96.22%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 96.22%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1899, Train Acc: 94.47%\n", + " Val Loss: 0.0428, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1291, Train Acc: 96.09%\n", + " Val Loss: 0.1257, Val Acc: 94.05%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0932, Train Acc: 97.17%\n", + " Val Loss: 0.0170, Val Acc: 99.46%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 99.46%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0713, Train Acc: 97.84%\n", + " Val Loss: 0.0216, Val Acc: 98.92%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0901, Train Acc: 97.04%\n", + " Val Loss: 0.0368, Val Acc: 98.38%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0527, Train Acc: 98.25%\n", + " Val Loss: 0.0971, Val Acc: 97.30%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0565, Train Acc: 98.11%\n", + " Val Loss: 0.0617, Val Acc: 98.38%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0409, Train Acc: 98.52%\n", + " Val Loss: 0.0751, Val Acc: 96.76%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0332, Train Acc: 99.06%\n", + " Val Loss: 0.0562, Val Acc: 97.84%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0197, Train Acc: 99.73%\n", + " Val Loss: 0.0392, Val Acc: 98.38%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0207, Train Acc: 99.60%\n", + " Val Loss: 0.0268, Val Acc: 98.92%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0142, Train Acc: 99.46%\n", + " Val Loss: 0.0252, Val Acc: 98.92%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0111, Train Acc: 99.87%\n", + " Val Loss: 0.0396, Val Acc: 98.92%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0119, Train Acc: 99.73%\n", + " Val Loss: 0.0264, Val Acc: 98.92%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0073, Train Acc: 100.00%\n", + " Val Loss: 0.0390, Val Acc: 98.92%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0080, Train Acc: 99.73%\n", + " Val Loss: 0.0209, Val Acc: 98.92%\n", + " Early Stopping Counter: 13/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0128, Train Acc: 99.60%\n", + " Val Loss: 0.0256, Val Acc: 98.92%\n", + " Early Stopping Counter: 14/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0144, Train Acc: 99.73%\n", + " Val Loss: 0.0309, Val Acc: 98.92%\n", + " Early Stopping Counter: 15/15\n", + " Early Stopping at epoch 21 for Fold 5\n", + "\n", + "Fold 5 finished. Best Validation Accuracy: 99.46%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-10-19 13:42:28,101 - INFO - \n", + "============================================================\n", + "2025-10-19 13:42:28,102 - INFO - ============================================================\n", + "2025-10-19 13:42:28,102 - INFO - Device: cpu\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Fold 5 Detailed Metrics:\n", + " Accuracy: 99.46%\n", + " Precision: 0.9947\n", + " Recall: 0.9946\n", + " F1-Score: 0.9946\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_resnet/confusion_matrices/fold_5_confusion_matrix.png\n", + "\n", + "============================================================\n", + "answer_2 / RESNET Cross Validation Results (K=5)\n", + "============================================================\n", + "Average Validation Accuracy: 99.68% ยฑ 0.26%\n", + "Individual Fold Accuracies: [100.0, 99.46236559139786, 99.45945945945947, 100.0, 99.45945945945947]\n", + "\n", + "๐Ÿ† Best model across all folds saved! Validation Acc: 100.00%\n", + " Model saved to: answer_models_cv_results/answer_2_resnet/best_model_overall_cv.pth\n", + "\n", + "RESNET - answer_2 Cross Validation ์™„๋ฃŒ\n", + "answer_1 Fine-tuning with MOBILENET (K=5 Cross Validation)\n", + " ํด๋ž˜์Šค 1: 189๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 2: 208๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 3: 193๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 4: 214๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 5: 228๊ฐœ ์ด๋ฏธ์ง€\n", + " ์ด 1032๊ฐœ ์ด๋ฏธ์ง€ ๋กœ๋“œ\n", + "\n", + "########################################\n", + "Starting Fold 1/5\n", + "########################################\n", + " Fold 1: Train samples = 825, Validation samples = 207\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6358, Train Acc: 22.30%\n", + " Val Loss: 1.5973, Val Acc: 24.64%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 24.64%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5861, Train Acc: 27.15%\n", + " Val Loss: 1.5669, Val Acc: 27.54%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 27.54%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5534, Train Acc: 29.58%\n", + " Val Loss: 1.5343, Val Acc: 28.02%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 28.02%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5105, Train Acc: 31.52%\n", + " Val Loss: 1.5046, Val Acc: 29.95%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 29.95%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4899, Train Acc: 33.45%\n", + " Val Loss: 1.4207, Val Acc: 36.23%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 36.23%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4003, Train Acc: 37.94%\n", + " Val Loss: 1.3957, Val Acc: 37.20%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 37.20%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3953, Train Acc: 38.06%\n", + " Val Loss: 1.3438, Val Acc: 40.10%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 40.10%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3280, Train Acc: 44.00%\n", + " Val Loss: 1.2679, Val Acc: 43.48%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 43.48%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2310, Train Acc: 48.48%\n", + " Val Loss: 1.2021, Val Acc: 50.72%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 50.72%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2086, Train Acc: 48.12%\n", + " Val Loss: 1.1322, Val Acc: 51.69%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 51.69%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1564, Train Acc: 48.00%\n", + " Val Loss: 1.0544, Val Acc: 55.56%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 55.56%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0950, Train Acc: 55.52%\n", + " Val Loss: 0.9908, Val Acc: 59.90%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 59.90%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0541, Train Acc: 56.24%\n", + " Val Loss: 0.9667, Val Acc: 60.39%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 60.39%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9777, Train Acc: 61.21%\n", + " Val Loss: 0.9052, Val Acc: 59.90%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9419, Train Acc: 60.48%\n", + " Val Loss: 0.8666, Val Acc: 62.80%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 62.80%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8889, Train Acc: 64.36%\n", + " Val Loss: 0.8339, Val Acc: 65.70%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 65.70%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8519, Train Acc: 66.30%\n", + " Val Loss: 0.8565, Val Acc: 64.25%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7872, Train Acc: 68.48%\n", + " Val Loss: 0.8285, Val Acc: 69.57%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 69.57%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7908, Train Acc: 68.12%\n", + " Val Loss: 0.8108, Val Acc: 69.57%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7920, Train Acc: 68.97%\n", + " Val Loss: 0.7579, Val Acc: 71.50%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 71.50%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7443, Train Acc: 72.85%\n", + " Val Loss: 0.7863, Val Acc: 70.53%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7310, Train Acc: 70.55%\n", + " Val Loss: 0.7595, Val Acc: 68.60%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7259, Train Acc: 70.91%\n", + " Val Loss: 0.7646, Val Acc: 69.57%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6564, Train Acc: 74.18%\n", + " Val Loss: 0.7269, Val Acc: 71.01%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6364, Train Acc: 76.24%\n", + " Val Loss: 0.7283, Val Acc: 71.01%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6502, Train Acc: 75.52%\n", + " Val Loss: 0.7246, Val Acc: 71.98%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 71.98%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6602, Train Acc: 73.09%\n", + " Val Loss: 0.7421, Val Acc: 73.91%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 73.91%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6665, Train Acc: 75.76%\n", + " Val Loss: 0.7127, Val Acc: 73.91%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5991, Train Acc: 76.24%\n", + " Val Loss: 0.6959, Val Acc: 74.40%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 74.40%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5815, Train Acc: 78.42%\n", + " Val Loss: 0.7244, Val Acc: 71.98%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6089, Train Acc: 77.70%\n", + " Val Loss: 0.7472, Val Acc: 72.46%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5610, Train Acc: 78.42%\n", + " Val Loss: 0.7497, Val Acc: 72.95%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5680, Train Acc: 78.55%\n", + " Val Loss: 0.7154, Val Acc: 73.43%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5686, Train Acc: 78.18%\n", + " Val Loss: 0.7118, Val Acc: 73.91%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5753, Train Acc: 79.52%\n", + " Val Loss: 0.7375, Val Acc: 72.46%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5415, Train Acc: 80.24%\n", + " Val Loss: 0.6891, Val Acc: 72.46%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5157, Train Acc: 81.09%\n", + " Val Loss: 0.7086, Val Acc: 71.50%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5680, Train Acc: 77.94%\n", + " Val Loss: 0.6830, Val Acc: 75.36%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 75.36%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5698, Train Acc: 79.27%\n", + " Val Loss: 0.7202, Val Acc: 72.46%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5427, Train Acc: 80.61%\n", + " Val Loss: 0.6879, Val Acc: 74.40%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5399, Train Acc: 79.27%\n", + " Val Loss: 0.6999, Val Acc: 75.85%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 75.85%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5148, Train Acc: 79.76%\n", + " Val Loss: 0.6819, Val Acc: 73.91%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4693, Train Acc: 84.12%\n", + " Val Loss: 0.6862, Val Acc: 72.46%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4988, Train Acc: 81.33%\n", + " Val Loss: 0.6961, Val Acc: 74.88%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5250, Train Acc: 79.15%\n", + " Val Loss: 0.7129, Val Acc: 73.91%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5158, Train Acc: 79.76%\n", + " Val Loss: 0.6873, Val Acc: 74.88%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5018, Train Acc: 82.42%\n", + " Val Loss: 0.6955, Val Acc: 73.43%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4753, Train Acc: 82.79%\n", + " Val Loss: 0.6893, Val Acc: 73.43%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4910, Train Acc: 82.06%\n", + " Val Loss: 0.6995, Val Acc: 74.88%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5266, Train Acc: 80.48%\n", + " Val Loss: 0.6944, Val Acc: 76.33%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 76.33%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4893, Train Acc: 81.09%\n", + " Val Loss: 0.6864, Val Acc: 75.36%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5006, Train Acc: 80.97%\n", + " Val Loss: 0.6913, Val Acc: 74.88%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5148, Train Acc: 80.85%\n", + " Val Loss: 0.6909, Val Acc: 73.91%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4818, Train Acc: 83.64%\n", + " Val Loss: 0.7135, Val Acc: 73.91%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 55/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5061, Train Acc: 81.58%\n", + " Val Loss: 0.7115, Val Acc: 71.50%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 56/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5182, Train Acc: 80.24%\n", + " Val Loss: 0.7025, Val Acc: 73.91%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 57/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5368, Train Acc: 79.52%\n", + " Val Loss: 0.6926, Val Acc: 74.88%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 58/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4884, Train Acc: 82.18%\n", + " Val Loss: 0.6945, Val Acc: 73.43%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 59/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4914, Train Acc: 81.09%\n", + " Val Loss: 0.6895, Val Acc: 73.43%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 60/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4825, Train Acc: 81.70%\n", + " Val Loss: 0.6967, Val Acc: 73.91%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "Fold 1 finished. Best Validation Accuracy: 76.33%\n", + " Fold 1 Detailed Metrics:\n", + " Accuracy: 76.33%\n", + " Precision: 0.7743\n", + " Recall: 0.7633\n", + " F1-Score: 0.7670\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_mobilenet/confusion_matrices/fold_1_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 2/5\n", + "########################################\n", + " Fold 2: Train samples = 825, Validation samples = 207\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6306, Train Acc: 19.76%\n", + " Val Loss: 1.5947, Val Acc: 24.64%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 24.64%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6006, Train Acc: 23.15%\n", + " Val Loss: 1.5795, Val Acc: 25.60%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 25.60%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5721, Train Acc: 26.79%\n", + " Val Loss: 1.5518, Val Acc: 28.50%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 28.50%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5650, Train Acc: 26.42%\n", + " Val Loss: 1.5115, Val Acc: 30.92%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 30.92%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5234, Train Acc: 31.03%\n", + " Val Loss: 1.4395, Val Acc: 38.16%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 38.16%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4822, Train Acc: 34.55%\n", + " Val Loss: 1.3906, Val Acc: 38.65%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 38.65%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4193, Train Acc: 38.79%\n", + " Val Loss: 1.3376, Val Acc: 42.51%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 42.51%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3753, Train Acc: 42.18%\n", + " Val Loss: 1.2765, Val Acc: 47.83%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 47.83%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2962, Train Acc: 44.73%\n", + " Val Loss: 1.1989, Val Acc: 51.21%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 51.21%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2562, Train Acc: 45.21%\n", + " Val Loss: 1.1351, Val Acc: 54.59%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 54.59%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1672, Train Acc: 52.12%\n", + " Val Loss: 1.0996, Val Acc: 57.00%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 57.00%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1381, Train Acc: 53.21%\n", + " Val Loss: 1.1042, Val Acc: 56.52%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1267, Train Acc: 54.30%\n", + " Val Loss: 0.9882, Val Acc: 58.45%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 58.45%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0569, Train Acc: 58.18%\n", + " Val Loss: 0.9101, Val Acc: 62.32%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 62.32%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9594, Train Acc: 60.00%\n", + " Val Loss: 0.9007, Val Acc: 64.25%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 64.25%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9472, Train Acc: 61.45%\n", + " Val Loss: 0.8816, Val Acc: 64.73%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 64.73%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9020, Train Acc: 62.06%\n", + " Val Loss: 0.8381, Val Acc: 65.70%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 65.70%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8826, Train Acc: 66.18%\n", + " Val Loss: 0.8325, Val Acc: 71.50%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 71.50%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8982, Train Acc: 63.52%\n", + " Val Loss: 0.8218, Val Acc: 68.12%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8031, Train Acc: 68.36%\n", + " Val Loss: 0.7468, Val Acc: 70.53%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8226, Train Acc: 68.48%\n", + " Val Loss: 0.7673, Val Acc: 72.46%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 72.46%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8097, Train Acc: 68.73%\n", + " Val Loss: 0.7641, Val Acc: 72.46%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7671, Train Acc: 70.55%\n", + " Val Loss: 0.7238, Val Acc: 70.53%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7024, Train Acc: 73.33%\n", + " Val Loss: 0.7468, Val Acc: 72.46%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7073, Train Acc: 73.45%\n", + " Val Loss: 0.6914, Val Acc: 73.43%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 73.43%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6620, Train Acc: 74.06%\n", + " Val Loss: 0.6590, Val Acc: 73.43%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6753, Train Acc: 74.67%\n", + " Val Loss: 0.7102, Val Acc: 73.43%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6039, Train Acc: 76.12%\n", + " Val Loss: 0.6551, Val Acc: 79.23%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 79.23%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6446, Train Acc: 76.24%\n", + " Val Loss: 0.6523, Val Acc: 77.78%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5934, Train Acc: 76.61%\n", + " Val Loss: 0.6241, Val Acc: 80.19%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 80.19%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5728, Train Acc: 78.55%\n", + " Val Loss: 0.6609, Val Acc: 77.29%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5720, Train Acc: 79.15%\n", + " Val Loss: 0.6413, Val Acc: 78.74%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6055, Train Acc: 74.79%\n", + " Val Loss: 0.6392, Val Acc: 78.74%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5762, Train Acc: 77.82%\n", + " Val Loss: 0.6127, Val Acc: 76.33%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5410, Train Acc: 78.18%\n", + " Val Loss: 0.6029, Val Acc: 77.29%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5091, Train Acc: 82.79%\n", + " Val Loss: 0.5935, Val Acc: 77.78%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5127, Train Acc: 80.73%\n", + " Val Loss: 0.6128, Val Acc: 77.29%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5334, Train Acc: 79.52%\n", + " Val Loss: 0.6006, Val Acc: 78.26%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4354, Train Acc: 83.03%\n", + " Val Loss: 0.5917, Val Acc: 75.85%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5168, Train Acc: 81.82%\n", + " Val Loss: 0.5873, Val Acc: 76.33%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4874, Train Acc: 82.06%\n", + " Val Loss: 0.6107, Val Acc: 78.26%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4592, Train Acc: 81.94%\n", + " Val Loss: 0.5955, Val Acc: 75.36%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4540, Train Acc: 83.64%\n", + " Val Loss: 0.5899, Val Acc: 76.81%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4442, Train Acc: 84.12%\n", + " Val Loss: 0.6057, Val Acc: 77.29%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4353, Train Acc: 83.15%\n", + " Val Loss: 0.6018, Val Acc: 78.26%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4529, Train Acc: 82.79%\n", + " Val Loss: 0.6102, Val Acc: 76.81%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4608, Train Acc: 82.67%\n", + " Val Loss: 0.6008, Val Acc: 76.33%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4423, Train Acc: 83.52%\n", + " Val Loss: 0.6011, Val Acc: 78.26%\n", + " Early Stopping Counter: 18/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4445, Train Acc: 83.27%\n", + " Val Loss: 0.6018, Val Acc: 76.33%\n", + " Early Stopping Counter: 19/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4640, Train Acc: 82.79%\n", + " Val Loss: 0.5952, Val Acc: 77.78%\n", + " Early Stopping Counter: 20/20\n", + " Early Stopping at epoch 50 for Fold 2\n", + "\n", + "Fold 2 finished. Best Validation Accuracy: 80.19%\n", + " Fold 2 Detailed Metrics:\n", + " Accuracy: 80.19%\n", + " Precision: 0.7982\n", + " Recall: 0.8019\n", + " F1-Score: 0.7990\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_mobilenet/confusion_matrices/fold_2_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 3/5\n", + "########################################\n", + " Fold 3: Train samples = 826, Validation samples = 206\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6199, Train Acc: 21.79%\n", + " Val Loss: 1.5652, Val Acc: 30.58%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 30.58%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5906, Train Acc: 23.97%\n", + " Val Loss: 1.5284, Val Acc: 28.16%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5617, Train Acc: 28.93%\n", + " Val Loss: 1.4779, Val Acc: 33.50%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 33.50%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5576, Train Acc: 30.75%\n", + " Val Loss: 1.4347, Val Acc: 35.92%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 35.92%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4987, Train Acc: 34.02%\n", + " Val Loss: 1.3679, Val Acc: 41.26%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 41.26%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4167, Train Acc: 38.50%\n", + " Val Loss: 1.3120, Val Acc: 44.17%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 44.17%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3519, Train Acc: 41.16%\n", + " Val Loss: 1.2485, Val Acc: 46.12%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 46.12%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2653, Train Acc: 47.46%\n", + " Val Loss: 1.2005, Val Acc: 47.57%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 47.57%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2683, Train Acc: 47.09%\n", + " Val Loss: 1.1552, Val Acc: 53.40%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 53.40%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1409, Train Acc: 52.18%\n", + " Val Loss: 1.0950, Val Acc: 53.88%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 53.88%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1163, Train Acc: 54.12%\n", + " Val Loss: 1.0605, Val Acc: 53.88%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0595, Train Acc: 55.69%\n", + " Val Loss: 0.9824, Val Acc: 57.28%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 57.28%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0424, Train Acc: 57.87%\n", + " Val Loss: 0.9778, Val Acc: 58.74%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 58.74%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9813, Train Acc: 60.90%\n", + " Val Loss: 0.9764, Val Acc: 59.71%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 59.71%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8739, Train Acc: 66.10%\n", + " Val Loss: 1.0111, Val Acc: 58.74%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9215, Train Acc: 62.95%\n", + " Val Loss: 0.9576, Val Acc: 59.71%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8883, Train Acc: 64.77%\n", + " Val Loss: 0.9187, Val Acc: 61.17%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 61.17%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8202, Train Acc: 68.52%\n", + " Val Loss: 0.9184, Val Acc: 61.17%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7974, Train Acc: 68.64%\n", + " Val Loss: 0.8873, Val Acc: 63.11%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 63.11%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8229, Train Acc: 67.80%\n", + " Val Loss: 0.9015, Val Acc: 61.65%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7850, Train Acc: 68.52%\n", + " Val Loss: 0.8653, Val Acc: 63.59%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 63.59%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7555, Train Acc: 69.13%\n", + " Val Loss: 0.8301, Val Acc: 65.53%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 65.53%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7278, Train Acc: 71.43%\n", + " Val Loss: 0.8527, Val Acc: 66.02%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 66.02%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6921, Train Acc: 73.61%\n", + " Val Loss: 0.8548, Val Acc: 69.42%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 69.42%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6501, Train Acc: 76.15%\n", + " Val Loss: 0.8407, Val Acc: 70.87%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 70.87%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6160, Train Acc: 77.00%\n", + " Val Loss: 0.8486, Val Acc: 67.96%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5854, Train Acc: 76.63%\n", + " Val Loss: 0.8278, Val Acc: 68.45%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5869, Train Acc: 78.57%\n", + " Val Loss: 0.8187, Val Acc: 68.45%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5984, Train Acc: 77.36%\n", + " Val Loss: 0.7729, Val Acc: 71.36%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 71.36%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5619, Train Acc: 78.69%\n", + " Val Loss: 0.8277, Val Acc: 68.93%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5585, Train Acc: 77.48%\n", + " Val Loss: 0.8286, Val Acc: 69.90%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5361, Train Acc: 79.66%\n", + " Val Loss: 0.8174, Val Acc: 68.93%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5350, Train Acc: 80.63%\n", + " Val Loss: 0.7997, Val Acc: 69.42%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5496, Train Acc: 79.42%\n", + " Val Loss: 0.7917, Val Acc: 68.45%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4748, Train Acc: 81.84%\n", + " Val Loss: 0.7522, Val Acc: 70.39%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5071, Train Acc: 81.36%\n", + " Val Loss: 0.7894, Val Acc: 70.39%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4855, Train Acc: 83.17%\n", + " Val Loss: 0.7870, Val Acc: 70.39%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5108, Train Acc: 81.36%\n", + " Val Loss: 0.7738, Val Acc: 71.36%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4318, Train Acc: 84.99%\n", + " Val Loss: 0.7838, Val Acc: 70.39%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4472, Train Acc: 82.69%\n", + " Val Loss: 0.7619, Val Acc: 71.36%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4744, Train Acc: 82.08%\n", + " Val Loss: 0.7713, Val Acc: 70.87%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4457, Train Acc: 82.32%\n", + " Val Loss: 0.7688, Val Acc: 70.87%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4547, Train Acc: 83.17%\n", + " Val Loss: 0.7513, Val Acc: 71.84%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 71.84%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4450, Train Acc: 83.17%\n", + " Val Loss: 0.7663, Val Acc: 71.84%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4805, Train Acc: 83.05%\n", + " Val Loss: 0.7594, Val Acc: 72.82%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 72.82%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4175, Train Acc: 83.78%\n", + " Val Loss: 0.7701, Val Acc: 73.79%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 73.79%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4580, Train Acc: 82.08%\n", + " Val Loss: 0.7767, Val Acc: 70.87%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4220, Train Acc: 85.11%\n", + " Val Loss: 0.7831, Val Acc: 69.90%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4541, Train Acc: 82.93%\n", + " Val Loss: 0.7640, Val Acc: 72.82%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4121, Train Acc: 84.02%\n", + " Val Loss: 0.7425, Val Acc: 72.82%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4379, Train Acc: 83.29%\n", + " Val Loss: 0.7507, Val Acc: 73.79%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4605, Train Acc: 82.45%\n", + " Val Loss: 0.7480, Val Acc: 71.84%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4407, Train Acc: 83.05%\n", + " Val Loss: 0.7623, Val Acc: 73.30%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4090, Train Acc: 85.47%\n", + " Val Loss: 0.7449, Val Acc: 73.30%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 55/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4649, Train Acc: 83.90%\n", + " Val Loss: 0.7642, Val Acc: 70.87%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 56/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4206, Train Acc: 84.75%\n", + " Val Loss: 0.7628, Val Acc: 70.87%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 57/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4223, Train Acc: 84.75%\n", + " Val Loss: 0.7613, Val Acc: 71.36%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 58/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3914, Train Acc: 85.84%\n", + " Val Loss: 0.7523, Val Acc: 73.79%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 59/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4286, Train Acc: 83.17%\n", + " Val Loss: 0.7845, Val Acc: 71.84%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 60/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4223, Train Acc: 83.41%\n", + " Val Loss: 0.7663, Val Acc: 72.82%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "Fold 3 finished. Best Validation Accuracy: 73.79%\n", + " Fold 3 Detailed Metrics:\n", + " Accuracy: 73.79%\n", + " Precision: 0.7566\n", + " Recall: 0.7379\n", + " F1-Score: 0.7428\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_mobilenet/confusion_matrices/fold_3_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 4/5\n", + "########################################\n", + " Fold 4: Train samples = 826, Validation samples = 206\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6300, Train Acc: 20.10%\n", + " Val Loss: 1.5995, Val Acc: 23.30%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 23.30%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5904, Train Acc: 24.70%\n", + " Val Loss: 1.5764, Val Acc: 23.79%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 23.79%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5840, Train Acc: 24.33%\n", + " Val Loss: 1.5411, Val Acc: 33.98%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 33.98%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5539, Train Acc: 27.97%\n", + " Val Loss: 1.4991, Val Acc: 34.47%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 34.47%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5111, Train Acc: 33.54%\n", + " Val Loss: 1.4533, Val Acc: 37.86%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 37.86%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4672, Train Acc: 33.17%\n", + " Val Loss: 1.3837, Val Acc: 40.78%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 40.78%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4070, Train Acc: 36.32%\n", + " Val Loss: 1.3162, Val Acc: 46.60%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 46.60%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3335, Train Acc: 41.77%\n", + " Val Loss: 1.2263, Val Acc: 47.57%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 47.57%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3333, Train Acc: 40.92%\n", + " Val Loss: 1.1590, Val Acc: 50.49%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 50.49%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2606, Train Acc: 45.40%\n", + " Val Loss: 1.0840, Val Acc: 56.31%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 56.31%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2018, Train Acc: 49.03%\n", + " Val Loss: 1.0267, Val Acc: 54.37%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0982, Train Acc: 52.66%\n", + " Val Loss: 0.9343, Val Acc: 59.71%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 59.71%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0885, Train Acc: 55.57%\n", + " Val Loss: 0.8927, Val Acc: 62.62%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 62.62%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0011, Train Acc: 59.20%\n", + " Val Loss: 0.8946, Val Acc: 64.08%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 64.08%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0105, Train Acc: 56.54%\n", + " Val Loss: 0.8667, Val Acc: 64.08%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0045, Train Acc: 59.32%\n", + " Val Loss: 0.8185, Val Acc: 67.48%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 67.48%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9142, Train Acc: 61.74%\n", + " Val Loss: 0.8193, Val Acc: 64.56%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9300, Train Acc: 61.86%\n", + " Val Loss: 0.7486, Val Acc: 67.48%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8453, Train Acc: 64.41%\n", + " Val Loss: 0.7642, Val Acc: 69.42%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 69.42%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8549, Train Acc: 62.83%\n", + " Val Loss: 0.7211, Val Acc: 70.39%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 70.39%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8486, Train Acc: 63.44%\n", + " Val Loss: 0.7206, Val Acc: 70.87%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 70.87%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7976, Train Acc: 65.86%\n", + " Val Loss: 0.7090, Val Acc: 71.36%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 71.36%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8351, Train Acc: 67.92%\n", + " Val Loss: 0.6643, Val Acc: 74.27%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 74.27%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7661, Train Acc: 69.13%\n", + " Val Loss: 0.7182, Val Acc: 71.84%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7055, Train Acc: 70.22%\n", + " Val Loss: 0.7002, Val Acc: 72.82%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7046, Train Acc: 71.31%\n", + " Val Loss: 0.6979, Val Acc: 71.84%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7396, Train Acc: 69.49%\n", + " Val Loss: 0.6620, Val Acc: 76.21%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 76.21%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6972, Train Acc: 71.67%\n", + " Val Loss: 0.6748, Val Acc: 72.82%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6635, Train Acc: 72.88%\n", + " Val Loss: 0.6544, Val Acc: 74.76%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6600, Train Acc: 72.76%\n", + " Val Loss: 0.6504, Val Acc: 76.21%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6168, Train Acc: 74.70%\n", + " Val Loss: 0.6259, Val Acc: 76.70%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 76.70%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6165, Train Acc: 76.39%\n", + " Val Loss: 0.6160, Val Acc: 80.58%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 80.58%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6092, Train Acc: 76.27%\n", + " Val Loss: 0.6629, Val Acc: 78.16%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5939, Train Acc: 74.21%\n", + " Val Loss: 0.6334, Val Acc: 80.10%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6187, Train Acc: 77.60%\n", + " Val Loss: 0.6654, Val Acc: 75.73%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5668, Train Acc: 78.33%\n", + " Val Loss: 0.6743, Val Acc: 78.64%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5996, Train Acc: 75.79%\n", + " Val Loss: 0.6312, Val Acc: 78.16%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5846, Train Acc: 78.09%\n", + " Val Loss: 0.6252, Val Acc: 77.67%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5610, Train Acc: 78.33%\n", + " Val Loss: 0.6375, Val Acc: 77.18%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5031, Train Acc: 80.87%\n", + " Val Loss: 0.6323, Val Acc: 79.13%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4886, Train Acc: 82.08%\n", + " Val Loss: 0.6263, Val Acc: 78.16%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4811, Train Acc: 80.39%\n", + " Val Loss: 0.6186, Val Acc: 78.64%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5357, Train Acc: 77.24%\n", + " Val Loss: 0.6351, Val Acc: 78.64%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5107, Train Acc: 81.48%\n", + " Val Loss: 0.6162, Val Acc: 78.64%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4939, Train Acc: 79.42%\n", + " Val Loss: 0.6132, Val Acc: 79.13%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4943, Train Acc: 80.99%\n", + " Val Loss: 0.6224, Val Acc: 78.16%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5123, Train Acc: 80.15%\n", + " Val Loss: 0.6291, Val Acc: 77.67%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5253, Train Acc: 79.30%\n", + " Val Loss: 0.6211, Val Acc: 78.16%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4802, Train Acc: 79.78%\n", + " Val Loss: 0.6159, Val Acc: 79.61%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4966, Train Acc: 81.96%\n", + " Val Loss: 0.6199, Val Acc: 78.64%\n", + " Early Stopping Counter: 18/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5274, Train Acc: 78.81%\n", + " Val Loss: 0.6194, Val Acc: 79.61%\n", + " Early Stopping Counter: 19/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4912, Train Acc: 81.36%\n", + " Val Loss: 0.6265, Val Acc: 80.10%\n", + " Early Stopping Counter: 20/20\n", + " Early Stopping at epoch 52 for Fold 4\n", + "\n", + "Fold 4 finished. Best Validation Accuracy: 80.58%\n", + " Fold 4 Detailed Metrics:\n", + " Accuracy: 80.58%\n", + " Precision: 0.8056\n", + " Recall: 0.8058\n", + " F1-Score: 0.8054\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_mobilenet/confusion_matrices/fold_4_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 5/5\n", + "########################################\n", + " Fold 5: Train samples = 826, Validation samples = 206\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6436, Train Acc: 18.16%\n", + " Val Loss: 1.5840, Val Acc: 28.64%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 28.64%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5883, Train Acc: 23.24%\n", + " Val Loss: 1.5588, Val Acc: 29.61%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 29.61%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5756, Train Acc: 25.91%\n", + " Val Loss: 1.5449, Val Acc: 29.61%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5341, Train Acc: 31.11%\n", + " Val Loss: 1.4983, Val Acc: 30.58%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 30.58%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4871, Train Acc: 32.57%\n", + " Val Loss: 1.4528, Val Acc: 38.35%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 38.35%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4257, Train Acc: 36.56%\n", + " Val Loss: 1.3781, Val Acc: 39.32%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 39.32%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3510, Train Acc: 41.40%\n", + " Val Loss: 1.3105, Val Acc: 44.66%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 44.66%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3004, Train Acc: 44.92%\n", + " Val Loss: 1.2519, Val Acc: 47.57%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 47.57%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2353, Train Acc: 49.03%\n", + " Val Loss: 1.2049, Val Acc: 50.49%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 50.49%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2090, Train Acc: 48.79%\n", + " Val Loss: 1.1633, Val Acc: 47.57%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1491, Train Acc: 51.09%\n", + " Val Loss: 1.1219, Val Acc: 49.51%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0723, Train Acc: 55.57%\n", + " Val Loss: 1.0680, Val Acc: 52.43%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 52.43%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0269, Train Acc: 58.84%\n", + " Val Loss: 1.0691, Val Acc: 55.34%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 55.34%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0175, Train Acc: 58.23%\n", + " Val Loss: 0.9855, Val Acc: 61.65%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 61.65%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9984, Train Acc: 58.72%\n", + " Val Loss: 0.9710, Val Acc: 56.80%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9398, Train Acc: 62.59%\n", + " Val Loss: 0.9304, Val Acc: 60.68%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9221, Train Acc: 61.86%\n", + " Val Loss: 0.8804, Val Acc: 63.11%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 63.11%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8496, Train Acc: 66.34%\n", + " Val Loss: 0.8693, Val Acc: 63.59%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 63.59%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8394, Train Acc: 65.86%\n", + " Val Loss: 0.8522, Val Acc: 65.05%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 65.05%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8603, Train Acc: 64.77%\n", + " Val Loss: 0.8471, Val Acc: 63.59%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8184, Train Acc: 67.19%\n", + " Val Loss: 0.8241, Val Acc: 66.02%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 66.02%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7851, Train Acc: 69.73%\n", + " Val Loss: 0.8239, Val Acc: 67.48%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 67.48%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7561, Train Acc: 70.46%\n", + " Val Loss: 0.8010, Val Acc: 65.05%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7473, Train Acc: 72.88%\n", + " Val Loss: 0.7962, Val Acc: 68.93%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 68.93%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7176, Train Acc: 71.55%\n", + " Val Loss: 0.7592, Val Acc: 66.02%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7096, Train Acc: 70.58%\n", + " Val Loss: 0.7558, Val Acc: 70.39%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 70.39%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6719, Train Acc: 74.70%\n", + " Val Loss: 0.7632, Val Acc: 68.45%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6786, Train Acc: 73.85%\n", + " Val Loss: 0.7603, Val Acc: 66.50%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6343, Train Acc: 74.82%\n", + " Val Loss: 0.6969, Val Acc: 70.39%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6686, Train Acc: 74.58%\n", + " Val Loss: 0.7262, Val Acc: 70.87%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 70.87%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5898, Train Acc: 76.63%\n", + " Val Loss: 0.7202, Val Acc: 69.90%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5559, Train Acc: 78.93%\n", + " Val Loss: 0.6999, Val Acc: 70.39%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5104, Train Acc: 80.75%\n", + " Val Loss: 0.6941, Val Acc: 73.30%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 73.30%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5633, Train Acc: 79.30%\n", + " Val Loss: 0.7246, Val Acc: 71.36%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5306, Train Acc: 80.75%\n", + " Val Loss: 0.6987, Val Acc: 72.33%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5005, Train Acc: 83.66%\n", + " Val Loss: 0.7271, Val Acc: 71.84%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5156, Train Acc: 80.87%\n", + " Val Loss: 0.6780, Val Acc: 73.79%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 73.79%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5239, Train Acc: 80.75%\n", + " Val Loss: 0.6898, Val Acc: 72.82%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5004, Train Acc: 79.42%\n", + " Val Loss: 0.6876, Val Acc: 74.27%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 74.27%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5292, Train Acc: 79.18%\n", + " Val Loss: 0.6889, Val Acc: 72.82%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4499, Train Acc: 82.45%\n", + " Val Loss: 0.6500, Val Acc: 73.30%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4672, Train Acc: 81.72%\n", + " Val Loss: 0.6651, Val Acc: 74.76%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 74.76%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4634, Train Acc: 83.41%\n", + " Val Loss: 0.6799, Val Acc: 76.21%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 76.21%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4469, Train Acc: 82.08%\n", + " Val Loss: 0.6503, Val Acc: 77.67%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 77.67%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4307, Train Acc: 84.14%\n", + " Val Loss: 0.6684, Val Acc: 75.24%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4252, Train Acc: 84.14%\n", + " Val Loss: 0.6500, Val Acc: 72.82%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4202, Train Acc: 83.05%\n", + " Val Loss: 0.6791, Val Acc: 75.24%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4300, Train Acc: 83.54%\n", + " Val Loss: 0.6297, Val Acc: 74.27%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3748, Train Acc: 86.08%\n", + " Val Loss: 0.5993, Val Acc: 78.64%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 78.64%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3989, Train Acc: 85.84%\n", + " Val Loss: 0.6140, Val Acc: 77.18%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3788, Train Acc: 85.96%\n", + " Val Loss: 0.6146, Val Acc: 75.24%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3762, Train Acc: 84.99%\n", + " Val Loss: 0.5787, Val Acc: 77.67%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3435, Train Acc: 87.77%\n", + " Val Loss: 0.6014, Val Acc: 77.67%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3310, Train Acc: 87.29%\n", + " Val Loss: 0.6071, Val Acc: 78.16%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 55/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3631, Train Acc: 87.53%\n", + " Val Loss: 0.6161, Val Acc: 77.18%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 56/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3251, Train Acc: 87.53%\n", + " Val Loss: 0.6293, Val Acc: 76.21%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 57/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3387, Train Acc: 88.26%\n", + " Val Loss: 0.6231, Val Acc: 77.67%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 58/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3560, Train Acc: 87.29%\n", + " Val Loss: 0.6219, Val Acc: 77.18%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 59/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3334, Train Acc: 86.92%\n", + " Val Loss: 0.6286, Val Acc: 77.18%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 60/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3379, Train Acc: 87.65%\n", + " Val Loss: 0.6219, Val Acc: 79.13%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 79.13%\n", + "\n", + "Fold 5 finished. Best Validation Accuracy: 79.13%\n", + " Fold 5 Detailed Metrics:\n", + " Accuracy: 79.13%\n", + " Precision: 0.8064\n", + " Recall: 0.7913\n", + " F1-Score: 0.7954\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_mobilenet/confusion_matrices/fold_5_confusion_matrix.png\n", + "\n", + "============================================================\n", + "answer_1 / MOBILENET Cross Validation Results (K=5)\n", + "============================================================\n", + "Average Validation Accuracy: 78.00% ยฑ 2.58%\n", + "Individual Fold Accuracies: [76.32850241545893, 80.19323671497585, 73.7864077669903, 80.58252427184466, 79.12621359223301]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-10-19 15:38:58,793 - INFO - \n", + "============================================================\n", + "2025-10-19 15:38:58,793 - INFO - ============================================================\n", + "2025-10-19 15:38:58,793 - INFO - Device: cpu\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ† Best model across all folds saved! Validation Acc: 80.58%\n", + " Model saved to: answer_models_cv_results/answer_1_mobilenet/best_model_overall_cv.pth\n", + "\n", + "MOBILENET - answer_1 Cross Validation ์™„๋ฃŒ\n", + "answer_2 Fine-tuning with MOBILENET (K=5 Cross Validation)\n", + " ํด๋ž˜์Šค 1: 165๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 2: 196๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 3: 188๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 4: 210๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 5: 168๊ฐœ ์ด๋ฏธ์ง€\n", + " ์ด 927๊ฐœ ์ด๋ฏธ์ง€ ๋กœ๋“œ\n", + "\n", + "########################################\n", + "Starting Fold 1/5\n", + "########################################\n", + " Fold 1: Train samples = 741, Validation samples = 186\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2924, Train Acc: 43.86%\n", + " Val Loss: 0.7162, Val Acc: 74.73%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 74.73%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7143, Train Acc: 72.20%\n", + " Val Loss: 0.4329, Val Acc: 83.33%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 83.33%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3868, Train Acc: 84.75%\n", + " Val Loss: 0.2995, Val Acc: 89.25%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 89.25%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3283, Train Acc: 87.85%\n", + " Val Loss: 0.2079, Val Acc: 91.94%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 91.94%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2256, Train Acc: 91.50%\n", + " Val Loss: 0.2265, Val Acc: 92.47%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 92.47%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2343, Train Acc: 91.77%\n", + " Val Loss: 0.1744, Val Acc: 94.62%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 94.62%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1993, Train Acc: 93.12%\n", + " Val Loss: 0.1862, Val Acc: 94.62%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1587, Train Acc: 94.60%\n", + " Val Loss: 0.1167, Val Acc: 95.70%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 95.70%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1335, Train Acc: 95.95%\n", + " Val Loss: 0.1613, Val Acc: 94.09%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1484, Train Acc: 94.74%\n", + " Val Loss: 0.1758, Val Acc: 94.09%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1086, Train Acc: 97.03%\n", + " Val Loss: 0.1394, Val Acc: 95.70%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0885, Train Acc: 96.49%\n", + " Val Loss: 0.0850, Val Acc: 96.77%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 96.77%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0718, Train Acc: 97.57%\n", + " Val Loss: 0.0995, Val Acc: 96.77%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0736, Train Acc: 97.98%\n", + " Val Loss: 0.0659, Val Acc: 97.85%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 97.85%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0615, Train Acc: 97.98%\n", + " Val Loss: 0.0577, Val Acc: 98.39%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 98.39%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0787, Train Acc: 96.90%\n", + " Val Loss: 0.0757, Val Acc: 97.85%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0501, Train Acc: 98.65%\n", + " Val Loss: 0.1727, Val Acc: 96.24%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0618, Train Acc: 97.17%\n", + " Val Loss: 0.1373, Val Acc: 95.70%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0937, Train Acc: 96.63%\n", + " Val Loss: 0.0453, Val Acc: 97.85%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0495, Train Acc: 98.11%\n", + " Val Loss: 0.0677, Val Acc: 98.39%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0364, Train Acc: 98.65%\n", + " Val Loss: 0.0675, Val Acc: 98.39%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0834, Train Acc: 98.11%\n", + " Val Loss: 0.0837, Val Acc: 98.39%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0595, Train Acc: 98.65%\n", + " Val Loss: 0.1056, Val Acc: 98.39%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0448, Train Acc: 98.52%\n", + " Val Loss: 0.0628, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0596, Train Acc: 98.25%\n", + " Val Loss: 0.0733, Val Acc: 98.92%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "Fold 1 finished. Best Validation Accuracy: 98.92%\n", + " Fold 1 Detailed Metrics:\n", + " Accuracy: 98.92%\n", + " Precision: 0.9898\n", + " Recall: 0.9892\n", + " F1-Score: 0.9893\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_mobilenet/confusion_matrices/fold_1_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 2/5\n", + "########################################\n", + " Fold 2: Train samples = 741, Validation samples = 186\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2881, Train Acc: 45.88%\n", + " Val Loss: 0.5109, Val Acc: 83.33%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 83.33%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6021, Train Acc: 77.87%\n", + " Val Loss: 0.2778, Val Acc: 90.32%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 90.32%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4572, Train Acc: 83.13%\n", + " Val Loss: 0.1319, Val Acc: 93.01%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 93.01%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3155, Train Acc: 89.07%\n", + " Val Loss: 0.0838, Val Acc: 97.31%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 97.31%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2437, Train Acc: 91.50%\n", + " Val Loss: 0.1007, Val Acc: 97.31%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2237, Train Acc: 91.50%\n", + " Val Loss: 0.1226, Val Acc: 95.70%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1613, Train Acc: 93.93%\n", + " Val Loss: 0.0961, Val Acc: 96.24%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2217, Train Acc: 92.17%\n", + " Val Loss: 0.1038, Val Acc: 95.16%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1737, Train Acc: 94.87%\n", + " Val Loss: 0.0554, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1143, Train Acc: 96.90%\n", + " Val Loss: 0.0371, Val Acc: 98.92%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1665, Train Acc: 93.79%\n", + " Val Loss: 0.0458, Val Acc: 98.92%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0797, Train Acc: 97.30%\n", + " Val Loss: 0.0354, Val Acc: 98.39%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1077, Train Acc: 96.22%\n", + " Val Loss: 0.0366, Val Acc: 97.85%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0914, Train Acc: 96.36%\n", + " Val Loss: 0.0386, Val Acc: 98.39%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0825, Train Acc: 96.63%\n", + " Val Loss: 0.0365, Val Acc: 97.85%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0598, Train Acc: 98.11%\n", + " Val Loss: 0.0258, Val Acc: 98.92%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0725, Train Acc: 97.17%\n", + " Val Loss: 0.0430, Val Acc: 98.39%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0723, Train Acc: 97.57%\n", + " Val Loss: 0.0245, Val Acc: 98.39%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0503, Train Acc: 98.38%\n", + " Val Loss: 0.0240, Val Acc: 98.39%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0475, Train Acc: 98.92%\n", + " Val Loss: 0.0224, Val Acc: 98.92%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0823, Train Acc: 98.38%\n", + " Val Loss: 0.0302, Val Acc: 98.92%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0509, Train Acc: 98.25%\n", + " Val Loss: 0.0252, Val Acc: 99.46%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 99.46%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0600, Train Acc: 97.84%\n", + " Val Loss: 0.0210, Val Acc: 99.46%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0558, Train Acc: 97.84%\n", + " Val Loss: 0.0292, Val Acc: 98.92%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0629, Train Acc: 98.38%\n", + " Val Loss: 0.0243, Val Acc: 99.46%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "Fold 2 finished. Best Validation Accuracy: 99.46%\n", + " Fold 2 Detailed Metrics:\n", + " Accuracy: 99.46%\n", + " Precision: 0.9948\n", + " Recall: 0.9946\n", + " F1-Score: 0.9946\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_mobilenet/confusion_matrices/fold_2_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 3/5\n", + "########################################\n", + " Fold 3: Train samples = 742, Validation samples = 185\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1690, Train Acc: 49.46%\n", + " Val Loss: 0.5966, Val Acc: 76.22%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 76.22%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6072, Train Acc: 76.01%\n", + " Val Loss: 0.2493, Val Acc: 91.89%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 91.89%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3977, Train Acc: 86.66%\n", + " Val Loss: 0.2150, Val Acc: 92.43%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 92.43%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3298, Train Acc: 88.54%\n", + " Val Loss: 0.1413, Val Acc: 95.14%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 95.14%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2507, Train Acc: 91.37%\n", + " Val Loss: 0.1169, Val Acc: 95.14%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1745, Train Acc: 93.67%\n", + " Val Loss: 0.1147, Val Acc: 93.51%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2208, Train Acc: 92.45%\n", + " Val Loss: 0.0966, Val Acc: 96.22%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 96.22%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1677, Train Acc: 93.53%\n", + " Val Loss: 0.1316, Val Acc: 94.59%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1515, Train Acc: 95.55%\n", + " Val Loss: 0.0856, Val Acc: 96.76%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 96.76%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1386, Train Acc: 95.15%\n", + " Val Loss: 0.1649, Val Acc: 94.05%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1716, Train Acc: 93.80%\n", + " Val Loss: 0.0627, Val Acc: 97.30%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 97.30%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1339, Train Acc: 95.96%\n", + " Val Loss: 0.0340, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1206, Train Acc: 95.82%\n", + " Val Loss: 0.0524, Val Acc: 97.84%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0652, Train Acc: 98.38%\n", + " Val Loss: 0.0324, Val Acc: 98.38%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0794, Train Acc: 97.44%\n", + " Val Loss: 0.0300, Val Acc: 98.38%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0946, Train Acc: 96.77%\n", + " Val Loss: 0.0561, Val Acc: 98.38%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0677, Train Acc: 97.98%\n", + " Val Loss: 0.0172, Val Acc: 98.92%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0602, Train Acc: 97.84%\n", + " Val Loss: 0.0180, Val Acc: 98.92%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0460, Train Acc: 98.38%\n", + " Val Loss: 0.0113, Val Acc: 100.00%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 100.00%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0538, Train Acc: 97.98%\n", + " Val Loss: 0.0153, Val Acc: 99.46%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0548, Train Acc: 98.38%\n", + " Val Loss: 0.0198, Val Acc: 100.00%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0472, Train Acc: 98.25%\n", + " Val Loss: 0.0205, Val Acc: 99.46%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0478, Train Acc: 98.52%\n", + " Val Loss: 0.0192, Val Acc: 99.46%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0455, Train Acc: 98.52%\n", + " Val Loss: 0.0136, Val Acc: 99.46%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0213, Train Acc: 99.60%\n", + " Val Loss: 0.0169, Val Acc: 99.46%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "Fold 3 finished. Best Validation Accuracy: 100.00%\n", + " Fold 3 Detailed Metrics:\n", + " Accuracy: 100.00%\n", + " Precision: 1.0000\n", + " Recall: 1.0000\n", + " F1-Score: 1.0000\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_mobilenet/confusion_matrices/fold_3_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 4/5\n", + "########################################\n", + " Fold 4: Train samples = 742, Validation samples = 185\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2406, Train Acc: 47.30%\n", + " Val Loss: 0.5207, Val Acc: 81.62%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 81.62%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6884, Train Acc: 73.99%\n", + " Val Loss: 0.2282, Val Acc: 92.97%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 92.97%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4427, Train Acc: 84.10%\n", + " Val Loss: 0.2347, Val Acc: 91.35%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2972, Train Acc: 89.49%\n", + " Val Loss: 0.1674, Val Acc: 95.14%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 95.14%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2552, Train Acc: 92.05%\n", + " Val Loss: 0.1195, Val Acc: 95.68%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 95.68%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1915, Train Acc: 93.53%\n", + " Val Loss: 0.0798, Val Acc: 96.76%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 96.76%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1949, Train Acc: 93.53%\n", + " Val Loss: 0.0750, Val Acc: 96.76%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1106, Train Acc: 96.09%\n", + " Val Loss: 0.1279, Val Acc: 97.30%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 97.30%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1962, Train Acc: 94.20%\n", + " Val Loss: 0.0953, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1458, Train Acc: 94.34%\n", + " Val Loss: 0.1048, Val Acc: 96.76%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1436, Train Acc: 94.74%\n", + " Val Loss: 0.0816, Val Acc: 96.76%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1047, Train Acc: 96.77%\n", + " Val Loss: 0.0622, Val Acc: 97.84%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1235, Train Acc: 95.96%\n", + " Val Loss: 0.0725, Val Acc: 96.76%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0620, Train Acc: 97.71%\n", + " Val Loss: 0.0498, Val Acc: 97.84%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0565, Train Acc: 97.84%\n", + " Val Loss: 0.0665, Val Acc: 98.38%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0450, Train Acc: 98.11%\n", + " Val Loss: 0.0655, Val Acc: 97.84%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0782, Train Acc: 98.25%\n", + " Val Loss: 0.0584, Val Acc: 98.38%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0496, Train Acc: 98.38%\n", + " Val Loss: 0.0722, Val Acc: 97.30%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0561, Train Acc: 97.84%\n", + " Val Loss: 0.0818, Val Acc: 98.38%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0305, Train Acc: 99.06%\n", + " Val Loss: 0.0799, Val Acc: 97.84%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0758, Train Acc: 98.38%\n", + " Val Loss: 0.0793, Val Acc: 98.38%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0424, Train Acc: 98.52%\n", + " Val Loss: 0.0686, Val Acc: 98.38%\n", + " Early Stopping Counter: 13/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0428, Train Acc: 98.52%\n", + " Val Loss: 0.0590, Val Acc: 98.38%\n", + " Early Stopping Counter: 14/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0238, Train Acc: 99.60%\n", + " Val Loss: 0.0636, Val Acc: 98.38%\n", + " Early Stopping Counter: 15/15\n", + " Early Stopping at epoch 24 for Fold 4\n", + "\n", + "Fold 4 finished. Best Validation Accuracy: 98.92%\n", + " Fold 4 Detailed Metrics:\n", + " Accuracy: 98.92%\n", + " Precision: 0.9895\n", + " Recall: 0.9892\n", + " F1-Score: 0.9892\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_mobilenet/confusion_matrices/fold_4_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 5/5\n", + "########################################\n", + " Fold 5: Train samples = 742, Validation samples = 185\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_mobilenet_mnist_model.pth\n", + "Loaded pretrained mobilenet model.\n", + " MNIST Test Acc: 99.56%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3082, Train Acc: 45.15%\n", + " Val Loss: 0.7296, Val Acc: 71.35%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 71.35%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6753, Train Acc: 75.34%\n", + " Val Loss: 0.2896, Val Acc: 91.89%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 91.89%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4019, Train Acc: 84.91%\n", + " Val Loss: 0.2698, Val Acc: 91.89%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3345, Train Acc: 88.14%\n", + " Val Loss: 0.1622, Val Acc: 94.05%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 94.05%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2404, Train Acc: 90.43%\n", + " Val Loss: 0.2089, Val Acc: 95.14%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 95.14%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1850, Train Acc: 93.13%\n", + " Val Loss: 0.1084, Val Acc: 96.22%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 96.22%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1941, Train Acc: 93.40%\n", + " Val Loss: 0.2106, Val Acc: 94.59%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1514, Train Acc: 93.94%\n", + " Val Loss: 0.1288, Val Acc: 96.22%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2086, Train Acc: 92.99%\n", + " Val Loss: 0.1201, Val Acc: 95.68%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1067, Train Acc: 96.63%\n", + " Val Loss: 0.0595, Val Acc: 97.84%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 97.84%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1272, Train Acc: 95.96%\n", + " Val Loss: 0.1431, Val Acc: 94.59%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1699, Train Acc: 94.74%\n", + " Val Loss: 0.1371, Val Acc: 95.14%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0756, Train Acc: 97.04%\n", + " Val Loss: 0.0836, Val Acc: 96.22%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1214, Train Acc: 95.01%\n", + " Val Loss: 0.1235, Val Acc: 94.59%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1080, Train Acc: 96.23%\n", + " Val Loss: 0.1107, Val Acc: 96.22%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0558, Train Acc: 98.11%\n", + " Val Loss: 0.1039, Val Acc: 96.76%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0564, Train Acc: 98.52%\n", + " Val Loss: 0.0718, Val Acc: 97.30%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0362, Train Acc: 98.79%\n", + " Val Loss: 0.0816, Val Acc: 97.30%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0465, Train Acc: 98.38%\n", + " Val Loss: 0.0768, Val Acc: 97.30%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0452, Train Acc: 98.52%\n", + " Val Loss: 0.0760, Val Acc: 96.76%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0226, Train Acc: 99.33%\n", + " Val Loss: 0.0906, Val Acc: 96.22%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0311, Train Acc: 99.06%\n", + " Val Loss: 0.0865, Val Acc: 97.30%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0564, Train Acc: 98.92%\n", + " Val Loss: 0.0732, Val Acc: 97.84%\n", + " Early Stopping Counter: 13/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0238, Train Acc: 99.33%\n", + " Val Loss: 0.0835, Val Acc: 96.76%\n", + " Early Stopping Counter: 14/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0555, Train Acc: 98.92%\n", + " Val Loss: 0.1230, Val Acc: 96.22%\n", + " Early Stopping Counter: 15/15\n", + " Early Stopping at epoch 25 for Fold 5\n", + "\n", + "Fold 5 finished. Best Validation Accuracy: 97.84%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-10-19 16:25:29,848 - INFO - \n", + "============================================================\n", + "2025-10-19 16:25:29,848 - INFO - ============================================================\n", + "2025-10-19 16:25:29,849 - INFO - Device: cpu\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Fold 5 Detailed Metrics:\n", + " Accuracy: 97.84%\n", + " Precision: 0.9786\n", + " Recall: 0.9784\n", + " F1-Score: 0.9784\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_mobilenet/confusion_matrices/fold_5_confusion_matrix.png\n", + "\n", + "============================================================\n", + "answer_2 / MOBILENET Cross Validation Results (K=5)\n", + "============================================================\n", + "Average Validation Accuracy: 99.03% ยฑ 0.72%\n", + "Individual Fold Accuracies: [98.9247311827957, 99.46236559139786, 100.0, 98.91891891891892, 97.83783783783784]\n", + "\n", + "๐Ÿ† Best model across all folds saved! Validation Acc: 100.00%\n", + " Model saved to: answer_models_cv_results/answer_2_mobilenet/best_model_overall_cv.pth\n", + "\n", + "MOBILENET - answer_2 Cross Validation ์™„๋ฃŒ\n", + "answer_1 Fine-tuning with EFFICIENTNET (K=5 Cross Validation)\n", + " ํด๋ž˜์Šค 1: 189๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 2: 208๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 3: 193๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 4: 214๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 5: 228๊ฐœ ์ด๋ฏธ์ง€\n", + " ์ด 1032๊ฐœ ์ด๋ฏธ์ง€ ๋กœ๋“œ\n", + "\n", + "########################################\n", + "Starting Fold 1/5\n", + "########################################\n", + " Fold 1: Train samples = 825, Validation samples = 207\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6050, Train Acc: 22.91%\n", + " Val Loss: 1.5571, Val Acc: 30.92%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 30.92%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5587, Train Acc: 27.15%\n", + " Val Loss: 1.5068, Val Acc: 38.65%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 38.65%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5067, Train Acc: 31.03%\n", + " Val Loss: 1.4188, Val Acc: 36.23%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4159, Train Acc: 39.27%\n", + " Val Loss: 1.3191, Val Acc: 42.03%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 42.03%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3312, Train Acc: 43.15%\n", + " Val Loss: 1.2081, Val Acc: 48.31%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 48.31%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1768, Train Acc: 50.67%\n", + " Val Loss: 1.0991, Val Acc: 56.04%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 56.04%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0927, Train Acc: 56.61%\n", + " Val Loss: 1.0058, Val Acc: 62.80%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 62.80%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0388, Train Acc: 55.88%\n", + " Val Loss: 0.9300, Val Acc: 64.73%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 64.73%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9176, Train Acc: 63.64%\n", + " Val Loss: 0.8406, Val Acc: 67.15%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 67.15%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8804, Train Acc: 65.45%\n", + " Val Loss: 0.7853, Val Acc: 70.53%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 70.53%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8223, Train Acc: 67.39%\n", + " Val Loss: 0.7900, Val Acc: 69.57%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7591, Train Acc: 68.85%\n", + " Val Loss: 0.7655, Val Acc: 70.53%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7235, Train Acc: 71.88%\n", + " Val Loss: 0.7232, Val Acc: 71.01%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 71.01%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6787, Train Acc: 73.94%\n", + " Val Loss: 0.7180, Val Acc: 71.98%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 71.98%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6954, Train Acc: 72.61%\n", + " Val Loss: 0.7064, Val Acc: 74.40%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 74.40%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6728, Train Acc: 74.55%\n", + " Val Loss: 0.6819, Val Acc: 75.85%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 75.85%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5906, Train Acc: 76.12%\n", + " Val Loss: 0.7040, Val Acc: 75.36%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6323, Train Acc: 76.97%\n", + " Val Loss: 0.6599, Val Acc: 77.78%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 77.78%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5507, Train Acc: 80.00%\n", + " Val Loss: 0.6753, Val Acc: 76.81%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5361, Train Acc: 81.45%\n", + " Val Loss: 0.6889, Val Acc: 77.78%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5607, Train Acc: 79.39%\n", + " Val Loss: 0.6639, Val Acc: 77.29%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5025, Train Acc: 81.82%\n", + " Val Loss: 0.6634, Val Acc: 76.81%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4335, Train Acc: 83.76%\n", + " Val Loss: 0.6676, Val Acc: 79.23%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 79.23%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4863, Train Acc: 80.97%\n", + " Val Loss: 0.6893, Val Acc: 78.26%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4842, Train Acc: 82.18%\n", + " Val Loss: 0.6878, Val Acc: 77.78%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4256, Train Acc: 84.97%\n", + " Val Loss: 0.7068, Val Acc: 77.78%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4587, Train Acc: 83.15%\n", + " Val Loss: 0.7017, Val Acc: 76.81%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4320, Train Acc: 84.12%\n", + " Val Loss: 0.7015, Val Acc: 77.78%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4029, Train Acc: 85.70%\n", + " Val Loss: 0.7048, Val Acc: 78.26%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3548, Train Acc: 87.52%\n", + " Val Loss: 0.7049, Val Acc: 78.74%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3896, Train Acc: 86.91%\n", + " Val Loss: 0.7088, Val Acc: 77.78%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3923, Train Acc: 86.06%\n", + " Val Loss: 0.7116, Val Acc: 77.29%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4200, Train Acc: 84.97%\n", + " Val Loss: 0.6924, Val Acc: 77.29%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4150, Train Acc: 84.48%\n", + " Val Loss: 0.7072, Val Acc: 78.26%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3969, Train Acc: 85.70%\n", + " Val Loss: 0.6864, Val Acc: 79.23%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3872, Train Acc: 85.70%\n", + " Val Loss: 0.6878, Val Acc: 78.26%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3436, Train Acc: 87.64%\n", + " Val Loss: 0.7080, Val Acc: 78.26%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3551, Train Acc: 86.67%\n", + " Val Loss: 0.6963, Val Acc: 79.23%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3427, Train Acc: 87.27%\n", + " Val Loss: 0.6866, Val Acc: 79.23%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4361, Train Acc: 84.12%\n", + " Val Loss: 0.7382, Val Acc: 77.78%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4142, Train Acc: 85.94%\n", + " Val Loss: 0.7031, Val Acc: 78.74%\n", + " Early Stopping Counter: 18/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3875, Train Acc: 85.45%\n", + " Val Loss: 0.6833, Val Acc: 78.74%\n", + " Early Stopping Counter: 19/20\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3896, Train Acc: 85.70%\n", + " Val Loss: 0.7081, Val Acc: 78.26%\n", + " Early Stopping Counter: 20/20\n", + " Early Stopping at epoch 43 for Fold 1\n", + "\n", + "Fold 1 finished. Best Validation Accuracy: 79.23%\n", + " Fold 1 Detailed Metrics:\n", + " Accuracy: 79.23%\n", + " Precision: 0.8093\n", + " Recall: 0.7923\n", + " F1-Score: 0.7982\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_efficientnet/confusion_matrices/fold_1_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 2/5\n", + "########################################\n", + " Fold 2: Train samples = 825, Validation samples = 207\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6312, Train Acc: 18.30%\n", + " Val Loss: 1.5587, Val Acc: 23.67%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 23.67%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5607, Train Acc: 26.55%\n", + " Val Loss: 1.4954, Val Acc: 31.88%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 31.88%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5006, Train Acc: 33.45%\n", + " Val Loss: 1.3909, Val Acc: 38.16%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 38.16%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4380, Train Acc: 35.88%\n", + " Val Loss: 1.3084, Val Acc: 41.55%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 41.55%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3486, Train Acc: 39.88%\n", + " Val Loss: 1.1959, Val Acc: 45.41%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 45.41%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2714, Train Acc: 42.55%\n", + " Val Loss: 1.0968, Val Acc: 58.45%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 58.45%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1469, Train Acc: 52.97%\n", + " Val Loss: 0.9874, Val Acc: 60.87%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 60.87%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0512, Train Acc: 54.79%\n", + " Val Loss: 0.8907, Val Acc: 65.22%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 65.22%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0080, Train Acc: 58.42%\n", + " Val Loss: 0.8150, Val Acc: 67.63%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 67.63%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9090, Train Acc: 62.42%\n", + " Val Loss: 0.7484, Val Acc: 70.05%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 70.05%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8443, Train Acc: 64.85%\n", + " Val Loss: 0.7235, Val Acc: 71.98%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 71.98%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7967, Train Acc: 69.82%\n", + " Val Loss: 0.7174, Val Acc: 71.98%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7605, Train Acc: 70.42%\n", + " Val Loss: 0.6823, Val Acc: 71.01%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7234, Train Acc: 72.61%\n", + " Val Loss: 0.6631, Val Acc: 74.88%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 74.88%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7103, Train Acc: 72.73%\n", + " Val Loss: 0.6497, Val Acc: 73.91%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6222, Train Acc: 76.97%\n", + " Val Loss: 0.6065, Val Acc: 75.85%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 75.85%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6825, Train Acc: 73.94%\n", + " Val Loss: 0.6071, Val Acc: 77.29%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 77.29%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5905, Train Acc: 78.30%\n", + " Val Loss: 0.6172, Val Acc: 71.50%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6143, Train Acc: 76.73%\n", + " Val Loss: 0.5778, Val Acc: 79.71%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 79.71%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6092, Train Acc: 76.48%\n", + " Val Loss: 0.6116, Val Acc: 78.26%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5953, Train Acc: 79.03%\n", + " Val Loss: 0.5826, Val Acc: 76.33%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5201, Train Acc: 80.48%\n", + " Val Loss: 0.5608, Val Acc: 78.74%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5031, Train Acc: 81.45%\n", + " Val Loss: 0.5766, Val Acc: 76.33%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4554, Train Acc: 82.91%\n", + " Val Loss: 0.5478, Val Acc: 80.19%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 80.19%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4509, Train Acc: 83.88%\n", + " Val Loss: 0.5406, Val Acc: 81.64%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 81.64%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4557, Train Acc: 82.67%\n", + " Val Loss: 0.5384, Val Acc: 82.61%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 82.61%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4165, Train Acc: 84.61%\n", + " Val Loss: 0.5500, Val Acc: 82.13%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4487, Train Acc: 84.73%\n", + " Val Loss: 0.5280, Val Acc: 83.09%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 83.09%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4319, Train Acc: 83.15%\n", + " Val Loss: 0.5265, Val Acc: 82.13%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4086, Train Acc: 84.73%\n", + " Val Loss: 0.5334, Val Acc: 81.16%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3971, Train Acc: 86.55%\n", + " Val Loss: 0.5153, Val Acc: 81.64%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3923, Train Acc: 85.58%\n", + " Val Loss: 0.5313, Val Acc: 83.57%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 83.57%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4062, Train Acc: 85.70%\n", + " Val Loss: 0.5096, Val Acc: 82.61%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4258, Train Acc: 84.73%\n", + " Val Loss: 0.5198, Val Acc: 81.64%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4157, Train Acc: 85.82%\n", + " Val Loss: 0.5139, Val Acc: 82.61%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3812, Train Acc: 86.06%\n", + " Val Loss: 0.5321, Val Acc: 82.61%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3391, Train Acc: 87.39%\n", + " Val Loss: 0.5059, Val Acc: 80.68%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3726, Train Acc: 86.55%\n", + " Val Loss: 0.5048, Val Acc: 82.13%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3646, Train Acc: 87.76%\n", + " Val Loss: 0.5105, Val Acc: 82.61%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3732, Train Acc: 86.67%\n", + " Val Loss: 0.5178, Val Acc: 83.09%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3199, Train Acc: 89.21%\n", + " Val Loss: 0.5039, Val Acc: 82.61%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3351, Train Acc: 88.97%\n", + " Val Loss: 0.5113, Val Acc: 81.64%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3492, Train Acc: 87.76%\n", + " Val Loss: 0.5140, Val Acc: 81.64%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3283, Train Acc: 87.64%\n", + " Val Loss: 0.5047, Val Acc: 83.09%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3324, Train Acc: 87.15%\n", + " Val Loss: 0.4973, Val Acc: 83.09%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3217, Train Acc: 88.85%\n", + " Val Loss: 0.5082, Val Acc: 82.13%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3078, Train Acc: 89.45%\n", + " Val Loss: 0.5212, Val Acc: 81.64%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3365, Train Acc: 87.88%\n", + " Val Loss: 0.5142, Val Acc: 82.61%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3286, Train Acc: 88.85%\n", + " Val Loss: 0.5090, Val Acc: 82.61%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3000, Train Acc: 88.73%\n", + " Val Loss: 0.5101, Val Acc: 83.57%\n", + " Early Stopping Counter: 18/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3116, Train Acc: 88.48%\n", + " Val Loss: 0.4952, Val Acc: 82.61%\n", + " Early Stopping Counter: 19/20\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3312, Train Acc: 88.36%\n", + " Val Loss: 0.5163, Val Acc: 82.13%\n", + " Early Stopping Counter: 20/20\n", + " Early Stopping at epoch 52 for Fold 2\n", + "\n", + "Fold 2 finished. Best Validation Accuracy: 83.57%\n", + " Fold 2 Detailed Metrics:\n", + " Accuracy: 83.57%\n", + " Precision: 0.8427\n", + " Recall: 0.8357\n", + " F1-Score: 0.8351\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_efficientnet/confusion_matrices/fold_2_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 3/5\n", + "########################################\n", + " Fold 3: Train samples = 826, Validation samples = 206\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6164, Train Acc: 22.52%\n", + " Val Loss: 1.5899, Val Acc: 24.76%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 24.76%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5667, Train Acc: 27.00%\n", + " Val Loss: 1.5307, Val Acc: 27.67%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 27.67%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5056, Train Acc: 34.02%\n", + " Val Loss: 1.4509, Val Acc: 31.55%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 31.55%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4464, Train Acc: 34.99%\n", + " Val Loss: 1.3652, Val Acc: 39.32%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 39.32%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3828, Train Acc: 39.35%\n", + " Val Loss: 1.2784, Val Acc: 42.23%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 42.23%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2528, Train Acc: 47.58%\n", + " Val Loss: 1.1991, Val Acc: 48.54%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 48.54%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1501, Train Acc: 51.82%\n", + " Val Loss: 1.0612, Val Acc: 57.28%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 57.28%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0765, Train Acc: 55.57%\n", + " Val Loss: 1.0220, Val Acc: 56.31%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9778, Train Acc: 60.41%\n", + " Val Loss: 0.9313, Val Acc: 58.74%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 58.74%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9154, Train Acc: 63.68%\n", + " Val Loss: 0.9052, Val Acc: 58.25%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8413, Train Acc: 65.74%\n", + " Val Loss: 0.8412, Val Acc: 63.59%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 63.59%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8330, Train Acc: 65.98%\n", + " Val Loss: 0.8523, Val Acc: 63.59%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7711, Train Acc: 67.43%\n", + " Val Loss: 0.7859, Val Acc: 66.50%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 66.50%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7065, Train Acc: 73.00%\n", + " Val Loss: 0.7678, Val Acc: 64.08%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7088, Train Acc: 73.61%\n", + " Val Loss: 0.7533, Val Acc: 66.02%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6720, Train Acc: 73.37%\n", + " Val Loss: 0.7381, Val Acc: 66.50%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6130, Train Acc: 76.15%\n", + " Val Loss: 0.7405, Val Acc: 68.45%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 68.45%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6795, Train Acc: 73.00%\n", + " Val Loss: 0.7145, Val Acc: 68.93%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 68.93%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5442, Train Acc: 79.90%\n", + " Val Loss: 0.7042, Val Acc: 71.36%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 71.36%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6028, Train Acc: 77.24%\n", + " Val Loss: 0.6630, Val Acc: 71.84%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 71.84%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5491, Train Acc: 79.30%\n", + " Val Loss: 0.6864, Val Acc: 68.45%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5027, Train Acc: 80.99%\n", + " Val Loss: 0.6729, Val Acc: 71.36%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5153, Train Acc: 80.39%\n", + " Val Loss: 0.6811, Val Acc: 70.39%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5069, Train Acc: 80.27%\n", + " Val Loss: 0.6614, Val Acc: 72.33%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 72.33%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4563, Train Acc: 83.78%\n", + " Val Loss: 0.6476, Val Acc: 73.79%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 73.79%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4361, Train Acc: 83.90%\n", + " Val Loss: 0.6598, Val Acc: 72.33%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4357, Train Acc: 84.62%\n", + " Val Loss: 0.6844, Val Acc: 72.33%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3952, Train Acc: 85.84%\n", + " Val Loss: 0.7007, Val Acc: 73.79%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3930, Train Acc: 86.56%\n", + " Val Loss: 0.6526, Val Acc: 71.84%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3543, Train Acc: 86.44%\n", + " Val Loss: 0.6366, Val Acc: 74.76%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 74.76%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3522, Train Acc: 88.26%\n", + " Val Loss: 0.5977, Val Acc: 77.67%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 77.67%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3497, Train Acc: 87.29%\n", + " Val Loss: 0.6007, Val Acc: 77.18%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3565, Train Acc: 87.17%\n", + " Val Loss: 0.5827, Val Acc: 76.21%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3576, Train Acc: 86.92%\n", + " Val Loss: 0.6190, Val Acc: 75.73%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3225, Train Acc: 87.89%\n", + " Val Loss: 0.5626, Val Acc: 77.67%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2999, Train Acc: 88.62%\n", + " Val Loss: 0.5874, Val Acc: 77.67%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3200, Train Acc: 88.74%\n", + " Val Loss: 0.5869, Val Acc: 77.18%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2995, Train Acc: 89.23%\n", + " Val Loss: 0.5805, Val Acc: 77.67%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2946, Train Acc: 89.59%\n", + " Val Loss: 0.5761, Val Acc: 77.18%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2966, Train Acc: 89.59%\n", + " Val Loss: 0.5823, Val Acc: 77.67%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2878, Train Acc: 90.56%\n", + " Val Loss: 0.5734, Val Acc: 77.18%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3321, Train Acc: 89.35%\n", + " Val Loss: 0.5551, Val Acc: 80.58%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 80.58%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2560, Train Acc: 90.68%\n", + " Val Loss: 0.5772, Val Acc: 80.10%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2682, Train Acc: 90.92%\n", + " Val Loss: 0.5864, Val Acc: 80.10%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3048, Train Acc: 89.47%\n", + " Val Loss: 0.5710, Val Acc: 77.18%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2974, Train Acc: 89.10%\n", + " Val Loss: 0.5643, Val Acc: 79.61%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2758, Train Acc: 89.83%\n", + " Val Loss: 0.5785, Val Acc: 78.64%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2724, Train Acc: 91.40%\n", + " Val Loss: 0.5643, Val Acc: 78.64%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2986, Train Acc: 90.07%\n", + " Val Loss: 0.5713, Val Acc: 79.13%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2653, Train Acc: 91.28%\n", + " Val Loss: 0.5744, Val Acc: 79.61%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2460, Train Acc: 91.77%\n", + " Val Loss: 0.5728, Val Acc: 78.64%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2676, Train Acc: 90.44%\n", + " Val Loss: 0.5616, Val Acc: 80.10%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2895, Train Acc: 89.35%\n", + " Val Loss: 0.5753, Val Acc: 78.16%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2989, Train Acc: 89.35%\n", + " Val Loss: 0.5850, Val Acc: 79.13%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 55/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2970, Train Acc: 89.95%\n", + " Val Loss: 0.5810, Val Acc: 77.18%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 56/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3370, Train Acc: 89.35%\n", + " Val Loss: 0.5661, Val Acc: 79.13%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 57/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3103, Train Acc: 88.74%\n", + " Val Loss: 0.5915, Val Acc: 79.13%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 58/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2452, Train Acc: 90.80%\n", + " Val Loss: 0.5819, Val Acc: 79.13%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 59/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2731, Train Acc: 90.80%\n", + " Val Loss: 0.5730, Val Acc: 79.61%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 60/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2844, Train Acc: 89.35%\n", + " Val Loss: 0.5647, Val Acc: 79.13%\n", + " Early Stopping Counter: 18/20\n", + "\n", + "Fold 3 finished. Best Validation Accuracy: 80.58%\n", + " Fold 3 Detailed Metrics:\n", + " Accuracy: 80.58%\n", + " Precision: 0.8150\n", + " Recall: 0.8058\n", + " F1-Score: 0.8076\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_efficientnet/confusion_matrices/fold_3_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 4/5\n", + "########################################\n", + " Fold 4: Train samples = 826, Validation samples = 206\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5960, Train Acc: 24.46%\n", + " Val Loss: 1.5816, Val Acc: 26.70%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 26.70%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5541, Train Acc: 29.18%\n", + " Val Loss: 1.5238, Val Acc: 33.50%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 33.50%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5063, Train Acc: 32.32%\n", + " Val Loss: 1.4338, Val Acc: 43.20%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 43.20%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4446, Train Acc: 36.20%\n", + " Val Loss: 1.3241, Val Acc: 50.49%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 50.49%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3834, Train Acc: 40.56%\n", + " Val Loss: 1.1735, Val Acc: 59.71%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 59.71%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2455, Train Acc: 50.12%\n", + " Val Loss: 1.0042, Val Acc: 61.17%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 61.17%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1576, Train Acc: 53.03%\n", + " Val Loss: 0.9019, Val Acc: 65.05%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 65.05%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0496, Train Acc: 55.81%\n", + " Val Loss: 0.7735, Val Acc: 71.84%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 71.84%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9646, Train Acc: 59.44%\n", + " Val Loss: 0.6851, Val Acc: 74.76%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 74.76%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9184, Train Acc: 62.95%\n", + " Val Loss: 0.6535, Val Acc: 74.27%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8694, Train Acc: 64.04%\n", + " Val Loss: 0.6445, Val Acc: 73.30%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8894, Train Acc: 65.38%\n", + " Val Loss: 0.6020, Val Acc: 78.16%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 78.16%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8031, Train Acc: 69.73%\n", + " Val Loss: 0.5845, Val Acc: 77.18%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7757, Train Acc: 69.25%\n", + " Val Loss: 0.6097, Val Acc: 77.18%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7202, Train Acc: 71.43%\n", + " Val Loss: 0.5428, Val Acc: 80.10%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 80.10%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6783, Train Acc: 73.61%\n", + " Val Loss: 0.5081, Val Acc: 82.04%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 82.04%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7028, Train Acc: 73.00%\n", + " Val Loss: 0.4968, Val Acc: 83.98%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 83.98%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6551, Train Acc: 74.82%\n", + " Val Loss: 0.5095, Val Acc: 81.07%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6178, Train Acc: 77.48%\n", + " Val Loss: 0.4476, Val Acc: 83.01%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5960, Train Acc: 76.03%\n", + " Val Loss: 0.4561, Val Acc: 83.50%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5431, Train Acc: 78.45%\n", + " Val Loss: 0.4726, Val Acc: 82.04%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5313, Train Acc: 79.18%\n", + " Val Loss: 0.4328, Val Acc: 84.47%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 84.47%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4962, Train Acc: 82.93%\n", + " Val Loss: 0.4203, Val Acc: 84.47%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5002, Train Acc: 81.23%\n", + " Val Loss: 0.4615, Val Acc: 82.52%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5084, Train Acc: 80.15%\n", + " Val Loss: 0.4515, Val Acc: 83.01%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4693, Train Acc: 80.87%\n", + " Val Loss: 0.4411, Val Acc: 84.47%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4463, Train Acc: 82.08%\n", + " Val Loss: 0.4597, Val Acc: 82.52%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4516, Train Acc: 83.66%\n", + " Val Loss: 0.4245, Val Acc: 83.98%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4251, Train Acc: 84.87%\n", + " Val Loss: 0.4316, Val Acc: 84.47%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4444, Train Acc: 82.57%\n", + " Val Loss: 0.4424, Val Acc: 83.50%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4375, Train Acc: 82.81%\n", + " Val Loss: 0.4246, Val Acc: 84.47%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4378, Train Acc: 83.41%\n", + " Val Loss: 0.4236, Val Acc: 84.47%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4522, Train Acc: 82.57%\n", + " Val Loss: 0.4562, Val Acc: 83.50%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4530, Train Acc: 83.41%\n", + " Val Loss: 0.4342, Val Acc: 83.98%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4310, Train Acc: 84.50%\n", + " Val Loss: 0.4403, Val Acc: 83.50%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4035, Train Acc: 85.71%\n", + " Val Loss: 0.4367, Val Acc: 83.98%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4398, Train Acc: 82.57%\n", + " Val Loss: 0.4234, Val Acc: 83.98%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4423, Train Acc: 83.78%\n", + " Val Loss: 0.4368, Val Acc: 84.47%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4110, Train Acc: 84.87%\n", + " Val Loss: 0.4258, Val Acc: 84.47%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4694, Train Acc: 82.69%\n", + " Val Loss: 0.4236, Val Acc: 84.95%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 84.95%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4159, Train Acc: 85.23%\n", + " Val Loss: 0.4300, Val Acc: 84.47%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4262, Train Acc: 84.38%\n", + " Val Loss: 0.4336, Val Acc: 83.98%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4350, Train Acc: 84.99%\n", + " Val Loss: 0.4318, Val Acc: 83.50%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4327, Train Acc: 83.54%\n", + " Val Loss: 0.4393, Val Acc: 84.95%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3781, Train Acc: 85.71%\n", + " Val Loss: 0.4242, Val Acc: 85.44%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 85.44%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4315, Train Acc: 83.41%\n", + " Val Loss: 0.4344, Val Acc: 83.98%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4167, Train Acc: 84.62%\n", + " Val Loss: 0.4310, Val Acc: 85.44%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4296, Train Acc: 84.02%\n", + " Val Loss: 0.4285, Val Acc: 84.95%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3980, Train Acc: 85.23%\n", + " Val Loss: 0.4327, Val Acc: 83.98%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4670, Train Acc: 82.08%\n", + " Val Loss: 0.4304, Val Acc: 83.50%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4269, Train Acc: 83.29%\n", + " Val Loss: 0.4266, Val Acc: 85.92%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 85.92%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4339, Train Acc: 83.41%\n", + " Val Loss: 0.4254, Val Acc: 84.47%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4409, Train Acc: 82.57%\n", + " Val Loss: 0.4333, Val Acc: 84.95%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4402, Train Acc: 84.50%\n", + " Val Loss: 0.4327, Val Acc: 85.44%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 55/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4309, Train Acc: 84.26%\n", + " Val Loss: 0.4304, Val Acc: 85.44%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 56/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4166, Train Acc: 86.68%\n", + " Val Loss: 0.4231, Val Acc: 85.44%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 57/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3787, Train Acc: 87.53%\n", + " Val Loss: 0.4411, Val Acc: 83.98%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 58/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4395, Train Acc: 83.41%\n", + " Val Loss: 0.4323, Val Acc: 84.95%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 59/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4184, Train Acc: 85.23%\n", + " Val Loss: 0.4282, Val Acc: 83.98%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 60/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4339, Train Acc: 83.29%\n", + " Val Loss: 0.4200, Val Acc: 84.47%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "Fold 4 finished. Best Validation Accuracy: 85.92%\n", + " Fold 4 Detailed Metrics:\n", + " Accuracy: 85.92%\n", + " Precision: 0.8577\n", + " Recall: 0.8592\n", + " F1-Score: 0.8583\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_efficientnet/confusion_matrices/fold_4_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 5/5\n", + "########################################\n", + " Fold 5: Train samples = 826, Validation samples = 206\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 1/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.6230, Train Acc: 21.79%\n", + " Val Loss: 1.5762, Val Acc: 29.13%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 29.13%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 2/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5676, Train Acc: 28.21%\n", + " Val Loss: 1.5325, Val Acc: 28.64%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 3/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.5041, Train Acc: 31.48%\n", + " Val Loss: 1.4448, Val Acc: 36.89%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 36.89%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 4/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.4305, Train Acc: 35.11%\n", + " Val Loss: 1.3474, Val Acc: 38.35%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 38.35%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 5/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.3456, Train Acc: 41.40%\n", + " Val Loss: 1.2428, Val Acc: 45.63%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 45.63%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 6/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2617, Train Acc: 45.88%\n", + " Val Loss: 1.1569, Val Acc: 49.51%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 49.51%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 7/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.2023, Train Acc: 48.67%\n", + " Val Loss: 1.0862, Val Acc: 54.37%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 54.37%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 8/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.1090, Train Acc: 54.24%\n", + " Val Loss: 1.0472, Val Acc: 56.80%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 56.80%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 9/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0756, Train Acc: 55.57%\n", + " Val Loss: 0.9854, Val Acc: 62.14%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 62.14%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 10/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9727, Train Acc: 60.17%\n", + " Val Loss: 0.9269, Val Acc: 63.11%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 63.11%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 11/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9565, Train Acc: 61.26%\n", + " Val Loss: 0.8744, Val Acc: 65.53%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 65.53%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 12/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8834, Train Acc: 65.74%\n", + " Val Loss: 0.8412, Val Acc: 65.53%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 13/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.8419, Train Acc: 65.74%\n", + " Val Loss: 0.8234, Val Acc: 67.96%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 67.96%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 14/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7923, Train Acc: 68.77%\n", + " Val Loss: 0.7727, Val Acc: 68.45%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 68.45%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 15/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7554, Train Acc: 69.85%\n", + " Val Loss: 0.7098, Val Acc: 73.30%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 73.30%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 16/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.7529, Train Acc: 70.82%\n", + " Val Loss: 0.7241, Val Acc: 71.84%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 17/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6960, Train Acc: 72.76%\n", + " Val Loss: 0.7035, Val Acc: 73.30%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 18/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6624, Train Acc: 75.18%\n", + " Val Loss: 0.6745, Val Acc: 75.24%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 75.24%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 19/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.6526, Train Acc: 75.91%\n", + " Val Loss: 0.6548, Val Acc: 74.76%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 20/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5801, Train Acc: 79.54%\n", + " Val Loss: 0.6410, Val Acc: 77.67%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 77.67%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 21/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5896, Train Acc: 77.48%\n", + " Val Loss: 0.6325, Val Acc: 75.73%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 22/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5806, Train Acc: 77.72%\n", + " Val Loss: 0.5979, Val Acc: 76.70%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 23/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5290, Train Acc: 80.63%\n", + " Val Loss: 0.6503, Val Acc: 77.18%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 24/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5260, Train Acc: 81.11%\n", + " Val Loss: 0.5817, Val Acc: 76.70%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 25/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.5072, Train Acc: 81.72%\n", + " Val Loss: 0.5907, Val Acc: 76.70%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 26/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4477, Train Acc: 83.17%\n", + " Val Loss: 0.5921, Val Acc: 78.16%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 78.16%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 27/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4919, Train Acc: 80.27%\n", + " Val Loss: 0.6009, Val Acc: 77.67%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 28/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4819, Train Acc: 82.81%\n", + " Val Loss: 0.5794, Val Acc: 77.18%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 29/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4115, Train Acc: 84.50%\n", + " Val Loss: 0.5767, Val Acc: 78.64%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 78.64%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 30/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4474, Train Acc: 83.41%\n", + " Val Loss: 0.5858, Val Acc: 78.16%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 31/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4487, Train Acc: 83.17%\n", + " Val Loss: 0.5766, Val Acc: 75.73%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 32/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4606, Train Acc: 82.81%\n", + " Val Loss: 0.5860, Val Acc: 77.67%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 33/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4037, Train Acc: 85.47%\n", + " Val Loss: 0.5807, Val Acc: 77.18%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 34/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3795, Train Acc: 85.47%\n", + " Val Loss: 0.5658, Val Acc: 78.16%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 35/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4353, Train Acc: 83.78%\n", + " Val Loss: 0.5818, Val Acc: 78.64%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 36/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3758, Train Acc: 85.47%\n", + " Val Loss: 0.5705, Val Acc: 80.10%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 80.10%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 37/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3865, Train Acc: 85.11%\n", + " Val Loss: 0.5667, Val Acc: 79.13%\n", + " Early Stopping Counter: 1/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 38/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3753, Train Acc: 86.56%\n", + " Val Loss: 0.5741, Val Acc: 76.70%\n", + " Early Stopping Counter: 2/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 39/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3878, Train Acc: 85.35%\n", + " Val Loss: 0.5523, Val Acc: 79.61%\n", + " Early Stopping Counter: 3/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 40/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3724, Train Acc: 86.80%\n", + " Val Loss: 0.5655, Val Acc: 77.67%\n", + " Early Stopping Counter: 4/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 41/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3654, Train Acc: 87.53%\n", + " Val Loss: 0.5919, Val Acc: 79.61%\n", + " Early Stopping Counter: 5/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 42/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3043, Train Acc: 89.59%\n", + " Val Loss: 0.5758, Val Acc: 77.67%\n", + " Early Stopping Counter: 6/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 43/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2969, Train Acc: 89.47%\n", + " Val Loss: 0.5663, Val Acc: 79.13%\n", + " Early Stopping Counter: 7/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 44/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3698, Train Acc: 86.92%\n", + " Val Loss: 0.5696, Val Acc: 79.61%\n", + " Early Stopping Counter: 8/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 45/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3758, Train Acc: 86.20%\n", + " Val Loss: 0.5638, Val Acc: 79.61%\n", + " Early Stopping Counter: 9/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 46/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3701, Train Acc: 85.59%\n", + " Val Loss: 0.5617, Val Acc: 78.64%\n", + " Early Stopping Counter: 10/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 47/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3270, Train Acc: 88.74%\n", + " Val Loss: 0.5631, Val Acc: 78.16%\n", + " Early Stopping Counter: 11/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 48/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3717, Train Acc: 86.20%\n", + " Val Loss: 0.5709, Val Acc: 80.10%\n", + " Early Stopping Counter: 12/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 49/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3745, Train Acc: 86.20%\n", + " Val Loss: 0.5571, Val Acc: 79.13%\n", + " Early Stopping Counter: 13/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 50/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3546, Train Acc: 88.38%\n", + " Val Loss: 0.5599, Val Acc: 80.10%\n", + " Early Stopping Counter: 14/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 51/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3595, Train Acc: 86.56%\n", + " Val Loss: 0.5782, Val Acc: 79.13%\n", + " Early Stopping Counter: 15/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 52/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3981, Train Acc: 85.35%\n", + " Val Loss: 0.5632, Val Acc: 77.67%\n", + " Early Stopping Counter: 16/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 53/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3419, Train Acc: 89.23%\n", + " Val Loss: 0.5468, Val Acc: 79.61%\n", + " Early Stopping Counter: 17/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 54/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3469, Train Acc: 88.01%\n", + " Val Loss: 0.5619, Val Acc: 78.16%\n", + " Early Stopping Counter: 18/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 55/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3532, Train Acc: 87.05%\n", + " Val Loss: 0.5531, Val Acc: 79.61%\n", + " Early Stopping Counter: 19/20\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 56/60\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3363, Train Acc: 87.89%\n", + " Val Loss: 0.5597, Val Acc: 79.61%\n", + " Early Stopping Counter: 20/20\n", + " Early Stopping at epoch 56 for Fold 5\n", + "\n", + "Fold 5 finished. Best Validation Accuracy: 80.10%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-10-19 19:35:12,658 - INFO - \n", + "============================================================\n", + "2025-10-19 19:35:12,659 - INFO - ============================================================\n", + "2025-10-19 19:35:12,659 - INFO - Device: cpu\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Fold 5 Detailed Metrics:\n", + " Accuracy: 80.10%\n", + " Precision: 0.8002\n", + " Recall: 0.8010\n", + " F1-Score: 0.8001\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_1_efficientnet/confusion_matrices/fold_5_confusion_matrix.png\n", + "\n", + "============================================================\n", + "answer_1 / EFFICIENTNET Cross Validation Results (K=5)\n", + "============================================================\n", + "Average Validation Accuracy: 81.88% ยฑ 2.49%\n", + "Individual Fold Accuracies: [79.22705314009661, 83.57487922705315, 80.58252427184466, 85.92233009708737, 80.09708737864078]\n", + "\n", + "๐Ÿ† Best model across all folds saved! Validation Acc: 85.92%\n", + " Model saved to: answer_models_cv_results/answer_1_efficientnet/best_model_overall_cv.pth\n", + "\n", + "EFFICIENTNET - answer_1 Cross Validation ์™„๋ฃŒ\n", + "answer_2 Fine-tuning with EFFICIENTNET (K=5 Cross Validation)\n", + " ํด๋ž˜์Šค 1: 165๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 2: 196๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 3: 188๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 4: 210๊ฐœ ์ด๋ฏธ์ง€\n", + " ํด๋ž˜์Šค 5: 168๊ฐœ ์ด๋ฏธ์ง€\n", + " ์ด 927๊ฐœ ์ด๋ฏธ์ง€ ๋กœ๋“œ\n", + "\n", + "########################################\n", + "Starting Fold 1/5\n", + "########################################\n", + " Fold 1: Train samples = 741, Validation samples = 186\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0357, Train Acc: 61.81%\n", + " Val Loss: 0.3279, Val Acc: 90.86%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 90.86%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4066, Train Acc: 87.72%\n", + " Val Loss: 0.1933, Val Acc: 92.47%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 92.47%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2810, Train Acc: 89.34%\n", + " Val Loss: 0.1030, Val Acc: 97.31%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 97.31%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2196, Train Acc: 93.25%\n", + " Val Loss: 0.2097, Val Acc: 92.47%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1382, Train Acc: 95.01%\n", + " Val Loss: 0.1583, Val Acc: 96.24%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1361, Train Acc: 95.82%\n", + " Val Loss: 0.1146, Val Acc: 96.77%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1538, Train Acc: 94.74%\n", + " Val Loss: 0.1233, Val Acc: 97.31%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1061, Train Acc: 95.82%\n", + " Val Loss: 0.1008, Val Acc: 97.85%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 97.85%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0882, Train Acc: 97.03%\n", + " Val Loss: 0.1184, Val Acc: 97.31%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0574, Train Acc: 97.98%\n", + " Val Loss: 0.0859, Val Acc: 97.85%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0515, Train Acc: 98.11%\n", + " Val Loss: 0.0638, Val Acc: 97.31%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0550, Train Acc: 98.25%\n", + " Val Loss: 0.0828, Val Acc: 97.31%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1170, Train Acc: 97.71%\n", + " Val Loss: 0.0546, Val Acc: 98.39%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 98.39%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0482, Train Acc: 98.79%\n", + " Val Loss: 0.0652, Val Acc: 98.39%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0498, Train Acc: 98.38%\n", + " Val Loss: 0.0743, Val Acc: 98.39%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0357, Train Acc: 98.79%\n", + " Val Loss: 0.0506, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 1 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0434, Train Acc: 98.38%\n", + " Val Loss: 0.0662, Val Acc: 98.39%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0560, Train Acc: 98.11%\n", + " Val Loss: 0.0908, Val Acc: 98.39%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0529, Train Acc: 98.38%\n", + " Val Loss: 0.0827, Val Acc: 98.39%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0417, Train Acc: 98.92%\n", + " Val Loss: 0.0624, Val Acc: 98.39%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0595, Train Acc: 98.38%\n", + " Val Loss: 0.0535, Val Acc: 98.39%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0270, Train Acc: 99.46%\n", + " Val Loss: 0.0636, Val Acc: 98.39%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0220, Train Acc: 99.73%\n", + " Val Loss: 0.0838, Val Acc: 98.39%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0313, Train Acc: 98.79%\n", + " Val Loss: 0.0560, Val Acc: 98.39%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 1 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0470, Train Acc: 98.79%\n", + " Val Loss: 0.0625, Val Acc: 98.39%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "Fold 1 finished. Best Validation Accuracy: 98.92%\n", + " Fold 1 Detailed Metrics:\n", + " Accuracy: 98.92%\n", + " Precision: 0.9898\n", + " Recall: 0.9892\n", + " F1-Score: 0.9893\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_efficientnet/confusion_matrices/fold_1_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 2/5\n", + "########################################\n", + " Fold 2: Train samples = 741, Validation samples = 186\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0500, Train Acc: 56.28%\n", + " Val Loss: 0.3290, Val Acc: 88.71%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 88.71%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3864, Train Acc: 87.04%\n", + " Val Loss: 0.1118, Val Acc: 97.31%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 97.31%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2723, Train Acc: 90.55%\n", + " Val Loss: 0.1132, Val Acc: 95.70%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1931, Train Acc: 94.06%\n", + " Val Loss: 0.0910, Val Acc: 97.31%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2346, Train Acc: 91.90%\n", + " Val Loss: 0.0640, Val Acc: 97.85%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 97.85%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1835, Train Acc: 94.06%\n", + " Val Loss: 0.0766, Val Acc: 97.31%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1365, Train Acc: 95.82%\n", + " Val Loss: 0.0822, Val Acc: 96.77%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1353, Train Acc: 95.55%\n", + " Val Loss: 0.0396, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1147, Train Acc: 96.63%\n", + " Val Loss: 0.0426, Val Acc: 98.92%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1073, Train Acc: 96.22%\n", + " Val Loss: 0.0763, Val Acc: 96.24%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0555, Train Acc: 98.38%\n", + " Val Loss: 0.0306, Val Acc: 98.92%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0981, Train Acc: 96.63%\n", + " Val Loss: 0.0129, Val Acc: 100.00%\n", + " ๐ŸŽฏ Best model for Fold 2 saved! Val Acc: 100.00%\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0805, Train Acc: 97.57%\n", + " Val Loss: 0.0127, Val Acc: 99.46%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1211, Train Acc: 96.76%\n", + " Val Loss: 0.0276, Val Acc: 99.46%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0779, Train Acc: 97.17%\n", + " Val Loss: 0.0146, Val Acc: 100.00%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0487, Train Acc: 98.65%\n", + " Val Loss: 0.0331, Val Acc: 97.85%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0587, Train Acc: 98.52%\n", + " Val Loss: 0.0165, Val Acc: 99.46%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0506, Train Acc: 98.25%\n", + " Val Loss: 0.0229, Val Acc: 99.46%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0549, Train Acc: 97.44%\n", + " Val Loss: 0.0592, Val Acc: 98.39%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0497, Train Acc: 98.38%\n", + " Val Loss: 0.0418, Val Acc: 98.39%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0311, Train Acc: 99.06%\n", + " Val Loss: 0.0166, Val Acc: 100.00%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0249, Train Acc: 99.33%\n", + " Val Loss: 0.0100, Val Acc: 99.46%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0210, Train Acc: 99.46%\n", + " Val Loss: 0.0094, Val Acc: 100.00%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 24/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0367, Train Acc: 98.52%\n", + " Val Loss: 0.0187, Val Acc: 99.46%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "========================================\n", + "Fold 2 - Epoch 25/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0448, Train Acc: 98.92%\n", + " Val Loss: 0.0228, Val Acc: 98.92%\n", + " Early Stopping Counter: 13/15\n", + "\n", + "Fold 2 finished. Best Validation Accuracy: 100.00%\n", + " Fold 2 Detailed Metrics:\n", + " Accuracy: 100.00%\n", + " Precision: 1.0000\n", + " Recall: 1.0000\n", + " F1-Score: 1.0000\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_efficientnet/confusion_matrices/fold_2_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 3/5\n", + "########################################\n", + " Fold 3: Train samples = 742, Validation samples = 185\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0020, Train Acc: 59.30%\n", + " Val Loss: 0.3122, Val Acc: 90.81%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 90.81%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4562, Train Acc: 84.10%\n", + " Val Loss: 0.1253, Val Acc: 95.68%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 95.68%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2550, Train Acc: 91.78%\n", + " Val Loss: 0.0681, Val Acc: 97.30%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 97.30%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1937, Train Acc: 93.40%\n", + " Val Loss: 0.1081, Val Acc: 95.14%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1829, Train Acc: 93.53%\n", + " Val Loss: 0.0631, Val Acc: 97.30%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1548, Train Acc: 95.69%\n", + " Val Loss: 0.0599, Val Acc: 98.38%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 98.38%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1679, Train Acc: 95.15%\n", + " Val Loss: 0.1373, Val Acc: 95.14%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1155, Train Acc: 95.96%\n", + " Val Loss: 0.0159, Val Acc: 100.00%\n", + " ๐ŸŽฏ Best model for Fold 3 saved! Val Acc: 100.00%\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0956, Train Acc: 96.50%\n", + " Val Loss: 0.0266, Val Acc: 99.46%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0571, Train Acc: 97.84%\n", + " Val Loss: 0.0529, Val Acc: 97.84%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1004, Train Acc: 96.23%\n", + " Val Loss: 0.0646, Val Acc: 98.38%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0880, Train Acc: 96.77%\n", + " Val Loss: 0.0260, Val Acc: 98.92%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0904, Train Acc: 96.36%\n", + " Val Loss: 0.0309, Val Acc: 98.92%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0520, Train Acc: 98.25%\n", + " Val Loss: 0.0252, Val Acc: 98.92%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0176, Train Acc: 99.87%\n", + " Val Loss: 0.0070, Val Acc: 100.00%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0315, Train Acc: 99.33%\n", + " Val Loss: 0.0116, Val Acc: 98.92%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0454, Train Acc: 98.65%\n", + " Val Loss: 0.0110, Val Acc: 99.46%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0415, Train Acc: 98.92%\n", + " Val Loss: 0.0061, Val Acc: 100.00%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0251, Train Acc: 99.06%\n", + " Val Loss: 0.0108, Val Acc: 99.46%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0247, Train Acc: 98.92%\n", + " Val Loss: 0.0164, Val Acc: 99.46%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0327, Train Acc: 99.06%\n", + " Val Loss: 0.0159, Val Acc: 99.46%\n", + " Early Stopping Counter: 13/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0276, Train Acc: 99.46%\n", + " Val Loss: 0.0121, Val Acc: 99.46%\n", + " Early Stopping Counter: 14/15\n", + "\n", + "========================================\n", + "Fold 3 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0241, Train Acc: 98.79%\n", + " Val Loss: 0.0164, Val Acc: 99.46%\n", + " Early Stopping Counter: 15/15\n", + " Early Stopping at epoch 23 for Fold 3\n", + "\n", + "Fold 3 finished. Best Validation Accuracy: 100.00%\n", + " Fold 3 Detailed Metrics:\n", + " Accuracy: 100.00%\n", + " Precision: 1.0000\n", + " Recall: 1.0000\n", + " F1-Score: 1.0000\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_efficientnet/confusion_matrices/fold_3_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 4/5\n", + "########################################\n", + " Fold 4: Train samples = 742, Validation samples = 185\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 1.0286, Train Acc: 59.57%\n", + " Val Loss: 0.3428, Val Acc: 88.11%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 88.11%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.3346, Train Acc: 87.47%\n", + " Val Loss: 0.1914, Val Acc: 93.51%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 93.51%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2333, Train Acc: 92.72%\n", + " Val Loss: 0.0922, Val Acc: 96.76%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 96.76%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1948, Train Acc: 93.13%\n", + " Val Loss: 0.0770, Val Acc: 97.30%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 97.30%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1673, Train Acc: 95.01%\n", + " Val Loss: 0.1253, Val Acc: 97.30%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1597, Train Acc: 94.20%\n", + " Val Loss: 0.1046, Val Acc: 97.30%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1091, Train Acc: 95.55%\n", + " Val Loss: 0.1021, Val Acc: 98.38%\n", + " ๐ŸŽฏ Best model for Fold 4 saved! Val Acc: 98.38%\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0675, Train Acc: 97.57%\n", + " Val Loss: 0.1019, Val Acc: 98.38%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1679, Train Acc: 94.07%\n", + " Val Loss: 0.0892, Val Acc: 98.38%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1258, Train Acc: 95.69%\n", + " Val Loss: 0.1575, Val Acc: 95.14%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0588, Train Acc: 98.11%\n", + " Val Loss: 0.1327, Val Acc: 97.30%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0761, Train Acc: 97.98%\n", + " Val Loss: 0.0660, Val Acc: 97.84%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0713, Train Acc: 98.11%\n", + " Val Loss: 0.0732, Val Acc: 97.30%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0613, Train Acc: 97.84%\n", + " Val Loss: 0.0695, Val Acc: 97.84%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0509, Train Acc: 98.52%\n", + " Val Loss: 0.0736, Val Acc: 97.84%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0316, Train Acc: 99.46%\n", + " Val Loss: 0.0633, Val Acc: 97.84%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0366, Train Acc: 99.33%\n", + " Val Loss: 0.0669, Val Acc: 97.84%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0328, Train Acc: 99.33%\n", + " Val Loss: 0.0723, Val Acc: 97.30%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0464, Train Acc: 99.46%\n", + " Val Loss: 0.0620, Val Acc: 97.84%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0232, Train Acc: 99.33%\n", + " Val Loss: 0.0575, Val Acc: 97.84%\n", + " Early Stopping Counter: 13/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0185, Train Acc: 99.60%\n", + " Val Loss: 0.0625, Val Acc: 97.84%\n", + " Early Stopping Counter: 14/15\n", + "\n", + "========================================\n", + "Fold 4 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0339, Train Acc: 98.92%\n", + " Val Loss: 0.0742, Val Acc: 97.84%\n", + " Early Stopping Counter: 15/15\n", + " Early Stopping at epoch 22 for Fold 4\n", + "\n", + "Fold 4 finished. Best Validation Accuracy: 98.38%\n", + " Fold 4 Detailed Metrics:\n", + " Accuracy: 98.38%\n", + " Precision: 0.9841\n", + " Recall: 0.9838\n", + " F1-Score: 0.9838\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_efficientnet/confusion_matrices/fold_4_confusion_matrix.png\n", + "\n", + "########################################\n", + "Starting Fold 5/5\n", + "########################################\n", + " Fold 5: Train samples = 742, Validation samples = 185\n", + " Data augmentation enabled for training.\n", + "Loading pretrained model from: mnist_models/best_efficientnet_mnist_model.pth\n", + "Loaded pretrained efficientnet model.\n", + " MNIST Test Acc: 99.61%\n", + "Output layer๋ฅผ 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 1/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.9776, Train Acc: 62.40%\n", + " Val Loss: 0.3393, Val Acc: 89.19%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 89.19%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 2/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.4164, Train Acc: 85.31%\n", + " Val Loss: 0.1102, Val Acc: 96.22%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 96.22%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 3/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2437, Train Acc: 92.32%\n", + " Val Loss: 0.1166, Val Acc: 96.76%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 96.76%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 4/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.2037, Train Acc: 93.26%\n", + " Val Loss: 0.0782, Val Acc: 96.76%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 5/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1893, Train Acc: 94.20%\n", + " Val Loss: 0.0505, Val Acc: 98.92%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 98.92%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 6/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1731, Train Acc: 94.74%\n", + " Val Loss: 0.1390, Val Acc: 95.14%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 7/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1279, Train Acc: 95.28%\n", + " Val Loss: 0.0419, Val Acc: 98.38%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 8/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1306, Train Acc: 96.77%\n", + " Val Loss: 0.0324, Val Acc: 99.46%\n", + " ๐ŸŽฏ Best model for Fold 5 saved! Val Acc: 99.46%\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 9/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.1006, Train Acc: 96.09%\n", + " Val Loss: 0.0713, Val Acc: 97.84%\n", + " Early Stopping Counter: 1/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 10/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0635, Train Acc: 97.98%\n", + " Val Loss: 0.0492, Val Acc: 97.84%\n", + " Early Stopping Counter: 2/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 11/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0873, Train Acc: 96.63%\n", + " Val Loss: 0.0638, Val Acc: 97.30%\n", + " Early Stopping Counter: 3/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 12/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0573, Train Acc: 98.11%\n", + " Val Loss: 0.0413, Val Acc: 97.30%\n", + " Early Stopping Counter: 4/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 13/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0756, Train Acc: 97.44%\n", + " Val Loss: 0.0492, Val Acc: 97.30%\n", + " Early Stopping Counter: 5/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 14/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0586, Train Acc: 97.57%\n", + " Val Loss: 0.0344, Val Acc: 98.92%\n", + " Early Stopping Counter: 6/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 15/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0352, Train Acc: 98.79%\n", + " Val Loss: 0.0289, Val Acc: 99.46%\n", + " Early Stopping Counter: 7/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 16/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0324, Train Acc: 99.06%\n", + " Val Loss: 0.0263, Val Acc: 98.38%\n", + " Early Stopping Counter: 8/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 17/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0388, Train Acc: 99.06%\n", + " Val Loss: 0.0286, Val Acc: 98.38%\n", + " Early Stopping Counter: 9/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 18/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0369, Train Acc: 99.19%\n", + " Val Loss: 0.0288, Val Acc: 99.46%\n", + " Early Stopping Counter: 10/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 19/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0256, Train Acc: 99.19%\n", + " Val Loss: 0.0385, Val Acc: 98.92%\n", + " Early Stopping Counter: 11/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 20/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0264, Train Acc: 99.06%\n", + " Val Loss: 0.0419, Val Acc: 98.92%\n", + " Early Stopping Counter: 12/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 21/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0477, Train Acc: 98.79%\n", + " Val Loss: 0.0427, Val Acc: 98.38%\n", + " Early Stopping Counter: 13/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 22/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0521, Train Acc: 98.38%\n", + " Val Loss: 0.0403, Val Acc: 97.84%\n", + " Early Stopping Counter: 14/15\n", + "\n", + "========================================\n", + "Fold 5 - Epoch 23/25\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Train Loss: 0.0427, Train Acc: 98.65%\n", + " Val Loss: 0.0313, Val Acc: 99.46%\n", + " Early Stopping Counter: 15/15\n", + " Early Stopping at epoch 23 for Fold 5\n", + "\n", + "Fold 5 finished. Best Validation Accuracy: 99.46%\n", + " Fold 5 Detailed Metrics:\n", + " Accuracy: 99.46%\n", + " Precision: 0.9947\n", + " Recall: 0.9946\n", + " F1-Score: 0.9946\n", + " Confusion Matrix ์ €์žฅ: answer_models_cv_results/answer_2_efficientnet/confusion_matrices/fold_5_confusion_matrix.png\n", + "\n", + "============================================================\n", + "answer_2 / EFFICIENTNET Cross Validation Results (K=5)\n", + "============================================================\n", + "Average Validation Accuracy: 99.35% ยฑ 0.63%\n", + "Individual Fold Accuracies: [98.9247311827957, 100.0, 100.0, 98.37837837837839, 99.45945945945947]\n", + "\n", + "๐Ÿ† Best model across all folds saved! Validation Acc: 100.00%\n", + " Model saved to: answer_models_cv_results/answer_2_efficientnet/best_model_overall_cv.pth\n", + "\n", + "EFFICIENTNET - answer_2 Cross Validation ์™„๋ฃŒ\n", + "\n", + "============================================================\n", + "๐Ÿ† Cross Validation ์ตœ์ข… ๊ฒฐ๊ณผ ์š”์•ฝ\n", + "============================================================\n", + "\n", + " answer_1 ํ‰๊ท  Validation Accuracy:\n", + " EFFICIENTNET: 81.88%\n", + " RESNET: 92.44%\n", + " MOBILENET: 78.00%\n", + "\n", + " answer_2 ํ‰๊ท  Validation Accuracy:\n", + " EFFICIENTNET: 99.35%\n", + " RESNET: 99.68%\n", + " MOBILENET: 99.03%\n", + "\n", + "============================================================\n", + "๋ชจ๋“  Cross Validation ํ•™์Šต ์™„๋ฃŒ\n", + "๊ฒฐ๊ณผ ์ €์žฅ ์œ„์น˜: answer_models_cv_results\n", + "============================================================\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "๋‘ ๋ฒˆ์งธ ์ฝ”๋“œ: Answer Classifier with Advanced Models\n", + "- 3๊ฐ€์ง€ ๋ชจ๋ธ base model: EfficientNet, ResNet, MobileNet\n", + "- Answer_1, Answer_2 ๋ฐ์ดํ„ฐ์…‹ ์ถ”๊ฐ€ ํŒŒ์ธํŠœ๋‹\n", + "\"\"\"\n", + "\n", + "import torch\n", + "import torch.nn as nn\n", + "import torch.optim as optim\n", + "from torch.utils.data import Dataset, DataLoader\n", + "from torchvision import transforms\n", + "from PIL import Image\n", + "from pathlib import Path\n", + "import logging\n", + "from tqdm import tqdm\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "from sklearn.metrics import accuracy_score, precision_recall_fscore_support, confusion_matrix\n", + "from sklearn.model_selection import StratifiedKFold\n", + "import numpy as np\n", + "from huggingface_hub import hf_hub_download\n", + "import os\n", + "import copy \n", + "\n", + "logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "\n", + "# ========== Model Architectures (์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ์™€ ๋™์ผํ•˜๊ฒŒ ์„ค์ •) ==========\n", + "\n", + "class SEBlock(nn.Module):\n", + " \"\"\"Squeeze-and-Excitation block\"\"\"\n", + " def __init__(self, in_channels, se_channels):\n", + " super().__init__()\n", + " self.avg_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.fc = nn.Sequential(\n", + " nn.Linear(in_channels, se_channels, bias=False),\n", + " nn.SiLU(inplace=True),\n", + " nn.Linear(se_channels, in_channels, bias=False),\n", + " nn.Sigmoid()\n", + " )\n", + "\n", + " def forward(self, x):\n", + " b, c, _, _ = x.size()\n", + " y = self.avg_pool(x).view(b, c)\n", + " y = self.fc(y).view(b, c, 1, 1)\n", + " return x * y\n", + "\n", + "\n", + "class ResidualBlock(nn.Module):\n", + " \"\"\"Residual connection wrapper\"\"\"\n", + " def __init__(self, module):\n", + " super().__init__()\n", + " self.module = module\n", + "\n", + " def forward(self, x):\n", + " return x + self.module(x)\n", + "\n", + "\n", + "class BasicBlock(nn.Module):\n", + " \"\"\"Basic block for ResNet\"\"\"\n", + " def __init__(self, in_channels, out_channels, stride=1):\n", + " super().__init__()\n", + "\n", + " self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride, 1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(out_channels)\n", + " self.relu = nn.ReLU(inplace=True)\n", + "\n", + " self.conv2 = nn.Conv2d(out_channels, out_channels, 3, 1, 1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(out_channels)\n", + "\n", + " self.shortcut = nn.Sequential()\n", + " if stride != 1 or in_channels != out_channels:\n", + " self.shortcut = nn.Sequential(\n", + " nn.Conv2d(in_channels, out_channels, 1, stride, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " out = self.relu(self.bn1(self.conv1(x)))\n", + " out = self.bn2(self.conv2(out))\n", + " out += self.shortcut(x)\n", + " out = self.relu(out)\n", + " return out\n", + "\n", + "\n", + "class InvertedResidual(nn.Module):\n", + " \"\"\"Inverted Residual block for MobileNetV3\"\"\"\n", + " def __init__(self, in_channels, out_channels, kernel, stride, expand_ratio, se_ratio=None):\n", + " super().__init__()\n", + "\n", + " hidden_dim = int(in_channels * expand_ratio)\n", + " self.use_res_connect = stride == 1 and in_channels == out_channels\n", + "\n", + " layers = []\n", + "\n", + " if expand_ratio != 1:\n", + " layers.extend([\n", + " nn.Conv2d(in_channels, hidden_dim, 1, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.Hardswish(inplace=True)\n", + " ])\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, hidden_dim, kernel, stride,\n", + " kernel//2, groups=hidden_dim, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.Hardswish(inplace=True)\n", + " ])\n", + "\n", + " if se_ratio is not None:\n", + " se_channels = int(in_channels * se_ratio)\n", + " layers.append(SEBlock(hidden_dim, se_channels))\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, out_channels, 1, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " ])\n", + "\n", + " self.conv = nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " if self.use_res_connect:\n", + " return x + self.conv(x)\n", + " else:\n", + " return self.conv(x)\n", + "\n", + "\n", + "class EfficientNetB0_MNIST(nn.Module):\n", + " \"\"\"EfficientNet-B0 for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " self.conv_stem = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(32)\n", + " self.act1 = nn.SiLU(inplace=True)\n", + "\n", + " self.blocks = nn.Sequential(\n", + " self._make_mbconv(32, 16, kernel=3, stride=1, expand_ratio=1),\n", + " self._make_mbconv(16, 24, kernel=3, stride=2, expand_ratio=6),\n", + " self._make_mbconv(24, 24, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(24, 40, kernel=5, stride=2, expand_ratio=6),\n", + " self._make_mbconv(40, 40, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(40, 80, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(80, 80, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(80, 112, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(112, 112, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(112, 192, kernel=5, stride=1, expand_ratio=6),\n", + " )\n", + "\n", + " self.conv_head = nn.Conv2d(192, 1280, kernel_size=1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(1280)\n", + " self.act2 = nn.SiLU(inplace=True)\n", + "\n", + " self.global_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.classifier = nn.Sequential(\n", + " nn.Dropout(0.2),\n", + " nn.Linear(1280, num_classes)\n", + " )\n", + "\n", + " def _make_mbconv(self, in_channels, out_channels, kernel, stride, expand_ratio):\n", + " layers = []\n", + " hidden_dim = in_channels * expand_ratio\n", + "\n", + " if expand_ratio != 1:\n", + " layers.extend([\n", + " nn.Conv2d(in_channels, hidden_dim, 1, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.SiLU(inplace=True)\n", + " ])\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, hidden_dim, kernel, stride,\n", + " padding=kernel//2, groups=hidden_dim, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.SiLU(inplace=True)\n", + " ])\n", + "\n", + " se_channels = max(1, in_channels // 4)\n", + " layers.append(SEBlock(hidden_dim, se_channels))\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, out_channels, 1, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " ])\n", + "\n", + " if stride == 1 and in_channels == out_channels:\n", + " return ResidualBlock(nn.Sequential(*layers))\n", + "\n", + " return nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " x = self.conv_stem(x)\n", + " x = self.bn1(x)\n", + " x = self.act1(x)\n", + " x = self.blocks(x)\n", + " x = self.conv_head(x)\n", + " x = self.bn2(x)\n", + " x = self.act2(x)\n", + " x = self.global_pool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.classifier(x)\n", + " return x\n", + "\n", + "\n", + "class ResNet18_MNIST(nn.Module):\n", + " \"\"\"ResNet-18 for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(64)\n", + " self.relu = nn.ReLU(inplace=True)\n", + "\n", + " self.layer1 = self._make_layer(64, 64, 2, stride=1)\n", + " self.layer2 = self._make_layer(64, 128, 2, stride=2)\n", + " self.layer3 = self._make_layer(128, 256, 2, stride=2)\n", + " self.layer4 = self._make_layer(256, 512, 2, stride=2)\n", + "\n", + " self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n", + " self.fc = nn.Linear(512, num_classes)\n", + "\n", + " def _make_layer(self, in_channels, out_channels, blocks, stride=1):\n", + " layers = []\n", + " layers.append(BasicBlock(in_channels, out_channels, stride))\n", + " for _ in range(1, blocks):\n", + " layers.append(BasicBlock(out_channels, out_channels, stride=1))\n", + " return nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " x = self.conv1(x)\n", + " x = self.bn1(x)\n", + " x = self.relu(x)\n", + " x = self.layer1(x)\n", + " x = self.layer2(x)\n", + " x = self.layer3(x)\n", + " x = self.layer4(x)\n", + " x = self.avgpool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.fc(x)\n", + " return x\n", + "\n", + "\n", + "class MobileNetV3_MNIST(nn.Module):\n", + " \"\"\"MobileNetV3-Small for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " self.conv_stem = nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(16)\n", + " self.act1 = nn.Hardswish(inplace=True)\n", + "\n", + " self.blocks = nn.Sequential(\n", + " InvertedResidual(16, 16, kernel=3, stride=1, expand_ratio=1, se_ratio=0.25),\n", + " InvertedResidual(16, 24, kernel=3, stride=2, expand_ratio=4.5, se_ratio=None),\n", + " InvertedResidual(24, 24, kernel=3, stride=1, expand_ratio=3.67, se_ratio=None),\n", + " InvertedResidual(24, 40, kernel=5, stride=2, expand_ratio=4, se_ratio=0.25),\n", + " InvertedResidual(40, 40, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(40, 40, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(40, 48, kernel=5, stride=1, expand_ratio=3, se_ratio=0.25),\n", + " InvertedResidual(48, 48, kernel=5, stride=1, expand_ratio=3, se_ratio=0.25),\n", + " InvertedResidual(48, 96, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(96, 96, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " )\n", + "\n", + " self.conv_head = nn.Conv2d(96, 576, kernel_size=1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(576)\n", + " self.act2 = nn.Hardswish(inplace=True)\n", + "\n", + " self.global_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.classifier = nn.Sequential(\n", + " nn.Linear(576, 1024),\n", + " nn.Hardswish(inplace=True),\n", + " nn.Dropout(0.2),\n", + " nn.Linear(1024, num_classes)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " x = self.conv_stem(x)\n", + " x = self.bn1(x)\n", + " x = self.act1(x)\n", + " x = self.blocks(x)\n", + " x = self.conv_head(x)\n", + " x = self.bn2(x)\n", + " x = self.act2(x)\n", + " x = self.global_pool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.classifier(x)\n", + " return x\n", + "\n", + "\n", + "# ========== Dataset Class ==========\n", + "\n", + "class AnswerDataset(Dataset):\n", + " \"\"\"Answer_1, Answer_2 ๋ฐ์ดํ„ฐ์…‹ + ์ฆ๊ฐ•\"\"\"\n", + "\n", + " def __init__(self, image_paths, labels, augment=False):\n", + " self.image_paths = image_paths\n", + " self.labels = labels\n", + " self.augment = augment\n", + "\n", + " def __len__(self):\n", + " return len(self.image_paths)\n", + "\n", + " def __getitem__(self, idx):\n", + " image_path = self.image_paths[idx]\n", + " label = self.labels[idx]\n", + "\n", + " image = Image.open(image_path).convert('L')\n", + " image = image.resize((28, 28))\n", + "\n", + " # Tensor ๋ณ€ํ™˜\n", + " image = torch.FloatTensor(np.array(image)).unsqueeze(0) / 255.0\n", + "\n", + " # ๋ฐ์ดํ„ฐ ์ฆ๊ฐ• (Train๋งŒ)\n", + " if self.augment:\n", + " # ๋žœ๋ค ํšŒ์ „\n", + " if torch.rand(1) > 0.5:\n", + " angle = torch.randint(-10, 11, (1,)).item()\n", + " image = transforms.functional.rotate(\n", + " transforms.ToPILImage()(image.squeeze(0)), angle\n", + " )\n", + " image = torch.FloatTensor(np.array(image)).unsqueeze(0) / 255.0\n", + "\n", + " # ์ˆ˜์ง/์ˆ˜ํ‰ ์ด๋™\n", + " if torch.rand(1) > 0.5:\n", + " tx = torch.randint(-2, 3, (1,)).item() # ์ˆ˜ํ‰ ์ด๋™ -2 ~ +2 ํ”ฝ์…€\n", + " ty = torch.randint(-2, 3, (1,)).item() # ์ˆ˜์ง ์ด๋™ -2 ~ +2 ํ”ฝ์…€\n", + " image = transforms.functional.affine(\n", + " transforms.ToPILImage()(image.squeeze(0)),\n", + " angle=0, translate=(tx, ty), scale=1.0, shear=0\n", + " )\n", + " image = torch.FloatTensor(np.array(image)).unsqueeze(0) / 255.0\n", + "\n", + " # ๋ฐ๊ธฐ/๋Œ€๋น„ ์กฐ์ ˆ\n", + " if torch.rand(1) > 0.5:\n", + " brightness_factor = torch.FloatTensor(1).uniform_(0.8, 1.2).item()\n", + " image = transforms.functional.adjust_brightness(\n", + " transforms.ToPILImage()(image.squeeze(0)), brightness_factor\n", + " )\n", + " image = torch.FloatTensor(np.array(image)).unsqueeze(0) / 255.0\n", + "\n", + " # ๊ฐ€์šฐ์‹œ์•ˆ ๋…ธ์ด์ฆˆ\n", + " if torch.rand(1) > 0.5:\n", + " noise = torch.randn(image.size()) * 0.02\n", + " image = image + noise\n", + " image = torch.clamp(image, 0.0, 1.0)\n", + "\n", + " # ๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ ์ถ”๊ฐ€\n", + " if torch.rand(1) > 0.5:\n", + " sigma = torch.FloatTensor(1).uniform_(0.1, 1.0).item()\n", + " image = transforms.functional.gaussian_blur(\n", + " transforms.ToPILImage()(image.squeeze(0)), kernel_size=3, sigma=sigma\n", + " )\n", + " image = torch.FloatTensor(np.array(image)).unsqueeze(0) / 255.0\n", + "\n", + " # Affine Shear (์™œ๊ณก)\n", + " if torch.rand(1) > 0.5:\n", + " shear_factor = torch.FloatTensor(1).uniform_(-5, 5).item() # -5 ~ +5๋„\n", + " image = transforms.functional.affine(\n", + " transforms.ToPILImage()(image.squeeze(0)),\n", + " angle=0, translate=(0, 0), scale=1.0, shear=shear_factor\n", + " )\n", + " image = torch.FloatTensor(np.array(image)).unsqueeze(0) / 255.0\n", + "\n", + "\n", + " # MNIST ์ •๊ทœํ™”\n", + " image = (image - 0.1307) / 0.3081\n", + "\n", + " return image, torch.tensor(label, dtype=torch.long)\n", + "\n", + "MNIST_MODEL_ROOT_DIR = Path(\"mnist_models\")\n", + "\n", + "def load_pretrained(model_type, num_classes_new=5, device='cpu'):\n", + " \"\"\"์‚ฌ์ „ํ•™์Šต ๋ชจ๋ธ ๋กœ๋“œ ๋ฐ ์ˆ˜์ •\"\"\"\n", + "\n", + " filename = f\"best_{model_type}_mnist_model.pth\"\n", + " model_path = MNIST_MODEL_ROOT_DIR / filename\n", + " \n", + " if not model_path.exists():\n", + " raise FileNotFoundError(f\"์‚ฌ์ „ ํ•™์Šต๋œ ๋ชจ๋ธ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {model_path}\")\n", + " \n", + " print(f\"Loading pretrained model from: {model_path}\")\n", + "\n", + " # 1. ๋ชจ๋ธ ์•„ํ‚คํ…์ฒ˜ ์ •์˜\n", + " if model_type == 'efficientnet':\n", + " model = EfficientNetB0_MNIST(num_classes=10) # 10 ํด๋ž˜์Šค๋กœ ์ •์˜ ํ›„ ๊ฐ€์ค‘์น˜ ๋กœ๋“œ\n", + " elif model_type == 'resnet':\n", + " model = ResNet18_MNIST(num_classes=10)\n", + " elif model_type == 'mobilenet':\n", + " model = MobileNetV3_MNIST(num_classes=10)\n", + " else:\n", + " raise ValueError(f\"Unknown model type: {model_type}\")\n", + " \n", + " # 2. ๊ฐ€์ค‘์น˜ ๋กœ๋“œ\n", + " checkpoint = torch.load(model_path, map_location=device)\n", + " model.load_state_dict(checkpoint['model_state_dict'])\n", + " print(f\"Loaded pretrained {model_type} model.\")\n", + " print(f\" MNIST Test Acc: {checkpoint.get('test_acc', 'N/A'):.2f}%\")\n", + " \n", + " # 3. ๋งˆ์ง€๋ง‰ ๋ ˆ์ด์–ด 5 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\n", + " if model_type == 'efficientnet':\n", + " in_features = model.classifier[1].in_features\n", + " model.classifier[1] = nn.Linear(in_features, num_classes_new)\n", + " elif model_type == 'resnet': \n", + " in_features = model.fc.in_features\n", + " model.fc = nn.Linear(in_features, num_classes_new)\n", + " elif model_type == 'mobilenet':\n", + " in_features = model.classifier[3].in_features\n", + " model.classifier[3] = nn.Linear(in_features, num_classes_new)\n", + "\n", + " model = model.to(device)\n", + " print(f\"Output layer๋ฅผ {num_classes_new} ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝ\")\n", + "\n", + " return model\n", + "\n", + "# ========== Training Functions ==========\n", + "\n", + "def load_answer_data_for_cv(data_dir):\n", + " \"\"\"Answer ๋ฐ์ดํ„ฐ ๋กœ๋“œ: Cross-validation ์šฉ\"\"\"\n", + " image_paths = []\n", + " labels = []\n", + "\n", + " for class_idx in range(1, 6):\n", + " class_dir = data_dir / str(class_idx)\n", + " if not class_dir.exists():\n", + " print(f\"ํด๋ž˜์Šค ๋””๋ ‰ํ† ๋ฆฌ ์—†์Œ: {class_dir}\")\n", + " continue\n", + "\n", + " class_images = list(class_dir.glob(\"*.jpg\")) + list(class_dir.glob(\"*.png\"))\n", + " image_paths.extend(class_images)\n", + " labels.extend([class_idx - 1] * len(class_images))\n", + "\n", + " print(f\" ํด๋ž˜์Šค {class_idx}: {len(class_images)}๊ฐœ ์ด๋ฏธ์ง€\")\n", + "\n", + " if len(image_paths) == 0:\n", + " raise ValueError(f\"๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {data_dir}\")\n", + "\n", + " print(f\" ์ด {len(image_paths)}๊ฐœ ์ด๋ฏธ์ง€ ๋กœ๋“œ\")\n", + "\n", + " return np.array(image_paths), np.array(labels)\n", + "\n", + "\n", + "def train_one_epoch(model, train_loader, criterion, optimizer, device):\n", + " \"\"\"1 ์—ํฌํฌ ํ•™์Šต\"\"\"\n", + " model.train()\n", + " total_loss = 0\n", + " correct = 0\n", + " total = 0\n", + "\n", + " for images, labels in tqdm(train_loader, desc=\"Training\", leave=False):\n", + " images, labels = images.to(device), labels.to(device)\n", + "\n", + " optimizer.zero_grad()\n", + " outputs = model(images)\n", + " loss = criterion(outputs, labels)\n", + "\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + " total_loss += loss.item()\n", + " _, predicted = outputs.max(1)\n", + " total += labels.size(0)\n", + " correct += predicted.eq(labels).sum().item()\n", + "\n", + " avg_loss = total_loss / len(train_loader)\n", + " accuracy = 100. * correct / total\n", + "\n", + " return avg_loss, accuracy\n", + "\n", + "\n", + "def evaluate(model, val_loader, criterion, device):\n", + " \"\"\"๋ชจ๋ธ ํ‰๊ฐ€\"\"\"\n", + " model.eval()\n", + " total_loss = 0\n", + " correct = 0\n", + " total = 0\n", + "\n", + " with torch.no_grad():\n", + " for images, labels in tqdm(val_loader, desc=\"Validation\", leave=False):\n", + " images, labels = images.to(device), labels.to(device)\n", + " outputs = model(images)\n", + " loss = criterion(outputs, labels)\n", + "\n", + " total_loss += loss.item()\n", + " _, predicted = outputs.max(1)\n", + " total += labels.size(0)\n", + " correct += predicted.eq(labels).sum().item()\n", + "\n", + " avg_loss = total_loss / len(val_loader)\n", + " accuracy = 100. * correct / total\n", + "\n", + " return avg_loss, accuracy\n", + "\n", + "\n", + "def evaluate_detailed(model, val_loader, device):\n", + " \"\"\"์ƒ์„ธ ํ‰๊ฐ€ ์ง€ํ‘œ\"\"\"\n", + " model.eval()\n", + " all_preds = []\n", + " all_labels = []\n", + "\n", + " with torch.no_grad():\n", + " for images, labels in val_loader:\n", + " images, labels = images.to(device), labels.to(device)\n", + " outputs = model(images)\n", + " _, predicted = outputs.max(1)\n", + "\n", + " all_preds.extend(predicted.cpu().numpy())\n", + " all_labels.extend(labels.cpu().numpy())\n", + "\n", + " accuracy = accuracy_score(all_labels, all_preds)\n", + " precision, recall, f1, _ = precision_recall_fscore_support(\n", + " all_labels, all_preds, average='weighted', zero_division=0\n", + " )\n", + " cm = confusion_matrix(all_labels, all_preds)\n", + "\n", + " return {\n", + " 'accuracy': accuracy * 100,\n", + " 'precision': precision,\n", + " 'recall': recall,\n", + " 'f1_score': f1,\n", + " 'confusion_matrix': cm\n", + " }\n", + "\n", + "\n", + "def plot_confusion_matrix(cm, model_type, answer_type, fold_idx, save_path):\n", + " \"\"\"Confusion Matrix ์‹œ๊ฐํ™”\"\"\"\n", + " plt.figure(figsize=(8, 6))\n", + " sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',\n", + " xticklabels=['1', '2', '3', '4', '5'],\n", + " yticklabels=['1', '2', '3', '4', '5'])\n", + " plt.xlabel('Predicted')\n", + " plt.ylabel('Actual')\n", + " plt.title(f'{model_type.upper()} - {answer_type} Fold {fold_idx+1} Confusion Matrix')\n", + " plt.savefig(save_path, dpi=150, bbox_inches='tight')\n", + " plt.close()\n", + " print(f\" Confusion Matrix ์ €์žฅ: {save_path}\")\n", + "\n", + "\n", + "# ========== Fine-tuning Function ==========\n", + "\n", + "def finetune_answer_model_with_cv(answer_type, model_type, data_dir, output_dir,\n", + " num_epochs=30, learning_rate=0.0005,\n", + " use_augmentation=True, early_stopping_patience=10,\n", + " n_splits=5):\n", + " \"\"\"Answer ๋ชจ๋ธ Fine-tuning\"\"\"\n", + "\n", + " logger.info(f\"\\n{'='*60}\")\n", + " print(f\"{answer_type} Fine-tuning with {model_type.upper()} (K={n_splits} Cross Validation)\")\n", + " logger.info(f\"{'='*60}\")\n", + "\n", + " device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n", + " logger.info(f\"Device: {device}\")\n", + "\n", + " all_image_paths, all_labels = load_answer_data_for_cv(data_dir)\n", + "\n", + " # Stratified K-Fold for balanced splits\n", + " skf = StratifiedKFold(n_splits=n_splits, shuffle=True, random_state=42)\n", + "\n", + " fold_results = []\n", + " best_overall_acc = 0.0\n", + " best_overall_model_state_dict = None \n", + "\n", + " for fold_idx, (train_index, val_index) in enumerate(skf.split(all_image_paths, all_labels)):\n", + " print(f\"\\n{'#'*40}\")\n", + " print(f\"Starting Fold {fold_idx+1}/{n_splits}\")\n", + " print(f\"{'#'*40}\")\n", + "\n", + " # Create train and validation datasets for this fold\n", + " train_paths, val_paths = all_image_paths[train_index], all_image_paths[val_index]\n", + " train_labels, val_labels = all_labels[train_index], all_labels[val_index]\n", + "\n", + " train_dataset = AnswerDataset(train_paths, train_labels, augment=use_augmentation)\n", + " val_dataset = AnswerDataset(val_paths, val_labels, augment=False)\n", + "\n", + " train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)\n", + " val_loader = DataLoader(val_dataset, batch_size=16, shuffle=False)\n", + "\n", + " print(f\" Fold {fold_idx+1}: Train samples = {len(train_paths)}, Validation samples = {len(val_paths)}\")\n", + " if use_augmentation:\n", + " print(\" Data augmentation enabled for training.\")\n", + "\n", + "\n", + " # 1. ๋ชจ๋ธ ๋กœ๋“œ ๋ฐ ์ˆ˜์ •\n", + " model = load_pretrained(model_type, num_classes_new=5, device=device)\n", + "\n", + " # 2. ํ•™์Šต ์„ค์ •\n", + " criterion = nn.CrossEntropyLoss() \n", + "\n", + " # ๋ชจ๋ธ๋ณ„ ์ตœ์ ํ™” ์„ค์ •\n", + " if model_type == 'efficientnet':\n", + " optimizer = optim.AdamW(model.parameters(), lr=learning_rate, weight_decay=1e-4)\n", + " else:\n", + " optimizer = optim.Adam(model.parameters(), lr=learning_rate, weight_decay=1e-4)\n", + "\n", + " scheduler = optim.lr_scheduler.ReduceLROnPlateau(\n", + " optimizer, mode='max', factor=0.5, patience=3\n", + " )\n", + "\n", + " # 3. ํ•™์Šต ๋ฐ ๊ฒ€์ฆ ๋ฃจํ”„\n", + " best_fold_acc = 0.0\n", + " patience_counter = 0\n", + " fold_history = {'train_loss': [], 'train_acc': [], 'val_loss': [], 'val_acc': []}\n", + " best_model_state_dict_this_fold = None \n", + "\n", + " for epoch in range(num_epochs):\n", + " print(f\"\\n{'='*40}\") # Reduce verbosity during CV epochs\n", + " print(f\"Fold {fold_idx+1} - Epoch {epoch+1}/{num_epochs}\")\n", + "\n", + " train_loss, train_acc = train_one_epoch(model, train_loader, criterion, optimizer, device)\n", + " val_loss, val_acc = evaluate(model, val_loader, criterion, device)\n", + "\n", + " fold_history['train_loss'].append(train_loss)\n", + " fold_history['train_acc'].append(train_acc)\n", + " fold_history['val_loss'].append(val_loss)\n", + " fold_history['val_acc'].append(val_acc)\n", + "\n", + " print(f\" Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.2f}%\")\n", + " print(f\" Val Loss: {val_loss:.4f}, Val Acc: {val_acc:.2f}%\")\n", + "\n", + " scheduler.step(val_acc)\n", + "\n", + " # Best model saving for this fold\n", + " if val_acc > best_fold_acc:\n", + " best_fold_acc = val_acc\n", + " patience_counter = 0\n", + " best_model_state_dict_this_fold = copy.deepcopy(model.state_dict()) # Deep copy the state dict\n", + "\n", + " # Optionally save the best model for this fold\n", + " save_dir = Path(output_dir) / f\"{answer_type}_{model_type}\" / f\"fold_{fold_idx+1}\"\n", + " save_dir.mkdir(parents=True, exist_ok=True)\n", + " save_path = save_dir / \"best_model.pth\"\n", + " torch.save(model.state_dict(), save_path)\n", + " print(f\" ๐ŸŽฏ Best model for Fold {fold_idx+1} saved! Val Acc: {val_acc:.2f}%\")\n", + "\n", + "\n", + " else:\n", + " patience_counter += 1\n", + " print(f\" Early Stopping Counter: {patience_counter}/{early_stopping_patience}\")\n", + "\n", + " if patience_counter >= early_stopping_patience:\n", + " print(f\" Early Stopping at epoch {epoch+1} for Fold {fold_idx+1}\")\n", + " break\n", + "\n", + " # End of Epoch loop for a fold\n", + "\n", + " print(f\"\\nFold {fold_idx+1} finished. Best Validation Accuracy: {best_fold_acc:.2f}%\")\n", + "\n", + " # Evaluate the best model of this fold on its validation set for detailed metrics\n", + " if best_model_state_dict_this_fold is not None:\n", + " model.load_state_dict(best_model_state_dict_this_fold) \n", + " metrics = evaluate_detailed(model, val_loader, device)\n", + " print(f\" Fold {fold_idx+1} Detailed Metrics:\")\n", + " print(f\" Accuracy: {metrics['accuracy']:.2f}%\")\n", + " print(f\" Precision: {metrics['precision']:.4f}\")\n", + " print(f\" Recall: {metrics['recall']:.4f}\")\n", + " print(f\" F1-Score: {metrics['f1_score']:.4f}\")\n", + "\n", + " # Plot Confusion Matrix for this fold\n", + " cm_save_dir = Path(output_dir) / f\"{answer_type}_{model_type}\" / \"confusion_matrices\"\n", + " cm_save_dir.mkdir(parents=True, exist_ok=True)\n", + " cm_path = cm_save_dir / f\"fold_{fold_idx+1}_confusion_matrix.png\"\n", + " plot_confusion_matrix(metrics['confusion_matrix'], model_type, answer_type, fold_idx, cm_path)\n", + "\n", + " fold_results.append(metrics['accuracy'])\n", + "\n", + " # Track the best model across all folds\n", + " if best_fold_acc > best_overall_acc:\n", + " best_overall_acc = best_fold_acc\n", + " best_overall_model_state_dict = copy.deepcopy(best_model_state_dict_this_fold) # Store the state dict\n", + "\n", + " # End of Fold loop\n", + "\n", + " # 4. ๊ฒฐ๊ณผ ์ง‘๊ณ„ ๋ฐ ๋ถ„์„\n", + " print(f\"\\n{'='*60}\")\n", + " print(f\"{answer_type} / {model_type.upper()} Cross Validation Results (K={n_splits})\")\n", + " print(f\"{'='*60}\")\n", + "\n", + " if fold_results:\n", + " mean_accuracy = np.mean(fold_results)\n", + " std_accuracy = np.std(fold_results)\n", + " print(f\"Average Validation Accuracy: {mean_accuracy:.2f}% ยฑ {std_accuracy:.2f}%\")\n", + " print(f\"Individual Fold Accuracies: {fold_results}\")\n", + "\n", + " # Save the model with the highest validation accuracy across all folds\n", + " if best_overall_model_state_dict is not None:\n", + " save_dir = Path(output_dir) / f\"{answer_type}_{model_type}\"\n", + " save_dir.mkdir(parents=True, exist_ok=True)\n", + " save_path = save_dir / \"best_model_overall_cv.pth\" # Save with a distinct name\n", + "\n", + " torch.save({\n", + " 'model_type': model_type,\n", + " 'model_state_dict': best_overall_model_state_dict,\n", + " 'best_cv_acc': best_overall_acc,\n", + " 'mean_cv_acc': mean_accuracy,\n", + " 'std_cv_acc': std_accuracy\n", + " }, save_path)\n", + "\n", + " print(f\"\\n๐Ÿ† Best model across all folds saved! Validation Acc: {best_overall_acc:.2f}%\")\n", + " print(f\" Model saved to: {save_path}\")\n", + "\n", + " else:\n", + " print(\"No fold results available.\")\n", + "\n", + "\n", + " print(f\"\\n{model_type.upper()} - {answer_type} Cross Validation ์™„๋ฃŒ\")\n", + "\n", + "\n", + " # Return average accuracy for overall summary\n", + " return mean_accuracy if fold_results else 0.0\n", + "\n", + "\n", + "# ========== Main Execution ==========\n", + "\n", + "def main():\n", + " \"\"\"๋ฉ”์ธ ์‹คํ–‰ - ์ง€์ •๋œ ๋ชจ๋ธ๋กœ Answer_1, Answer_2 ํ•™์Šต\"\"\"\n", + "\n", + " # ๊ฒฝ๋กœ ์„ค์ •\n", + " base_dir = Path(\".\")\n", + "\n", + " answer_data_root = base_dir\n", + " output_root = base_dir / \"answer_models_cv_results\" \n", + "\n", + " # ์‹คํ–‰ํ•  ๋ชจ๋ธ ๋ฐ ๋ฐ์ดํ„ฐ์…‹ ์กฐํ•ฉ\n", + " models_to_run_cv = [\n", + " {'answer': 'answer_1', 'type': 'resnet'}, \n", + " {'answer': 'answer_2', 'type': 'resnet'},\n", + " {'answer': 'answer_1', 'type': 'mobilenet'},\n", + " {'answer': 'answer_2', 'type': 'mobilenet'},\n", + " {'answer': 'answer_1', 'type': 'efficientnet'},\n", + " {'answer': 'answer_2', 'type': 'efficientnet'},\n", + " ]\n", + "\n", + " # fold ์ˆ˜\n", + " N_SPLITS = 5\n", + "\n", + " # ๊ฒฐ๊ณผ ์ €์žฅ์šฉ\n", + " cv_results_summary = {}\n", + "\n", + " for item in models_to_run_cv:\n", + " answer_type = item['answer']\n", + " model_type = item['type']\n", + " data_dir = answer_data_root / answer_type\n", + "\n", + " if not data_dir.exists():\n", + " print(f\"๋ฐ์ดํ„ฐ ํด๋” ์—†์Œ: {data_dir}. {answer_type}\")\n", + " continue\n", + "\n", + " # Determine appropriate epochs and patience based on previous runs or knowledge\n", + " if answer_type == 'answer_1':\n", + " num_epochs = 60 \n", + " learning_rate = 0.0001\n", + " early_stopping_patience = 20\n", + " elif answer_type == 'answer_2':\n", + " num_epochs = 25\n", + " learning_rate = 0.0005\n", + " early_stopping_patience = 15\n", + " else:\n", + " num_epochs = 30\n", + " learning_rate = 0.0005\n", + " early_stopping_patience = 10\n", + "\n", + "\n", + " mean_acc = finetune_answer_model_with_cv(\n", + " answer_type=answer_type,\n", + " model_type=model_type,\n", + " data_dir=data_dir,\n", + " output_dir=output_root,\n", + " num_epochs=num_epochs,\n", + " learning_rate=learning_rate,\n", + " use_augmentation=True,\n", + " early_stopping_patience=early_stopping_patience,\n", + " n_splits=N_SPLITS\n", + " )\n", + " cv_results_summary[f\"{answer_type}_{model_type}\"] = mean_acc\n", + "\n", + "\n", + " # ========== ์ตœ์ข… ๊ฒฐ๊ณผ ์š”์•ฝ ==========\n", + " print(f\"\\n{'='*60}\")\n", + " print(\"๐Ÿ† Cross Validation ์ตœ์ข… ๊ฒฐ๊ณผ ์š”์•ฝ\")\n", + " print(f\"{'='*60}\")\n", + "\n", + " for answer_type in ['answer_1', 'answer_2']:\n", + " print(f\"\\n {answer_type} ํ‰๊ท  Validation Accuracy:\")\n", + " for model_type in ['efficientnet', 'resnet', 'mobilenet']:\n", + " key = f\"{answer_type}_{model_type}\"\n", + " if key in cv_results_summary:\n", + " print(f\" {model_type.upper()}: {cv_results_summary[key]:.2f}%\")\n", + "\n", + "\n", + " print(f\"\\n{'='*60}\")\n", + " print(\"๋ชจ๋“  Cross Validation ํ•™์Šต ์™„๋ฃŒ\")\n", + " print(f\"๊ฒฐ๊ณผ ์ €์žฅ ์œ„์น˜: {output_root}\")\n", + " print(f\"{'='*60}\")\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3efe0a7", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "ffcb9ad3", + "metadata": {}, + "source": [ + "Kaggle์— ๋ชจ๋ธ ์—…๋กœ๋“œ" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "ea344d8c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "======================================================================\n", + "๐Ÿ“ฆ Fine-tuned ๋ชจ๋ธ ์—…๋กœ๋“œ ์ค€๋น„\n", + "======================================================================\n", + "\n", + "๐Ÿ“‹ ๋ณต์‚ฌํ•  ๋ชจ๋ธ:\n", + " โœ… answer_1_efficientnet.pth (4.15 MB)\n", + " โœ… answer_1_resnet.pth (42.69 MB)\n", + " โœ… answer_1_mobilenet.pth (3.86 MB)\n", + " โœ… answer_2_efficientnet.pth (4.15 MB)\n", + " โœ… answer_2_resnet.pth (42.69 MB)\n", + " โœ… answer_2_mobilenet.pth (3.86 MB)\n", + " โœ… README.md\n", + "\n", + "======================================================================\n", + "โœ… ์ค€๋น„ ์™„๋ฃŒ!\n", + "๐Ÿ“ ์—…๋กœ๋“œ ํด๋”: /Users/min-yujin/Gradi_25Fall/ai-service/test/CNN/kaggle_finetuned_upload\n", + "๐Ÿ“ฆ ํŒŒ์ผ ๊ฐœ์ˆ˜: 7 (๋ชจ๋ธ 6๊ฐœ + README)\n", + "\n", + "๐Ÿ’ก ๋‹ค์Œ ๋‹จ๊ณ„:\n", + " 1. https://www.kaggle.com/datasets ์ ‘์†\n", + " 2. 'New Dataset' ํด๋ฆญ\n", + " 3. 'kaggle_finetuned_upload' ํด๋”์˜ ๋ชจ๋“  ํŒŒ์ผ์„ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ\n", + " 4. Title: 'mnist-finetuned-models'\n", + " 5. 'Create' ํด๋ฆญ\n", + "======================================================================\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "Fine-tuned ๋ชจ๋ธ์„ Kaggle ์—…๋กœ๋“œ์šฉ์œผ๋กœ ์ค€๋น„ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ\n", + "\"\"\"\n", + "\n", + "import shutil\n", + "from pathlib import Path\n", + "\n", + "def prepare_finetuned_models():\n", + " \"\"\"Fine-tuned ๋ชจ๋ธ ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํด๋”๋กœ ๋ณต์‚ฌ\"\"\"\n", + " \n", + " print(\"=\"*70)\n", + " print(\"๐Ÿ“ฆ Fine-tuned ๋ชจ๋ธ ์—…๋กœ๋“œ ์ค€๋น„\")\n", + " print(\"=\"*70)\n", + " \n", + " # ์†Œ์Šค ๋””๋ ‰ํ† ๋ฆฌ\n", + " source_dir = Path(\"answer_models_cv_results\")\n", + " \n", + " # ์—…๋กœ๋“œ ํด๋” ์ƒ์„ฑ\n", + " upload_dir = Path(\"kaggle_finetuned_upload\")\n", + " if upload_dir.exists():\n", + " shutil.rmtree(upload_dir)\n", + " upload_dir.mkdir()\n", + " \n", + " # ๋ชจ๋ธ ์„ค์ •\n", + " models = [\n", + " ('answer_1', 'efficientnet'),\n", + " ('answer_1', 'resnet'),\n", + " ('answer_1', 'mobilenet'),\n", + " ('answer_2', 'efficientnet'),\n", + " ('answer_2', 'resnet'),\n", + " ('answer_2', 'mobilenet'),\n", + " ]\n", + " \n", + " print(\"\\n๐Ÿ“‹ ๋ณต์‚ฌํ•  ๋ชจ๋ธ:\")\n", + " copied_files = []\n", + " \n", + " for answer_type, model_type in models:\n", + " # ์†Œ์Šค ํŒŒ์ผ ๊ฒฝ๋กœ\n", + " source_file = source_dir / f\"{answer_type}_{model_type}\" / \"best_model_overall_cv.pth\"\n", + " \n", + " if not source_file.exists():\n", + " print(f\" โš ๏ธ ํŒŒ์ผ ์—†์Œ: {source_file}\")\n", + " continue\n", + " \n", + " # ๋Œ€์ƒ ํŒŒ์ผ ๊ฒฝ๋กœ\n", + " dest_file = upload_dir / f\"{answer_type}_{model_type}.pth\"\n", + " \n", + " # ๋ณต์‚ฌ\n", + " shutil.copy(source_file, dest_file)\n", + " \n", + " # ํŒŒ์ผ ํฌ๊ธฐ ํ™•์ธ\n", + " size_mb = source_file.stat().st_size / (1024 * 1024)\n", + " print(f\" โœ… {dest_file.name} ({size_mb:.2f} MB)\")\n", + " copied_files.append(dest_file.name)\n", + " \n", + " # README.md ์ƒ์„ฑ\n", + " readme_content = \"\"\"# MNIST Fine-tuned Models (Answer Classification)\n", + "\n", + "MNIST base ๋ชจ๋ธ์„ Answer_1, Answer_2 ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ fine-tuningํ•œ ๋ชจ๋ธ๋“ค์ž…๋‹ˆ๋‹ค.\n", + "\n", + "## ๋ชจ๋ธ ๋ชฉ๋ก\n", + "\n", + "### Answer_1 ๋ชจ๋ธ (5-class classification)\n", + "- `answer_1_efficientnet.pth` - EfficientNet-B0 fine-tuned\n", + "- `answer_1_resnet.pth` - ResNet-18 fine-tuned\n", + "- `answer_1_mobilenet.pth` - MobileNetV3-Small fine-tuned\n", + "\n", + "### Answer_2 ๋ชจ๋ธ (5-class classification)\n", + "- `answer_2_efficientnet.pth` - EfficientNet-B0 fine-tuned\n", + "- `answer_2_resnet.pth` - ResNet-18 fine-tuned\n", + "- `answer_2_mobilenet.pth` - MobileNetV3-Small fine-tuned\n", + "\n", + "## ์‚ฌ์šฉ ๋ฐฉ๋ฒ•\n", + "\n", + "```python\n", + "import torch\n", + "from kaggle.api.kaggle_api_extended import KaggleApi\n", + "\n", + "# ๋‹ค์šด๋กœ๋“œ\n", + "api = KaggleApi()\n", + "api.authenticate()\n", + "api.dataset_download_files('minyujin03/mnist-finetuned-models', path='./models', unzip=True)\n", + "\n", + "# ๋ชจ๋ธ ๋กœ๋“œ\n", + "checkpoint = torch.load('./models/answer_1_efficientnet.pth')\n", + "# checkpoint์—๋Š” 'model_state_dict', 'best_cv_acc', 'mean_cv_acc' ๋“ฑ์ด ํฌํ•จ๋จ\n", + "```\n", + "\n", + "## ๋ชจ๋ธ ์ •๋ณด\n", + "- **Base Models**: MNIST pre-trained (from `minyujin03/mnist-base-models`)\n", + "- **Fine-tuning**: Answer_1, Answer_2 datasets \n", + "- **ํด๋ž˜์Šค ์ˆ˜**: 5 (1, 2, 3, 4, 5)\n", + "- **Cross Validation**: 5-fold\n", + "- **Input Size**: 28x28 (grayscale)\n", + "\"\"\"\n", + " \n", + " readme_path = upload_dir / \"README.md\"\n", + " with open(readme_path, 'w', encoding='utf-8') as f:\n", + " f.write(readme_content)\n", + " \n", + " print(f\" โœ… README.md\")\n", + " \n", + " print(f\"\\n{'='*70}\")\n", + " print(f\"โœ… ์ค€๋น„ ์™„๋ฃŒ!\")\n", + " print(f\"๐Ÿ“ ์—…๋กœ๋“œ ํด๋”: {upload_dir.absolute()}\")\n", + " print(f\"๐Ÿ“ฆ ํŒŒ์ผ ๊ฐœ์ˆ˜: {len(copied_files) + 1} (๋ชจ๋ธ {len(copied_files)}๊ฐœ + README)\")\n", + " print(f\"\\n๐Ÿ’ก ๋‹ค์Œ ๋‹จ๊ณ„:\")\n", + " print(f\" 1. https://www.kaggle.com/datasets ์ ‘์†\")\n", + " print(f\" 2. 'New Dataset' ํด๋ฆญ\")\n", + " print(f\" 3. '{upload_dir}' ํด๋”์˜ ๋ชจ๋“  ํŒŒ์ผ์„ ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ\")\n", + " print(f\" 4. Title: 'mnist-finetuned-models'\")\n", + " print(f\" 5. 'Create' ํด๋ฆญ\")\n", + " print(f\"{'='*70}\")\n", + "\n", + "if __name__ == \"__main__\":\n", + " prepare_finetuned_models()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "gradi", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ai-service/test/Classification/answer_classifier_README.md b/ai-service/test/Classification/answer_classifier_README.md new file mode 100644 index 0000000..736b6c5 --- /dev/null +++ b/ai-service/test/Classification/answer_classifier_README.md @@ -0,0 +1,50 @@ +`answer_classifier.ipynb` ์ฝ”๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค. + +ํ•ด๋‹น ์ฝ”๋“œ๋Š” mnist๋ฅผ ํ•™์Šต์‹œํ‚จ 3๊ฐ€์ง€ base model์— ์ถ”๊ฐ€์ ์œผ๋กœ answer_1, answer_2๋ฅผ finetunedํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. +mnist_base_model.ipynb์—์„œ ํ•™์Šต ์™„๋ฃŒ๋œ ๋ชจ๋ธ ๋งˆ์ง€๋ง‰ ๋ ˆ์ด์–ด๋ฅผ 5-class๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ answer_1, answer_2๋ฅผ ๋งž์ถœ ์ˆ˜ ์žˆ๋„๋ก ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. + +๋ฐ์ดํ„ฐ์…‹์ด ์ƒ๋Œ€์ ์œผ๋กœ ์ ๊ธฐ ๋•Œ๋ฌธ์— ์ฆ๊ฐ•์„ ์ ์šฉํ–ˆ์œผ๋ฉฐ 5-fold validation์„ ์ ์šฉํ•ด ์„ฑ๋Šฅ์„ ํ™•์ธํ•˜์˜€์Šต๋‹ˆ๋‹ค. + +*๊ฒฐ๊ณผ ๋ชจ๋ธ (์ด 6๊ฐ€์ง€)* +1. answer_1์˜ EfficientNet-B0 +2. answer_2์˜ EfficientNet-B0 +3. answer_1์˜ ResNet18 +4. answer_2์˜ ResNet18 +5. answer_1์˜ MobileNetV3 +6. answer_2์˜ MobileNetV3 + + +*Best CV ์„ฑ๋Šฅ ๊ฒฐ๊ณผ* +############################################################ +############################################################ +answer_1์˜ ResNet18: Best CV Validation Acc: 94.20% +answer_2์˜ ResNet18: Best CV Validation Acc: 100.00% + +answer_1์˜ EfficientNet-B0: Best CV Validation Acc: 85.92% +answer_2์˜ EfficientNet-B0: Best CV Validation Acc: 100.00% + +answer_1์˜ MobileNetV3: Best CV Validation Acc: 80.58% +answer_2์˜ MobileNetV3: Best CV Validation Acc: 100.00% + +############################################################ +############################################################ + + +*ํ‰๊ท  ์„ฑ๋Šฅ ๊ฒฐ๊ณผ* +############################################################ +############################################################ +๐Ÿ“Š answer_1 ํ‰๊ท  Validation Accuracy (Cross Validation): + EFFICIENTNET: 83.82% + RESNET: 91.28% + MOBILENET: 77.04% + +๐Ÿ“Š answer_2 ํ‰๊ท  Validation Accuracy (Cross Validation): + EFFICIENTNET: 99.89% + RESNET: 99.78% + MOBILENET: 99.35% +############################################################ +############################################################ + +์œ„ 6๊ฐ€์ง€ ๋ชจ๋ธ์— ๋Œ€ํ•œ ๋ฏธ์„ธ์กฐ์ • ํ•™์Šต์€ ์ด๋ฏธ ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉฐ +**๋”ฐ๋ผ์„œ, `answer_classifier.ipynb` ์ฝ”๋“œ๋Š” ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.** + diff --git a/ai-service/test/Classification/kaggle_models/answer_1_efficientnet.pth b/ai-service/test/Classification/kaggle_models/answer_1_efficientnet.pth new file mode 100644 index 0000000..6b880df Binary files /dev/null and b/ai-service/test/Classification/kaggle_models/answer_1_efficientnet.pth differ diff --git a/ai-service/test/Classification/kaggle_models/answer_1_mobilenet.pth b/ai-service/test/Classification/kaggle_models/answer_1_mobilenet.pth new file mode 100644 index 0000000..2126a28 Binary files /dev/null and b/ai-service/test/Classification/kaggle_models/answer_1_mobilenet.pth differ diff --git a/ai-service/test/Classification/kaggle_models/answer_1_resnet.pth b/ai-service/test/Classification/kaggle_models/answer_1_resnet.pth new file mode 100644 index 0000000..eff1a8e Binary files /dev/null and b/ai-service/test/Classification/kaggle_models/answer_1_resnet.pth differ diff --git a/ai-service/test/Classification/kaggle_models/answer_2_efficientnet.pth b/ai-service/test/Classification/kaggle_models/answer_2_efficientnet.pth new file mode 100644 index 0000000..08d0e83 Binary files /dev/null and b/ai-service/test/Classification/kaggle_models/answer_2_efficientnet.pth differ diff --git a/ai-service/test/Classification/kaggle_models/answer_2_mobilenet.pth b/ai-service/test/Classification/kaggle_models/answer_2_mobilenet.pth new file mode 100644 index 0000000..6ace207 Binary files /dev/null and b/ai-service/test/Classification/kaggle_models/answer_2_mobilenet.pth differ diff --git a/ai-service/test/Classification/kaggle_models/answer_2_resnet.pth b/ai-service/test/Classification/kaggle_models/answer_2_resnet.pth new file mode 100644 index 0000000..b52495b Binary files /dev/null and b/ai-service/test/Classification/kaggle_models/answer_2_resnet.pth differ diff --git a/ai-service/test/Classification/mnist_base_model.ipynb b/ai-service/test/Classification/mnist_base_model.ipynb new file mode 100644 index 0000000..104de34 --- /dev/null +++ b/ai-service/test/Classification/mnist_base_model.ipynb @@ -0,0 +1,1746 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "283f36f2", + "metadata": {}, + "source": [ + "'mnist_base_model.ipynb'๋Š” ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ํ•ด๋‹น README.md๋ฅผ ์ฝ์–ด์ฃผ์„ธ์š”" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c2c79e24", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "############################################################\n", + "# EFFICIENTNET ๋ชจ๋ธ ํ•™์Šต ์‹œ์ž‘\n", + "############################################################\n", + "๋””๋ฐ”์ด์Šค: cpu\n", + "๋ชจ๋ธ ํƒ€์ž…: efficientnet\n", + "Train dataset: 60000๊ฐœ\n", + "Test dataset: 10000๊ฐœ\n", + "EfficientNet-B0 ๋ชจ๋ธ ์ƒ์„ฑ\n", + "Total parameters: 1,060,042\n", + "Trainable parameters: 1,060,042\n", + "\n", + "==================================================\n", + "EFFICIENTNET MNIST ๋ชจ๋ธ ํ•™์Šต ์‹œ์ž‘\n", + "==================================================\n", + "\n", + "==================================================\n", + "Epoch 1/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [43:06<00:00, 5.51s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:41<00:00, 1.91it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.1922, Train Acc: 93.82%\n", + "Test Loss: 0.0402, Test Acc: 98.69%\n", + "Learning Rate: 0.001000\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_efficientnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 2/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:30<00:00, 5.44s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:41<00:00, 1.91it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0517, Train Acc: 98.46%\n", + "Test Loss: 0.0316, Test Acc: 98.98%\n", + "Learning Rate: 0.000989\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_efficientnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 3/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:42<00:00, 5.46s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:39<00:00, 2.02it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0388, Train Acc: 98.85%\n", + "Test Loss: 0.0262, Test Acc: 99.19%\n", + "Learning Rate: 0.000957\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_efficientnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 4/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:31<00:00, 5.44s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:40<00:00, 1.95it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0335, Train Acc: 98.95%\n", + "Test Loss: 0.0267, Test Acc: 99.17%\n", + "Learning Rate: 0.000905\n", + "\n", + "==================================================\n", + "Epoch 5/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [43:34<00:00, 5.58s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:50<00:00, 1.58it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0301, Train Acc: 99.06%\n", + "Test Loss: 0.0229, Test Acc: 99.36%\n", + "Learning Rate: 0.000835\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_efficientnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 6/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:32<00:00, 5.44s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:50<00:00, 1.58it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0241, Train Acc: 99.26%\n", + "Test Loss: 0.0234, Test Acc: 99.32%\n", + "Learning Rate: 0.000750\n", + "\n", + "==================================================\n", + "Epoch 7/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:25<00:00, 5.43s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:49<00:00, 1.58it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0185, Train Acc: 99.44%\n", + "Test Loss: 0.0194, Test Acc: 99.42%\n", + "Learning Rate: 0.000655\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_efficientnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 8/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:22<00:00, 5.42s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:41<00:00, 1.91it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0160, Train Acc: 99.49%\n", + "Test Loss: 0.0185, Test Acc: 99.40%\n", + "Learning Rate: 0.000552\n", + "\n", + "==================================================\n", + "Epoch 9/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:37<00:00, 5.45s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:40<00:00, 1.95it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0124, Train Acc: 99.62%\n", + "Test Loss: 0.0199, Test Acc: 99.42%\n", + "Learning Rate: 0.000448\n", + "\n", + "==================================================\n", + "Epoch 10/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:45<00:00, 5.47s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:41<00:00, 1.92it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0091, Train Acc: 99.71%\n", + "Test Loss: 0.0182, Test Acc: 99.37%\n", + "Learning Rate: 0.000345\n", + "\n", + "==================================================\n", + "Epoch 11/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:41<00:00, 5.46s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:49<00:00, 1.61it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0069, Train Acc: 99.78%\n", + "Test Loss: 0.0163, Test Acc: 99.53%\n", + "Learning Rate: 0.000250\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_efficientnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 12/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:49<00:00, 5.48s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:50<00:00, 1.58it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0051, Train Acc: 99.85%\n", + "Test Loss: 0.0155, Test Acc: 99.53%\n", + "Learning Rate: 0.000165\n", + "\n", + "==================================================\n", + "Epoch 13/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:45<00:00, 5.47s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:52<00:00, 1.51it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0037, Train Acc: 99.88%\n", + "Test Loss: 0.0146, Test Acc: 99.52%\n", + "Learning Rate: 0.000095\n", + "\n", + "==================================================\n", + "Epoch 14/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [42:02<00:00, 5.38s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:49<00:00, 1.60it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0024, Train Acc: 99.94%\n", + "Test Loss: 0.0148, Test Acc: 99.61%\n", + "Learning Rate: 0.000043\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_efficientnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 15/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [41:55<00:00, 5.36s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:48<00:00, 1.62it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0023, Train Acc: 99.93%\n", + "Test Loss: 0.0149, Test Acc: 99.60%\n", + "Learning Rate: 0.000011\n", + "\n", + "==================================================\n", + "ํ•™์Šต ์™„๋ฃŒ - ์ตœ๊ณ  Test Accuracy: 99.61%\n", + "==================================================\n" + ] + }, + { + "data": { + "image/png": "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fTFt2jQ888wz6NOnj+mYSZMmqawp6lql1fVqxWLBoBQREZGLTt+75JJL8N1336nnBw4cUEU5JTB13333qdVjyLVIECoxIlA9z+EUPiIiIpciwabt27fjpZdewr59+/Dkk09aBaREr169cNFFFzntGr1t6l73yCCEBnJCARERkUsGpf766y8cc8wx6vl///tfDBgwAL/88gvee+89vPXWW/a+RrJjXantDEoRERG5lB07dmDp0qW44IIL4O9vO5s5NDRUZVPZQ0VFhSqunpqaiuDgYIwePRpr16417ZdseFvtiSeegNdM3WM9KSIiItcNSknNg8BAY+aN1Dc455xz1HO5q5eXl3dY53rxxReRlpaGoKAgjBw5UmVctWXz5s2YPHmyOl4GR/Pnz+/UOWtra3HDDTcgNjYWYWFh6pz5+fnwhil8LHZORETkWgoKCvDbb7+12i7b1q1bZ/fPu/LKK1XNqnfeeQebNm3CqaeeivHjx6ssLSFjOcsmRdZl3CXjJU/HIudERERuEJTq378/FixYgB9//FENak477TS1XVaLkUBPRy1evBi33367WmFG6ikMGjQIEyZMUIMzW6qrq5Geno5HH30USUlJnT7nbbfdhi+++AIffvghvv/+e3Xd5513HjxZlqnYeYWzL4WIiIgsyI0yqdfZkgSJZJ891dTU4OOPP8bjjz+OsWPHIjMzE7Nnz1aPMn1QyBjLsn322Wc46aST1BjM0zEoRURE5Fidmiz/2GOPqYKbksY9ffp0FfgRn3/+uWlaX0c8/fTTuOqqq3DZZZep1xLo+vLLL9UduXvuucdmzQWtyKet/R05Z1lZGV5//XVVmP3kk09Wx0g6fN++ffHrr7+qlW48EafvERERuaYtW7Zg6NChrbYPGTJE7bOnxsZGNDU1qWxySzKN76effmp1vGSSyzhq4cKF7Z63rq5ONU15ebl61Ov1qtmTnM9gMNj9vJZBqYy40C45v711ZV+4G/aFGfvCjH1hxr4wY184pi86es5OBaVOPPFEFBUVqQFHdHS0abusvBcSEtKhc9TX12P9+vWYOXOmaZusOCPp46tXr+7MZXXonLJfph/KNo1MO+zZs6c6xlODUtodv70lNaiub0RIAIt3EhERuQIpiSDBn5aZSDJ1zs/Pvr+vw8PDMWrUKMydO1fdkEtMTFSr/skYSLKlWpJglLzn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UNugR4DOFz2ig519OURERNSMQSmyWew8O591pYiIiMizpu71iguFn47DXyIiIlfB38pkJbO5rhQzpYiIiMhT5BRy6h4REZErYlCKrHD6HhEREXlqplQGg1JEREQuhUEpsjl9b1dRFRqa9M6+HCIiIiL7rbzHoBQREZFLYVCKrCRFBCEs0A+NegN2F3MFPiIiInJvBoMB2dr0vXgGpYiIiFwJg1LUagU+LbV9ez6n8BEREZF7K66qR2l1A3x8gPT4UGdfDhEREVlgUIpaYV0pIiIi8rSpeynRIQjy1zn7coiIiMgCg1LUCoNSRERE5HFFzpklRURE5HIYlKI2i51vz69w9qUQERERHREWOSciInJdDEpRK1kJ4epxR1EVmvQGZ18OERERUaflaEXOGZQiIiJyOQxKUSvJUcEI8vdFfaMeew5WO/tyiIiIiDoth5lSRERELotBKWrF19cHGc1LJrOuFBEREbmrqrpG7C+rVc8z442Z4EREROQ6XCIo9eKLLyItLQ1BQUEYOXIk1qxZ0+7xH374Ifr06aOOP/roo/HVV19Z7b/00kvh4+Nj1U477TSrYw4ePIipU6ciIiICUVFRuOKKK1BZyQBM62LnrCtFRERE7j11Ly4sEJEh/s6+HCIiInK1oNTixYtx++23Y9asWdiwYQMGDRqECRMmoKCgwObxv/zyCy6++GIVRPr9998xceJE1f766y+r4yQIlZeXZ2rvv/++1X4JSG3evBnLly/H//73P/zwww+4+uqru/RrdSdZica7iZ9v3I8t+8udfTlERERER1DknCvvERERuSKnB6WefvppXHXVVbjsssvQr18/LFiwACEhIXjjjTdsHv/ss8+qgNOMGTPQt29fzJ07F0OHDsULL7xgdVxgYCCSkpJMLTo62rTv77//xtKlS/Haa6+pzKwxY8bg+eefxwcffID9+/d3+dfsDib0T1R1pbYeqMCZz/+IGR/+gfxyY/o7ERERkTvgyntERESuzc+ZH15fX4/169dj5syZpm2+vr4YP348Vq9ebfM9sl0yqyxJZtWnn35qtW3VqlVISEhQwaiTTz4ZDz/8MGJjY03nkCl7w4cPNx0vnymf/dtvv2HSpEmtPreurk41TXm5MXtIr9erZk9yPoPBYPfzHo70uFAsu+V4PLHsH/xvUx4+XL8X//szD1cd3wtXj+2FkADH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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ํ•™์Šต ๊ทธ๋ž˜ํ”„ ์ €์žฅ: mnist_models/efficientnet_history.png\n", + "\n", + "############################################################\n", + "# RESNET ๋ชจ๋ธ ํ•™์Šต ์‹œ์ž‘\n", + "############################################################\n", + "๋””๋ฐ”์ด์Šค: cpu\n", + "๋ชจ๋ธ ํƒ€์ž…: resnet\n", + "Train dataset: 60000๊ฐœ\n", + "Test dataset: 10000๊ฐœ\n", + "ResNet-18 ๋ชจ๋ธ ์ƒ์„ฑ\n", + "Total parameters: 11,172,810\n", + "Trainable parameters: 11,172,810\n", + "\n", + "==================================================\n", + "RESNET MNIST ๋ชจ๋ธ ํ•™์Šต ์‹œ์ž‘\n", + "==================================================\n", + "\n", + "==================================================\n", + "Epoch 1/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:37<00:00, 1.74s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.68it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.1215, Train Acc: 96.23%\n", + "Test Loss: 0.0438, Test Acc: 98.67%\n", + "Learning Rate: 0.001000\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 2/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:41<00:00, 1.75s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.69it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0496, Train Acc: 98.44%\n", + "Test Loss: 0.0275, Test Acc: 99.15%\n", + "Learning Rate: 0.000989\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 3/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:29<00:00, 1.73s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.70it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0362, Train Acc: 98.89%\n", + "Test Loss: 0.0284, Test Acc: 99.06%\n", + "Learning Rate: 0.000957\n", + "\n", + "==================================================\n", + "Epoch 4/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:40<00:00, 1.75s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.70it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0308, Train Acc: 99.05%\n", + "Test Loss: 0.0276, Test Acc: 99.23%\n", + "Learning Rate: 0.000905\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 5/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:42<00:00, 1.75s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.69it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0259, Train Acc: 99.19%\n", + "Test Loss: 0.0236, Test Acc: 99.24%\n", + "Learning Rate: 0.000835\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 6/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:43<00:00, 1.76s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:47<00:00, 1.66it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0212, Train Acc: 99.33%\n", + "Test Loss: 0.0200, Test Acc: 99.27%\n", + "Learning Rate: 0.000750\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 7/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:25<00:00, 1.72s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.69it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0191, Train Acc: 99.37%\n", + "Test Loss: 0.0251, Test Acc: 99.21%\n", + "Learning Rate: 0.000655\n", + "\n", + "==================================================\n", + "Epoch 8/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:41<00:00, 1.75s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.68it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0164, Train Acc: 99.48%\n", + "Test Loss: 0.0209, Test Acc: 99.38%\n", + "Learning Rate: 0.000552\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 9/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:43<00:00, 1.76s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:47<00:00, 1.67it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0116, Train Acc: 99.63%\n", + "Test Loss: 0.0158, Test Acc: 99.43%\n", + "Learning Rate: 0.000448\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 10/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:43<00:00, 1.76s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.69it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0092, Train Acc: 99.69%\n", + "Test Loss: 0.0154, Test Acc: 99.58%\n", + "Learning Rate: 0.000345\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 11/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:36<00:00, 1.74s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:43<00:00, 1.80it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0062, Train Acc: 99.80%\n", + "Test Loss: 0.0121, Test Acc: 99.63%\n", + "Learning Rate: 0.000250\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 12/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:34<00:00, 1.74s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.70it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0056, Train Acc: 99.84%\n", + "Test Loss: 0.0114, Test Acc: 99.61%\n", + "Learning Rate: 0.000165\n", + "\n", + "==================================================\n", + "Epoch 13/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:41<00:00, 1.75s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.69it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0036, Train Acc: 99.88%\n", + "Test Loss: 0.0112, Test Acc: 99.63%\n", + "Learning Rate: 0.000095\n", + "\n", + "==================================================\n", + "Epoch 14/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:43<00:00, 1.76s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.70it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0027, Train Acc: 99.93%\n", + "Test Loss: 0.0102, Test Acc: 99.68%\n", + "Learning Rate: 0.000043\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 15/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [13:36<00:00, 1.74s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:46<00:00, 1.70it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0026, Train Acc: 99.93%\n", + "Test Loss: 0.0101, Test Acc: 99.69%\n", + "Learning Rate: 0.000011\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_resnet_mnist_model.pth\n", + "\n", + "==================================================\n", + "ํ•™์Šต ์™„๋ฃŒ - ์ตœ๊ณ  Test Accuracy: 99.69%\n", + "==================================================\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAGGCAYAAACqvTJ0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAu3JJREFUeJzs3Qd4VNXWBuAvvVfSC4TeQu+ogIpUC0VA1IsCtqteu16xoNiwoGL7sVyxgBQBQVEEEQELIE0goXdITyC9l/mftU8mM2kQyCRT8r3P3Xdmzpw5c7LDmD3rrL22nU6n04GIiIiIiIiIiKgR2TfmmxEREREREREREQkGpYiIiIiIiIiIqNExKEVERERERERERI2OQSkiIiIiIiIiImp0DEoREREREREREVGjY1CKiIiIiIiIiIgaHYNSRERERERERETU6BiUIiIiIiIiIiKiRsegFBERERERERERNToGpYiIiIiIiIiIqNExKEVEdfbll1/Czs6uojk6OiI8PBx33nkn4uPjq+0/ZMiQSvsbtw4dOlTaNyYmBjfffDNatGgBV1dXddzrrrsOH3zwQaX9oqKi1Ov/85//VHu/TZs2qeeWL19e6zlXbdu2bVPnf6F99E32M2U/7ty50yTHIyIioobHcZBpxkHG/u///k8du1+/fiY/NhFZB0dznwARWZ+XXnoJLVu2REFBgRrMyIDnzz//RGxsrBpIGYuIiMDs2bOrHcPHx6fi/pYtW3D11VejefPmuPvuuxESEoKzZ8+qY7/33ns1Drw+++wzzJgxA2FhYZd0zlW1adMG9957L4YOHVqx7eTJk5g5cybuueceXHXVVRXbW7duXaf3IiIiItvFcZDpfPPNNyrQtn37dhw7dkydDxE1LQxKEdElGzlyJHr37q3u33XXXQgICMAbb7yBH374ARMnTqw26Lr99tsveLxXX31V7bdjxw74+vpWei4lJaXa/p07d8bhw4fx+uuv4/3337/kc65Kzn/AgAEVjyWDSQZjsu1i505ERERNC8dBpiHBLwnIfffddyowJgGqF154AZYoNzcXHh4e5j4NIpvE6XtEVG/6q2jHjx+/rNfL62SAVXUgJoKCgqptkytqU6ZMUVcJExISYKv++ecfNYj09vaGp6cnrr32WnXV1FhxcTFmzZqFtm3bqquzzZo1w5VXXon169dX7JOUlISp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ZQljSfkuLCxUj2UaYNXfiQzeZHlj/T5ERER0+TgOqvs4SAIvEniSUgIyNbFqe/DBB9XKeZKBJiQbTT+dsSp9n8k+siKfBAVr20dWOJTxlUy1NPZ///d/df459XWujH9Xcr9qPS+5uCgXCCWLXab71XQ+elILa+TIkeoioQTrpAyDbCNqSpgpRUQm8eSTT2LChAkqhfm+++6rNL++tmwcfXqyFKaU4IkUsZT59VJPYcuWLSodXAqESgbQheivEsqVq9r8/PPPKsuoKilOaVxMvDHJYGXt2rXVtkthzFdeeUVdeZMA1P33369qG8hVUAkkGQ86pcaEDIZ79eqlMqZ27typCmbKoE7IFb1rr71WpcTLvnIcGdhJgEuuzhEREVH9cRxUNxJskqBTbcXbpZ6SBHUkQCMZQ9KvMq6Rvp02bZoa75w/f14dR7KppAi6ZC19/fXXKuNo+/btuOqqq1QR8l9//VWNoaT2po+PjzrGBx98oKbySZ/9+OOPSElJqfO5y+9GXvfEE08gPj5eXSCUIutVa0uJ999/X43hpKTCPffcg5YtW6oLjTL1T2qEGZPzl4CcePnlly+5T4msnrmX/yMi66FfVliWCq6qtLRU17p1a9VKSkouuhSy8X9+fv75Z920adN0HTp00Hl6euqcnZ11bdq00f3nP//RJScn17oUsrGjR4+qpZQvZSnk2pY7builkC92TvolpXfv3q0bPny46hN3d3fd1VdfrduyZUulY73yyiu6vn376nx9fXVubm6qD1999dWKZaTT0tJ0DzzwgNru4eGh8/Hx0fXr10/37bffNsjPRkREZKs4Dqq/G264Qefq6qrLzc2tdZ8777xT5+TkpMYw4ty5c7oHH3xQFx4ervomIiJCd8cdd1Q8L/Ly8nTPPvusrmXLluq1ISEhuptvvll3/Pjxin1SU1N148ePV2MqPz8/3b333quLjY2t9rPKsWXMVJMDBw7ohg4dqn5PAQEBurvvvlu3d+/eGvtLjj127Fg1RpOfuX379rrnn3++2jELCwvV+cgYLT8//xJ7lMj62cn/mTswRkRERERERNTUSKH6sLAw3HDDDfj888/NfTpEjY41pYiIiIiIiIjMQFbxS01NrVQ8nagpYaYUERERERERUSOSFQP37dun6khJcfPdu3eb+5SIzIKZUkRERERERESNaN68efj3v/+N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bzTbOdGlKyopw8GkbHWfmVJERERmnr43c+ZMPPHEE4iKikLfvn0xYMCAiqwpWer4Unz00UfqOK6urqo21fbt2y+4/7Jly9ChQwe1f5cuXbBmzZpq+xw8eFAN9nx8fNRVyj59+qgBYVPTNtgTzo72yC4swenzeeY+HSIioibjxIkT6NatG6KjozF69GhVd1OaXNCTRtblSHK2Ckx5uzqiOYucExERmTcodfPNN6sgz86dO1WmlN61116Ld999t87HWbp0KR577DG88MILqk6VDN6GDx+uMq5qsmXLFkyePBnTp0/HP//8UzHAi42Nrdjn+PHjuPLKK1XgatOmTaqew/PPP6+CWE2NE4udExERmcXDDz+sCpvLmMbd3R379+/H77//jt69e6vxiallZ2fjkUceUYXV3dzcMHDgQOzYsaPi+ZycHDz44IOIiIhQz0udq48//viix63LxcCmQF+fs0uED+zsmHlORERk1qCUCAkJUVlRCQkJiIuLU9ska0oGLnX1zjvv4O6778bUqVMrBkcycJs/f36N+0uB0BEjRuDJJ59Ex44d8fLLL6Nnz5748MMPK/Z59tlnMWrUKFVYVM6vdevWKmsqKCgITVGXcC0oxWLnREREjWfr1q146aWXEBAQoOpuSpOLZrNnz8ZDDz1k8ve76667sH79eixYsEAVUx82bBiGDh2K+Ph49bxcBFy7di0WLlyoMsolgCVBqh9++KHWY9blYmBTsa98HMV6UkRERBZQU6qsrAyvvPKKWtJYrrwJKXz++OOPq6CQDLwuRmor7Nq1CzNmzKjYJq+TAZQM5Goi22VQZUwyq6S+lf68fvrpJzz11FNquwyg5CqlvIcMompTWFioml5WVlbF8aSZkhxPp9OZ/Li16RxWnikVl9Fo72mpfWHJ2Bca9oMB+8KAfaFhPzROX5jqmKWlpRWLwkhgSi7itW/fXmUyHT58GKaUn5+PFStW4Pvvv8egQYPUthdffBGrV6/GvHnz1JhNAkx33HEHhgwZop6XAuyffPKJKptQW30r44uBQi4GSuBLLgbWJcvKlugv7nUN9zX3qRAREdmUywpKSeDp888/x+uvv44rrrhCbfvzzz/VAKigoACvvvrqRY+RlpamBmzBwcGVtsvjQ4cO1fiapKSkGveX7UJS5CVIJuclA7A33nhDXRWU1QE3btyIwYMH13hc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zFJFzgM8nRHq42ru0yEiIrJZDEo1IS6ODmoVvv0JWWoKH4NSREREDePOO+809ylQPejrb0o9TmaWExERNRzWlGpi9CnoLHZORETUcGTF4mXLllXbLtu++uors5wT1V1MeZHzrpy6R0RE1KAYlGpiuAIfERFRw5s9ezYCAgKqbQ8KCsJrr71mlnOiy8uUIiIioobDoFQTXoFPiq4SERGR6Z05cwYtW7astr1FixbqObJc+UWlOJqSo+53jfA19+kQERHZNAalmmCxc0d7O6TnFSM+I9/cp0NERGSTJCNq37591bbv3bsXzZo1M8s5Ud0cSMxCqSpy7oJgbxdznw4REZFNY1CqiXF10oqd67OliIiIyPQmT56Mhx56CBs3bkRpaalqv/32Gx5++GHccsst5j49ugD9+KhrBIucExERNTSuvtdEp/DJVUCplzAiOtTcp0NERGRzXn75ZZw6dQrXXnstHB214VZZWRmmTJnCmlIWbl95kXPWkyIiImp4zJRqgrpFavURFv19BvviMsx9OkRERDbH2dkZS5cuxeHDh/HNN9/gu+++w/HjxzF//nz1HFlBphSDUkRERA2OmVJN0E3dw7B0xxnsjcvErZ/9jf/d0Rv9W7G+BRERkam1bdtWNbIOeUUlOJqSre53iWBQioiIqKExU6oJ8nBxxDd398eAVs2QU1iCO+Zvx2+Hks19WkRERDZj/PjxeOONN6ptf/PNNzFhwgSznBNd3MHELJTpgCAvKXLuau7TISIisnkMSjVRni6O+GJqHwztGITCkjLc8/UufL8n3tynRUREZBN+//13jBo1qtr2kSNHqufIsutJSf1NIiIiangMSjXxlfjm3d4LY7qHoaRMh0eW7sHCbafNfVpERERWLycnp8baUU5OTsjKyjLLOdHFySIwglP3iIiIGgeDUk2ck4M93pnYHf/q3wI6HfDcqljM23Tc3KdFRERk1bp06aIKnVe1ZMkSdOrUySznRBcXw0wpIiKiRsVC5wR7ezu8dFNneLs54qONx/HG2kPIKijGU8Pbw87OztynR0REZHWef/55jBs3Tq24d80116htGzZswOLFi7Fs2TJznx7VILewBMdTc9R9BqWIiIgaB4NSpEjw6cnhHeDt6oTZPx9S2VJZ+cV4+aZoFbQiIiKiurvhhhuwatUqvPbaa1i+fDnc3NzQtWtX/Prrrxg8eLC5T49qcKC8yHmwtwuCWOSciIioUTAoRZXcO7g1vN2c8MzKGHzz9xlkF5Tg7Ynd1DQ/IiIiqrvRo0erVlVsbCyio6PNck5Ul6l7vuY+FSIioiaDkQaqZnLf5nj/lh5wtLfDD3sTcO+CXSgoLjX3aREREVmt7OxsfPrpp+jbty+6detm7tOhCxU559Q9IiKiRsOgFNXohm5h+GxKb7g42uO3Qym4Y/52ZBcUm/u0iIiIrMrvv/+OKVOmIDQ0FHPmzFH1pbZt29YgQa9HHnkELVq0UFMFBw4ciB07dlSapl9Te+utt2o95osvvlht/w4dOsDWg1JdufIeERFRo2FQimp1dYcgfD2tLzxdHPH3yfO49bO/cT63yNynRUREZNGSkpLw+uuvo23btpgwYQJ8fHxQWFioakzJ9j59+pj8Pe+66y6sX78eCxYsQExMDIYNG4ahQ4ciPj5ePZ+YmFipzZ8/XwWZxo8ff8Hjdu7cudLr/vzzT9iiHKMi59HMlCIiImo0DEo1Np0OjqmxsBb9WjXD4rv7w9/DWV1BnPjJViRlFpj7tIiIiCy2wHn79u2xb98+zJ07FwkJCfjggw8a9D3z8/OxYsUKvPnmmxg0aBDatGmjspzkdt68eWqfkJCQSu3777/H1VdfjVatWl3w2I6OjpVeFxAQAFt0ICFLhmgI9XFFoJeLuU+HiIioyWBQqjGVlsBu9UNo9t1E4OgvsBZdInzw7b0DEOLtimMpObj54y04fS7X3KdFRERkcX7++WdMnz4ds2bNUkXOHRwcGvw9S0pKUFpaClfXyivGyTS+mjKbkpOT8dNPP6nzvJijR48iLCxMBa9uu+02nDlzBrZoX1yGumWWFBERUePi6nuNyd4B0JXCTlcKLJ8GTP0JCOsBa9AmyBPL7huAf33+N06dy8PNH2/Fgul90SHE29ynRkREZDEkCPT555+jV69e6NixI/71r3/hlltuadD39PLywoABA/Dyyy+r9wwODsbixYuxdetWlS1V1VdffaVeM27cuAset1+/fvjyyy9V5pdM3ZNA21VXXaVWD5TX10SmKUrTy8rKUrdlZWWqmZIcT6fTmeS4FUXOw7xNfp6NwZR9Yc3YDwbsCwP2hYb9YMC+aJy+qOsxGZRqTHZ20F0/F0Vpp+ESvwX4ZiJw16+AXwtYg0h/d3x73wBM+Xw7DiVlY9In2/Dl1D7o0dzP3KdGRERkEfr376+aTN1bunSpqt302GOPqYGZ1HyKjIysNaBTH1JLatq0aQgPD1fZWT179sTkyZOxa9euavvKOUnWU9XMqqpGjhxZcb9r164qSCWF1L/99ttas6xmz56tgldVpaamoqDAtNP/pU8zMzPVYNrevn7J/3tOn1O3ER46pKSkwNqYsi+sGfvBgH1hwL7QsB8M2BeN0xeyCEtdMCjV2ByckTH8AwT9NAV2yfuBb24Gpv8CuFlHYCfIyxVL7xmAO7/cjn/OZOC2//2tVum7oo1t1pggIiK6HB4eHipIJO3w4cMqe0qKnD/99NO47rrr8MMPP5j0/Vq3bo3NmzcjNzdXZSfJan+TJk2qVjPqjz/+UOcjAbNL5evri3bt2uHYsWO17jNjxgwVhNOTc5FAXGBgILy9vU0+kJZi7XLs+gykZXXhMxladteVnZsjwNP6akqZqi+sHfvBgH1hwL7QsB8M2BeN0xcXu/ilx6CUGeicPaGbvBR2nw8D0o4AS24D/rUScLSOQZCPuxMWTu+Hexfswp/H0jD1ix348NYeGNY5xNynRkREZHFk+psUIZcsotWrV6tMpYYMhklLT0/HunXr1Psa008t7Nat2yUfOycnB8ePH1dTEmvj4uKiWlUy0G2Igb8MpOt77INJOarIebivG4K83WCtTNEXtoD9YMC+MGBfaNgPBuyLhu+Luh7PIn4DH330EaKiolQkTVLDt2/ffsH9ly1bhg4dOqj9u3TpgjVr1tS673333ac6WdLoLYp3OHD7csDFGzj9F7Dq3xKmhLXwcHHE53f2xvDOwSgqLcO/v9mN73bHmfu0iIiILJZMqxszZozJs6SEBKDWrl2LkydPqmmCsrKejJWmTp1aKWtJxlB33XVXjce49tpr8eGHH1Y8fuKJJ1T21alTp7BlyxaMHTtW/QwyLdCWxJbXk4oOZ51MIiKixmb2oJSkj0ua9wsvvIDdu3erK3fDhw+vdT6/DIpkMCS1DP755x81uJMmRTerWrlyJbZt26ZWjbFIwZ2BSQsAe0cgdgWw4UVYExdHB3x0a0+M7xmB0jIdHvt2L77acsrcp0VERNTkSD2IBx54QAWipkyZgiuvvFIFqpycnCr2WbJkiaoZUVtQSbKg0tLSKh7HxcWpfSXTa+LEiWjWrJkaV0mKvy3ZF6cFpbpG+Jr7VIiIiJocswel3nnnHdx9993qSl6nTp3w8ccfw93dvdbU9vfeew8jRozAk08+qVaYkZVmpJin8ZU9ER8fj//85z/45ptvKg3ILE6rIcCN5ef+13vA9s9gTRwd7PHWzV1x58Ao9fiFH/bjgw1H1aCXiIiIGocEjSSoJCvfyUp5Mi7y8fGptM8999yDvLy8atv1JCPqxRdfrBTESkhIUMeUAJU8ltpVtka/8l50eM39QkRERDYalCoqKlKrwgwdOtRwQvb26rEsY1wT2W68v5DMKuP9pViX1DuQwFXnzp1h8bpPBq5+Trv/81PAodqnI1oie3s7vHBDJzx8bVv1+O31R/DamoMMTBEREZFFyyooxsm0XHW/C4NSREREjc6shc4lRby0tBTBwcGVtsvjQ4cO1fiapKSkGveX7XpvvPEGHB0d8dBDD9XpPOQKoDTjmgv64JY0U5LjSbCm2nGvfAx2GWdg98/X0C2fBt0dq4HwXrAmD1/bBl6uDnjlp0P47I+TyMwvxqtjouFgb3dpfdEEsS807AcD9oUB+0LDfmicvmD/Ni36elJS5Nzfw9ncp0NERNTk2Nzqe5J5JVP8pD6VFDivC1kNZ9asWdW2p6amoqCgwOSDXan7IIPpatXoez8Fv7STcDn7B8q+mYjz475FqXckrMn1bT2A61rgtV9P49udcTiXmYsXR0TBycH+0vqiiWFfaNgPBuwLA/aFhv3QOH2RnZ1t0uORdQSlukYwS4qIiKjJBaUCAgLUKi7JycmVtsvjkJCQGl8j2y+0/x9//KGKpDdv3rziecnGevzxx9UKfFIvoaoZM2aoYuvGmVKRkZGqkKe3t7fJB9ISLJNj1ziQvvUb6L66Hg5J+xCw7j7opq4D3P1hTaYFBSE00B+PLN2DDUfTUWLngP+7tSfcnB0urS+aEPaFhv1gwL4wYF9o2A+N0xeysi81Hfoi56wnRURE1ASDUs7OzujVqxc2bNigVtDTDzTl8YMPPljjawYMGKCef+SRRyq2ydLHsl1ILamaak7JduNlkY25uLioVpUMdBti4C8D6VqP7eYD3LYM+N9Q2J07BrultwJTvgec3GBNRncNg5erE+5dsAubj6Thji924PM7+8DHzanufdHEsC807AcD9oUB+0LDfmj4vmDfNi3MlCIiIjIvs4+8JEPps88+w1dffYWDBw/i3//+N3JzcysCSLKssWQy6T388MNYu3Yt3n77bVV3SlaJ2blzZ0UQS5Yrjo6OrtRk9T3JpJIlja2CVwhw23LA1Qc4+zfw3T0SrYO1GdQuEAvv6gsvV0fsPJ2OyZ9uQ1qOoXYXERERkblI7ctT5/LU/egwBqWIiIiaZFBq0qRJmDNnDmbOnInu3btjz549KuikL2Z+5swZtbSx3sCBA7Fo0SJ8+umn6NatG5YvX45Vq1ap4JNNCeoA3LIIcHAGDv4A/FK+Op+V6dXCH0vu6Y8AT2ccSMzCxI+3Ij4j39ynRURERE3c/vIsqUh/N/ixyDkREVHTLXQuWU61TdfbtGlTtW0TJkxQra5qqiNlFaKuBMbMA1ZMB7Z9BPhGAv3/DWvTOcwH3947ALf/72+cSMvFhHlbsPCufohq5m7uUyMiIqImal95UKoL60kRERE13UwpuoguNwNDX9Tur50BHPgB1qhVoCeW/3sgWgV6ICGzABM/2YoDCVnmPi0iIiJqomIqglK+5j4VIiKiJotBKWtwxSNA7+kAdMB3dwNn/oY1CvN1UxlTnUK9kZZThMn/+xu747j0NhERETW+mPKV95gpRUREZD4MSlkDOztg5JtAuxFASQGw+Bbg3HFYowBPFyy+pz96t/BDdkEJ7l9+BGP+bwu+3noK6blF5j49IiIiagIy84px5rxW5JxBKSIiIvNhUMpaODgCN88HwnoA+eeBheOBnFRYIx83JyyY3g9juofBwQ7YF5eJmd/vR9/XfsV9C3Zh/YFkFJda32qDREREZF1T95r7u8PH3cncp0NERNRkWUShc6ojZw/g1m+B/w0F0k8CiycBd/wIOFtfwXA3Zwe8M7Eb7ukbgC3xRfhud4JanW/t/iTVmnk448buYRjfMwKdw7xhJ9liRERERKasJxXBLCkiIiJzYqaUtfEMAm5fAbj5AfG7gBV3AWWlsFb+7k6YdkVLrHn4Kvz88FW468qWaorfudwifPHXKVz/wZ8Y+d4f+Oz3E0jJLjD36RIREZENiInPULecukdERGReDEpZo4C2wC2LAQcX4PBPwNqnAZ0O1q5jqDeeu74Tts24BvPv7I3RXULh7GCPQ0nZeHXNQQyY/RumfrEdP+5LQEGx9QbiiIiIyDIypboyKEVERGRWnL5nrVoMAMZ9AiybCmz/FPCJBK54CLbA0cEe13QIVk0Kka7el4AVu+Pwz5kMbDycqpq3qyOu76ZN7+vZ3JfT+4iIiKhOZGGVs+fz1f3ODEoRERGZFYNS1qzzWCAzHvjlWWD984BPBBA9DrZEio/e3r+FasdTc/Dd7jis3B2PhMwCLPr7jGqtAjwwrmc4xvaMQLivm7lPmYiIiCxYbIKWJRXVzF0tvkJERETmw+l71m7AA0Dfe7X7K+8FTm+BrWod6Iknh3fAn/+9Bt/c1Q/jeoTDzckBJ9JyMeeXI7jyjd9w62fbsGJXHPKKSsx9ukRERGSBZNVfEc0sKSIiIrNjUMraybS1EbOBDtcDpUXA4slA6hHYMnt7O1zRJgDvTOqOHc8NxVs3d0X/Vv6qrNaW4+fw+LK96P3Kr3j8273YcjwNZWXWX2+LiIiITCNWX0+KK+8RERGZHafv2QJ7B2DcZ8DXNwJxO4BvxgPTfwW8gmHrPF0cMaF3pGpnz+dh5T/xqv7U6XN56laaTOmT6X1SfyoqwMPcp0xERERmxEwpIiIiy8FMKVvh7A5MXgL4twIyzgCLJgKFOWhKIv3d8dC1bbHpiSFYft8ATO4bCS8XR8Rn5OOD345hyJxNGD9vi6pDlZlfbO7TJSIiokZ2PrdIjQsEg1JERETmx6CULfEIAG5bDrg3AxL3AMunAaVNr7aSrMTXO8ofs8d1VdP73p/cA4PbBcLeDth1Oh3PrIxB31d/xYOLdmPj4RSUlJaZ+5SJiIioEcSUT91rGeABb1cWOSciIjI3Tt+zNc1aA5OXAl9dDxxdB6x5Arj+Xa32VBPk6uSAG7uFqZacVYBV5dP7jiTn4Md9iaoFerng+q6hap/ukb4qqEVERES2W0+qC7OkiIiILAKDUrYosg8w/n/A0n8Bu74AfCOBqx5HUxfs7Yp7B7fGPYNaITY+SwWnvt8Tj9TsQnzx1ynVmvu744ZuEqAKR/sQL3OfMhEREZnQvrgMdcsi50RERJaBQSlb1fEGYOQbwM9PARteAnwiga4TzX1WFkEyobpE+Kj2zKiO+P1IKlbvS8D6A8k4cz4PH208rlr7YK+KAFXzZu7mPm0iIiKqpxgWOSciIrIoDErZsn73akXPt34IrLof8AoBWg4y91lZFGdHewztFKxaXlEJNhxMwQ97E7D5cCoOJ2fj8C/ZmPPLEXSL9FXT+2San2RcERERkXVJyylEQmaBqmjQOczb3KdDREREDEo1Ade9DGTGAQdWAUtuB6avA4I6mvusLJK7syNu6BammqzOty42SQWothxPw96zGaq98tMB9Gvpr7KnRkaHwM/D2dynTURERJdY5NyLRc6JiIgsAlffs3X29sDYT4DI/kBhJrDwZiAr0TznotMBhdlAxlkgKQY4+Qec47cBiXuB8yeA3HNAaTEsgY+bEyb2icTCu/rh72eGYtaNndGrhZ/6EbadOK9W8Ovz6q+Y9uUOVTw9t7DprXJIRESWIzs7G4888ghatGgBNzc3DBw4EDt27Kg0db2m9tZbb13wuB999BGioqLg6uqKfv36Yfv27bBWseVT97py6h4REZHFYKZUU+DkCkxeDHw+DDh3FFg0AZj6M+ByGYW8JSpTnAfkZwAFGdptfrrhvrpNr/y8fltBJlBWUiki6l/Tezi6Aa7e2vm5eJff19/6VHlsfOtjeOzoAlOR1fnuGBilWlx6HlbvTcTqvQk4kJiF3w6lqObqZI9rOwbjhq5hGNI+UK36R0RE1FjuuusuxMbGYsGCBQgLC8PChQsxdOhQHDhwAOHh4UhMrHxB6ueff8b06dMxfvz4Wo+5dOlSPPbYY/j4449VQGru3LkYPnw4Dh8+jKCgIFibfeWZUqwnRUREZDkYlGoq3P2B25cD/xuqZSl9OwW48UOgMOvSA0ylRfU7FwdnwNUXOjdflJaWwqEkD3aSQVWUoz1fkg/kSEuux3u4VAlaeVUPXOlvPYKA5v0BN9+LHjbCzx3/HtJatWMp2fihPEB1Mi0XP+1LVM3LxRHDo0NUDaqBrZvB0YEJiURE1HDy8/OxYsUKfP/99xg0SKsd+eKLL2L16tWYN28eXnnlFYSEhFR6jex79dVXo1WrVrUe95133sHdd9+NqVOnqscSnPrpp58wf/58PP3007A2seVBqa4RF/97T0RERI2DQammxC8KuPVb4MvRwPHfgHc7Xf6x7B1VYEkFctStn9H98seVnjfa5uQm8wigKytDWkqKutpqJ9MMy0q1IFlBVi23mRd4Plu7L02UFgK5qVqrCzsHIKIP0GYo0OYaILSHNvXxAtoEeeGx67zw6NC2iI3PUiv4SYAqMbMAy3fFqdbMwxmjuoTixu5h6NXcD/b2dpff50RERDUoKSlRF3lkip0xmcb3559/Vts/OTlZBZe++uqrWo9ZVFSEXbt2YcaMGRXb7O3tVfbV1q1ba31dYWGhanpZWdrf5bKyMtVMSY6n0+nqdNzU7EL191mKnHcM8TT5uZjbpfSFLWM/GLAvDNgXGvaDAfuicfqirsdkUKqpCe8JTPgSWPVvLQuqauCoTgEmP8DZQwWWTMreofy9/S7/GPIPvyi7lsBVZs3bpZ6VTGs8u01rG18B3JsBra7WglStrwG8gmt9S6nJ0SXCR7WnR3TAztPp+GFvPNbEJOFcbhEWbDutWrivm1q9Twqpy6o/8joiIqL68vLywoABA/Dyyy+jY8eOCA4OxuLFi1XwqE2bNtX2l2CUvGbcuHG1HjMtLU0FuuRYxuTxoUOHan3d7NmzMWvWrGrbU1NTUVBQAFMPdjMzM9VgWgJmF7LlpJYl1cLPFbmZ55EL23IpfWHL2A8G7AsD9oWG/WDAvmicvpB6l3XBoFRT1G448MRRCadcNBvI6sjPI1P0pF2KjDPAsQ3AsV+Bk78DeeeA2OVaEyFdygNU1wKR/QDHmlfdk0yovi39VXvhhs7461iaWsHvl/3JiM/Ixye/n1CtVaCHqj8lGVStAz1N8IMTEVFTJrWkpk2bpupHOTg4oGfPnpg8ebLKdqpKpt/ddttt1TKrTEEyq6QOlXGmVGRkJAIDA+Ht7W3ygbRc4JFjX2wgfSZGC0p1b+5vlfWwTNkXtoz9YMC+MGBfaNgPBuyLxumLuo4zGJRqqiQriQx8mwO9p2pNVgCM22EIUiXu0epwSfvzXcDZE2g5CGhzrRak8m9Z4yGdHOwxpH2QagXFpdh0OEUFqDYcTMGJ1Fy8t+GoapI1dUPXUPQNdYINjpOJiKgRtG7dGps3b0Zubq4KBIWGhmLSpEnVakb98ccfqlC5FDG/kICAABXckql+xuRx1fpUxlxcXFSrSga6DTHwl4F0XY4dm5BdUU/KVr+A1LUvbB37wYB9YcC+0LAfDNgXDd8XdT0eg1JEVTk4AS0Gau3a54GcVODERi1AJbW4pE7V4TVaE/6ttQCVZFJFXalNbaxCVuMbER2qWnZBMdYfSFb1p/44mob9CVmqiS7hZzGySwhGRYciKqD6cYiIiC7Ew8NDtfT0dKxbtw5vvvlmpec///xz9OrVC926dbvgcZydndV+GzZswJgxYyqupsrjBx98ENYmJj5D3cpUeyIiIrIcDEoRXYxnINB1otakZlXSPuC4ZFFtAM7+DZw/DmyX9qm2smDzAYYgVVCnarW3vFydMK5nhGrnc4vwc2wiVu9JwPZT5xETn6nam2sPo2OoN0ZGh2BUlxBVVN3m5Z4D9q+EZ8JBoON1QKvBWlF8IiK6KAlAST2I9u3b49ixY3jyySfRoUOHipXzhGRQLVu2DG+//XaNx7j22msxduzYiqCTTMO744470Lt3b/Tt2xdz585VmVjGx7QGKVkFSM4qhKw10inUtFMIiYiIqH4YlCK6FJKCGNZda1c9rhVKlxpUKkj1q1ab6uRmra2fCXiFalP8ZEU/KZzu7l/pcP4ezritXwtM7hOJQ6fi8U9KKdbuT8aW4+dwMDFLtXfWH0GbIE+Mig7ByC6h6BDiZTtF0ovytIyzmGWq/+zLSqAqbO35H+Dopk2TbDcMaDsc8I0099kSEVksKVIq9Zzi4uLg7++P8ePH49VXX4WTk1PFPkuWLFGBK6k1VZPjx4+rAud6Mv1PCpTPnDkTSUlJ6N69O9auXVut+Lmlk4s9Qmo4erhw6EtERGRJ7HQyOqFK5Eqij4+PGuA1RFHOlJQUVWSzqc9ftbm+kI/SuWOGWlSn/gRK8g3P29kD4b3Kg1RDtZUQy2t7Ve2L9NwirD+YjLWxSfjjaCqKSw0f06hm7io4JVlUXcJ9rC9AVVoCnNgExHwLHPwRKDasgaQL6YJ8n7ZwS/wbdlnxlV8X1NkQoIroAzjY9hcLm/t81AP7QsN+aJy+aMgxQFNkCWOqub8ewdxfj2Jcz3C8M7E7bBH/+6BhPxiwLwzYFxr2gwH7wrLGVLb9rY6oMUlwKKCt1vrfBxQXAGe2lAepNgCpB7UC6tI2vw64+gKtr9aCVJJFZfRx9PNwxsTekaplFRTjt4MpWBOTiM1HUnHqXB7mbTquWrivm5reJ7WqekRK8VY7yw3Yxe8C9n0L7P9Oq8ul59sC6DJBNV1AO2SlpMA1MBB2aYeAI2uBI78AcduBlP1ak2Lz0ndtr9MCVDJVskoGGhERkV5MnJYpJRdyiIiIyLIwKEXUUJxcgdbXaG34q0BmvKEWlRROL8hQNZSkSUw6wLcl7FoN0qastbgC8A5Vh/F2dcKYHuGq5RaWYOPhFPwck4TfDqUgPiMfn/1xUrUQb1eMkCl+0SHoHeUPB0sIUKUd1abmSTAq/aRhu3szoPNYoMtEILKvoe6W1OwS8ji4s9ZkmmTeea3fjq4Djq7X+k6OK00y0CL6GrKo5DXWlj1GREQNPn2vK4ucExERWRwGpYgai0840HOK1mQKm2QOldei0sXvhmPGSWC3tK+0/f1baav5tbgSiLoC8IlQtTCu7xqmWn5RqcqckkLpGw6mICmrAF9uOaVagKcLhncOxqguoejX0h+ODo2YlpqdBMSu0AJRiXsM253cgQ6jtUCUZIjJKod1JZlQXSdoTfpOss0kQCVZVJI9dXab1ja8BHhHGAJUEuBzdm+QH5OIiCxfclYBUrL1Rc4ZlCIiIrI0DEoRmYPUQ2reT2tXPwNd7jlkxKyFb3os7M78BSTFAOdPaG3319pr/KIMAaoWV8DNr4XKjJJWUFyKv46lYU1MEtYfSEJaTiG++fuMan7uThjWSYqkh2Bg6wA4OzZAgKogU6sPJXWipPC7Tp/x5KBlisnKhe1HAS6qjHn9+67FAK0NfRHIOGsIUEmB+aw4YOd8rTm6aoGptsOAdlIsvXn935+IiKxu6l7bIC+4OWt1HImIiMhyMChFZAnc/FAYdS10fSfDTgrM5WcAZ7YBp/8ETv2lZRyln9LanoXaa3yaVwSoXKOuxLUdonBtx2AUlXTB1hPnsDY2Eev2J+N8bhGW7jyrmrerI4Z2Csao6FBc2TYArk71GKCXFGpT6SQQdXgtUFpoeE6m00mdKJmi5xmIBiWr8vW5S2vF+cDJP8qDVOuATAlY/aK1NU8AgR21LKp2I7RztPFi6URETd2+8ql70awnRUREZJH4jYzIErn5Au1HaE0UZAFn/9ZW9Dv9FxC/G8g8A+yVtljbxztcBaico67A4KirMHhsF7x8UzS2nzyPn2OTsHZ/ElKzC/Hd7njVPJwdVBBLalANaR9UtyvIUvNJirfL1LwDq7QMKb2AdtrUvC43A/4tYRZObuVBp2HAqDlAykFDFpX0nxSbl/bXe1qxdCmSroqlDwU8mpnnnImIqMHEsp4UERGRRbOIoNRHH32Et956C0lJSejWrRs++OAD9O3bt9b9ly1bhueffx6nTp1C27Zt8cYbb2DUqFHqueLiYjz33HNYs2YNTpw4oZYgHDp0KF5//XWEhYU14k9FZEKu3uWrzV2nPS7M0YIsEqCSQJUEqbLitawlacIzBI5RV2Bg1JUYeMWVePGGa7DrTIaqQbU2NgmJmQX4YW+Cam5ODhjSPlBlT7UM8ECrAE8Ee7vATgqGy8p5ybFaIEpqRcn76HmGaEEoyYoK7WZZBcZVsfROWrvyUa1Y+vHftAyqY+uB/HTt55GmiqX3MUzzC462rJ+FiIgumU6nw77y6XvMlCIiIrJMZg9KLV26FI899hg+/vhj9OvXD3PnzsXw4cNx+PBhBAUFVdt/y5YtmDx5MmbPno3rr78eixYtwpgxY7B7925ER0cjLy9P3ZeglQS40tPT8fDDD+PGG2/Ezp07zfIzEpmc1GaSLB9poigPiNuuTfVTQaqdQE55wXFpUorJIwh9o65A3xZX4Pk+V2BPYQjW7k/GmphExKXnq2wqaXptnM/jdvftGFb2O8KKTlVs1zl7wa7zTVpWlBRit7eSGh1SLF0F0G4GykqBuJ2GaX4SdJMgn7TfXtayzjqN0WphWVqwjYiI6iQ5q1DVWJTVaDuFepv7dIiIiKgGdjq5jGRGEojq06cPPvzwQ/W4rKwMkZGR+M9//oOnn3662v6TJk1Cbm4ufvzxx4pt/fv3R/fu3VVgqyY7duxQmVenT59G8+YXL3SclZWlMqwyMzPh7W3aQYz8fCkpKSrgZi+1g5ow9kUD9oXUVpKgi36639ntlWs+CfcAoMVA6FpcgWPu3fF9gg9Ox8ejVcp6XJW/Eb3tD1fsWqhzxMayHlhVegU2lnWHu7uHyqhqGeCJlgHu5bceiApwh7uzo/X9m8iM0+pOyTS/E5uAknzDc4EdtOCUBOGkflUj4efDgH2hYT80Tl805BigKTLnmOqX/Um4Z8EudAjxwtpHBsGW8b8PGvaDAfvCgH2hYT8YsC8sa0xl1kypoqIi7Nq1CzNmzKjYJh0h0+22bt1a42tku2RWGZPMqlWrVtX6PtIJMg3J19e3xucLCwtVM+48/S9IminJ8SQOaOrjWiP2RQP2hYOLqi+lmr4oefwuFaCyKw9S2eWlAQd/gN3BH9AWwONSY6koB3ZlJYA9oIMd0oP6IsZ/ODY59MehdAecOpeLwswCFOYVI/1MBnafyaj21qE+rohqJgErd0SpwJXWIv3c4ORgb5n/JrzCgJ53aq2kQE3zs4tZDhxeA7vUQ8CGl1STAJ5OglOdbgJcG3YqCD8fBuwLDfuhcfqC/Wt79aS6cOoeERGRxTJrUCotLQ2lpaUIDg6utF0eHzp0qMbXSN2pmvaX7TUpKCjAf//7XzXlr7bonEwFnDVrVrXtqamp6vWmHuxKkEwG04zKsi8atS/c2gAdpN0BlBbBKSUGzok74JywA05Ju2BfoAWYipt1RH7bG1DQZjTKPEPQHlBNL7+4FHEZhTiTXogzGQU4m16As+pxATILSlWtKmmyAqAxBzsgzMcFkb4uaO7nikhfVzT30+4HejrB3s7Ocv5N+PUGBvWGXb9n4XpyHVyP/ADnhO0qoCdN9/OTKGxxNfLb3YTCyKsAB2eTn4LF9IUFYF9o2A+N0xfZ2dkmPR6Zf+W9LixyTkREZLHMXlOqIUnR84kTJ6pB67x582rdTzK1jLOvJFNKphAGBgY2SKq5ZG3Jsfmlgn1h1r4IjQC6jdTulxajLCkGcPGCQ0BbeEoN8wu8tEU4UJ6DVUl6XhFOpeXiZFoeTqblqsyqk+WPJZglwStpW05p2Yh6rk72aNHMA1HN3BHqboeerb0QHe6F5n7usLc3Zz2nICDyfmDQ/dBlxkEXuxx2+5aq7CnXE+tU07n5A53HahlUUizdRPWn+PkwYF9o2A+N0xeurq4mPR6Zh4z9YsqLnDNTioiIyHKZNSgVEBAABwcHJCcnV9ouj0NCQmp8jWyvy/76gJTUkfrtt98uGFxycXFRrSoZ6DbEwF8G0g11bGvDvrCQvrB3ASJ71/swzTxdVesV1azalwMpOHsiLUcLVqlAVS5OpOXizLk8FBSX4XBStmriyx1a5qOniyM6hnqpArWdw3zQKcwbbYM94eJohuLqfs2Bqx7TVvKTAN6+pUDMcthJQfmdn8Nu5+eAX0ug6yStBlWz1vV+S34+DNgXGvZDw/cF+9Y2SMbuudwiVeS8I4ucExERWSyzBqWcnZ3Rq1cvbNiwQa2gp7/6KY8ffPDBGl8zYMAA9fwjjzxSsW39+vVqe9WA1NGjR7Fx40Y0a1b5CzIRNf6XxxAfV9UGtg6o9FxJaZla/U8FqVJzsO90Kk5mFONQUjZyCkuw41S6anqO9nZoE+RZEaTqHOatvnD4uDk11g8DhHbV2nUvASc3A/u+BQ78AKSfBDa/rjXJmpIAVedxgAf/G0RE1Jj2lWdJtQv2gquTlawSS0RE1ASZffqeTJu744470Lt3b7VC3ty5c9XqelOnTlXPT5kyBeHh4aruk3j44YcxePBgvP322xg9ejSWLFmCnTt34tNPP60ISN18883YvXu3WqFPalbp6035+/urQBgRWQ5HB3tVEF3a4HYBSGnrrlZ/KNMBx1NzcSAxE/vjs3AgMQv7E7KQma8FrKSt2G04TqS/myGjSm7DvRHi7aoCYg3G3gFofY3WRr8NHFoD7FuiCqUjbofW1j4NtLlOy55qPxJwcmu48yEiokpFzrty6h4REZFFM3tQatKkSaqg+MyZM1XwqHv37li7dm1FMfMzZ85USqUfOHAgFi1ahOeeew7PPPMM2rZtq1bei46OVs/Hx8fjhx9+UPflWMYka2rIkCGN+vMR0eUHq9qHeKk2todhGmBCZgH2x2dWBKkOJGQhPiMfZ89rbd1+w/Refw9nFaDSZ1TJ/VaBnmo6h8k5ewBdJ2gtOxmIXaFN8UvcAxz5WWsu3kCnG7UMqhZXyjwh058HERFVFDmPZpFzIiIii2b2oJSQqXq1TdfbtGlTtW0TJkxQrSZRUVHqiysR2R7Jegr3dVNtWGdDHbmMvCIVpJIAlTQJVh1LzcH53CL8eSxNNeOi6u1DDEEque0Q4g03ZxNO7/AKBgbcr7XUw1pwSqb4ZZ4F/lmoNe9woMsEoNstQFBH0703EVETJ+NAZkoRERFZB4sIShER1Yevu7OqVWVcr6qguBRHkrMrglQStDqYmIW8olLsPZuhmp4kTkkGlT5IJVMAe0f5maYOSWB74NqZwNXPAWe2agGq/auArHjgr7laC+miZU9JkMqr5kUeiIiobiR7Vi5KSA1CybYlIiIiy8WgFBHZJAkodY3wVU2vtEyH0+dyK4JU2vS/TKTlFOFYSo5qP+xNUPt6ODvgmo7BGN0lBEPaB9U/QCVT9aKu0NrIN4Gj67TsqSPrtNX8pK2fCbQcrAWoOoyubxcQETVJ+iwpCUixyDkREZFlY1CKiJoMqSUlGVHSbugWVrE9JasA+42m/+0+k66WE1+9N0E1dwlQdQjC6C6hKkBV76l+Tq5Ap5u0lnce2L9Sy6A6+zdwYqNqdk7u8PdrCztXD8DRGXBwMdw6OBvddwIcXYyeL2/6bcbPV9zXP+9c8317R22VQSIiK155rwun7hEREVk8BqWIqMkL8nZV7er2QRX1SPaczcCamESsiUlSU0F+3JeomgSori4PUF1tigCVuz/QZ7rWzp8EYpYBe5fA7vxxOKfshXnYGQJUbr5AeG8gsh8Q2VebaijBLSIiCxVTninVhUXOiYiILB6DUkRENRRU79HcT7VnRnXE3rhMFaD6aV+iClDJrTQ3p/IMqq4mClD5twQGPwUMehJlCXuQefYAfDzdYF9aDJQWAaWFQInclreSQm2bPK/uG2/X3xaXv874fvmx1D7l93VlRieiK3++ECjMAjLOAPu/055ycgfCe2kBKglURfTRAmtERBZALipUBKWYKUVERGTxGJQiIrpIgKp7pK9qM0Z2UNNCVIAqJhFx6fnqVpo+QDVKMqg6BMLduR7/eZWpc6HdUOgQCgQFafWoGlpZqSHIZRz4yowD4rYDZ6X9DRRkAqf+0JpeQLvyTKryFtCW0/+IyCzkv8sZecVwcmCRcyIiImvAoBQR0SUEqLpF+qr29MgO6mq8ypqqEqBydbKvCFDJbb0CVI3F3gFwdpf5hJW3N2sNtBqs3S8rA9KOaMEpfZDq3FFtm7R/Fmj7ufkBEZJJ1Rdo3h8I61l+bCKihqXPkpKAlIsji5wTERFZOiv4pkREZJkBKv3qfhUBKlWDKhFnz+erWlTSJEAlU/v0ASoPFyv+z65kbAV10FqvO7RtueeAuB3A2W1aoCp+F5Cfrq0uKE29zlGrRaWvSyW3PhFm/VGIyDYZpu4ZVl4lIiIiy2XF346IiCwwQDWiA2LjsyoCVGfO5+Hn2CTVJEA1pF0QRnUNxbXWHqDS82gGtB+hNSFT/5JjDJlUZ/4GshOAhH+09vfH2n7eEYYAFQuoE5GJxHDlPSIiIqtiA9+IiIgsK0AlKz5J+++I9tifYAhQnT6Xh7X7k1RzcSzPoLKlAJVwdNYKoUvr/2+pOqzVpTKe8pcUA2TFAfvjDAXUHd201zQvr0vFAupElyQ7OxvPP/88Vq5ciZSUFPTo0QPvvfce+vTpU7HPwYMH8d///hebN29GSUkJOnXqhBUrVqB58+Y1HvPLL7/E1KlTK21zcXFBQUEBLL3IeVeuvEdERGQVbORbEBGRZQaoosN9VHtquBagkuCUtFNVAlRD2geqKX7XdgyGp60EqIQUPPeN1FqXm7VtRbnaNL+KQNV2oCADOP2n1ioVUO8LhPeGS4kzkBsOuHoBzl6AiyfgLM1Dq4dF1MTdddddiI2NxYIFCxAWFoaFCxdi6NChOHDgAMLDw3H8+HFceeWVmD59OmbNmgVvb2/s378frq6uFzyu7Hf48OFK/12zVDJ1OjO/GM4O9mgXzCLnRERE1sCGvvkQEVlHgOrJ4e1xIFEfoErCybRcrNufrJoEqAa3C8TI6BB09AOCYIMkkNRykNb0BdSlYLoKUpVP+TMqoG7/z0L4Xeh4Tu5agEoFqjyqB61cvIye96x8v6ZtDHKRlcnPz1cZT99//z0GDdI+Vy+++CJWr16NefPm4ZVXXsGzzz6LUaNG4c0336x4XevWrev0366QkBBYA32WVIdQLzg7NsKqpURERFRvDEoRETUy+ZLXOcxHtSeGtcfBxOyKDKoTabn45UCyaiLA86BaRaptkJe6bRfsibbBXvB2taH6S1JAPbC91npOqVJA/W/oEveiODsNTrpC2BXmAEXlraxE27c4T2u5KaY5H5lKWFPQytFFC1jZOWjF2yvu65tj5cfG+1Xat8p+lR7LfXuj1+mfky/YDnDKzgPsW2pTG119temS1OTJVLzS0tJqWU9ubm74888/UVZWhp9++glPPfUUhg8fjn/++QctW7bEjBkzMGbMmAseOycnBy1atFDH6NmzJ1577TV07twZlmhffIa6leA/ERERWQcGpYiIzByg6hTmrdrjw9rhUJIWoPo5JhHHUnORllOEtGPn8Nexc5VeF+rjqqanSJBKbiVg1SbIE+7ONvKfdaMC6rqyMpxPSUFQUBDsVHBGFY8BSgoNAapC49tsbYqg/r66zS1/Pttovyrb9EGuknyt5abCkshP3qzqRicPwM0XcPPTglTqvm/5fb8aniu/7+rDjDAb4uXlhQEDBuDll19Gx44dERwcjMWLF2Pr1q1o06aNqjElwaXXX39dZU298cYbWLt2LcaNG4eNGzdi8ODBNR63ffv2mD9/Prp27YrMzEzMmTMHAwcOVNP+IiJqXkGzsLBQNb2srCx1K0EtaaYkx5M6UvrjVhQ5D/M2+XtZuqp90VSxHwzYFwbsCw37wYB90Th9Uddj2si3FyIi2whQdQz1Vu3RoW1xKi4RmXDD0ZRcHE3OxuHkHBxJykZSVgESM7W2+YghcCKlXiL93CsCVfrWKtADrk42FoCQH9bJVWseAfU/ngS5SouqBLKqBLzk+bJSrenktqTmx+q+vpVUflzpdfJcWZX95LmyKq/T9tOVlaC0IAcOxdmwK5Av+jqgOFdrWfGX2oGAq3fNASt9MKu2wJZkjVlwXaGmSmpJTZs2TdWPcnBwUFlNkydPxq5duyoGhTfddBMeffRRdb979+7YsmULPv7441qDUhLokqYnASkJen3yyScqAFaT2bNnq5pVVaWmppq8QLr8XBIsk8G0/PczJk7LlApzK1WBuKbEuC/s9cH7Joj9YMC+MGBfaNgPBuyLxukLWYSlLhiUIiKyUO7ODogK8kWP5pVXoZNCvhKkOiJBKglWJWXjaEq2yqo6cz5PtV8PGr6Q2dsBUQEeaBfkhXYhXmhfnmEl25wcmvYf4goSZJHpedIkS8sCScZYmj5jTAJSBZlagfh8aenl99O1x8b3Kx6Xb5MgVsXrtcySS6KfXijTCuV+RbOr8ri8qamLtTxX6bVVj1fLse0dYAc7eDv7Azd/3BBdbZWkPpSsqpebm6uyk0JDQzFp0iS0atUKAQEBcHR0VKvtGZMAk0zvqysnJye1qt+xY8dq3UemBD722GMVj+VcIiMjERgYqIqmm3ogLcEoOfbZ9Hxk/3979wIcVX09cPxk805IQkLIC8JLI09B5SXClFGcAjK2WBV1qKTYymChYm2prRKpD6TICCg6WJzqTGdUrG2hth3lj1SobUUQkUfloRV5xRBeIS+TkOz9z/lddm82JIiY3M3mfj8zPzb37s1mc0g2Z8/93fOrbTC9pEb26+G5nlKNY+HlN1jEwUEsHMTCRhwcxMKdWHzVYioBFKUAIMKkJcbKsF4ZZjR2orI2WKgKDC1YldfUy2fHqszQ1f4CYqOjpE9mJ1Oouizr7G12ivTISJJorWSh/dJCj/aV0vF11dc1U8z6qsLW2ft0tpjO7tLbMNKfzrjOfcL6HNqr5ORkM06dOiVr1641jc3j4uJk+PDhIavoqX379pl+URdK+1bt3LnTNExvSXx8vBlNaaLbFom/JtL6uLuK7bOx/XNSJKGjXMZ8kbHw+hss4uAgFg5iYSMODmLR9rG40Mfz5l9tAOiAunSKl1E6LnFm+uhU3NKKWlOccopVlWamVVVdg+w1lwWGTq3VFQC1P1Xfs72qLu+eJpd3S5OUjtRc3cu0OXqnLHt83Uscz3xpz67SSwu1OBUclnMpYsj+Jvef83kX9xh+f4NU1PiFdtYOLUDp77v2gdKZTHPnzpV+/frJ9OnTzf26rTOndHW+a6+91vSU0tX5NmzYEHyMadOmmcv/9BI89eijj8rVV19t+lKVlZXJ4sWL5cCBA/KjH/1I2ptdZ1fe09crAAAQOShKAUAHP/ORnZpgxrcu6xrc7/dbcqTsS3PZ394Su0ilxalPSyultt4v/y0uN8N5HJE+mckyuHtnGdw9zdwOzEvteL2q0DL9IYhLske4+f1S67GeQV9F+0HopXOHDx+WjIwMufnmm2XBggXmkjt10003mf5RWnC69957TfHqT3/6k4wZMyb4GAcPHgw5q6mzre6++24pKSmR9PR0GTp0qOlD1fQywPZgR6DJOSvvAQAQUShKAYAH+XxRkp+RZMZ1/bKD+xv8lulJZfpUHa2Qj78oN2/2tID1v2NVZqzeZjfVjvFFmcv9AkUqvdWZVfSpAtw3ZcoUM85HG6HraEnjWVNq6dKlZrR3WmTfVRwoSnUO99MBAABfA0UpAECQ9pLqnZlsxoRBOcH9xypqZeeRMtl+6LTsPHJadhwuM43VtWilY9WWQ8FL/wbkpcrgbnahakh+mulbpUUwAGgLB05WS0VNvWluXpDdKdxPBwAAfA0UpQAAX6lrSryZURWYVaW9a4pP18iOQ2Wy/bAWqsrMjCp9Y7jtYJkZIgfMsZ3iY2RQt1QZ0r2z6feit93TE82lhQDwTWmhXA3ITWWmJgAAEYaiFADga9OCUrfOiWZMvDw3eAnN5yeqTHHKHmXmkprK2nrZ9NlJMwIykuNM75ch2kRdZ1R1T5Os1AtbNhYAGtt1xO5/Rz8pAAAiD0UpAECr0Ev0+nTtZMbkK7uZffUNfvmktNIUqALFqj0l5XKyqk427jtmRkBOaoLpSzUkv7N5c6kfd06KC+N3BCCSZkqx8h4AAJGHohQAoM3ERPukf26qGbcNt/fVnGmQPSUVjQpVZaZwVVJeIyUf18j/fXw0+Pk9uyTJwNxUSfA1SJe0k5IUFyNJcdFm6Mp/ge3Es/ua7tceV1wmCHRcfsuS/wabnFOUAgAg0lCUAgC4SotGV+R3NiOgqrZedh2xm6hvP1uoOnCiOjhszqyqC6X91RNjtWgVI4lxPkmKjQkpYJn9sT5TxDL7zbF2UUuPT4x1imBZKQmS1znBFNoAtA+HTtVKZW2DKUAXZNHkHACASENRCgAQdsnxMTKyTxczAsqq6+zL/b4ol6MnT0tUbIJ8eabBHnUNUl139vZMvbm1P7b319X7zWP4LZGqugYzWkNsdJTkpydJr8xk6dVFVylMkp7mNlnyOiea1QsBuGdPqV20HpiXSsEYAIAIRFEKANAuaT+pb13WVcZc2kVKS0slKytLfL4Le9OpvayaFrACRSzdV11nF7KqQ7b1c+pDjjX7z/jN7Rena0yx67PjVWY0FRftk/yMRFOg0kKVFq56m9skyUtLND23ALSu3Uft30Uu3QMAIDJRlAIAdDg6YyJFR0Jsqz2mri74RXmNfH68SvYfrzK3n5+oNisOHjxRLXUNfvnfsSozmoqL8UmPjKTg7KrATCu9zU1NoGAFXKS9Z2dK6SqeAAAg8lCUAgDgAmjhqFvnRDNGX5oZcl+D35Lisi9N/6v9J84WrLR4daJKDp2sNjOsPi2tNKMp7YWjDd0DRSr7NsnMuMpOoWAFnK9QHCxKMVMKAICIRFEKAIBvSHtJ5WckmTGmoPmClZldZQpW9uwqLVodPFkttfV+2Xe00oymEmJ90jPDLlJp4So1ul7yup6RtMQ4MwssJSHm7IiVlPgYCljwFP2dqj7jN4sZXNI1OdxPBwAAXASKUgAAuFSw+pZ0Paf31ZGyL+3LAAOXBZ6oMjOudIZVzRm/7D1aYYbjUItfq1N8TGihKuQ2RlIbF7LiQ+/X+zolxNCsHRFDV+tUA3JTaHIOAECEoigFAECY6BtpbYquY+xloQWrM1qwOvWluQTwQKBgVXpa6qxoqaytN6Oi5oyU19QHVxsM7P/Cfq9+UZLjos+dhXX2NjUhxhS+oqOjxBcVJdFRURIVZRfedFtnamlN63z32fujzu63L4sMHB+y7RP7OLM/9LGixJLK07WSlfVN/wcQyXYWl5tbLt0DACByUZQCAKAdio322T2mMpNF+mr/HH+LqxDW1jdIRY0WqexCVeC2vJl9TY+zjzljLiNUVXUNZpTY7/fbrR7p8bJhbn64nwbCaOdhu/o6iKIUAAARi6IUAAARLj4mWuI7RUtmp/iLfgydbdW0aBUoWDXeV1VXb/pkNfhFLMuSBssSv2U3nfbrtrkV83Fg2zq7HfjY/hzr7OfYfbcCx4c8ljlGmr1Pe2jB28zMO5/OlEoN91MBAAAXqV1kdM8995wsXrxYSkpKZMiQIbJ8+XIZMWJEi8e//vrrUlRUJJ9//rkUFBTIokWL5IYbbgjer0ny/Pnz5YUXXpCysjIZPXq0rFixwhwLAADOFRfjky6d4s1o7wKzxuBtq2ZcLYeLSySva6dwPxUAAHCRwt4V8rXXXpP777/fFJE+/PBDU5QaP358i8nmf/7zH7njjjvkhz/8oWzbtk0mT55sxq5du4LHPPnkk/LMM8/I888/L++//74kJyebx6ypqXHxOwMAAEBbF1NZdRIAgMgV9qLUkiVL5O6775bp06fLgAEDTCEpKSlJXnzxxWaPf/rpp2XChAkyd+5c6d+/vzz22GNy1VVXybPPPhucJbVs2TKZN2+efPe735XBgwfL73//eykuLpY1a9a4/N0BAAAAAACg3RWl6urqZOvWrXL99dc7T8jnM9vvvfdes5+j+xsfr3QWVOD4/fv3m8sAGx+TlpYmI0eObPExAQAAAAAA4KGeUsePH5eGhgbJzs4O2a/be/bsafZztODU3PG6P3B/YF9LxzRVW1trRkB5eXmwZ4WO1qSPp7O5WvtxIxGxcBALG3FwEAsHsbARB3diQXwBAAA81ug83BYuXCiPPPLIOfuPHTvW6n2oNNk9ffq0SaabLuntNcTCQSxsxMFBLBzEwkYc3IlFRUVFqz4eAAAA2mlRKjMzU6Kjo+Xo0aMh+3U7Jyen2c/R/ec7PnCr+3Jzc0OOueKKK5p9zF/96lem2XrjmVL5+fnStWtXSU1NbfVEOioqyjw2byqIRQCxsBEHB7FwEAsbcXAnFgkJCa36eAAAAGinRam4uDgZOnSorF+/3qygF0g0dXv27NnNfs6oUaPM/ffdd19w37p168x+1bt3b1OY0mMCRSgtMukqfPfcc0+zjxkfH29GU5rotkXir4l0Wz12pCEWDmJhIw4OYuEgFjbi0PaxILYAAAAeunxPZygVFhbKsGHDZMSIEWblvKqqKrMan5o2bZp069bNXGKn5syZI2PHjpWnnnpKJk2aJKtWrZIPPvhAVq5cGUxStWD1+OOPS0FBgSlSFRUVSV5eXrDwBQAAAAAAAI8XpW677TbTu+nhhx82jch1dtNbb70VbFR+8ODBkLOW11xzjbzyyisyb948efDBB03hac2aNTJo0KDgMb/4xS9MYWvGjBlSVlYmY8aMMY/JlHwAAAAAAID2IexFKaWX6rV0ud6GDRvO2Xfrrbea0RKdLfXoo4+aAQAAAAAAgPaHxgkAAAAAAADw5kyp9kaXmA40SG9t2shdl5vWSwm93kyVWDiIhY04OIiFg1jYiIM7sQj87Q/kAvhmyKncQSxsxMFBLBzEwkYcHMSifeVUFKWaof8pKj8/P9xPBQAAhIHmAmlpaeF+GhGPnAoAAG+r+IqcKsriVGCz1cLi4mJJSUkx/alau1qoidmhQ4ckNTVVvIxYOIiFjTg4iIWDWNiIgzux0LRIkyddtdfrZ09bAzmVO4iFjTg4iIWDWNiIg4NYtK+ciplSzdCAde/evU2/hv6He/0XIIBYOIiFjTg4iIWDWNiIQ9vHghlSrYecyl3EwkYcHMTCQSxsxMFBLNpHTsUpQAAAAAAAALiOohQAAAAAAABcR1HKZfHx8TJ//nxz63XEwkEsbMTBQSwcxMJGHBzEAoqfAwexsBEHB7FwEAsbcXAQi/YVCxqdAwAAAAAAwHXMlAIAAAAAAIDrKEoBAAAAAADAdRSlAAAAAAAA4DqKUi577rnnpFevXpKQkCAjR46UzZs3i9csXLhQhg8fLikpKZKVlSWTJ0+WvXv3itf95je/kaioKLnvvvvEi44cOSLf//73pUuXLpKYmCiXX365fPDBB+IlDQ0NUlRUJL179zYxuOSSS+Sxxx4TL7T+++c//yk33nij5OXlmd+DNWvWhNyvMXj44YclNzfXxOb666+XTz75RLwWizNnzsgDDzxgfj+Sk5PNMdOmTZPi4mLx4s9FYzNnzjTHLFu2zNXniPDxek5FPtUycipyKnIqcipFThUZ+RRFKRe99tprcv/995vu9h9++KEMGTJExo8fL6WlpeIlGzdulFmzZsmmTZtk3bp15gXh29/+tlRVVYlXbdmyRX7729/K4MGDxYtOnTolo0ePltjYWHnzzTfl448/lqeeekrS09PFSxYtWiQrVqyQZ599Vnbv3m22n3zySVm+fLl0dPr7r6+J+iazORqHZ555Rp5//nl5//33TfKgr581NTXipVhUV1ebvx+aaOvtn//8Z/Mm9Dvf+Y548eciYPXq1eZviiZb8AZyKvKplpBTkVMpcipyKkVOFSH5lK6+B3eMGDHCmjVrVnC7oaHBysvLsxYuXGh5WWlpqZ6ysDZu3Gh5UUVFhVVQUGCtW7fOGjt2rDVnzhzLax544AFrzJgxltdNmjTJuuuuu0L2fe9737OmTp1qeYm+HqxevTq47ff7rZycHGvx4sXBfWVlZVZ8fLz16quvWl6KRXM2b95sjjtw4IDlxVgcPnzY6tatm7Vr1y6rZ8+e1tKlS8Py/OAucqpzeT2fUuRU5FQB5FQ2cioHOVX7zaeYKeWSuro62bp1q5keGeDz+cz2e++9J152+vRpc5uRkSFepGc5J02aFPKz4TVvvPGGDBs2TG699VZzCcKVV14pL7zwgnjNNddcI+vXr5d9+/aZ7e3bt8u//vUvmThxonjZ/v37paSkJOR3JC0tzVyu4/XXz8BrqE6z7ty5s3iN3++XO++8U+bOnSsDBw4M99OBS8ipmuf1fEqRU5FTBZBTNY+c6vy8mlP5w5xPxbj+FT3q+PHj5trm7OzskP26vWfPHvEq/QXQ6/11mvGgQYPEa1atWmWmi+pUcy/77LPPzBRrvRTjwQcfNPG49957JS4uTgoLC8P99Fzzy1/+UsrLy6Vfv34SHR1tXjMWLFggU6dOFS/T5Ek19/oZuM+rdKq99kO44447JDU1VbxGL8eIiYkxrxfwDnKqc3k9n1LkVDZyKhs5VfPIqVrm5ZxqUZjzKYpSCPsZrV27dpkzF15z6NAhmTNnjukDoU1avUyTaT2r98QTT5htPaunPxd6rbuXEqg//OEP8vLLL8srr7xizlJ89NFH5k2GXtftpTjgwmj/mClTppiGpfoGxGt0pszTTz9t3oTqWU3Ay7ycTylyKgc5lY2cCl+Hl3Oqre0gn+LyPZdkZmaaKv3Ro0dD9ut2Tk6OeNHs2bPlb3/7m7zzzjvSvXt38Rp9AdCGrFdddZWpTOvQpqXaeFA/1jM6XqGrfwwYMCBkX//+/eXgwYPiJTplVs/s3X777WYlEJ1G+9Of/tSssORlgddIXj/PTZ4OHDhg3oR57Yyeevfdd81raI8ePYKvoRqPn/3sZ2ZFNnRc5FShvJ5PKXIqBzmVjZyqeeRU5/J6TvVuO8inKEq5RKfMDh061Fzb3PhMhm6PGjVKvEQr0JpAaXf/f/zjH2apVi8aN26c7Ny505y5CQw9s6XTivVjTbi9Qi83aLqMtfYA6Nmzp3iJrgKifVEa058Dfa3wMn2N0ESp8eunTsnXFWO89vrZOHnS5Zvffvtts+S3F+kbjB07doS8huoZcH0jsnbt2nA/PbQhciob+ZSDnMpBTmUjp2oeOVUocippF/kUl++5SK/t1umi+kdyxIgRsmzZMrM84/Tp08VrU8x1Ku1f/vIXSUlJCV6/rE32EhMTxSv0e2/a90GXZNUXQ6/1g9AzV9qQUqea6x+GzZs3y8qVK83wkhtvvNH0O9AzFTrVfNu2bbJkyRK56667pKOrrKyUTz/9NKQRp/5R1Ia9Gg+dcv/4449LQUGBSah0+V79gzl58mTxUiz0DPgtt9xipljrzAg9+x94DdX79c26l34umiaPugS6Jtt9+/YNw7OFm8ipyKcaI6dykFPZyKnIqRQ5VYTkU66t8wdj+fLlVo8ePay4uDiznPGmTZssr9Efu+bGSy+9ZHmdV5cvVn/961+tQYMGmSVp+/XrZ61cudLymvLycvP/r68RCQkJVp8+fayHHnrIqq2ttTq6d955p9nXhcLCwuASxkVFRVZ2drb5GRk3bpy1d+9ey2ux2L9/f4uvofp5Xvu5aMrtJYwRXl7Pqcinzo+cipyKnIqcipwqMvKpKP3HnfIXAAAAAAAAYKOnFAAAAAAAAFxHUQoAAAAAAACuoygFAAAAAAAA11GUAgAAAAAAgOsoSgEAAAAAAMB1FKUAAAAAAADgOopSAAAAAAAAcB1FKQAAAAAAALiOohQAtJKoqChZs2ZNuJ8GAABARCOnAryDohSADuEHP/iBSWCajgkTJoT7qQEAAEQMcioAbopx9asBQBvSZOmll14K2RcfHx+25wMAABCJyKkAuIWZUgA6DE2WcnJyQkZ6erq5T8/wrVixQiZOnCiJiYnSp08f+eMf/xjy+Tt37pTrrrvO3N+lSxeZMWOGVFZWhhzz4osvysCBA83Xys3NldmzZ4fcf/z4cbnpppskKSlJCgoK5I033nDhOwcAAGg95FQA3EJRCoBnFBUVyc033yzbt2+XqVOnyu233y67d+8291VVVcn48eNNwrVlyxZ5/fXX5e233w5JkDQBmzVrlkmsNNnS5OjSSy8N+RqPPPKITJkyRXbs2CE33HCD+TonT550/XsFAABoK+RUAFqNBQAdQGFhoRUdHW0lJyeHjAULFpj79eVu5syZIZ8zcuRI65577jEfr1y50kpPT7cqKyuD9//973+3fD6fVVJSYrbz8vKshx56qMXnoF9j3rx5wW19LN335ptvtvr3CwAA0BbIqQC4iZ5SADqMa6+91px5aywjIyP48ahRo0Lu0+2PPvrIfKxn94YMGSLJycnB+0ePHi1+v1/27t1rpqoXFxfLuHHjzvscBg8eHPxYHys1NVVKS0u/8fcGAADgFnIqAG6hKAWgw9CEpenU79aiPREuRGxsbMi2Jl6ahAEAAEQKcioAbqGnFADP2LRp0znb/fv3Nx/rrfZF0D4IAf/+97/F5/NJ3759JSUlRXr16iXr1693/XkDAAC0J+RUAFoLM6UAdBi1tbVSUlISsi8mJkYyMzPNx9poc9iwYTJmzBh5+eWXZfPmzfK73/3O3KfNM+fPny+FhYXy61//Wo4dOyY/+clP5M4775Ts7GxzjO6fOXOmZGVlmRVnKioqTJKlxwEAAHQU5FQA3EJRCkCH8dZbb5klhRvTM3J79uwJruKyatUq+fGPf2yOe/XVV2XAgAHmPl1ueO3atTJnzhwZPny42dZVZZYsWRJ8LE2uampqZOnSpfLzn//cJGa33HKLy98lAABA2yKnAuCWKO127tpXA4Aw0T4Eq1evlsmTJ4f7qQAAAEQscioArYmeUgAAAAAAAHAdRSkAAAAAAAC4jsv3AAAAAAAA4DpmSgEAAAAAAMB1FKUAAAAAAADgOopSAAAAAAAAcB1FKQAAAAAAALiOohQAAAAAAABcR1EKAAAAAAAArqMoBQAAAAAAANdRlAIAAAAAAIDrKEoBAAAAAABA3Pb/he2JJYQmApYAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ํ•™์Šต ๊ทธ๋ž˜ํ”„ ์ €์žฅ: mnist_models/resnet_history.png\n", + "\n", + "############################################################\n", + "# MOBILENET ๋ชจ๋ธ ํ•™์Šต ์‹œ์ž‘\n", + "############################################################\n", + "๋””๋ฐ”์ด์Šค: cpu\n", + "๋ชจ๋ธ ํƒ€์ž…: mobilenet\n", + "Train dataset: 60000๊ฐœ\n", + "Test dataset: 10000๊ฐœ\n", + "MobileNetV3-Small ๋ชจ๋ธ ์ƒ์„ฑ\n", + "Total parameters: 989,986\n", + "Trainable parameters: 989,986\n", + "\n", + "==================================================\n", + "MOBILENET MNIST ๋ชจ๋ธ ํ•™์Šต ์‹œ์ž‘\n", + "==================================================\n", + "\n", + "==================================================\n", + "Epoch 1/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [25:08<00:00, 3.22s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:27<00:00, 2.88it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.2430, Train Acc: 91.81%\n", + "Test Loss: 0.0571, Test Acc: 98.25%\n", + "Learning Rate: 0.001000\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_mobilenet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 2/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [24:38<00:00, 3.15s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:27<00:00, 2.87it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0573, Train Acc: 98.30%\n", + "Test Loss: 0.0398, Test Acc: 98.88%\n", + "Learning Rate: 0.000989\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_mobilenet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 3/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [24:58<00:00, 3.20s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:25<00:00, 3.13it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0433, Train Acc: 98.70%\n", + "Test Loss: 0.0277, Test Acc: 99.23%\n", + "Learning Rate: 0.000957\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_mobilenet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 4/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [24:40<00:00, 3.16s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:27<00:00, 2.89it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0367, Train Acc: 98.84%\n", + "Test Loss: 0.0566, Test Acc: 98.32%\n", + "Learning Rate: 0.000905\n", + "\n", + "==================================================\n", + "Epoch 5/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [24:40<00:00, 3.16s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:27<00:00, 2.90it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0310, Train Acc: 99.05%\n", + "Test Loss: 0.0264, Test Acc: 99.19%\n", + "Learning Rate: 0.000835\n", + "\n", + "==================================================\n", + "Epoch 6/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [25:29<00:00, 3.26s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:25<00:00, 3.12it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0252, Train Acc: 99.23%\n", + "Test Loss: 0.0419, Test Acc: 98.88%\n", + "Learning Rate: 0.000750\n", + "\n", + "==================================================\n", + "Epoch 7/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [24:39<00:00, 3.15s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:27<00:00, 2.91it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0210, Train Acc: 99.37%\n", + "Test Loss: 0.0211, Test Acc: 99.31%\n", + "Learning Rate: 0.000655\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_mobilenet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 8/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [25:30<00:00, 3.26s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:25<00:00, 3.10it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0174, Train Acc: 99.47%\n", + "Test Loss: 0.0245, Test Acc: 99.28%\n", + "Learning Rate: 0.000552\n", + "\n", + "==================================================\n", + "Epoch 9/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [24:54<00:00, 3.19s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:28<00:00, 2.81it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0139, Train Acc: 99.57%\n", + "Test Loss: 0.0188, Test Acc: 99.41%\n", + "Learning Rate: 0.000448\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_mobilenet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 10/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [25:13<00:00, 3.23s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:26<00:00, 2.97it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0096, Train Acc: 99.72%\n", + "Test Loss: 0.0212, Test Acc: 99.36%\n", + "Learning Rate: 0.000345\n", + "\n", + "==================================================\n", + "Epoch 11/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [25:44<00:00, 3.29s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:30<00:00, 2.62it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0064, Train Acc: 99.79%\n", + "Test Loss: 0.0196, Test Acc: 99.46%\n", + "Learning Rate: 0.000250\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_mobilenet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 12/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [25:50<00:00, 3.31s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:31<00:00, 2.50it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0056, Train Acc: 99.81%\n", + "Test Loss: 0.0186, Test Acc: 99.43%\n", + "Learning Rate: 0.000165\n", + "\n", + "==================================================\n", + "Epoch 13/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [26:52<00:00, 3.44s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:25<00:00, 3.04it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0037, Train Acc: 99.89%\n", + "Test Loss: 0.0190, Test Acc: 99.47%\n", + "Learning Rate: 0.000095\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_mobilenet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 14/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [25:47<00:00, 3.30s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:23<00:00, 3.37it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0026, Train Acc: 99.91%\n", + "Test Loss: 0.0179, Test Acc: 99.56%\n", + "Learning Rate: 0.000043\n", + "๋ชจ๋ธ ์ €์žฅ: mnist_models/best_mobilenet_mnist_model.pth\n", + "\n", + "==================================================\n", + "Epoch 15/15\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Training: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 469/469 [26:00<00:00, 3.33s/it]\n", + "Evaluating: 100%|โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ| 79/79 [00:23<00:00, 3.36it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Loss: 0.0023, Train Acc: 99.93%\n", + "Test Loss: 0.0176, Test Acc: 99.54%\n", + "Learning Rate: 0.000011\n", + "\n", + "==================================================\n", + "ํ•™์Šต ์™„๋ฃŒ - ์ตœ๊ณ  Test Accuracy: 99.56%\n", + "==================================================\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAGGCAYAAACqvTJ0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAtmlJREFUeJzs3Qd4FNXXBvA3vfcGoYUkdKQXQQQVBLsUpVhAsH/Wv70hINgQsYsVpQmIiGIDEUVBQZogHUmAEFoK6T3Z/Z5zZ0s2BQJsTd7f84yzOzs7e3MTzM2Zc8910+v1ehAREREREREREdmRuz0/jIiIiIiIiIiISDAoRUREREREREREdsegFBERERERERER2R2DUkREREREREREZHcMShERERERERERkd0xKEVERERERERERHbHoBQREREREREREdkdg1JERERERERERGR3DEoREREREREREZHdMShFRERERERERER2x6AUUQP2+eefw83NTW3r1q2r9rper0ezZs3U69dcc0211wsKCjB16lR06tQJ/v7+CAkJwcUXX4y5c+eq91Zl/CzjFhAQgPbt22PatGkoLCy0OPe2225DYGCgxbFLLrkEHTt2PO3XNHny5GqfU3k7ceKEOu/QoUOmY0uXLq31OhkZGRZtqu26vr6+6py4uLjTfr5xk763hpr6iYiIiDQc67j+WKeykSNHqms/+eSTVr82ETmGp4M+l4iciAwyvvjiC/Tr18/i+O+//47U1FT4+PhUe8/JkycxcOBA7NmzB6NHj8b999+P4uJiNegZN24cfvzxRyxYsAAeHh4W77v88ssxduxY9Tg/Px9r167FxIkTsX37dixZssRqX9OsWbNqDNaEhoZWO/bCCy9g+PDhapBzJtIXn3zySbXjxq/zzTffVF+XkfTDwoUL8cYbbyAyMtJ0vG/fvmf19RAREdG541jH9cc6ubm5+O6771RQTD7vlVdeqdPXQ0TOjUEpIsJVV12lBklvv/02PD3N/1uQwVv37t0t7qAZyWBMBmnLli3DddddZzr+4IMP4vHHH8eMGTPQtWvXaneyWrdujVtuucX0/J577kFpaSm+/vprNdAz3oU7XzfccIPFwKg2Xbp0wbZt29TXIYO1M5H+qdz+qoYOHWrxXO5WysBJjssgioiIiOyPYx3XH+tIMLCiogKzZ8/GZZddhj/++AMD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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ํ•™์Šต ๊ทธ๋ž˜ํ”„ ์ €์žฅ: mnist_models/mobilenet_history.png\n", + "\n", + "============================================================\n", + "MNIST ํ•™์Šต ๊ฒฐ๊ณผ ์š”์•ฝ\n", + "============================================================\n", + "EFFICIENTNET:\n", + " - Best Test Accuracy: 99.61%\n", + " - Model Path: mnist_models/best_efficientnet_mnist_model.pth\n", + "RESNET:\n", + " - Best Test Accuracy: 99.69%\n", + " - Model Path: mnist_models/best_resnet_mnist_model.pth\n", + "MOBILENET:\n", + " - Best Test Accuracy: 99.56%\n", + " - Model Path: mnist_models/best_mobilenet_mnist_model.pth\n", + "\n", + "์ตœ๊ณ  ์„ฑ๋Šฅ ๋ชจ๋ธ: RESNET (99.69%)\n", + "\n", + "============================================================\n", + "๋ชจ๋“  MNIST ํ•™์Šต ์™„๋ฃŒ!\n", + "============================================================\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "EfficientNet-B0, ResNet18, MobileNetV3 ๋ชจ๋ธ์„ MNIST๋กœ ํ•™์Šต\n", + "\"\"\"\n", + "\n", + "import torch\n", + "import torch.nn as nn\n", + "import torch.optim as optim\n", + "from torch.utils.data import DataLoader\n", + "from torchvision import datasets, transforms\n", + "import torch.nn.functional as F\n", + "from pathlib import Path\n", + "import logging\n", + "from tqdm import tqdm\n", + "import matplotlib.pyplot as plt\n", + "\n", + "logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "\n", + "# ========== Model Architectures ==========\n", + "\n", + "class EfficientNetB0_MNIST(nn.Module):\n", + " \"\"\"EfficientNet-B0 modified for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " # Initial convolution\n", + " self.conv_stem = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(32)\n", + " self.act1 = nn.SiLU(inplace=True)\n", + "\n", + " # Simplified MBConv blocks for MNIST\n", + " self.blocks = nn.Sequential(\n", + " # 1\n", + " self._make_mbconv(32, 16, kernel=3, stride=1, expand_ratio=1),\n", + " # 2\n", + " self._make_mbconv(16, 24, kernel=3, stride=2, expand_ratio=6),\n", + " self._make_mbconv(24, 24, kernel=3, stride=1, expand_ratio=6),\n", + " # 3\n", + " self._make_mbconv(24, 40, kernel=5, stride=2, expand_ratio=6),\n", + " self._make_mbconv(40, 40, kernel=5, stride=1, expand_ratio=6),\n", + " # 4\n", + " self._make_mbconv(40, 80, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(80, 80, kernel=3, stride=1, expand_ratio=6),\n", + " # 5\n", + " self._make_mbconv(80, 112, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(112, 112, kernel=5, stride=1, expand_ratio=6),\n", + " # 6\n", + " self._make_mbconv(112, 192, kernel=5, stride=1, expand_ratio=6),\n", + " )\n", + "\n", + " # Head\n", + " self.conv_head = nn.Conv2d(192, 1280, kernel_size=1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(1280)\n", + " self.act2 = nn.SiLU(inplace=True)\n", + "\n", + " self.global_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.classifier = nn.Sequential(\n", + " nn.Dropout(0.2),\n", + " nn.Linear(1280, num_classes)\n", + " )\n", + "\n", + " def _make_mbconv(self, in_channels, out_channels, kernel, stride, expand_ratio):\n", + " \"\"\"MBConv block with Squeeze-and-Excitation\"\"\"\n", + " layers = []\n", + " hidden_dim = in_channels * expand_ratio\n", + "\n", + " # Expansion phase\n", + " if expand_ratio != 1:\n", + " layers.extend([\n", + " nn.Conv2d(in_channels, hidden_dim, 1, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.SiLU(inplace=True)\n", + " ])\n", + "\n", + " # Depthwise convolution\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, hidden_dim, kernel, stride,\n", + " padding=kernel//2, groups=hidden_dim, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.SiLU(inplace=True)\n", + " ])\n", + "\n", + " # Squeeze-and-Excitation\n", + " se_channels = max(1, in_channels // 4)\n", + " layers.append(SEBlock(hidden_dim, se_channels))\n", + "\n", + " # Projection phase\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, out_channels, 1, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " ])\n", + "\n", + " # Skip connection if dimensions match\n", + " if stride == 1 and in_channels == out_channels:\n", + " return ResidualBlock(nn.Sequential(*layers))\n", + "\n", + " return nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " x = self.conv_stem(x)\n", + " x = self.bn1(x)\n", + " x = self.act1(x)\n", + "\n", + " x = self.blocks(x)\n", + "\n", + " x = self.conv_head(x)\n", + " x = self.bn2(x)\n", + " x = self.act2(x)\n", + "\n", + " x = self.global_pool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.classifier(x)\n", + "\n", + " return x\n", + "\n", + "\n", + "class ResNet18_MNIST(nn.Module):\n", + " \"\"\"ResNet-18 adapted for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " # Initial layer: no pooling for small images\n", + " self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(64)\n", + " self.relu = nn.ReLU(inplace=True)\n", + "\n", + " # ResNet blocks\n", + " self.layer1 = self._make_layer(64, 64, 2, stride=1)\n", + " self.layer2 = self._make_layer(64, 128, 2, stride=2)\n", + " self.layer3 = self._make_layer(128, 256, 2, stride=2)\n", + " self.layer4 = self._make_layer(256, 512, 2, stride=2)\n", + "\n", + " self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n", + " self.fc = nn.Linear(512, num_classes)\n", + "\n", + " def _make_layer(self, in_channels, out_channels, blocks, stride=1):\n", + " layers = []\n", + "\n", + " # First block handles dimension change\n", + " layers.append(BasicBlock(in_channels, out_channels, stride))\n", + "\n", + " # Remaining blocks\n", + " for _ in range(1, blocks):\n", + " layers.append(BasicBlock(out_channels, out_channels, stride=1))\n", + "\n", + " return nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " x = self.conv1(x)\n", + " x = self.bn1(x)\n", + " x = self.relu(x)\n", + "\n", + " x = self.layer1(x)\n", + " x = self.layer2(x)\n", + " x = self.layer3(x)\n", + " x = self.layer4(x)\n", + "\n", + " x = self.avgpool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.fc(x)\n", + "\n", + " return x\n", + "\n", + "\n", + "class MobileNetV3_MNIST(nn.Module):\n", + " \"\"\"MobileNetV3-Small adapted for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " # Initial layer\n", + " self.conv_stem = nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(16)\n", + " self.act1 = nn.Hardswish(inplace=True)\n", + "\n", + " # MobileNetV3 blocks\n", + " self.blocks = nn.Sequential(\n", + " # 1\n", + " InvertedResidual(16, 16, kernel=3, stride=1, expand_ratio=1, se_ratio=0.25),\n", + " # 2\n", + " InvertedResidual(16, 24, kernel=3, stride=2, expand_ratio=4.5, se_ratio=None),\n", + " InvertedResidual(24, 24, kernel=3, stride=1, expand_ratio=3.67, se_ratio=None),\n", + " # 3\n", + " InvertedResidual(24, 40, kernel=5, stride=2, expand_ratio=4, se_ratio=0.25),\n", + " InvertedResidual(40, 40, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(40, 40, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " # 4\n", + " InvertedResidual(40, 48, kernel=5, stride=1, expand_ratio=3, se_ratio=0.25),\n", + " InvertedResidual(48, 48, kernel=5, stride=1, expand_ratio=3, se_ratio=0.25),\n", + " # 5\n", + " InvertedResidual(48, 96, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(96, 96, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " )\n", + "\n", + " # Final layers\n", + " self.conv_head = nn.Conv2d(96, 576, kernel_size=1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(576)\n", + " self.act2 = nn.Hardswish(inplace=True)\n", + "\n", + " self.global_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.classifier = nn.Sequential(\n", + " nn.Linear(576, 1024),\n", + " nn.Hardswish(inplace=True),\n", + " nn.Dropout(0.2),\n", + " nn.Linear(1024, num_classes)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " x = self.conv_stem(x)\n", + " x = self.bn1(x)\n", + " x = self.act1(x)\n", + "\n", + " x = self.blocks(x)\n", + "\n", + " x = self.conv_head(x)\n", + " x = self.bn2(x)\n", + " x = self.act2(x)\n", + "\n", + " x = self.global_pool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.classifier(x)\n", + "\n", + " return x\n", + "\n", + "\n", + "# ========== Helper Blocks ==========\n", + "\n", + "class SEBlock(nn.Module):\n", + " \"\"\"Squeeze-and-Excitation block\"\"\"\n", + " def __init__(self, in_channels, se_channels):\n", + " super().__init__()\n", + " self.avg_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.fc = nn.Sequential(\n", + " nn.Linear(in_channels, se_channels, bias=False),\n", + " nn.SiLU(inplace=True),\n", + " nn.Linear(se_channels, in_channels, bias=False),\n", + " nn.Sigmoid()\n", + " )\n", + "\n", + " def forward(self, x):\n", + " b, c, _, _ = x.size()\n", + " y = self.avg_pool(x).view(b, c)\n", + " y = self.fc(y).view(b, c, 1, 1)\n", + " return x * y\n", + "\n", + "\n", + "class ResidualBlock(nn.Module):\n", + " \"\"\"Residual connection wrapper\"\"\"\n", + " def __init__(self, module):\n", + " super().__init__()\n", + " self.module = module\n", + "\n", + " def forward(self, x):\n", + " return x + self.module(x)\n", + "\n", + "\n", + "class BasicBlock(nn.Module):\n", + " \"\"\"Basic block for ResNet\"\"\"\n", + " def __init__(self, in_channels, out_channels, stride=1):\n", + " super().__init__()\n", + "\n", + " self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride, 1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(out_channels)\n", + " self.relu = nn.ReLU(inplace=True)\n", + "\n", + " self.conv2 = nn.Conv2d(out_channels, out_channels, 3, 1, 1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(out_channels)\n", + "\n", + " self.shortcut = nn.Sequential()\n", + " if stride != 1 or in_channels != out_channels:\n", + " self.shortcut = nn.Sequential(\n", + " nn.Conv2d(in_channels, out_channels, 1, stride, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " out = self.relu(self.bn1(self.conv1(x)))\n", + " out = self.bn2(self.conv2(out))\n", + " out += self.shortcut(x)\n", + " out = self.relu(out)\n", + " return out\n", + "\n", + "\n", + "class InvertedResidual(nn.Module):\n", + " \"\"\"Inverted Residual block for MobileNetV3\"\"\"\n", + " def __init__(self, in_channels, out_channels, kernel, stride, expand_ratio, se_ratio=None):\n", + " super().__init__()\n", + "\n", + " hidden_dim = int(in_channels * expand_ratio)\n", + " self.use_res_connect = stride == 1 and in_channels == out_channels\n", + "\n", + " layers = []\n", + "\n", + " # Expand\n", + " if expand_ratio != 1:\n", + " layers.extend([\n", + " nn.Conv2d(in_channels, hidden_dim, 1, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.Hardswish(inplace=True)\n", + " ])\n", + "\n", + " # Depthwise\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, hidden_dim, kernel, stride,\n", + " kernel//2, groups=hidden_dim, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.Hardswish(inplace=True)\n", + " ])\n", + "\n", + " # SE\n", + " if se_ratio is not None:\n", + " se_channels = int(in_channels * se_ratio)\n", + " layers.append(SEBlock(hidden_dim, se_channels))\n", + "\n", + " # Project\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, out_channels, 1, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " ])\n", + "\n", + " self.conv = nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " if self.use_res_connect:\n", + " return x + self.conv(x)\n", + " else:\n", + " return self.conv(x)\n", + "\n", + "### =================================== ###\n", + "### ========== MNIST Trainer ========== ###\n", + "### =================================== ###\n", + "\n", + "class AdvancedMNISTTrainer:\n", + " \"\"\"3๊ฐ€์ง€ ๋ชจ๋ธ(EfficientNet, ResNet, MobileNetV3)๋กœ MNIST ํ•™์Šต\"\"\"\n", + "\n", + " def __init__(self, model_type='efficientnet', num_classes=10, batch_size=128,\n", + " learning_rate=0.001, num_epochs=10):\n", + "\n", + " self.model_type = model_type\n", + " self.num_classes = num_classes\n", + " self.batch_size = batch_size\n", + " self.learning_rate = learning_rate\n", + " self.num_epochs = num_epochs\n", + "\n", + " self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n", + " print(f\"๋””๋ฐ”์ด์Šค: {self.device}\")\n", + " print(f\"๋ชจ๋ธ ํƒ€์ž…: {model_type}\")\n", + "\n", + " self.model = None\n", + " self.criterion = None\n", + " self.optimizer = None\n", + " self.history = {\n", + " 'train_loss': [],\n", + " 'train_acc': [],\n", + " 'test_loss': [],\n", + " 'test_acc': []\n", + " }\n", + " self.best_acc = 0\n", + "\n", + " def make_model(self):\n", + " \"\"\"๋ชจ๋ธ ์ƒ์„ฑ\"\"\"\n", + " if self.model_type == 'efficientnet':\n", + " model = EfficientNetB0_MNIST(num_classes=self.num_classes)\n", + " print(\"EfficientNet-B0 ๋ชจ๋ธ ์ƒ์„ฑ\")\n", + " elif self.model_type == 'resnet':\n", + " model = ResNet18_MNIST(num_classes=self.num_classes)\n", + " print(\"ResNet-18 ๋ชจ๋ธ ์ƒ์„ฑ\")\n", + " elif self.model_type == 'mobilenet':\n", + " model = MobileNetV3_MNIST(num_classes=self.num_classes)\n", + " print(\"MobileNetV3-Small ๋ชจ๋ธ ์ƒ์„ฑ\")\n", + " else:\n", + " raise ValueError(f\"Unknown model type: {self.model_type}\")\n", + "\n", + " total_params = sum(p.numel() for p in model.parameters())\n", + " trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)\n", + " print(f\"Total parameters: {total_params:,}\")\n", + " print(f\"Trainable parameters: {trainable_params:,}\")\n", + "\n", + " return model\n", + "\n", + " def load_data(self):\n", + " \"\"\"MNIST ๋ฐ์ดํ„ฐ ๋กœ๋“œ ๋ฐ ์ „์ฒ˜๋ฆฌ\"\"\"\n", + "\n", + " # Test์šฉ transform (augmentation X)\n", + " test_transform = transforms.Compose([\n", + " transforms.ToTensor(),\n", + " transforms.Normalize((0.1307,), (0.3081,))\n", + " ])\n", + "\n", + " # Train์šฉ transform (augmentation O)\n", + " train_transform = transforms.Compose([\n", + " transforms.RandomRotation(10),\n", + " transforms.ToTensor(),\n", + " transforms.Normalize((0.1307,), (0.3081,))\n", + " ])\n", + "\n", + " train_dataset = datasets.MNIST('./data', train=True, download=True, transform=train_transform)\n", + " test_dataset = datasets.MNIST('./data', train=False, transform=test_transform)\n", + "\n", + " train_loader = DataLoader(train_dataset, batch_size=self.batch_size, shuffle=True)\n", + " test_loader = DataLoader(test_dataset, batch_size=self.batch_size, shuffle=False)\n", + "\n", + " print(f\"Train dataset: {len(train_dataset)}๊ฐœ\")\n", + " print(f\"Test dataset: {len(test_dataset)}๊ฐœ\")\n", + "\n", + " return train_loader, test_loader\n", + "\n", + " def train_one_epoch(self, train_loader):\n", + " \"\"\"ํ•œ ์—ํญ ํ•™์Šต ์ˆ˜ํ–‰\"\"\"\n", + " self.model.train()\n", + " total_loss, correct, total = 0, 0, 0\n", + "\n", + " for images, labels in tqdm(train_loader, desc=\"Training\"):\n", + " images, labels = images.to(self.device), labels.to(self.device)\n", + "\n", + " self.optimizer.zero_grad()\n", + " outputs = self.model(images)\n", + " loss = self.criterion(outputs, labels)\n", + " loss.backward()\n", + " self.optimizer.step()\n", + "\n", + " total_loss += loss.item()\n", + " _, predicted = outputs.max(1)\n", + " total += labels.size(0)\n", + " correct += predicted.eq(labels).sum().item()\n", + "\n", + " avg_loss = total_loss / len(train_loader)\n", + " accuracy = 100. * correct / total\n", + " return avg_loss, accuracy\n", + "\n", + " def evaluate(self, test_loader):\n", + " \"\"\"๋ชจ๋ธ ํ‰๊ฐ€ ์ˆ˜ํ–‰\"\"\"\n", + " self.model.eval()\n", + " total_loss, correct, total = 0, 0, 0\n", + "\n", + " with torch.no_grad():\n", + " for images, labels in tqdm(test_loader, desc=\"Evaluating\"):\n", + " images, labels = images.to(self.device), labels.to(self.device)\n", + " outputs = self.model(images)\n", + " loss = self.criterion(outputs, labels)\n", + "\n", + " total_loss += loss.item()\n", + " _, predicted = outputs.max(1)\n", + " total += labels.size(0)\n", + " correct += predicted.eq(labels).sum().item()\n", + "\n", + " avg_loss = total_loss / len(test_loader)\n", + " accuracy = 100. * correct / total\n", + " return avg_loss, accuracy\n", + "\n", + " def save_model(self, epoch, test_acc):\n", + " \"\"\"Save the best model\"\"\"\n", + " save_path = Path(f\"mnist_models/best_{self.model_type}_mnist_model.pth\")\n", + " save_path.parent.mkdir(exist_ok=True)\n", + "\n", + " torch.save({\n", + " 'epoch': epoch,\n", + " 'model_type': self.model_type,\n", + " 'model_state_dict': self.model.state_dict(),\n", + " 'optimizer_state_dict': self.optimizer.state_dict(),\n", + " 'test_acc': test_acc\n", + " }, save_path)\n", + "\n", + " print(f\"๋ชจ๋ธ ์ €์žฅ: {save_path}\")\n", + "\n", + " def train(self):\n", + " \"\"\"์ „์ฒด ํ•™์Šต ์ˆ˜ํ–‰\"\"\"\n", + " # ๋ฐ์ดํ„ฐ ๋กœ๋“œ\n", + " train_loader, test_loader = self.load_data()\n", + "\n", + " # ๋ชจ๋ธ ์ƒ์„ฑ\n", + " self.model = self.make_model().to(self.device)\n", + "\n", + " # ์†์‹ค ํ•จ์ˆ˜ & ์˜ตํ‹ฐ๋งˆ์ด์ €\n", + " self.criterion = nn.CrossEntropyLoss()\n", + "\n", + " # ๋ชจ๋ธ๋ณ„ ์ตœ์ ํ™” ์„ค์ •\n", + " if self.model_type == 'efficientnet':\n", + " self.optimizer = optim.AdamW(self.model.parameters(),\n", + " lr=self.learning_rate,\n", + " weight_decay=1e-5)\n", + " else:\n", + " self.optimizer = optim.Adam(self.model.parameters(),\n", + " lr=self.learning_rate)\n", + "\n", + " # ํ•™์Šต๋ฅ  ์Šค์ผ€์ค„๋Ÿฌ\n", + " scheduler = optim.lr_scheduler.CosineAnnealingLR(\n", + " self.optimizer, T_max=self.num_epochs\n", + " )\n", + "\n", + " print(f\"\\n{'='*50}\")\n", + " print(f\"{self.model_type.upper()} MNIST ๋ชจ๋ธ ํ•™์Šต ์‹œ์ž‘\")\n", + " print(f\"{'='*50}\")\n", + "\n", + " for epoch in range(self.num_epochs):\n", + " print(f\"\\n{'='*50}\")\n", + " print(f\"Epoch {epoch+1}/{self.num_epochs}\")\n", + "\n", + " train_loss, train_acc = self.train_one_epoch(train_loader)\n", + " test_loss, test_acc = self.evaluate(test_loader)\n", + "\n", + " self.history['train_loss'].append(train_loss)\n", + " self.history['train_acc'].append(train_acc)\n", + " self.history['test_loss'].append(test_loss)\n", + " self.history['test_acc'].append(test_acc)\n", + "\n", + " print(f\"Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.2f}%\")\n", + " print(f\"Test Loss: {test_loss:.4f}, Test Acc: {test_acc:.2f}%\")\n", + " print(f\"Learning Rate: {scheduler.get_last_lr()[0]:.6f}\")\n", + "\n", + " # ์ตœ๊ณ  ์„ฑ๋Šฅ ๋ชจ๋ธ ์ €์žฅ\n", + " if test_acc > self.best_acc:\n", + " self.best_acc = test_acc\n", + " self.save_model(epoch, test_acc)\n", + "\n", + " scheduler.step()\n", + "\n", + " print(f\"\\n{'='*50}\")\n", + " print(f\"ํ•™์Šต ์™„๋ฃŒ - ์ตœ๊ณ  Test Accuracy: {self.best_acc:.2f}%\")\n", + " print(f\"{'='*50}\")\n", + "\n", + " return self.model, self.history\n", + "\n", + " def plot_history(self):\n", + " \"\"\"Plot training history\"\"\"\n", + " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\n", + "\n", + " # Loss plot\n", + " ax1.plot(self.history['train_loss'], label='Train Loss')\n", + " ax1.plot(self.history['test_loss'], label='Test Loss')\n", + " ax1.set_title(f'{self.model_type.upper()} - Loss')\n", + " ax1.set_xlabel('Epoch')\n", + " ax1.set_ylabel('Loss')\n", + " ax1.legend()\n", + " ax1.grid(True, alpha=0.3)\n", + "\n", + " # Accuracy plot\n", + " ax2.plot(self.history['train_acc'], label='Train Acc')\n", + " ax2.plot(self.history['test_acc'], label='Test Acc')\n", + " ax2.set_title(f'{self.model_type.upper()} - Accuracy')\n", + " ax2.set_xlabel('Epoch')\n", + " ax2.set_ylabel('Accuracy (%)')\n", + " ax2.legend()\n", + " ax2.grid(True, alpha=0.3)\n", + "\n", + " plt.tight_layout()\n", + " save_path = Path(f\"mnist_models/{self.model_type}_history.png\")\n", + " plt.savefig(save_path)\n", + " plt.show()\n", + "\n", + " print(f\"ํ•™์Šต ๊ทธ๋ž˜ํ”„ ์ €์žฅ: {save_path}\")\n", + "\n", + "\n", + "def main():\n", + " \"\"\"์„ธ ๋ชจ๋ธ ์ˆœ์ฐจ ํ•™์Šต ๋ฐ ๊ฒฐ๊ณผ ์š”์•ฝ\"\"\"\n", + "\n", + " results = {}\n", + "\n", + " # 3๊ฐ€์ง€ ๋ชจ๋ธ ์ˆœ์ฐจ ํ•™์Šต\n", + " for model_type in ['efficientnet', 'resnet', 'mobilenet']:\n", + " print(f\"\\n{'#'*60}\")\n", + " print(f\"# {model_type.upper()} ๋ชจ๋ธ ํ•™์Šต ์‹œ์ž‘\")\n", + " print(f\"{'#'*60}\")\n", + "\n", + " trainer = AdvancedMNISTTrainer(\n", + " model_type=model_type,\n", + " num_classes=10,\n", + " batch_size=128,\n", + " learning_rate=0.001,\n", + " num_epochs=15\n", + " )\n", + "\n", + " model, history = trainer.train()\n", + " trainer.plot_history()\n", + "\n", + " results[model_type] = {\n", + " 'best_acc': trainer.best_acc,\n", + " 'model_path': f\"mnist_models/best_{model_type}_mnist_model.pth\"\n", + " }\n", + "\n", + " # ๊ฒฐ๊ณผ ์š”์•ฝ\n", + " print(f\"\\n{'='*60}\")\n", + " print(\"MNIST ํ•™์Šต ๊ฒฐ๊ณผ ์š”์•ฝ\")\n", + " print(f\"{'='*60}\")\n", + "\n", + " for model_type, result in results.items():\n", + " print(f\"{model_type.upper()}:\")\n", + " print(f\" - Best Test Accuracy: {result['best_acc']:.2f}%\")\n", + " print(f\" - Model Path: {result['model_path']}\")\n", + "\n", + " # ์ตœ๊ณ  ์„ฑ๋Šฅ ๋ชจ๋ธ ํ™•์ธ\n", + " best_model = max(results.keys(), key=lambda x: results[x]['best_acc'])\n", + " print(f\"\\n์ตœ๊ณ  ์„ฑ๋Šฅ ๋ชจ๋ธ: {best_model.upper()} ({results[best_model]['best_acc']:.2f}%)\")\n", + "\n", + " print(f\"\\n{'='*60}\")\n", + " print(\"๋ชจ๋“  MNIST ํ•™์Šต ์™„๋ฃŒ!\")\n", + " print(f\"{'='*60}\")\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e545b5c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "eec71241", + "metadata": {}, + "source": [ + "ํ•™์Šต ์™„๋ฃŒ๋œ ๋ชจ๋ธ Kaggle์— ์—…๋กœ๋“œ " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7b3454c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๋‚ด ๋ฐ์ดํ„ฐ์…‹ ๋ชฉ๋ก:\n", + " - minyujin03/mnist-base-models\n" + ] + } + ], + "source": [ + "from kaggle.api.kaggle_api_extended import KaggleApi\n", + "\n", + "api = KaggleApi()\n", + "api.authenticate()\n", + "\n", + "# ์˜ฌ๋ฆฐ ๋ชจ๋ธ ํ™•์ธ\n", + "datasets = api.dataset_list(user='minyujin03')\n", + "print(\"๋‚ด ๋ฐ์ดํ„ฐ์…‹ ๋ชฉ๋ก:\")\n", + "for dataset in datasets:\n", + " print(f\" - {dataset.ref}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "gradi", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ai-service/test/Classification/mnist_base_model_README.md b/ai-service/test/Classification/mnist_base_model_README.md new file mode 100644 index 0000000..689bb54 --- /dev/null +++ b/ai-service/test/Classification/mnist_base_model_README.md @@ -0,0 +1,14 @@ +`mnist_base_model.ipynb` ์ฝ”๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค. + +ํ•ด๋‹น ์ฝ”๋“œ๋Š” answer_1, answer_2์˜ crop image์— ๋‚˜ํƒ€๋‚œ ์ˆซ์ž๋ฅผ ์˜ˆ์ธก(์ธ์‹)ํ•˜๊ธฐ ์ „ ๊ธฐ์ดˆ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค. + +ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ ๋ชจ๋ธ์ด 1~5 ์‚ฌ์ด ์ˆซ์ž๋ฅผ ์˜ˆ์ธกํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. +์šฐ์„  ๋ชจ๋ธ์—๊ฒŒ mnist๋ฅผ ํ•™์Šต์‹œ์ผœ ์ˆซ์ž ์†๊ธ€์”จ ์ธ์‹ ๋Šฅ๋ ฅ์„ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค. + +*base model ํ›„๋ณด* +1. EfficientNet-B0 +2. ResNet18 +3. MobileNetV3 + +์œ„ 3๊ฐ€์ง€ ๋ชจ๋ธ์— ๋Œ€ํ•œ mnist ํ•™์Šต์€ ์ด๋ฏธ ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉฐ +**๋”ฐ๋ผ์„œ, `mnist_base_model.ipynb` ์ฝ”๋“œ๋Š” ์‹คํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.** \ No newline at end of file diff --git a/ai-service/test/Classification/predict_answer.ipynb b/ai-service/test/Classification/predict_answer.ipynb new file mode 100644 index 0000000..51506ac --- /dev/null +++ b/ai-service/test/Classification/predict_answer.ipynb @@ -0,0 +1,1465 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d4a3a57a", + "metadata": {}, + "source": [ + "'predict_answer.ipynb'๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์˜ˆ์ธก ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์„ธ์š”.\n", + "\n", + "-> **README.md์— ์žˆ๋Š” ๋งํฌ์—์„œ answer_1, answer_2 ์ด๋ฏธ์ง€๋ฅผ ๋‹ค์šด๋ฐ›์•„ CNN ํด๋”์— ๋„ฃ์€ ํ›„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜์„ธ์š”**\n", + "\n", + "\n", + "-> **kaggle ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ, kaggle > setting์—์„œ kaggle.json์„ ๋‹ค์šด๋ฐ›์•„ CNN ํด๋”์— ๋„ฃ์€ ๋’ค ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • ์ฝ”๋“œ๋ฅผ ์ฃผ์„ ํ•ด์ œ ํ›„ ์‹คํ–‰ํ•˜์„ธ์š”.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e2d3f4e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… Kaggle API ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n", + "USERNAME: harukaggler\n" + ] + } + ], + "source": [ + "# import os\n", + "# import json\n", + "\n", + "# # 1๏ธโƒฃ kaggle.json ํŒŒ์ผ ๊ฒฝ๋กœ ์ง€์ •\n", + "# kaggle_json_path = os.path.expanduser(\"kaggle.json\")\n", + "\n", + "# # 2๏ธโƒฃ kaggle.json ํŒŒ์ผ์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ\n", + "# if not os.path.exists(kaggle_json_path):\n", + "# raise FileNotFoundError(\n", + "# f\"kaggle.json ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {kaggle_json_path}\\n\"\n", + "# )\n", + "\n", + "# # 3๏ธโƒฃ kaggle.json ๋‚ด์šฉ ์ฝ๊ธฐ\n", + "# with open(kaggle_json_path, \"r\") as f:\n", + "# kaggle_config = json.load(f)\n", + "\n", + "# # 4๏ธโƒฃ os ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •\n", + "# os.environ[\"KAGGLE_USERNAME\"] = kaggle_config.get(\"username\")\n", + "# os.environ[\"KAGGLE_KEY\"] = kaggle_config.get(\"key\")\n", + "\n", + "# print(\"โœ… Kaggle API ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\")\n", + "# print(f\"USERNAME: {os.environ['KAGGLE_USERNAME']}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "8abdc095", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "======================================================================\n", + "Fine-tuned ๋ชจ๋ธ ์˜ˆ์ธก ํ…Œ์ŠคํŠธ (Kaggle ๋ชจ๋ธ ์‚ฌ์šฉ)\n", + "======================================================================\n", + "\n", + "๋””๋ฐ”์ด์Šค: cuda\n", + "\n", + "======================================================================\n", + "Step 1: Kaggle์—์„œ ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ\n", + "======================================================================\n", + "Kaggle์—์„œ ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ ์ค‘\n", + "Dataset: minyujin03/mnist-finetuned-models\n", + "Dataset URL: https://www.kaggle.com/datasets/minyujin03/mnist-finetuned-models\n", + "โœ… ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ! 6๊ฐœ ํŒŒ์ผ\n", + " - answer_1_resnet.pth (42.69 MB)\n", + " - answer_2_efficientnet.pth (4.15 MB)\n", + " - answer_2_resnet.pth (42.69 MB)\n", + " - answer_1_mobilenet.pth (3.86 MB)\n", + " - answer_1_efficientnet.pth (4.15 MB)\n", + " - answer_2_mobilenet.pth (3.86 MB)\n", + "\n", + "======================================================================\n", + "Step 2: ๋ชจ๋ธ ํ‰๊ฐ€\n", + "======================================================================\n", + "\n", + "############################################################\n", + "๐Ÿ“Š answer_1 / RESNET ํ‰๊ฐ€\n", + "############################################################\n", + " ๋ชจ๋ธ: kaggle_models/answer_1_resnet.pth\n", + " ๋ฐ์ดํ„ฐ: answer_1\n", + " Model loaded from CV checkpoint\n", + " Best CV Validation Acc: 94.20%\n", + " RESNET ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ\n", + "\n", + "--- answer_1 / RESNET ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ---\n", + " ํด๋ž˜์Šค 1: 189/189 ์ •๋‹ต (100.00%)\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 3_answer_1_029_conf0.685.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=2\n", + " โŒ 2023 ์‹ค์ „ - 33_answer_1_090_conf0.245.jpg: ์˜ˆ์ธก=1, ์‹ค์ œ=2\n", + " ํด๋ž˜์Šค 2: 206/208 ์ •๋‹ต (99.04%)\n", + " โŒ 2023 ์‹ค์ „ - 33_answer_1_088_conf0.671.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=3\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์œ ํ˜•ํŽธ - 24_answer_1_237_conf0.551.jpg: ์˜ˆ์ธก=1, ์‹ค์ œ=3\n", + " ํด๋ž˜์Šค 3: 191/193 ์ •๋‹ต (98.96%)\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 54_answer_1_159_conf0.434.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=4\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 5_answer_1_037_conf0.602.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=4\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 7_answer_1_098_conf0.418.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=4\n", + " ํด๋ž˜์Šค 4: 211/214 ์ •๋‹ต (98.60%)\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 30_answer_1_149_conf0.542.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 68_answer_1_195_conf0.637.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 68_answer_1_197_conf0.408.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 16_answer_1_072_conf0.683.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 16_answer_1_017_conf0.583.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 26_answer_1_063_conf0.654.jpg: ์˜ˆ์ธก=1, ์‹ค์ œ=5\n", + " ํด๋ž˜์Šค 5: 222/228 ์ •๋‹ต (97.37%)\n", + "--- ์ „์ฒด ์ •ํ™•๋„: 98.74% (1019/1032) ---\n", + "\n", + "############################################################\n", + "๐Ÿ“Š answer_2 / RESNET ํ‰๊ฐ€\n", + "############################################################\n", + " ๋ชจ๋ธ: kaggle_models/answer_2_resnet.pth\n", + " ๋ฐ์ดํ„ฐ: answer_2\n", + " Model loaded from CV checkpoint\n", + " Best CV Validation Acc: 100.00%\n", + " RESNET ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ\n", + "\n", + "--- answer_2 / RESNET ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ---\n", + " ํด๋ž˜์Šค 1: 165/165 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 2: 196/196 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 3: 188/188 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 4: 210/210 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 5: 168/168 ์ •๋‹ต (100.00%)\n", + "--- ์ „์ฒด ์ •ํ™•๋„: 100.00% (927/927) ---\n", + "\n", + "############################################################\n", + "๐Ÿ“Š answer_1 / EFFICIENTNET ํ‰๊ฐ€\n", + "############################################################\n", + " ๋ชจ๋ธ: kaggle_models/answer_1_efficientnet.pth\n", + " ๋ฐ์ดํ„ฐ: answer_1\n", + " Model loaded from CV checkpoint\n", + " Best CV Validation Acc: 85.92%\n", + " EFFICIENTNET ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ\n", + "\n", + "--- answer_1 / EFFICIENTNET ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ---\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_120_conf0.575.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=1\n", + " ํด๋ž˜์Šค 1: 188/189 ์ •๋‹ต (99.47%)\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 43_answer_1_010_conf0.721.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=2\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 31_answer_1_154_conf0.229.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=2\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 7_answer_1_043_conf0.510.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=2\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 26_answer_1_137_conf0.490.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=2\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์œ ํ˜•ํŽธ - 15_answer_1_218_conf0.595.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=2\n", + " ํด๋ž˜์Šค 2: 203/208 ์ •๋‹ต (97.60%)\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 74_answer_1_082_conf0.651.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_1_162_conf0.410.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 16_answer_1_018_conf0.539.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=3\n", + " โŒ 2023 ์‹ค์ „ - 8_answer_1_150_conf0.621.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_225_conf0.542.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 34_answer_1_166_conf0.223.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_000_conf0.691.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 34_answer_1_164_conf0.358.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_answer_1_188_conf0.673.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=3\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 8_answer_1_204_conf0.442.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 3_answer_1_033_conf0.511.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=3\n", + " โŒ 2023 ์‹ค์ „ - 76_answer_1_140_conf0.403.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 34_answer_1_165_conf0.320.jpg: ์˜ˆ์ธก=1, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 17_answer_1_076_conf0.518.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " ํด๋ž˜์Šค 3: 179/193 ์ •๋‹ต (92.75%)\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 45_answer_1_015_conf0.439.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=4\n", + " โŒ 2023 ์‹ค์ „ - 6_answer_1_104_conf0.276.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=4\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 4_answer_1_034_conf0.569.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=4\n", + " โŒ 2023 ์œ ํ˜• - 57_answer_1_219_conf0.693.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=4\n", + " ํด๋ž˜์Šค 4: 210/214 ์ •๋‹ต (98.13%)\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 68_answer_1_195_conf0.637.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 9_answer_1_101_conf0.613.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 85_answer_1_167_conf0.277.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์œ ํ˜• - 47_answer_1_195_conf0.744.jpg: ์˜ˆ์ธก=1, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 20_answer_1_045_conf0.535.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 17_answer_1_074_conf0.617.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 27_answer_1_140_conf0.486.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 58_answer_1_047_conf0.603.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 63_answer_1_058_conf0.567.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 71_answer_1_124_conf0.335.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 85_answer_1_166_conf0.464.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_answer_1_204_conf0.711.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " ํด๋ž˜์Šค 5: 216/228 ์ •๋‹ต (94.74%)\n", + "--- ์ „์ฒด ์ •ํ™•๋„: 96.51% (996/1032) ---\n", + "\n", + "############################################################\n", + "๐Ÿ“Š answer_2 / EFFICIENTNET ํ‰๊ฐ€\n", + "############################################################\n", + " ๋ชจ๋ธ: kaggle_models/answer_2_efficientnet.pth\n", + " ๋ฐ์ดํ„ฐ: answer_2\n", + " Model loaded from CV checkpoint\n", + " Best CV Validation Acc: 100.00%\n", + " EFFICIENTNET ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ\n", + "\n", + "--- answer_2 / EFFICIENTNET ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ---\n", + " ํด๋ž˜์Šค 1: 165/165 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 2: 196/196 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 3: 188/188 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 4: 210/210 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 5: 168/168 ์ •๋‹ต (100.00%)\n", + "--- ์ „์ฒด ์ •ํ™•๋„: 100.00% (927/927) ---\n", + "\n", + "############################################################\n", + "๐Ÿ“Š answer_1 / MOBILENET ํ‰๊ฐ€\n", + "############################################################\n", + " ๋ชจ๋ธ: kaggle_models/answer_1_mobilenet.pth\n", + " ๋ฐ์ดํ„ฐ: answer_1\n", + " Model loaded from CV checkpoint\n", + " Best CV Validation Acc: 80.58%\n", + " MOBILENET ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ\n", + "\n", + "--- answer_1 / MOBILENET ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ---\n", + " โŒ 2023 ์‹ค์ „ - 11_answer_1_009_conf0.562.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=1\n", + " ํด๋ž˜์Šค 1: 188/189 ์ •๋‹ต (99.47%)\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 25_answer_1_059_conf0.563.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=2\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 68_answer_1_067_conf0.634.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=2\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 2_answer_1_027_conf0.549.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=2\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 43_answer_1_010_conf0.721.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=2\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 31_answer_1_154_conf0.229.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=2\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 21_answer_1_047_conf0.559.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=2\n", + " โŒ 2023 ์œ ํ˜• - 41_answer_1_180_conf0.603.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=2\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 2_answer_1_080_conf0.500.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=2\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_025_conf0.566.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=2\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 7_answer_1_043_conf0.510.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=2\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์œ ํ˜•ํŽธ - 36_answer_1_266_conf0.490.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=2\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์œ ํ˜•ํŽธ - 15_answer_1_218_conf0.595.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=2\n", + " ํด๋ž˜์Šค 2: 196/208 ์ •๋‹ต (94.23%)\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 33_answer_1_158_conf0.529.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 74_answer_1_082_conf0.651.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_1_162_conf0.410.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 3_answer_1_076_conf0.523.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_042_conf0.509.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=3\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 7_answer_1_201_conf0.272.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 34_answer_1_166_conf0.223.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 43_answer_1_120_conf0.730.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=3\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์œ ํ˜•ํŽธ - 34_answer_1_259_conf0.592.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=3\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 7_answer_1_199_conf0.570.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 47_answer_1_021_conf0.483.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 34_answer_1_164_conf0.358.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2023 ์‹ค์ „ - 19_answer_1_035_conf0.322.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=3\n", + " โŒ 2023 ์‹ค์ „ - 71_answer_1_122_conf0.660.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 3_answer_1_033_conf0.511.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2023 ์œ ํ˜• - 69_answer_1_245_conf0.743.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=3\n", + " โŒ 2023 ์œ ํ˜• - 43_answer_1_187_conf0.230.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 34_answer_1_165_conf0.320.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 18_answer_1_108_conf0.472.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 50_answer_1_028_conf0.615.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 64_answer_1_059_conf0.647.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 26_answer_1_138_conf0.368.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2023 ์‹ค์ „ - 2_answer_1_041_conf0.276.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 20_answer_1_119_conf0.517.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 4_answer_1_112_conf0.530.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " โŒ 2023 ์œ ํ˜• - 70_answer_1_248_conf0.718.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=3\n", + " ํด๋ž˜์Šค 3: 167/193 ์ •๋‹ต (86.53%)\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 45_answer_1_015_conf0.439.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=4\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 44_answer_1_013_conf0.488.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=4\n", + " โŒ 2023 ์‹ค์ „ - 6_answer_1_104_conf0.276.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=4\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 8_answer_1_046_conf0.480.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=4\n", + " โŒ 2023 ์‹ค์ „ - 70_answer_1_116_conf0.604.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=4\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 4_answer_1_034_conf0.569.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=4\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 1_answer_1_050_conf0.535.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=4\n", + " โŒ 2023 ์œ ํ˜• - 57_answer_1_219_conf0.693.jpg: ์˜ˆ์ธก=5, ์‹ค์ œ=4\n", + " ํด๋ž˜์Šค 4: 206/214 ์ •๋‹ต (96.26%)\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์œ ํ˜•ํŽธ - 12_answer_1_211_conf0.659.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 46_answer_1_019_conf0.229.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์œ ํ˜•ํŽธ - 11_answer_1_210_conf0.667.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_080_conf0.367.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 68_answer_1_195_conf0.637.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_028_conf0.670.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 19_answer_1_111_conf0.577.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 31_answer_1_084_conf0.780.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์œ ํ˜•ํŽธ - 12_answer_1_212_conf0.570.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_answer_1_073_conf0.659.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 75_answer_1_137_conf0.662.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_113_conf0.609.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 9_answer_1_101_conf0.613.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 9_answer_1_047_conf0.612.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 17_answer_1_024_conf0.260.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 27_answer_1_142_conf0.342.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 16_answer_1_072_conf0.683.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 1_answer_1_003_conf0.486.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 10_answer_1_057_conf0.475.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 16_answer_1_019_conf0.640.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์œ ํ˜• - 47_answer_1_195_conf0.744.jpg: ์˜ˆ์ธก=2, ์‹ค์ œ=5\n", + " โŒ 2023 ์œ ํ˜• - 53_answer_1_209_conf0.690.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 4_answer_1_099_conf0.228.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 10_answer_1_058_conf0.337.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 6_answer_1_094_conf0.511.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 18_answer_1_025_conf0.706.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 74_answer_1_134_conf0.358.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 1_answer_1_000_conf0.813.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 40_answer_1_004_conf0.611.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 3_answer_1_088_conf0.383.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 17_answer_1_074_conf0.617.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 71_answer_1_121_conf0.674.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_answer_1_008_conf0.569.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 12_answer_1_010_conf0.245.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_answer_1_052_conf0.635.jpg: ์˜ˆ์ธก=1, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 29_answer_1_070_conf0.371.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 1_answer_1_000_conf0.663.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์œ ํ˜• - 51_answer_1_204_conf0.694.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_answer_1_213_conf0.664.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 25_answer_1_136_conf0.418.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 7_answer_1_110_conf0.643.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 3_answer_1_030_conf0.650.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 63_answer_1_058_conf0.567.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 71_answer_1_124_conf0.335.jpg: ์˜ˆ์ธก=1, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์‹ค์ „ - 57_answer_1_168_conf0.353.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2023 ์‹ค์ „ - 85_answer_1_166_conf0.464.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ 5ํšŒ - 6_answer_1_040_conf0.630.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ 2025 ์ˆ˜๋Šฅ์™„์„ฑ ์œ ํ˜•ํŽธ - 13_answer_1_213_conf0.581.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ 2022 ์œ ํ˜•ํŽธ - 70_answer_1_073_conf0.671.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (๋งž์Œ) - 5_answer_1_092_conf0.654.jpg: ์˜ˆ์ธก=4, ์‹ค์ œ=5\n", + " โŒ ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_047_conf0.477.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " โŒ 2022 ์‹ค์ „ํŽธ ์ฒดํฌ (ํ‹€๋ฆผ) - 29_answer_1_148_conf0.544.jpg: ์˜ˆ์ธก=3, ์‹ค์ œ=5\n", + " ํด๋ž˜์Šค 5: 176/228 ์ •๋‹ต (77.19%)\n", + "--- ์ „์ฒด ์ •ํ™•๋„: 90.41% (933/1032) ---\n", + "\n", + "############################################################\n", + "๐Ÿ“Š answer_2 / MOBILENET ํ‰๊ฐ€\n", + "############################################################\n", + " ๋ชจ๋ธ: kaggle_models/answer_2_mobilenet.pth\n", + " ๋ฐ์ดํ„ฐ: answer_2\n", + " Model loaded from CV checkpoint\n", + " Best CV Validation Acc: 100.00%\n", + " MOBILENET ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ\n", + "\n", + "--- answer_2 / MOBILENET ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ---\n", + " ํด๋ž˜์Šค 1: 165/165 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 2: 196/196 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 3: 188/188 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 4: 210/210 ์ •๋‹ต (100.00%)\n", + " ํด๋ž˜์Šค 5: 168/168 ์ •๋‹ต (100.00%)\n", + "--- ์ „์ฒด ์ •ํ™•๋„: 100.00% (927/927) ---\n", + "\n", + "======================================================================\n", + "๐Ÿ† ์ตœ์ข… ์„ฑ๋Šฅ ์š”์•ฝ\n", + "======================================================================\n", + "\n", + "๐Ÿ“Š answer_1 ์„ฑ๋Šฅ:\n", + " RESNET : 98.74% (1019/1032)\n", + " EFFICIENTNET: 96.51% (996/1032)\n", + " MOBILENET : 90.41% (933/1032)\n", + "\n", + "๐Ÿ“Š answer_2 ์„ฑ๋Šฅ:\n", + " RESNET : 100.00% (927/927)\n", + " EFFICIENTNET: 100.00% (927/927)\n", + " MOBILENET : 100.00% (927/927)\n", + "\n", + "======================================================================\n", + "๋ชจ๋“  ํ‰๊ฐ€๋ฅผ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค!\n", + "======================================================================\n" + ] + } + ], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "from PIL import Image\n", + "import numpy as np\n", + "from pathlib import Path\n", + "import logging\n", + "import os\n", + "\n", + "logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "# ========== Model Architectures ==========\n", + "\n", + "class SEBlock(nn.Module):\n", + " \"\"\"Squeeze-and-Excitation block\"\"\"\n", + " def __init__(self, in_channels, se_channels):\n", + " super().__init__()\n", + " self.avg_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.fc = nn.Sequential(\n", + " nn.Linear(in_channels, se_channels, bias=False),\n", + " nn.SiLU(inplace=True),\n", + " nn.Linear(se_channels, in_channels, bias=False),\n", + " nn.Sigmoid()\n", + " )\n", + "\n", + " def forward(self, x):\n", + " b, c, _, _ = x.size()\n", + " y = self.avg_pool(x).view(b, c)\n", + " y = self.fc(y).view(b, c, 1, 1)\n", + " return x * y\n", + "\n", + "\n", + "class ResidualBlock(nn.Module):\n", + " \"\"\"Residual connection wrapper\"\"\"\n", + " def __init__(self, module):\n", + " super().__init__()\n", + " self.module = module\n", + "\n", + " def forward(self, x):\n", + " return x + self.module(x)\n", + "\n", + "\n", + "class BasicBlock(nn.Module):\n", + " \"\"\"Basic block for ResNet\"\"\"\n", + " def __init__(self, in_channels, out_channels, stride=1):\n", + " super().__init__()\n", + "\n", + " self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride, 1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(out_channels)\n", + " self.relu = nn.ReLU(inplace=True)\n", + "\n", + " self.conv2 = nn.Conv2d(out_channels, out_channels, 3, 1, 1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(out_channels)\n", + "\n", + " self.shortcut = nn.Sequential()\n", + " if stride != 1 or in_channels != out_channels:\n", + " self.shortcut = nn.Sequential(\n", + " nn.Conv2d(in_channels, out_channels, 1, stride, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " out = self.relu(self.bn1(self.conv1(x)))\n", + " out = self.bn2(self.conv2(out))\n", + " out += self.shortcut(x)\n", + " out = self.relu(out)\n", + " return out\n", + "\n", + "\n", + "class InvertedResidual(nn.Module):\n", + " \"\"\"Inverted Residual block for MobileNetV3\"\"\"\n", + " def __init__(self, in_channels, out_channels, kernel, stride, expand_ratio, se_ratio=None):\n", + " super().__init__()\n", + "\n", + " hidden_dim = int(in_channels * expand_ratio)\n", + " self.use_res_connect = stride == 1 and in_channels == out_channels\n", + "\n", + " layers = []\n", + "\n", + " if expand_ratio != 1:\n", + " layers.extend([\n", + " nn.Conv2d(in_channels, hidden_dim, 1, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.Hardswish(inplace=True)\n", + " ])\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, hidden_dim, kernel, stride,\n", + " kernel//2, groups=hidden_dim, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.Hardswish(inplace=True)\n", + " ])\n", + "\n", + " if se_ratio is not None:\n", + " se_channels = int(in_channels * se_ratio)\n", + " layers.append(SEBlock(hidden_dim, se_channels))\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, out_channels, 1, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " ])\n", + "\n", + " self.conv = nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " if self.use_res_connect:\n", + " return x + self.conv(x)\n", + " else:\n", + " return self.conv(x)\n", + "\n", + "\n", + "class EfficientNetB0_MNIST(nn.Module):\n", + " \"\"\"EfficientNet-B0 for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " self.conv_stem = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(32)\n", + " self.act1 = nn.SiLU(inplace=True)\n", + "\n", + " self.blocks = nn.Sequential(\n", + " self._make_mbconv(32, 16, kernel=3, stride=1, expand_ratio=1),\n", + " self._make_mbconv(16, 24, kernel=3, stride=2, expand_ratio=6),\n", + " self._make_mbconv(24, 24, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(24, 40, kernel=5, stride=2, expand_ratio=6),\n", + " self._make_mbconv(40, 40, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(40, 80, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(80, 80, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(80, 112, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(112, 112, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(112, 192, kernel=5, stride=1, expand_ratio=6),\n", + " )\n", + "\n", + " self.conv_head = nn.Conv2d(192, 1280, kernel_size=1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(1280)\n", + " self.act2 = nn.SiLU(inplace=True)\n", + "\n", + " self.global_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.classifier = nn.Sequential(\n", + " nn.Dropout(0.2),\n", + " nn.Linear(1280, num_classes)\n", + " )\n", + "\n", + " def _make_mbconv(self, in_channels, out_channels, kernel, stride, expand_ratio):\n", + " layers = []\n", + " hidden_dim = in_channels * expand_ratio\n", + "\n", + " if expand_ratio != 1:\n", + " layers.extend([\n", + " nn.Conv2d(in_channels, hidden_dim, 1, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.SiLU(inplace=True)\n", + " ])\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, hidden_dim, kernel, stride,\n", + " padding=kernel//2, groups=hidden_dim, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.SiLU(inplace=True)\n", + " ])\n", + "\n", + " se_channels = max(1, in_channels // 4)\n", + " layers.append(SEBlock(hidden_dim, se_channels))\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, out_channels, 1, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " ])\n", + "\n", + " if stride == 1 and in_channels == out_channels:\n", + " return ResidualBlock(nn.Sequential(*layers))\n", + "\n", + " return nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " x = self.conv_stem(x)\n", + " x = self.bn1(x)\n", + " x = self.act1(x)\n", + " x = self.blocks(x)\n", + " x = self.conv_head(x)\n", + " x = self.bn2(x)\n", + " x = self.act2(x)\n", + " x = self.global_pool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.classifier(x)\n", + " return x\n", + "\n", + "\n", + "class ResNet18_MNIST(nn.Module):\n", + " \"\"\"ResNet-18 for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(64)\n", + " self.relu = nn.ReLU(inplace=True)\n", + "\n", + " self.layer1 = self._make_layer(64, 64, 2, stride=1)\n", + " self.layer2 = self._make_layer(64, 128, 2, stride=2)\n", + " self.layer3 = self._make_layer(128, 256, 2, stride=2)\n", + " self.layer4 = self._make_layer(256, 512, 2, stride=2)\n", + "\n", + " self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n", + " self.fc = nn.Linear(512, num_classes)\n", + "\n", + " def _make_layer(self, in_channels, out_channels, blocks, stride=1):\n", + " layers = []\n", + " layers.append(BasicBlock(in_channels, out_channels, stride))\n", + " for _ in range(1, blocks):\n", + " layers.append(BasicBlock(out_channels, out_channels, stride=1))\n", + " return nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " x = self.conv1(x)\n", + " x = self.bn1(x)\n", + " x = self.relu(x)\n", + " x = self.layer1(x)\n", + " x = self.layer2(x)\n", + " x = self.layer3(x)\n", + " x = self.layer4(x)\n", + " x = self.avgpool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.fc(x)\n", + " return x\n", + "\n", + "\n", + "class MobileNetV3_MNIST(nn.Module):\n", + " \"\"\"MobileNetV3-Small for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " self.conv_stem = nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(16)\n", + " self.act1 = nn.Hardswish(inplace=True)\n", + "\n", + " self.blocks = nn.Sequential(\n", + " InvertedResidual(16, 16, kernel=3, stride=1, expand_ratio=1, se_ratio=0.25),\n", + " InvertedResidual(16, 24, kernel=3, stride=2, expand_ratio=4.5, se_ratio=None),\n", + " InvertedResidual(24, 24, kernel=3, stride=1, expand_ratio=3.67, se_ratio=None),\n", + " InvertedResidual(24, 40, kernel=5, stride=2, expand_ratio=4, se_ratio=0.25),\n", + " InvertedResidual(40, 40, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(40, 40, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(40, 48, kernel=5, stride=1, expand_ratio=3, se_ratio=0.25),\n", + " InvertedResidual(48, 48, kernel=5, stride=1, expand_ratio=3, se_ratio=0.25),\n", + " InvertedResidual(48, 96, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(96, 96, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " )\n", + "\n", + " self.conv_head = nn.Conv2d(96, 576, kernel_size=1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(576)\n", + " self.act2 = nn.Hardswish(inplace=True)\n", + "\n", + " self.global_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.classifier = nn.Sequential(\n", + " nn.Linear(576, 1024),\n", + " nn.Hardswish(inplace=True),\n", + " nn.Dropout(0.2),\n", + " nn.Linear(1024, num_classes)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " x = self.conv_stem(x)\n", + " x = self.bn1(x)\n", + " x = self.act1(x)\n", + " x = self.blocks(x)\n", + " x = self.conv_head(x)\n", + " x = self.bn2(x)\n", + " x = self.act2(x)\n", + " x = self.global_pool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.classifier(x)\n", + " return x\n", + "\n", + "\n", + "# ========== Kaggle Download Function ==========\n", + "\n", + "def download_models_from_kaggle(dataset_id='minyujin03/mnist-finetuned-models', \n", + " download_path='./kaggle_models'):\n", + " \"\"\"Kaggle์—์„œ fine-tuned ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ\"\"\"\n", + " \n", + " download_path = Path(download_path)\n", + " \n", + " # ์ด๋ฏธ ๋‹ค์šด๋กœ๋“œ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ\n", + " if download_path.exists() and len(list(download_path.glob('*.pth'))) == 6:\n", + " print(f\"โœ… ๋ชจ๋ธ์ด ์ด๋ฏธ ๋‹ค์šด๋กœ๋“œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค: {download_path}\")\n", + " return download_path\n", + " \n", + " print(f\"Kaggle์—์„œ ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ ์ค‘\")\n", + " print(f\"Dataset: {dataset_id}\")\n", + " \n", + " try:\n", + " from kaggle.api.kaggle_api_extended import KaggleApi\n", + " \n", + " api = KaggleApi()\n", + " api.authenticate()\n", + " \n", + " # ๋‹ค์šด๋กœ๋“œ ํด๋” ์ƒ์„ฑ\n", + " download_path.mkdir(parents=True, exist_ok=True)\n", + " \n", + " # ๋ฐ์ดํ„ฐ์…‹ ๋‹ค์šด๋กœ๋“œ\n", + " api.dataset_download_files(\n", + " dataset_id,\n", + " path=str(download_path),\n", + " unzip=True\n", + " )\n", + " \n", + " # ๋‹ค์šด๋กœ๋“œ๋œ ํŒŒ์ผ ํ™•์ธ\n", + " downloaded_files = list(download_path.glob('*.pth'))\n", + " print(f\"โœ… ๋‹ค์šด๋กœ๋“œ ์™„๋ฃŒ! {len(downloaded_files)}๊ฐœ ํŒŒ์ผ\")\n", + " for file in downloaded_files:\n", + " size_mb = file.stat().st_size / (1024 * 1024)\n", + " print(f\" - {file.name} ({size_mb:.2f} MB)\")\n", + " \n", + " return download_path\n", + " \n", + " except Exception as e:\n", + " print(f\"\\n Kaggle ๋‹ค์šด๋กœ๋“œ ์‹คํŒจ: {e}\")\n", + " print(\"\\n ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•:\")\n", + " print(\" 1. Kaggle API๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ: pip install kaggle\")\n", + " print(\" 2. ~/.kaggle/kaggle.json ํŒŒ์ผ์ด ์žˆ๋Š”์ง€ ํ™•์ธ\")\n", + " print(\" 3. Dataset์ด Public์ธ์ง€ ํ™•์ธ\")\n", + " raise\n", + "\n", + "\n", + "# ========== Model Loading ==========\n", + "\n", + "def load_answer_model(model_path, model_type, device='cpu'):\n", + " \"\"\"ํ•™์Šต๋œ Answer ๋ชจ๋ธ ๋กœ๋“œ\"\"\"\n", + "\n", + " try:\n", + " checkpoint = torch.load(model_path, map_location=device, weights_only=False)\n", + "\n", + " # CV ๊ฒฐ๊ณผ ํŒŒ์ผ ํ˜•์‹ (model_type ํฌํ•จ)\n", + " if isinstance(checkpoint, dict) and 'model_state_dict' in checkpoint and 'model_type' in checkpoint:\n", + " loaded_model_type = checkpoint['model_type']\n", + " model_state_dict = checkpoint['model_state_dict']\n", + " best_cv_acc = checkpoint.get('best_cv_acc', 'N/A')\n", + "\n", + " if loaded_model_type == 'resnet':\n", + " model = ResNet18_MNIST(num_classes=5) \n", + " elif loaded_model_type == 'efficientnet':\n", + " model = EfficientNetB0_MNIST(num_classes=5)\n", + " elif loaded_model_type == 'mobilenet':\n", + " model = MobileNetV3_MNIST(num_classes=5)\n", + " else:\n", + " raise ValueError(f\"Unsupported model type: {loaded_model_type}\")\n", + "\n", + " model.load_state_dict(model_state_dict, strict=False)\n", + " print(f\" Model loaded from CV checkpoint\")\n", + " if best_cv_acc != 'N/A':\n", + " print(f\" Best CV Validation Acc: {best_cv_acc:.2f}%\")\n", + "\n", + " # ๊ตฌ ํ˜•์‹ (model_state_dict๋งŒ)\n", + " elif isinstance(checkpoint, dict) and 'model_state_dict' in checkpoint:\n", + " if model_type == 'resnet':\n", + " model = ResNet18_MNIST(num_classes=5)\n", + " elif model_type == 'efficientnet':\n", + " model = EfficientNetB0_MNIST(num_classes=5)\n", + " elif model_type == 'mobilenet':\n", + " model = MobileNetV3_MNIST(num_classes=5)\n", + " else:\n", + " raise ValueError(f\"Unsupported model type: {model_type}\")\n", + "\n", + " model.load_state_dict(checkpoint['model_state_dict'], strict=False)\n", + " print(f\" Model loaded from old checkpoint\")\n", + " if 'val_acc' in checkpoint:\n", + " print(f\" Validation Acc: {checkpoint['val_acc']:.2f}%\")\n", + "\n", + " # Raw state_dict\n", + " else:\n", + " if model_type == 'resnet':\n", + " model = ResNet18_MNIST(num_classes=5)\n", + " elif model_type == 'efficientnet':\n", + " model = EfficientNetB0_MNIST(num_classes=5)\n", + " elif model_type == 'mobilenet':\n", + " model = MobileNetV3_MNIST(num_classes=5)\n", + " else:\n", + " raise ValueError(f\"Unsupported model type: {model_type}\")\n", + "\n", + " model.load_state_dict(checkpoint, strict=False)\n", + " print(f\" Raw state_dict loaded\")\n", + "\n", + " except RuntimeError as e:\n", + " if \"size mismatch\" in str(e):\n", + " logger.error(f\"โŒ Size mismatch: {model_path}\")\n", + " print(\"๐Ÿ’ก ๋ชจ๋ธ ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์ €์žฅ๋œ ๋ชจ๋ธ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค\")\n", + " else:\n", + " logger.error(f\"โŒ Failed to load: {model_path}. Error: {e}\")\n", + " raise e \n", + "\n", + " model = model.to(device)\n", + " model.eval()\n", + "\n", + " print(f\" {model_type.upper()} ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ\")\n", + "\n", + " return model\n", + "\n", + "\n", + "def preprocess_image(image_path):\n", + " \"\"\"์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ\"\"\"\n", + " image = Image.open(image_path).convert('L')\n", + " image = image.resize((28, 28))\n", + " image = torch.FloatTensor(np.array(image)).unsqueeze(0).unsqueeze(0) / 255.0\n", + " image = (image - 0.1307) / 0.3081\n", + " return image\n", + "\n", + "\n", + "def predict_single_image(model, image_path, device='cpu'):\n", + " \"\"\"๋‹จ์ผ ์ด๋ฏธ์ง€ ์˜ˆ์ธก\"\"\"\n", + " image = preprocess_image(image_path).to(device)\n", + "\n", + " with torch.no_grad():\n", + " output = model(image)\n", + " _, predicted = output.max(1)\n", + " prediction = predicted.item() + 1 \n", + "\n", + " return prediction\n", + "\n", + "\n", + "def evaluate_dataset(model, data_dir, model_type, answer_type, device):\n", + " \"\"\"๋ฐ์ดํ„ฐ์…‹ ์ „์ฒด ํ‰๊ฐ€\"\"\"\n", + "\n", + " total_correct = 0\n", + " total_images = 0\n", + "\n", + " print(f\"\\n--- {answer_type} / {model_type.upper()} ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ---\")\n", + "\n", + " # ๊ฐ ํด๋ž˜์Šค๋ณ„ ํ‰๊ฐ€\n", + " for class_idx in range(1, 6):\n", + " class_dir = data_dir / str(class_idx)\n", + " if not class_dir.exists():\n", + " print(f\" โš ๏ธ ํด๋ž˜์Šค {class_idx} ํด๋” ์—†์Œ\")\n", + " continue\n", + "\n", + " image_paths = list(class_dir.glob(\"*.jpg\")) + list(class_dir.glob(\"*.png\"))\n", + " correct = 0\n", + "\n", + " for img_path in image_paths:\n", + " prediction = predict_single_image(model, img_path, device)\n", + " if prediction == class_idx:\n", + " correct += 1\n", + " else:\n", + " print(f\" โŒ {img_path.name}: ์˜ˆ์ธก={prediction}, ์‹ค์ œ={class_idx}\")\n", + "\n", + " accuracy = 100. * correct / len(image_paths) if len(image_paths) > 0 else 0\n", + " print(f\" ํด๋ž˜์Šค {class_idx}: {correct}/{len(image_paths)} ์ •๋‹ต ({accuracy:.2f}%)\")\n", + "\n", + " total_correct += correct\n", + " total_images += len(image_paths)\n", + "\n", + " overall_accuracy = 100. * total_correct / total_images if total_images > 0 else 0\n", + " print(f\"--- ์ „์ฒด ์ •ํ™•๋„: {overall_accuracy:.2f}% ({total_correct}/{total_images}) ---\")\n", + " \n", + " return overall_accuracy, total_correct, total_images\n", + "\n", + "\n", + "# ========== Main Execution ==========\n", + "\n", + "def main():\n", + " \"\"\"๋ฉ”์ธ ์‹คํ–‰\"\"\"\n", + "\n", + " print(\"=\"*70)\n", + " print(\"Fine-tuned ๋ชจ๋ธ ์˜ˆ์ธก ํ…Œ์ŠคํŠธ (Kaggle ๋ชจ๋ธ ์‚ฌ์šฉ)\")\n", + " print(\"=\"*70)\n", + "\n", + " device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n", + " print(f\"\\n๋””๋ฐ”์ด์Šค: {device}\")\n", + "\n", + " # 1. Kaggle์—์„œ ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ\n", + " print(f\"\\n{'='*70}\")\n", + " print(f\"Step 1: Kaggle์—์„œ ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ\")\n", + " print(f\"{'='*70}\")\n", + " \n", + " KAGGLE_DATASET_ID = 'minyujin03/mnist-finetuned-models'\n", + " model_root = download_models_from_kaggle(\n", + " dataset_id=KAGGLE_DATASET_ID,\n", + " download_path='./kaggle_models'\n", + " )\n", + "\n", + " # 2. ๋กœ์ปฌ ๋ฐ์ดํ„ฐ ๊ฒฝ๋กœ ์„ค์ •\n", + " base_dir = Path(\".\")\n", + " data_root = base_dir # answer_1, answer_2 ํด๋”๊ฐ€ ์žˆ๋Š” ์œ„์น˜\n", + "\n", + " # 3. ํ‰๊ฐ€ํ•  ๋ชจ๋ธ ๋ชฉ๋ก\n", + " models_to_evaluate = [\n", + " {'answer': 'answer_1', 'type': 'resnet'},\n", + " {'answer': 'answer_2', 'type': 'resnet'},\n", + " {'answer': 'answer_1', 'type': 'efficientnet'}, \n", + " {'answer': 'answer_2', 'type': 'efficientnet'},\n", + " {'answer': 'answer_1', 'type': 'mobilenet'},\n", + " {'answer': 'answer_2', 'type': 'mobilenet'},\n", + " ]\n", + "\n", + " results = {}\n", + "\n", + " # 4. ๊ฐ ๋ชจ๋ธ ํ‰๊ฐ€\n", + " print(f\"\\n{'='*70}\")\n", + " print(f\"Step 2: ๋ชจ๋ธ ํ‰๊ฐ€\")\n", + " print(f\"{'='*70}\")\n", + "\n", + " for item in models_to_evaluate:\n", + " answer_type = item['answer']\n", + " model_type = item['type']\n", + " \n", + " # Kaggle์—์„œ ๋‹ค์šด๋กœ๋“œํ•œ ๋ชจ๋ธ ๊ฒฝ๋กœ\n", + " model_filename = f\"{answer_type}_{model_type}.pth\"\n", + " model_path = model_root / model_filename\n", + "\n", + " # ๋กœ์ปฌ ๋ฐ์ดํ„ฐ ๊ฒฝ๋กœ\n", + " data_dir = data_root / answer_type\n", + "\n", + " if not model_path.exists():\n", + " print(f\"\\nโŒ ๋ชจ๋ธ ํŒŒ์ผ ์—†์Œ: {model_path}\")\n", + " continue\n", + "\n", + " if not data_dir.exists():\n", + " print(f\"\\nโŒ ๋ฐ์ดํ„ฐ ํด๋” ์—†์Œ: {data_dir}\")\n", + " print(f\"{answer_type} ํด๋”๊ฐ€ ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์— ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”\")\n", + " continue\n", + "\n", + " try:\n", + " print(f\"\\n{'#'*60}\")\n", + " print(f\"๐Ÿ“Š {answer_type} / {model_type.upper()} ํ‰๊ฐ€\")\n", + " print(f\"{'#'*60}\")\n", + " print(f\" ๋ชจ๋ธ: {model_path}\")\n", + " print(f\" ๋ฐ์ดํ„ฐ: {data_dir}\")\n", + " \n", + " model = load_answer_model(model_path, model_type=model_type, device=device)\n", + " acc, correct, total = evaluate_dataset(model, data_dir, model_type, answer_type, device)\n", + " \n", + " results[f\"{answer_type}_{model_type}\"] = {\n", + " 'acc': acc, \n", + " 'correct': correct, \n", + " 'total': total\n", + " }\n", + " \n", + " except Exception as e:\n", + " print(f\"โŒ ํ‰๊ฐ€ ์ค‘ ์˜ค๋ฅ˜: {e}\")\n", + " import traceback\n", + " traceback.print_exc()\n", + "\n", + " # 5. ์ตœ์ข… ๊ฒฐ๊ณผ ์š”์•ฝ\n", + " print(f\"\\n{'='*70}\")\n", + " print(\"๐Ÿ† ์ตœ์ข… ์„ฑ๋Šฅ ์š”์•ฝ\")\n", + " print(f\"{'='*70}\")\n", + "\n", + " for answer_type in ['answer_1', 'answer_2']:\n", + " print(f\"\\n๐Ÿ“Š {answer_type} ์„ฑ๋Šฅ:\")\n", + " evaluated_models = [\n", + " m_type for m_type in ['resnet', 'efficientnet', 'mobilenet'] \n", + " if f\"{answer_type}_{m_type}\" in results\n", + " ]\n", + " \n", + " if evaluated_models:\n", + " for model_type in evaluated_models:\n", + " key = f\"{answer_type}_{model_type}\"\n", + " res = results[key]\n", + " print(f\" {model_type.upper():12s}: {res['acc']:6.2f}% ({res['correct']}/{res['total']})\")\n", + " else:\n", + " print(\" ํ‰๊ฐ€๋œ ๋ชจ๋ธ ์—†์Œ\")\n", + "\n", + " print(f\"\\n{'='*70}\")\n", + " print(\"๋ชจ๋“  ํ‰๊ฐ€๋ฅผ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค!\")\n", + " print(f\"{'='*70}\")\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50e15605", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "82858849", + "metadata": {}, + "source": [ + "์•„๋ž˜ ์…€์€ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9ef26610", + "metadata": {}, + "outputs": [ + { + "ename": "SyntaxError", + "evalue": "invalid syntax (3505671357.py, line 15)", + "output_type": "error", + "traceback": [ + "\u001b[0;36m Cell \u001b[0;32mIn[2], line 15\u001b[0;36m\u001b[0m\n\u001b[0;31m \"\"\"Squeeze-and-Excitation block\"\"\"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" + ] + } + ], + "source": [ + "\"\"\"\n", + "import torch\n", + "import torch.nn as nn\n", + "from PIL import Image\n", + "import numpy as np\n", + "from pathlib import Path\n", + "import logging\n", + "\n", + "logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "# ========== Model Architectures ==========\n", + "\n", + "class SEBlock(nn.Module):\n", + " \"\"\"Squeeze-and-Excitation block\"\"\"\n", + " def __init__(self, in_channels, se_channels):\n", + " super().__init__()\n", + " self.avg_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.fc = nn.Sequential(\n", + " nn.Linear(in_channels, se_channels, bias=False),\n", + " nn.SiLU(inplace=True),\n", + " nn.Linear(se_channels, in_channels, bias=False),\n", + " nn.Sigmoid()\n", + " )\n", + "\n", + " def forward(self, x):\n", + " b, c, _, _ = x.size()\n", + " y = self.avg_pool(x).view(b, c)\n", + " y = self.fc(y).view(b, c, 1, 1)\n", + " return x * y\n", + "\n", + "\n", + "class ResidualBlock(nn.Module):\n", + " \"\"\"Residual connection wrapper\"\"\"\n", + " def __init__(self, module):\n", + " super().__init__()\n", + " self.module = module\n", + "\n", + " def forward(self, x):\n", + " return x + self.module(x)\n", + "\n", + "\n", + "class BasicBlock(nn.Module):\n", + " \"\"\"Basic block for ResNet\"\"\"\n", + " def __init__(self, in_channels, out_channels, stride=1):\n", + " super().__init__()\n", + "\n", + " self.conv1 = nn.Conv2d(in_channels, out_channels, 3, stride, 1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(out_channels)\n", + " self.relu = nn.ReLU(inplace=True)\n", + "\n", + " self.conv2 = nn.Conv2d(out_channels, out_channels, 3, 1, 1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(out_channels)\n", + "\n", + " self.shortcut = nn.Sequential()\n", + " if stride != 1 or in_channels != out_channels:\n", + " self.shortcut = nn.Sequential(\n", + " nn.Conv2d(in_channels, out_channels, 1, stride, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " out = self.relu(self.bn1(self.conv1(x)))\n", + " out = self.bn2(self.conv2(out))\n", + " out += self.shortcut(x)\n", + " out = self.relu(out)\n", + " return out\n", + "\n", + "\n", + "class InvertedResidual(nn.Module):\n", + " \"\"\"Inverted Residual block for MobileNetV3\"\"\"\n", + " def __init__(self, in_channels, out_channels, kernel, stride, expand_ratio, se_ratio=None):\n", + " super().__init__()\n", + "\n", + " hidden_dim = int(in_channels * expand_ratio)\n", + " self.use_res_connect = stride == 1 and in_channels == out_channels\n", + "\n", + " layers = []\n", + "\n", + " if expand_ratio != 1:\n", + " layers.extend([\n", + " nn.Conv2d(in_channels, hidden_dim, 1, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.Hardswish(inplace=True)\n", + " ])\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, hidden_dim, kernel, stride,\n", + " kernel//2, groups=hidden_dim, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.Hardswish(inplace=True)\n", + " ])\n", + "\n", + " if se_ratio is not None:\n", + " se_channels = int(in_channels * se_ratio)\n", + " layers.append(SEBlock(hidden_dim, se_channels))\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, out_channels, 1, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " ])\n", + "\n", + " self.conv = nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " if self.use_res_connect:\n", + " return x + self.conv(x)\n", + " else:\n", + " return self.conv(x)\n", + "\n", + "\n", + "class EfficientNetB0_MNIST(nn.Module):\n", + " \"\"\"EfficientNet-B0 for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " self.conv_stem = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(32)\n", + " self.act1 = nn.SiLU(inplace=True)\n", + "\n", + " self.blocks = nn.Sequential(\n", + " self._make_mbconv(32, 16, kernel=3, stride=1, expand_ratio=1),\n", + " self._make_mbconv(16, 24, kernel=3, stride=2, expand_ratio=6),\n", + " self._make_mbconv(24, 24, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(24, 40, kernel=5, stride=2, expand_ratio=6),\n", + " self._make_mbconv(40, 40, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(40, 80, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(80, 80, kernel=3, stride=1, expand_ratio=6),\n", + " self._make_mbconv(80, 112, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(112, 112, kernel=5, stride=1, expand_ratio=6),\n", + " self._make_mbconv(112, 192, kernel=5, stride=1, expand_ratio=6),\n", + " )\n", + "\n", + " self.conv_head = nn.Conv2d(192, 1280, kernel_size=1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(1280)\n", + " self.act2 = nn.SiLU(inplace=True)\n", + "\n", + " self.global_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.classifier = nn.Sequential(\n", + " nn.Dropout(0.2),\n", + " nn.Linear(1280, num_classes)\n", + " )\n", + "\n", + " def _make_mbconv(self, in_channels, out_channels, kernel, stride, expand_ratio):\n", + " layers = []\n", + " hidden_dim = in_channels * expand_ratio\n", + "\n", + " if expand_ratio != 1:\n", + " layers.extend([\n", + " nn.Conv2d(in_channels, hidden_dim, 1, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.SiLU(inplace=True)\n", + " ])\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, hidden_dim, kernel, stride,\n", + " padding=kernel//2, groups=hidden_dim, bias=False),\n", + " nn.BatchNorm2d(hidden_dim),\n", + " nn.SiLU(inplace=True)\n", + " ])\n", + "\n", + " se_channels = max(1, in_channels // 4)\n", + " layers.append(SEBlock(hidden_dim, se_channels))\n", + "\n", + " layers.extend([\n", + " nn.Conv2d(hidden_dim, out_channels, 1, bias=False),\n", + " nn.BatchNorm2d(out_channels)\n", + " ])\n", + "\n", + " if stride == 1 and in_channels == out_channels:\n", + " return ResidualBlock(nn.Sequential(*layers))\n", + "\n", + " return nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " x = self.conv_stem(x)\n", + " x = self.bn1(x)\n", + " x = self.act1(x)\n", + " x = self.blocks(x)\n", + " x = self.conv_head(x)\n", + " x = self.bn2(x)\n", + " x = self.act2(x)\n", + " x = self.global_pool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.classifier(x)\n", + " return x\n", + "\n", + "\n", + "class ResNet18_MNIST(nn.Module):\n", + " \"\"\"ResNet-18 for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(64)\n", + " self.relu = nn.ReLU(inplace=True)\n", + "\n", + " self.layer1 = self._make_layer(64, 64, 2, stride=1)\n", + " self.layer2 = self._make_layer(64, 128, 2, stride=2)\n", + " self.layer3 = self._make_layer(128, 256, 2, stride=2)\n", + " self.layer4 = self._make_layer(256, 512, 2, stride=2)\n", + "\n", + " self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n", + " self.fc = nn.Linear(512, num_classes)\n", + "\n", + " def _make_layer(self, in_channels, out_channels, blocks, stride=1):\n", + " layers = []\n", + " layers.append(BasicBlock(in_channels, out_channels, stride))\n", + " for _ in range(1, blocks):\n", + " layers.append(BasicBlock(out_channels, out_channels, stride=1))\n", + " return nn.Sequential(*layers)\n", + "\n", + " def forward(self, x):\n", + " x = self.conv1(x)\n", + " x = self.bn1(x)\n", + " x = self.relu(x)\n", + " x = self.layer1(x)\n", + " x = self.layer2(x)\n", + " x = self.layer3(x)\n", + " x = self.layer4(x)\n", + " x = self.avgpool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.fc(x)\n", + " return x\n", + "\n", + "\n", + "class MobileNetV3_MNIST(nn.Module):\n", + " \"\"\"MobileNetV3-Small for MNIST\"\"\"\n", + " def __init__(self, num_classes=10):\n", + " super().__init__()\n", + "\n", + " self.conv_stem = nn.Conv2d(1, 16, kernel_size=3, stride=1, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(16)\n", + " self.act1 = nn.Hardswish(inplace=True)\n", + "\n", + " self.blocks = nn.Sequential(\n", + " InvertedResidual(16, 16, kernel=3, stride=1, expand_ratio=1, se_ratio=0.25),\n", + " InvertedResidual(16, 24, kernel=3, stride=2, expand_ratio=4.5, se_ratio=None),\n", + " InvertedResidual(24, 24, kernel=3, stride=1, expand_ratio=3.67, se_ratio=None),\n", + " InvertedResidual(24, 40, kernel=5, stride=2, expand_ratio=4, se_ratio=0.25),\n", + " InvertedResidual(40, 40, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(40, 40, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(40, 48, kernel=5, stride=1, expand_ratio=3, se_ratio=0.25),\n", + " InvertedResidual(48, 48, kernel=5, stride=1, expand_ratio=3, se_ratio=0.25),\n", + " InvertedResidual(48, 96, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " InvertedResidual(96, 96, kernel=5, stride=1, expand_ratio=6, se_ratio=0.25),\n", + " )\n", + "\n", + " self.conv_head = nn.Conv2d(96, 576, kernel_size=1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(576)\n", + " self.act2 = nn.Hardswish(inplace=True)\n", + "\n", + " self.global_pool = nn.AdaptiveAvgPool2d(1)\n", + " self.classifier = nn.Sequential(\n", + " nn.Linear(576, 1024),\n", + " nn.Hardswish(inplace=True),\n", + " nn.Dropout(0.2),\n", + " nn.Linear(1024, num_classes)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " x = self.conv_stem(x)\n", + " x = self.bn1(x)\n", + " x = self.act1(x)\n", + " x = self.blocks(x)\n", + " x = self.conv_head(x)\n", + " x = self.bn2(x)\n", + " x = self.act2(x)\n", + " x = self.global_pool(x)\n", + " x = torch.flatten(x, 1)\n", + " x = self.classifier(x)\n", + " return x\n", + "\n", + "#=================================================\n", + "\n", + "\n", + "def load_answer_model(model_path, model_type, device='cpu'):\n", + " \"\"\"ํ•™์Šต๋œ Answer ๋ชจ๋ธ ๋กœ๋“œ\"\"\"\n", + "\n", + " try:\n", + " \n", + " checkpoint = torch.load(model_path, map_location=device, weights_only=False)\n", + "\n", + " \n", + " if isinstance(checkpoint, dict) and 'model_state_dict' in checkpoint and 'model_type' in checkpoint:\n", + " loaded_model_type = checkpoint['model_type']\n", + " model_state_dict = checkpoint['model_state_dict']\n", + " best_cv_acc = checkpoint.get('best_cv_acc', 'N/A')\n", + "\n", + " \n", + " if loaded_model_type == 'resnet':\n", + " model = ResNet18_MNIST(num_classes=5) \n", + " elif loaded_model_type == 'efficientnet':\n", + " model = EfficientNetB0_MNIST(num_classes=5)\n", + " elif loaded_model_type == 'mobilenet':\n", + " model = MobileNetV3_MNIST(num_classes=5)\n", + " else:\n", + " raise ValueError(f\"Unsupported model type found in checkpoint: {loaded_model_type}\")\n", + "\n", + " model.load_state_dict(model_state_dict, strict=False)\n", + " print(f\"Model state_dict loaded from CV result file\")\n", + " if best_cv_acc != 'N/A':\n", + " print(f\" - Best CV Validation Acc: {best_cv_acc:.2f}%\")\n", + "\n", + "\n", + " elif isinstance(checkpoint, dict) and 'model_state_dict' in checkpoint:\n", + " if model_type == 'resnet':\n", + " model = ResNet18_MNIST(num_classes=5)\n", + " elif model_type == 'efficientnet':\n", + " model = EfficientNetB0_MNIST(num_classes=5)\n", + " elif model_type == 'mobilenet':\n", + " model = MobileNetV3_MNIST(num_classes=5)\n", + " else:\n", + " raise ValueError(f\"Unsupported model type specified: {model_type}\")\n", + "\n", + " model.load_state_dict(checkpoint['model_state_dict'], strict=False)\n", + " print(f\"Model state_dict loaded from old checkpoint format\")\n", + " if 'val_acc' in checkpoint:\n", + " print(f\" - Validation Acc: {checkpoint['val_acc']:.2f}%\")\n", + "\n", + " else:\n", + " if model_type == 'resnet':\n", + " model = ResNet18_MNIST(num_classes=5)\n", + " elif model_type == 'efficientnet':\n", + " model = EfficientNetB0_MNIST(num_classes=5)\n", + " elif model_type == 'mobilenet':\n", + " model = MobileNetV3_MNIST(num_classes=5)\n", + " else:\n", + " raise ValueError(f\"Unsupported model type specified for raw state_dict loading: {model_type}\")\n", + "\n", + " model.load_state_dict(checkpoint, strict=False)\n", + " print(f\"Raw model state_dict loaded\")\n", + "\n", + "\n", + " except RuntimeError as e:\n", + " if \"size mismatch\" in str(e):\n", + " logger.error(f\"โŒ Size mismatch error when loading {model_type.upper()} model from {model_path}. Saved model architecture likely differs from the instantiated one. Error: {e}\")\n", + " print(\"\\n๐Ÿ’ก Hint: The saved model file might not match the expected architecture. Please verify the model saved in this path.\")\n", + " else:\n", + " logger.error(f\"โŒ Failed to load model state dict for {model_type.upper()} from {model_path}. Error: {e}\")\n", + " raise e \n", + "\n", + "\n", + " model = model.to(device)\n", + " model.eval()\n", + "\n", + " print(f\"{model_type.upper()} ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ: {model_path}\")\n", + "\n", + "\n", + " return model\n", + "\n", + "\n", + "def preprocess_image(image_path):\n", + " \"\"\"์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ ํ•จ์ˆ˜\"\"\"\n", + " image = Image.open(image_path).convert('L')\n", + " image = image.resize((28, 28))\n", + " image = torch.FloatTensor(np.array(image)).unsqueeze(0).unsqueeze(0) / 255.0\n", + " image = (image - 0.1307) / 0.3081\n", + " return image\n", + "\n", + "\n", + "def predict_single_image(model, image_path, device='cpu'):\n", + " \"\"\"์ด๋ฏธ์ง€ ํด๋ž˜์Šค ์˜ˆ์ธก\"\"\"\n", + " image = preprocess_image(image_path).to(device)\n", + "\n", + " with torch.no_grad():\n", + " output = model(image)\n", + " _, predicted = output.max(1)\n", + " prediction = predicted.item() + 1 \n", + "\n", + " return prediction\n", + "\n", + "\n", + "def evaluate_dataset(model, data_dir, model_type, answer_type, device):\n", + " \"\"\"ํŠน์ • Answer ๋ฐ์ดํ„ฐ์…‹ ์ „์ฒด ํ‰๊ฐ€\"\"\"\n", + "\n", + " total_correct = 0\n", + " total_images = 0\n", + "\n", + " print(f\"\\n--- {answer_type} / {model_type.upper()} ํ…Œ์ŠคํŠธ ์‹œ์ž‘ ---\")\n", + "\n", + " # ๊ฐ ํด๋ž˜์Šค๋ณ„๋กœ ํ‰๊ฐ€\n", + " for class_idx in range(1, 6):\n", + " class_dir = data_dir / str(class_idx)\n", + " if not class_dir.exists():\n", + " print(f\"ํด๋ž˜์Šค {class_idx} ํด๋” ์—†์Œ\")\n", + " continue\n", + "\n", + " image_paths = list(class_dir.glob(\"*.jpg\")) + list(class_dir.glob(\"*.png\"))\n", + " correct = 0\n", + "\n", + "\n", + " for img_path in image_paths:\n", + " prediction = predict_single_image(model, img_path, device)\n", + " if prediction == class_idx:\n", + " correct += 1\n", + " else:\n", + " print(f\" โŒ ์˜ˆ์ธก ์‹คํŒจ: {img_path.name}: ์˜ˆ์ธก={prediction}, ์‹ค์ œ={class_idx}\")\n", + "\n", + " accuracy = 100. * correct / len(image_paths) if len(image_paths) > 0 else 0\n", + " print(f\" ํด๋ž˜์Šค {class_idx}: {correct}/{len(image_paths)} ์ •๋‹ต ({accuracy:.2f}%)\")\n", + "\n", + " total_correct += correct\n", + " total_images += len(image_paths)\n", + "\n", + " overall_accuracy = 100. * total_correct / total_images if total_images > 0 else 0\n", + " print(f\"\\n--- {answer_type} / {model_type.upper()} ์ „์ฒด ์ •ํ™•๋„: {overall_accuracy:.2f}% ({total_correct}/{total_images}) ---\")\n", + " return overall_accuracy, total_correct, total_images\n", + "\n", + "\n", + "def main():\n", + " \"\"\"๋ฉ”์ธ ์‹คํ–‰\"\"\"\n", + "\n", + " device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n", + " print(f\"๋””๋ฐ”์ด์Šค: {device}\")\n", + "\n", + " base_dir = Path(\".\")\n", + " # cross-validation ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋œ ํด๋”๋กœ ๋ณ€๊ฒฝ\n", + " model_root = base_dir / \"answer_models_cv_results\"\n", + " data_root = base_dir # ๋ฐ์ดํ„ฐ์…‹ ๋ฃจํŠธ ํด๋”\n", + "\n", + " # ํ‰๊ฐ€ํ•  ๋ชจ๋ธ ํƒ€์ž…๊ณผ ๋ฐ์ดํ„ฐ์…‹ ์Œ\n", + " models_to_evaluate = [\n", + " {'answer': 'answer_1', 'type': 'resnet'},\n", + " {'answer': 'answer_2', 'type': 'resnet'},\n", + " {'answer': 'answer_1', 'type': 'efficientnet'}, \n", + " {'answer': 'answer_2', 'type': 'efficientnet'},\n", + " {'answer': 'answer_1', 'type': 'mobilenet'},\n", + " {'answer': 'answer_2', 'type': 'mobilenet'},\n", + " ]\n", + "\n", + " results = {}\n", + "\n", + " for item in models_to_evaluate:\n", + " answer_type = item['answer']\n", + " model_type = item['type']\n", + " \n", + " model_dir = model_root / f\"{answer_type}_{model_type}\"\n", + " model_path = model_dir / \"best_model_overall_cv.pth\"\n", + "\n", + "\n", + " data_dir = data_root / answer_type\n", + "\n", + " if not model_path.exists():\n", + " print(f\"โŒ ๋ชจ๋ธ ํŒŒ์ผ ์—†์Œ: {model_path}. {answer_type} / {model_type} ํ‰๊ฐ€๋ฅผ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.\")\n", + " continue\n", + "\n", + " if not data_dir.exists():\n", + " print(f\"โŒ ๋ฐ์ดํ„ฐ ํด๋” ์—†์Œ: {data_dir}\")\n", + " continue\n", + "\n", + " try:\n", + " model = load_answer_model(model_path, model_type=model_type, device=device)\n", + "\n", + " acc, correct, total = evaluate_dataset(model, data_dir, model_type, answer_type, device)\n", + " results[f\"{answer_type}_{model_type}\"] = {'acc': acc, 'correct': correct, 'total': total}\n", + " except Exception as e:\n", + " print(f\"โŒ {answer_type} / {model_type} ํ‰๊ฐ€ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}\")\n", + "\n", + " # ์ตœ์ข… ๊ฒฐ๊ณผ ์š”์•ฝ\n", + " print(f\"\\n{'='*60}\")\n", + " print(\"๐Ÿ† ์ตœ์ข… ์„ฑ๋Šฅ ์š”์•ฝ\")\n", + " print(f\"{'='*60}\")\n", + "\n", + " for answer_type in ['answer_1', 'answer_2']:\n", + " print(f\"\\n๐Ÿ“Š {answer_type} ์„ฑ๋Šฅ:\")\n", + " evaluated_models = [m_type for m_type in ['resnet', 'efficientnet', 'mobilenet'] if f\"{answer_type}_{m_type}\" in results]\n", + " if evaluated_models:\n", + " for model_type in evaluated_models:\n", + " key = f\"{answer_type}_{model_type}\"\n", + " print(f\" {model_type.upper()}: {results[key]['acc']:.2f}%\")\n", + " else:\n", + " print(\" ํ‰๊ฐ€๋œ ๋ชจ๋ธ ์—†์Œ\")\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()\n", + "\"\"\"" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ocr", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ai-service/test/Classification/predict_answer_README.md b/ai-service/test/Classification/predict_answer_README.md new file mode 100644 index 0000000..e7f1767 --- /dev/null +++ b/ai-service/test/Classification/predict_answer_README.md @@ -0,0 +1,27 @@ +`predict_anser.ipynb` ์ฝ”๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…์ž…๋‹ˆ๋‹ค. + +'answer_classifie.ipynb'์—์„œ ํ•™์Šต์ด ์™„๋ฃŒ๋œ ๋ชจ๋ธ 6๊ฐ€์ง€๋ฅผ Kaggle์—์„œ ๋ถˆ๋Ÿฌ์™€ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. + +*test dataset ๋‹ค์šด๋กœ๋“œ ๋งํฌ* +answer_1: [text](https://drive.google.com/drive/folders/1A7LzAO8lTPCwhgckuZhMyPpbs_lUfdK3?usp=sharing) +answer_2: [text](https://drive.google.com/drive/folders/15EoIKLGbeLyOjLL_T7rua48TyyhdOZR3?usp=sharing) + +*์ตœ์ข… ์„ฑ๋Šฅ ์š”์•ฝ* +############################################################ +############################################################ +๐Ÿ“Š answer_1 ์„ฑ๋Šฅ: + RESNET : 98.74% (1019/1032) + EFFICIENTNET: 96.51% (996/1032) + MOBILENET : 90.50% (934/1032) + +๐Ÿ“Š answer_2 ์„ฑ๋Šฅ: + RESNET : 100.00% (927/927) + EFFICIENTNET: 100.00% (927/927) + MOBILENET : 100.00% (927/927) +############################################################ +############################################################ + +answer_1๊ณผ answer_2์˜ ํ‰๊ท  ์ฐจ์ด๊ฐ€ ๋‚˜๋Š” ์ด์œ ๋Š” ์ƒ๋Œ€์ ์œผ๋กœ answer_1์˜ ๋‚œ์ด๋„๊ฐ€ ๋†’๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. +(answer_1์˜ ๊ฒฝ์šฐ ์ฒดํฌ ํ‘œ์‹œ์— ์ˆซ์ž๊ฐ€ ๊ฐ€๋ ค์ ธ ์˜ˆ์ธก์— ์–ด๋ ค์›€์„ ๊ฒช๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.) + +`predict_anser.ipynb`๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ๋ชจ๋ธ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์„ธ์š”! \ No newline at end of file diff --git a/ai-service/test/Hierarchical_crop/__init__.py b/ai-service/test/Hierarchical_crop/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-service/test/Hierarchical_crop/__pycache__/__init__.cpython-311.pyc b/ai-service/test/Hierarchical_crop/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..40009ce Binary files /dev/null and b/ai-service/test/Hierarchical_crop/__pycache__/__init__.cpython-311.pyc differ diff --git a/ai-service/test/Hierarchical_crop/__pycache__/__init__.cpython-312.pyc b/ai-service/test/Hierarchical_crop/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..f4e7140 Binary files /dev/null and b/ai-service/test/Hierarchical_crop/__pycache__/__init__.cpython-312.pyc differ diff --git a/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop.cpython-311.pyc b/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop.cpython-311.pyc new file mode 100644 index 0000000..956203d Binary files /dev/null and b/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop.cpython-311.pyc differ diff --git a/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop.cpython-312.pyc b/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop.cpython-312.pyc new file mode 100644 index 0000000..2fe9c2a Binary files /dev/null and b/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop.cpython-312.pyc differ diff --git a/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop_test.cpython-311.pyc b/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop_test.cpython-311.pyc new file mode 100644 index 0000000..6287f77 Binary files /dev/null and b/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop_test.cpython-311.pyc differ diff --git a/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop_test.cpython-312.pyc b/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop_test.cpython-312.pyc new file mode 100644 index 0000000..8afeb18 Binary files /dev/null and b/ai-service/test/Hierarchical_crop/__pycache__/hierarchical_crop_test.cpython-312.pyc differ diff --git a/ai-service/test/Hierarchical_crop/__pycache__/services_hierarchical_crop_test.cpython-311.pyc b/ai-service/test/Hierarchical_crop/__pycache__/services_hierarchical_crop_test.cpython-311.pyc new file mode 100644 index 0000000..bf3e8e4 Binary files /dev/null and b/ai-service/test/Hierarchical_crop/__pycache__/services_hierarchical_crop_test.cpython-311.pyc differ diff --git a/ai-service/test/Hierarchical_crop/__pycache__/yolo_test_crop.cpython-312.pyc b/ai-service/test/Hierarchical_crop/__pycache__/yolo_test_crop.cpython-312.pyc new file mode 100644 index 0000000..d85b3e9 Binary files /dev/null and b/ai-service/test/Hierarchical_crop/__pycache__/yolo_test_crop.cpython-312.pyc differ diff --git a/ai-service/test/Hierarchical_crop/answers/accuracy_analysis_with_type.ipynb b/ai-service/test/Hierarchical_crop/answers/accuracy_analysis_with_type.ipynb new file mode 100644 index 0000000..37bb2ee --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/accuracy_analysis_with_type.ipynb @@ -0,0 +1,2278 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ๐Ÿ“Š YOLO ๋‹ต์•ˆ ์ธ์‹ ์ •ํ™•๋„ ๋ถ„์„ (์œ ํ˜•๋ณ„ ๋ถ„์„ ํฌํ•จ)\n", + "\n", + "## ๊ฐœ์š”\n", + "- **results_summary.txt**: ํŒŒ์ผ๋ช…, ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์˜ˆ์ธก๋‹ต์•ˆ\n", + " - ์˜ˆ: `ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1, 88, 04, 3`\n", + "- **test_answer.txt**: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต, ์œ ํ˜• (์ •๋‹ต์ง€)\n", + " - ์˜ˆ: `9, 01, 4, answer_12_xo`\n", + "\n", + "์ •๋‹ต์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ **ํŽ˜์ด์ง€๋ฒˆํ˜ธ + ๋ฌธ์ œ๋ฒˆํ˜ธ**๋กœ ๋งค์นญํ•˜์—ฌ ์ •ํ™•๋„๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , **์œ ํ˜•๋ณ„ ์˜ค๋‹ต ๋น„์œจ**๋„ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋“œ ์™„๋ฃŒ\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "from pathlib import Path\n", + "from typing import Dict, List, Tuple\n", + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "print(\"โœ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋“œ ์™„๋ฃŒ\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ •" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… Results ํŒŒ์ผ: results_summary.txt\n", + "โœ… Answer Key ํŒŒ์ผ: test_answer.txt\n" + ] + } + ], + "source": [ + "# ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • (ํ•„์š”์‹œ ์ˆ˜์ •)\n", + "results_path = Path(\"results_summary.txt\")\n", + "answer_key_path = Path(\"test_answer.txt\")\n", + "output_dir = Path(\"./\")\n", + "\n", + "# ํŒŒ์ผ ์กด์žฌ ํ™•์ธ\n", + "if not results_path.exists():\n", + " print(f\"โŒ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {results_path}\")\n", + "else:\n", + " print(f\"โœ… Results ํŒŒ์ผ: {results_path}\")\n", + "\n", + "if not answer_key_path.exists():\n", + " print(f\"โŒ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {answer_key_path}\")\n", + "else:\n", + " print(f\"โœ… Answer Key ํŒŒ์ผ: {answer_key_path}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. ๋ฐ์ดํ„ฐ ๋กœ๋“œ ๋ฐ ์ „์ฒ˜๋ฆฌ" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“„ Results Summary ๋กœ๋“œ ์™„๋ฃŒ: 292๊ฐœ ํ•ญ๋ชฉ\n", + " - None ๋‹ต์•ˆ: 2๊ฐœ\n", + " - ํŒŒ์ผ๋ช…: 147๊ฐœ ๊ณ ์œ  ํŒŒ์ผ\n", + " - ํŽ˜์ด์ง€ ์ˆ˜: 147๊ฐœ ๊ณ ์œ  ํŽ˜์ด์ง€\n", + "\n", + "๐Ÿ“˜ Answer Key ๋กœ๋“œ ์™„๋ฃŒ: 290๊ฐœ ํ•ญ๋ชฉ\n", + " - ์œ ํ˜• ์ •๋ณด: 290๊ฐœ ๋ฌธ์ œ์— ์œ ํ˜• ์žˆ์Œ\n", + " - ์œ ํ˜• ์ข…๋ฅ˜: 8๊ฐ€์ง€ (answer_12_xo, answer_12_ox, answer_12_xx, answer_1_x, answer_1_o, answer_2_x, answer_2_o, answer_12_oo)\n", + " - ํŽ˜์ด์ง€ ์ˆ˜: 147๊ฐœ ๊ณ ์œ  ํŽ˜์ด์ง€\n", + "\n", + "============================================================\n" + ] + } + ], + "source": [ + "def load_results(file_path: Path) -> pd.DataFrame:\n", + " \"\"\"results_summary.txt ๋กœ๋“œ\n", + " ํ˜•์‹: ํŒŒ์ผ๋ช…, ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์˜ˆ์ธก๋‹ต์•ˆ\n", + " ์˜ˆ: ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1, 88, 04, 3\n", + " \"\"\"\n", + " data = []\n", + " with open(file_path, 'r', encoding='utf-8') as f:\n", + " for line_num, line in enumerate(f, 1):\n", + " line = line.strip()\n", + " if not line:\n", + " continue\n", + " \n", + " parts = [p.strip() for p in line.split(',')]\n", + " if len(parts) >= 4:\n", + " data.append({\n", + " 'file_name': parts[0],\n", + " 'page_number': parts[1],\n", + " 'problem_number': parts[2],\n", + " 'predicted_answer': parts[3] if parts[3].lower() != 'none' else None\n", + " })\n", + " else:\n", + " print(f\"โš ๏ธ Warning: ๋ผ์ธ {line_num} ํ˜•์‹ ์˜ค๋ฅ˜: {line}\")\n", + " \n", + " df = pd.DataFrame(data)\n", + " print(f\"\\n๐Ÿ“„ Results Summary ๋กœ๋“œ ์™„๋ฃŒ: {len(df)}๊ฐœ ํ•ญ๋ชฉ\")\n", + " print(f\" - None ๋‹ต์•ˆ: {df['predicted_answer'].isna().sum()}๊ฐœ\")\n", + " print(f\" - ํŒŒ์ผ๋ช…: {df['file_name'].nunique()}๊ฐœ ๊ณ ์œ  ํŒŒ์ผ\")\n", + " print(f\" - ํŽ˜์ด์ง€ ์ˆ˜: {df['page_number'].nunique()}๊ฐœ ๊ณ ์œ  ํŽ˜์ด์ง€\")\n", + " return df\n", + "\n", + "def load_answer_key(file_path: Path) -> pd.DataFrame:\n", + " \"\"\"test_answer.txt ๋กœ๋“œ (์ •๋‹ต์ง€)\n", + " ํ˜•์‹: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต, ์œ ํ˜•\n", + " ์˜ˆ: 9, 01, 4, answer_12_xo\n", + " \"\"\"\n", + " data = []\n", + " with open(file_path, 'r', encoding='utf-8') as f:\n", + " for line_num, line in enumerate(f, 1):\n", + " line = line.strip()\n", + " if not line:\n", + " continue\n", + " \n", + " parts = [p.strip() for p in line.split(',')]\n", + " if len(parts) >= 4:\n", + " data.append({\n", + " 'page_number': parts[0],\n", + " 'problem_number': parts[1],\n", + " 'correct_answer': parts[2],\n", + " 'problem_type': parts[3]\n", + " })\n", + " else:\n", + " print(f\"โš ๏ธ Warning: ๋ผ์ธ {line_num} ํ˜•์‹ ์˜ค๋ฅ˜: {line}\")\n", + " \n", + " df = pd.DataFrame(data)\n", + " print(f\"\\n๐Ÿ“˜ Answer Key ๋กœ๋“œ ์™„๋ฃŒ: {len(df)}๊ฐœ ํ•ญ๋ชฉ\")\n", + " print(f\" - ์œ ํ˜• ์ •๋ณด: {df['problem_type'].notna().sum()}๊ฐœ ๋ฌธ์ œ์— ์œ ํ˜• ์žˆ์Œ\")\n", + " if df['problem_type'].notna().sum() > 0:\n", + " print(f\" - ์œ ํ˜• ์ข…๋ฅ˜: {df['problem_type'].nunique()}๊ฐ€์ง€ ({', '.join(df['problem_type'].dropna().unique())})\")\n", + " print(f\" - ํŽ˜์ด์ง€ ์ˆ˜: {df['page_number'].nunique()}๊ฐœ ๊ณ ์œ  ํŽ˜์ด์ง€\")\n", + " return df\n", + "\n", + "# ๋ฐ์ดํ„ฐ ๋กœ๋“œ\n", + "results_df = load_results(results_path)\n", + "answer_key_df = load_answer_key(answer_key_path)\n", + "\n", + "print(\"\\n\" + \"=\"*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ ํ™•์ธ" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“‹ Results Summary ์ƒ˜ํ”Œ:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
file_namepage_numberproblem_numberpredicted_answer
0แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 188043
1แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 188014
2แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 188022
3แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 188053
4แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 188033
5แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1097293
6แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1097302
7แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1198325
8แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1198313
9แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1299344
\n", + "
" + ], + "text/plain": [ + " file_name page_number problem_number \\\n", + "0 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1 88 04 \n", + "1 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1 88 01 \n", + "2 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1 88 02 \n", + "3 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1 88 05 \n", + "4 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1 88 03 \n", + "5 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10 97 29 \n", + "6 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10 97 30 \n", + "7 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11 98 32 \n", + "8 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11 98 31 \n", + "9 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12 99 34 \n", + "\n", + " predicted_answer \n", + "0 3 \n", + "1 4 \n", + "2 2 \n", + "3 3 \n", + "4 3 \n", + "5 3 \n", + "6 2 \n", + "7 5 \n", + "8 3 \n", + "9 4 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“‹ Answer Key ์ƒ˜ํ”Œ:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberproblem_numbercorrect_answerproblem_type
09014answer_12_xo
110024answer_12_xo
211033answer_12_xo
312045answer_12_xo
413054answer_12_xo
515011answer_12_xo
616023answer_12_xo
717035answer_12_xo
818045answer_12_xo
919055answer_12_xo
\n", + "
" + ], + "text/plain": [ + " page_number problem_number correct_answer problem_type\n", + "0 9 01 4 answer_12_xo\n", + "1 10 02 4 answer_12_xo\n", + "2 11 03 3 answer_12_xo\n", + "3 12 04 5 answer_12_xo\n", + "4 13 05 4 answer_12_xo\n", + "5 15 01 1 answer_12_xo\n", + "6 16 02 3 answer_12_xo\n", + "7 17 03 5 answer_12_xo\n", + "8 18 04 5 answer_12_xo\n", + "9 19 05 5 answer_12_xo" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(\"\\n๐Ÿ“‹ Results Summary ์ƒ˜ํ”Œ:\")\n", + "display(results_df.head(10))\n", + "\n", + "print(\"\\n๐Ÿ“‹ Answer Key ์ƒ˜ํ”Œ:\")\n", + "display(answer_key_df.head(10))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. ์ •๋‹ต ๋น„๊ต (ํŽ˜์ด์ง€๋ฒˆํ˜ธ + ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ธฐ์ค€)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "โœ… ์ •๋‹ต ๋น„๊ต ์™„๋ฃŒ (ํŽ˜์ด์ง€๋ฒˆํ˜ธ + ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ธฐ์ค€)\n", + "\n", + "๐Ÿ“Š ์ „์ฒด ๊ฒฐ๊ณผ:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberproblem_numbercorrect_answerproblem_typefile_namepredicted_answer_mergeresult
09014answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14bothcorrect
110024answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 24bothcorrect
211033answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 33bothcorrect
312045answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 45bothcorrect
413054answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 54bothcorrect
515011answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 61bothcorrect
616023answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 73bothcorrect
717035answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 85bothcorrect
818045answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 95bothcorrect
919055answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 105bothcorrect
1021013answer_12_xoแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 113bothcorrect
1122022answer_12_oxแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 122bothcorrect
1223034answer_12_oxแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 134bothcorrect
1324041answer_12_oxแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 141bothcorrect
1425051answer_12_oxแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 151bothcorrect
1527013answer_12_oxแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 163bothcorrect
1628024answer_12_oxแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 174bothcorrect
1729034answer_12_oxแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 184bothcorrect
1830042answer_12_oxแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 192bothcorrect
1931051answer_12_oxแ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 201bothcorrect
\n", + "
" + ], + "text/plain": [ + " page_number problem_number correct_answer problem_type \\\n", + "0 9 01 4 answer_12_xo \n", + "1 10 02 4 answer_12_xo \n", + "2 11 03 3 answer_12_xo \n", + "3 12 04 5 answer_12_xo \n", + "4 13 05 4 answer_12_xo \n", + "5 15 01 1 answer_12_xo \n", + "6 16 02 3 answer_12_xo \n", + "7 17 03 5 answer_12_xo \n", + "8 18 04 5 answer_12_xo \n", + "9 19 05 5 answer_12_xo \n", + "10 21 01 3 answer_12_xo \n", + "11 22 02 2 answer_12_ox \n", + "12 23 03 4 answer_12_ox \n", + "13 24 04 1 answer_12_ox \n", + "14 25 05 1 answer_12_ox \n", + "15 27 01 3 answer_12_ox \n", + "16 28 02 4 answer_12_ox \n", + "17 29 03 4 answer_12_ox \n", + "18 30 04 2 answer_12_ox \n", + "19 31 05 1 answer_12_ox \n", + "\n", + " file_name predicted_answer _merge result \n", + "0 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1 4 both correct \n", + "1 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2 4 both correct \n", + "2 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3 3 both correct \n", + "3 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4 5 both correct \n", + "4 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5 4 both correct \n", + "5 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6 1 both correct \n", + "6 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7 3 both correct \n", + "7 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8 5 both correct \n", + "8 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9 5 both correct \n", + "9 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10 5 both correct \n", + "10 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11 3 both correct \n", + "11 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 12 2 both correct \n", + "12 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 13 4 both correct \n", + "13 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14 1 both correct \n", + "14 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 15 1 both correct \n", + "15 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 16 3 both correct \n", + "16 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 17 4 both correct \n", + "17 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 18 4 both correct \n", + "18 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 19 2 both correct \n", + "19 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 20 1 both correct " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ์ •๋‹ต์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ results์™€ merge (ํŽ˜์ด์ง€๋ฒˆํ˜ธ + ๋ฌธ์ œ๋ฒˆํ˜ธ๋กœ ๋งค์นญ)\n", + "merged_df = answer_key_df.merge(\n", + " results_df,\n", + " on=['page_number', 'problem_number'],\n", + " how='left',\n", + " indicator=True\n", + ")\n", + "\n", + "# ๋น„๊ต ๊ฒฐ๊ณผ ์ปฌ๋Ÿผ ์ถ”๊ฐ€\n", + "def compare_answers(row):\n", + " \"\"\"์ •๋‹ต ๋น„๊ต\"\"\"\n", + " if row['_merge'] == 'left_only':\n", + " return 'missing' # results์— ์—†์Œ\n", + " elif pd.isna(row['predicted_answer']):\n", + " return 'none' # None์œผ๋กœ ์˜ˆ์ธก๋จ\n", + " elif str(row['predicted_answer']).strip() == str(row['correct_answer']).strip():\n", + " return 'correct' # ์ •๋‹ต\n", + " else:\n", + " return 'wrong' # ์˜ค๋‹ต\n", + "\n", + "merged_df['result'] = merged_df.apply(compare_answers, axis=1)\n", + "\n", + "print(\"\\nโœ… ์ •๋‹ต ๋น„๊ต ์™„๋ฃŒ (ํŽ˜์ด์ง€๋ฒˆํ˜ธ + ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ธฐ์ค€)\")\n", + "print(\"\\n๐Ÿ“Š ์ „์ฒด ๊ฒฐ๊ณผ:\")\n", + "display(merged_df.head(20))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. ์ •ํ™•๋„ ๊ณ„์‚ฐ" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "๐Ÿ“Š ์ •ํ™•๋„ ํ†ต๊ณ„\n", + "============================================================\n", + "\n", + "๐Ÿ“˜ ์ •๋‹ต์ง€ ๊ธฐ์ค€:\n", + " ์ด ๋ฌธ์ œ ์ˆ˜: 290๊ฐœ\n", + "\n", + "โœ… ์ •๋‹ต: 287๊ฐœ (98.97%)\n", + "โŒ ์˜ค๋‹ต: 3๊ฐœ (1.03%)\n", + "โš ๏ธ None: 0๊ฐœ (0.00%)\n", + "๐Ÿ” ๋ˆ„๋ฝ: 0๊ฐœ (0.00%)\n", + "\n", + "============================================================\n", + "๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: 98.97%\n", + "๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): 100.00%\n", + "โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„ (None ํฌํ•จ): 98.97%\n", + "============================================================\n" + ] + } + ], + "source": [ + "# ๊ฒฐ๊ณผ๋ณ„ ๊ฐœ์ˆ˜ ๊ณ„์‚ฐ\n", + "total_count = len(merged_df)\n", + "correct_count = (merged_df['result'] == 'correct').sum()\n", + "wrong_count = (merged_df['result'] == 'wrong').sum()\n", + "none_count = (merged_df['result'] == 'none').sum()\n", + "missing_count = (merged_df['result'] == 'missing').sum()\n", + "\n", + "# ์ •ํ™•๋„ ๊ณ„์‚ฐ\n", + "accuracy = correct_count / total_count * 100 if total_count > 0 else 0\n", + "\n", + "# ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ)\n", + "recognized_count = total_count - missing_count\n", + "recognition_rate = recognized_count / total_count * 100 if total_count > 0 else 0\n", + "\n", + "# ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„\n", + "accuracy_of_recognized = correct_count / recognized_count * 100 if recognized_count > 0 else 0\n", + "\n", + "print(\"=\"*60)\n", + "print(\"๐Ÿ“Š ์ •ํ™•๋„ ํ†ต๊ณ„\")\n", + "print(\"=\"*60)\n", + "print(f\"\\n๐Ÿ“˜ ์ •๋‹ต์ง€ ๊ธฐ์ค€:\")\n", + "print(f\" ์ด ๋ฌธ์ œ ์ˆ˜: {total_count}๊ฐœ\")\n", + "print(f\"\\nโœ… ์ •๋‹ต: {correct_count}๊ฐœ ({correct_count/total_count*100:.2f}%)\")\n", + "print(f\"โŒ ์˜ค๋‹ต: {wrong_count}๊ฐœ ({wrong_count/total_count*100:.2f}%)\")\n", + "print(f\"โš ๏ธ None: {none_count}๊ฐœ ({none_count/total_count*100:.2f}%)\")\n", + "print(f\"๐Ÿ” ๋ˆ„๋ฝ: {missing_count}๊ฐœ ({missing_count/total_count*100:.2f}%)\")\n", + "print(f\"\\n{'='*60}\")\n", + "print(f\"๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: {accuracy:.2f}%\")\n", + "print(f\"๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): {recognition_rate:.2f}%\")\n", + "print(f\"โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„ (None ํฌํ•จ): {accuracy_of_recognized:.2f}%\")\n", + "print(\"=\"*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. ์œ ํ˜•๋ณ„ ์˜ค๋‹ต ๋น„์œจ ๋ถ„์„ โญ NEW" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================================================================\n", + "๐Ÿ“Š ์œ ํ˜•๋ณ„ ์ •ํ™•๋„ ๋ฐ ์˜ค๋‹ต ๋น„์œจ ๋ถ„์„\n", + "================================================================================\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
totalcorrectwrongnonemissingaccuracywrong_ratenone_ratemissing_rate
problem_type
answer_1_o454230093.336.670.00.0
answer_12_oo2929000100.000.000.00.0
answer_12_xo2727000100.000.000.00.0
answer_12_ox2727000100.000.000.00.0
answer_12_xx2727000100.000.000.00.0
answer_1_x4545000100.000.000.00.0
answer_2_o4545000100.000.000.00.0
answer_2_x4545000100.000.000.00.0
\n", + "
" + ], + "text/plain": [ + " total correct wrong none missing accuracy wrong_rate \\\n", + "problem_type \n", + "answer_1_o 45 42 3 0 0 93.33 6.67 \n", + "answer_12_oo 29 29 0 0 0 100.00 0.00 \n", + "answer_12_xo 27 27 0 0 0 100.00 0.00 \n", + "answer_12_ox 27 27 0 0 0 100.00 0.00 \n", + "answer_12_xx 27 27 0 0 0 100.00 0.00 \n", + "answer_1_x 45 45 0 0 0 100.00 0.00 \n", + "answer_2_o 45 45 0 0 0 100.00 0.00 \n", + "answer_2_x 45 45 0 0 0 100.00 0.00 \n", + "\n", + " none_rate missing_rate \n", + "problem_type \n", + "answer_1_o 0.0 0.0 \n", + "answer_12_oo 0.0 0.0 \n", + "answer_12_xo 0.0 0.0 \n", + "answer_12_ox 0.0 0.0 \n", + "answer_12_xx 0.0 0.0 \n", + "answer_1_x 0.0 0.0 \n", + "answer_2_o 0.0 0.0 \n", + "answer_2_x 0.0 0.0 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "================================================================================\n", + "๐Ÿ“ˆ ์œ ํ˜•๋ณ„ ์ƒ์„ธ ๋ถ„์„\n", + "================================================================================\n", + "\n", + "๐Ÿ”น ์œ ํ˜•: answer_1_o\n", + " ์ด ๋ฌธ์ œ: 45.0๊ฐœ\n", + " โœ… ์ •๋‹ต: 42.0๊ฐœ (93.33%)\n", + " โŒ ์˜ค๋‹ต: 3.0๊ฐœ (6.67%)\n", + " โš ๏ธ None: 0.0๊ฐœ (0.00%)\n", + " ๐Ÿ” ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%)\n", + " ๐Ÿ“‹ ์˜ค๋‹ต ์ƒ˜ํ”Œ (์ตœ๋Œ€ 3๊ฐœ):\n", + " - ํŽ˜์ด์ง€ 105, ๋ฌธ์ œ 04: ์ •๋‹ต=4, ์˜ˆ์ธก=5\n", + " - ํŽ˜์ด์ง€ 106, ๋ฌธ์ œ 10: ์ •๋‹ต=4, ์˜ˆ์ธก=1\n", + " - ํŽ˜์ด์ง€ 112, ๋ฌธ์ œ 25: ์ •๋‹ต=4, ์˜ˆ์ธก=2\n", + "\n", + "๐Ÿ”น ์œ ํ˜•: answer_12_oo\n", + " ์ด ๋ฌธ์ œ: 29.0๊ฐœ\n", + " โœ… ์ •๋‹ต: 29.0๊ฐœ (100.00%)\n", + " โŒ ์˜ค๋‹ต: 0.0๊ฐœ (0.00%)\n", + " โš ๏ธ None: 0.0๊ฐœ (0.00%)\n", + " ๐Ÿ” ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%)\n", + "\n", + "๐Ÿ”น ์œ ํ˜•: answer_12_xo\n", + " ์ด ๋ฌธ์ œ: 27.0๊ฐœ\n", + " โœ… ์ •๋‹ต: 27.0๊ฐœ (100.00%)\n", + " โŒ ์˜ค๋‹ต: 0.0๊ฐœ (0.00%)\n", + " โš ๏ธ None: 0.0๊ฐœ (0.00%)\n", + " ๐Ÿ” ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%)\n", + "\n", + "๐Ÿ”น ์œ ํ˜•: answer_12_ox\n", + " ์ด ๋ฌธ์ œ: 27.0๊ฐœ\n", + " โœ… ์ •๋‹ต: 27.0๊ฐœ (100.00%)\n", + " โŒ ์˜ค๋‹ต: 0.0๊ฐœ (0.00%)\n", + " โš ๏ธ None: 0.0๊ฐœ (0.00%)\n", + " ๐Ÿ” ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%)\n", + "\n", + "๐Ÿ”น ์œ ํ˜•: answer_12_xx\n", + " ์ด ๋ฌธ์ œ: 27.0๊ฐœ\n", + " โœ… ์ •๋‹ต: 27.0๊ฐœ (100.00%)\n", + " โŒ ์˜ค๋‹ต: 0.0๊ฐœ (0.00%)\n", + " โš ๏ธ None: 0.0๊ฐœ (0.00%)\n", + " ๐Ÿ” ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%)\n", + "\n", + "๐Ÿ”น ์œ ํ˜•: answer_1_x\n", + " ์ด ๋ฌธ์ œ: 45.0๊ฐœ\n", + " โœ… ์ •๋‹ต: 45.0๊ฐœ (100.00%)\n", + " โŒ ์˜ค๋‹ต: 0.0๊ฐœ (0.00%)\n", + " โš ๏ธ None: 0.0๊ฐœ (0.00%)\n", + " ๐Ÿ” ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%)\n", + "\n", + "๐Ÿ”น ์œ ํ˜•: answer_2_o\n", + " ์ด ๋ฌธ์ œ: 45.0๊ฐœ\n", + " โœ… ์ •๋‹ต: 45.0๊ฐœ (100.00%)\n", + " โŒ ์˜ค๋‹ต: 0.0๊ฐœ (0.00%)\n", + " โš ๏ธ None: 0.0๊ฐœ (0.00%)\n", + " ๐Ÿ” ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%)\n", + "\n", + "๐Ÿ”น ์œ ํ˜•: answer_2_x\n", + " ์ด ๋ฌธ์ œ: 45.0๊ฐœ\n", + " โœ… ์ •๋‹ต: 45.0๊ฐœ (100.00%)\n", + " โŒ ์˜ค๋‹ต: 0.0๊ฐœ (0.00%)\n", + " โš ๏ธ None: 0.0๊ฐœ (0.00%)\n", + " ๐Ÿ” ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%)\n" + ] + } + ], + "source": [ + "# ์œ ํ˜•๋ณ„ ํ†ต๊ณ„ ๊ณ„์‚ฐ\n", + "if merged_df['problem_type'].notna().sum() > 0:\n", + " type_stats = merged_df.groupby('problem_type').agg({\n", + " 'result': 'count'\n", + " }).rename(columns={'result': 'total'})\n", + " \n", + " type_stats['correct'] = merged_df[merged_df['result'] == 'correct'].groupby('problem_type').size()\n", + " type_stats['wrong'] = merged_df[merged_df['result'] == 'wrong'].groupby('problem_type').size()\n", + " type_stats['none'] = merged_df[merged_df['result'] == 'none'].groupby('problem_type').size()\n", + " type_stats['missing'] = merged_df[merged_df['result'] == 'missing'].groupby('problem_type').size()\n", + " \n", + " type_stats = type_stats.fillna(0).astype(int)\n", + " \n", + " # ์ •ํ™•๋„ ๋ฐ ์˜ค๋‹ต๋ฅ  ๊ณ„์‚ฐ\n", + " type_stats['accuracy'] = (type_stats['correct'] / type_stats['total'] * 100).round(2)\n", + " type_stats['wrong_rate'] = (type_stats['wrong'] / type_stats['total'] * 100).round(2)\n", + " type_stats['none_rate'] = (type_stats['none'] / type_stats['total'] * 100).round(2)\n", + " type_stats['missing_rate'] = (type_stats['missing'] / type_stats['total'] * 100).round(2)\n", + " \n", + " # ์˜ค๋‹ต๋ฅ  ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ\n", + " type_stats = type_stats.sort_values('wrong_rate', ascending=False)\n", + " \n", + " print(\"=\"*80)\n", + " print(\"๐Ÿ“Š ์œ ํ˜•๋ณ„ ์ •ํ™•๋„ ๋ฐ ์˜ค๋‹ต ๋น„์œจ ๋ถ„์„\")\n", + " print(\"=\"*80)\n", + " display(type_stats)\n", + " \n", + " # ์˜ค๋‹ต๋ฅ ์ด ๋†’์€ ์œ ํ˜• ๊ฐ•์กฐ\n", + " high_wrong_rate = type_stats[type_stats['wrong_rate'] > 10]\n", + " if len(high_wrong_rate) > 0:\n", + " print(\"\\nโš ๏ธ ์˜ค๋‹ต๋ฅ ์ด 10% ์ด์ƒ์ธ ์œ ํ˜•:\")\n", + " display(high_wrong_rate[['total', 'wrong', 'wrong_rate', 'accuracy']])\n", + " \n", + " # ์œ ํ˜•๋ณ„ ์ƒ์„ธ ๋ถ„์„\n", + " print(\"\\n\" + \"=\"*80)\n", + " print(\"๐Ÿ“ˆ ์œ ํ˜•๋ณ„ ์ƒ์„ธ ๋ถ„์„\")\n", + " print(\"=\"*80)\n", + " for problem_type in type_stats.index:\n", + " stats = type_stats.loc[problem_type]\n", + " print(f\"\\n๐Ÿ”น ์œ ํ˜•: {problem_type}\")\n", + " print(f\" ์ด ๋ฌธ์ œ: {stats['total']}๊ฐœ\")\n", + " print(f\" โœ… ์ •๋‹ต: {stats['correct']}๊ฐœ ({stats['accuracy']:.2f}%)\")\n", + " print(f\" โŒ ์˜ค๋‹ต: {stats['wrong']}๊ฐœ ({stats['wrong_rate']:.2f}%)\")\n", + " print(f\" โš ๏ธ None: {stats['none']}๊ฐœ ({stats['none_rate']:.2f}%)\")\n", + " print(f\" ๐Ÿ” ๋ˆ„๋ฝ: {stats['missing']}๊ฐœ ({stats['missing_rate']:.2f}%)\")\n", + " \n", + " # ํ•ด๋‹น ์œ ํ˜•์˜ ์˜ค๋‹ต ์ƒ˜ํ”Œ ์ถœ๋ ฅ\n", + " type_wrong = merged_df[(merged_df['problem_type'] == problem_type) & (merged_df['result'] == 'wrong')]\n", + " if len(type_wrong) > 0:\n", + " print(f\" ๐Ÿ“‹ ์˜ค๋‹ต ์ƒ˜ํ”Œ (์ตœ๋Œ€ 3๊ฐœ):\")\n", + " for idx, row in type_wrong.head(3).iterrows():\n", + " print(f\" - ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}: ์ •๋‹ต={row['correct_answer']}, ์˜ˆ์ธก={row['predicted_answer']}\")\n", + "else:\n", + " print(\"โš ๏ธ ์œ ํ˜• ์ •๋ณด๊ฐ€ ์—†์–ด ์œ ํ˜•๋ณ„ ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. ์œ ํ˜•๋ณ„ ์‹œ๊ฐํ™” โญ NEW" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ’พ ์œ ํ˜•๋ณ„ ๋ถ„์„ ์‹œ๊ฐํ™” ์ €์žฅ: type_analysis_visualization.png\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABjUAAAScCAYAAADDDw0GAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3XdYFFcXBvB3KUsVKYIUEVBAEBuKmtjA3nvvxqixV4wmmqhRY8PEJLaoEY3RqEmMsWtixN4VRSVWlCgqFgRBabv3+4MwH0MH0d2F9/c8++zO3ClnZlaZs2fujEIIIUBERERERERERERERKTl9DQdABERERERERERERERUX6wqEFERERERERERERERDqBRQ0iIiIiIiIiIiIiItIJLGoQEREREREREREREZFOYFGDiIiIiIiIiIiIiIh0AosaRERERERERERERESkE1jUICIiIiIiIiIiIiIincCiBhERERERERERERER6QQWNYiIiIiIiIiIiIiISCewqEFEREREb5WrqysUCkWhXnfv3tV0+G/FoEGDZNsZEhKi6ZA05u7du7J9ERAQ8EbL69SpU5bvUbdu3Yom2LdAm74LISEhslgGDRqksViIiIiIiHLCogYRERERERULT548wZ49e7KM37lzJ54/f66BiIiIiIiIqKgZaDoAIiIiIire2rRpg+joaNm4a9euITw8XBp2cXGBn59flnnNzMzeenxUfPz0009ISUnJMj45ORmbNm3C6NGjNRCV7rC1tUXXrl2l4dq1a2swGiIiIiKi7LGoQURERERv1fLly7OMmzlzJmbNmiUNBwQEYN26de8wKiqO1q9fL33W19eHWq2GEAIAsG7dOhY18uDj44Nff/1V02EQEREREeWKt58iIiIiIq0ihICXl5d0X38zMzO8ePEiy3Tbtm2T3f9/8uTJUlvG8a6urlCpVFi+fDlq1aoFMzMzWFpaomXLljh8+HCOcbx+/RorV65Ey5YtYW9vD6VSidKlS8PPzw+zZs3Cs2fPinS7L126hK5du8LW1hbGxsbw8fHBokWLsu15cOzYMUyYMAGNGzdGxYoVYWVlBQMDA5QuXRpVq1bFiBEjcOnSpWzXk5CQgKCgIDRq1Ah2dnZQKpUwNzeHi4sLGjZsiAkTJmDXrl3Zznv79m0EBgbC19cXlpaWUCqVsLe3R7t27fDrr79K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DAwM4O7urukwiIiI6C3h7aforVCr1ZoOgYoR9jYhInrHYkKBrRZp70RE9FYxd6KixO8TEREVqdBQ2Hl4ALn0gNQE9tSgIqVUKqGnp4eoqCjY2tpCqVRCoVBoOizKRAiB1NRUGBgYaP3xEULgyZMnUCgUMDQ01HQ4REQlg1ADqS/T3omI6K1g7qT9dC1vSk5OxpMnT6CnpwelUqnpkIiIqDhQq6EXH691RXMWNahI6enpwc3NDQ8fPkRUVJSmw6EcCCGgVquhp6en9SfnAKBQKFCuXDno6+trOhQiIiIioiLB3En76VreBACmpqYoX7489PR4Yw4iIiq+WNSgIqdUKlG+fHmkpqZCpVJpOhzKhlqtxrNnz2BjY6MTJ7uGhoYsaBARERFRscPcSbvpWt6kr6+vE71KiIiI3hSLGvRWpN8qiLcL0k5qtRqGhoYwNjbWiZNzIiIiIqLiirmT9mLeREREpJ34V5mIiIiI5Cy8gFbn096JiIiIiIioZPLywtP9+wEv7coN2VODiIiIiOQMTAHrmpqOgoiIiIiIiDTJ1BSp1aoBpqaajkSGPTWIiIiISC4hEjg7Ku2diIiIiIiISqbISJT65BMgUrtyQxY1iIiIiEgu6Slwc3naOxEREREREZVMT5/CbN064Kl25YYsahARERERERERERERkU5gUYOIiIiIiIiIiIiIiHQCixpERERERERERERERKQTWNQgIiIiIjljO6DShLR3IiIiIiIiKpns7JAwbBhgp125oYGmAyAiIiIiLWNaDqj1laajICIiIiIiIk0qVw4vZ82CiZYVNdhTg4iIiIjkUuKBJyfT3omIiIiIiKhkio+H4blzQLx25YYsahARERGR3MsbwJ/10t6JiIiIiIioZLpxAzbt2wM3tCs3ZFGDiIiIiIiIiIiIiIh0AosaRERERERERERERESkE1jUICIiIiIiIiIiIiIincCiBhERERHJKQwAozJp70RERERERFQyGRhAbW0NGGhXbqhd0RARERGR5llVA7o+0XQUREREREREpEnVqiH66lXY2dlpOhIZ9tQgIiIiIiIiIiIiIiKdwKIGEREREcm9uArscE97JyIiIiIiopLp6lWUef994Kp25YYsahARERGRnDoJiL+d9k5EREREREQlU1ISDO7eBZK0KzdkUYOIiIiIiIiIiIiIiHQCixpERERE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jIBHLdCjnC9g4aHpaIpc+jEkIiIiIiKiXJQqhSR/fxiWKqXpSGRY1CAiIiIiOQsPoMl+TUdBREREREREmuThgZjNm2FnZ6fpSGSK6eWFRERERFRoahWQEpf2TkRERERERCWTSgXFy5eASrtyQxY1iIiIiEjuxSXgl9Jp70RERERERFQyXbqEsp6ewCXtyg1Z1CAiIiIiIiIiIiIiIp3AogYREREREREREREREekEFjWIiIiIiIiIiIiIiEgnsKhBREREREREREREREQ6wUDTARARERGRlrGsCnSJBpSWmo6EiIiIiIiINKVqVTwOC4Oth4emI5FhUYOIiIiI5PQMAWNbTUdBREREREREmmRoCFGmDGBoqOlIZHj7KSIiIiKSe3kbONwh7Z2IiIiIiIhKptu3YTlwIHBbu3JDFjWIiIiISC4lFniwM+2diIiIiIiISqbYWBgfOADEalduyKIGERERERERERERERHpBBY1iIiIiIiIiIiIiIhIJ7CoQUREREREREREREREOoFFDSIiIiKSM3ECfBenvRMREREREVHJ5OSEuBkzACftyg0NNB0AEREREWkZk7KA90RNR0FERERERESaVLYsXg0fDnM7O01HIsOeGkREREQklxwDRP6S9k5EREREREQlU0wMjHbuBGK0KzdkUYOIiIiI5OIjgGM90t6JiIiIiIioZIqIgNWwYUCEduWGLGoQEREREREREREREZFOYFGDiIiIiIiIiIiIiIh0AosaRERERERERERERESkE1jUICIiIiI5fRPAyjftnYiIiIiIiEomExOkVKkCmGhXbmig6QCIiIiISMuU9gZaX9B0FERERERERKRJ3t549uefsLOz03QkMuypQUREREREREREREREOoFFDSIiIiKSe34R2GyU9k5EREREREQl08WLKOviAlzUrtyQRQ0iIiIiykQA6uS0dyIiIiIiIiqZhIAiORkQ2pUbsqhBREREREREREREREQ6gUUNIiIiIiIiIiIiIiLSCSxqEBERERERERERERGRTmBRg4iIiIjkLLyBNlfS3omIiIiIiKhk8vbG05AQwFu7ckMDTQdAuuuH++EwiSul6TCoMISAcdwrJCY9ARQKTUdDBcXjp/t4DHVbSTp+cbc1HcHbIQS6GNlqOgoiIiIiIiLtZmKC1EqVABMTTUciw54aRERERCRjnhiFgJszYJ4YpelQiIiIiIiISFPu3YPFpEnAvXuajkSGRQ0iIiIikjFOfYHKj7fBOPWFpkMhIiIiIiIiTXn2DKabNgHPnmk6EhkWNYiIiIiIiIiIiIiISCewqEFERERERERERERERDqBRQ0iIiIiIiIiIiIiItIJLGoQERERkcxrQxtcKPchXhvaaDoUIiIiIiIi0pSyZRE/ejRQtqymI5Ex0HQARERERKRdEozK4pTreE2HQURERERERJrk5IT4adNgamen6Uhk2FODiIiIiGQMUxPg+OIsDFMTNB0KERERERERacrLl1CeOAG8fKnpSGRY1CAiIiIimdKJ99DpymCUTryn6VCIiIiIiIhIU27ehHXXrsDNm5qORIZFDSIiIiIiIiIiIiIi0gksahARERERERERERERkU5gUUMHXb16FV27doWrqysUCgWWLFmi6ZCIiIiIiIi0DnMnIiIiouKHRQ0to1KpoFarc53m1atXqFChAubPnw97e/t3FBkRERGVFGqFAeKVdlArDDQdChFRjpg7EREREb1lhoZQOTgAhoaajkSmWBY19u3bhwYNGsDS0hI2NjZo164dbt++DQC4e/cuFAoFtm3bhsaNG8PU1BTVq1fHyZMnpfnv3buH9u3bw8rKCmZmZvDx8cGePXsAAH5+fggKCpKm7dSpEwwNDREfHw8AuH//PhQKBW7dugUASEpKQmBgIJycnGBmZoa6desiJCREmn/dunWwtLTEjh07ULlyZRgZGSEyMjLX7atduzYWLVqEXr16wcjIqED75smTJ7C3t8eXX34pjTtx4gSUSiUOHjyY7TxJSUmIi4uTvYiIiKj4em7miR/rHMRzM09Nh0JEbxlzp5wxdyIiIqISr2pVPLlwAahaVdORyBTLokZCQgImTpyIc+fO4eDBg9DT00Pnzp1lV/FMmzYNgYGBCA0NhaenJ3r37o3U1FQAwKhRo5CUlIQjR44gLCwMCxYsgLm5OQDA399fOrEWQuDo0aOwtLTEsWPHAACHDx+Gk5MT3N3dAQCjR4/GyZMnsXnzZly+fBndu3dHq1atcDPDE+NfvXqFBQsWYM2aNbh69Srs7Oze2r6xtbXF2rVrMXPmTJw7dw4vX75E//79MXr0aDRt2jTbeebNm4fSpUtLL2dn57cWHxERERERvTvMnXLG3ImIiIhIOxXLewp07dpVNrx2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AK+1KzdkUYOIiIiIiIiIiIiIiHQCixpERERERERERERERKQTWNQgIiIiIiIiIiIiIiKdwKIGEREREcmZuwENtqa9ExERERERUcnk5oaYVasAN+3KDQ00HQARERERaRmlFVC+u6ajICIiIiIiIk2yskJS+/aAlZWmI5FhTw0iIiIiknv9GAj/Ku2diIiIiIiISqbHj2G6ciXwWLtyQxY1iIiIiEju9QPg4qS0dyIiIiIiIiqZHjyAxaxZwAPtyg1Z1CAiIiIiIiIiIiIiIp3AogYREREREREREREREekEFjWIiIiIiIiIiIiIiEgnsKhBRERERHKGpQGn9mnvREREREREVDKVLo3EFi2A0tqVGxpoOgAiIiIi0jKlKgL+OzQdBREREREREWlSxYp4sX497OzsNB2JDHtqEBEREZGcOgVIfJL2TkRERERERCVTSgoUT58CKdqVG7KoQURERERyL8KAbXZp70RERERERFQyhYWhbNWqQJh25YaFLmqoVCps3rwZH330ETp37oyw/zYsNjYW27Ztw+PHj4ssSCIiIiIiIl3F3ImIiIiIqOgUqqjx4sUL1K9fH3369MHPP/+MHTt24MmTJwAAc3NzjB07Ft98802RBkpERERERKRrmDsRERERERWtQhU1pk6diqtXr2L//v24c+cOhBBSm76+Prp164Y9e/YUWZBERERERES6iLkTEREREVHRKlRRY/v27RgzZgyaN28OhUKRpd3T0xN3795909iIiIiIiIh0GnMnIiIiIqKiZVCYmWJjY+Hm5pZje0pKClJTUwsdFBERERFpkGV1oHssoG+m6UiIdB5zJyIiIiLSWdWr4/GNG7B1ddV0JDKFKmpUrFgRFy5cyLH9wIEDqFy5cqGDIiIiIiIN0tMH9Cw0HQVRscDciYiIiIh0lr4+RKlSgL6+piORKdTtp4YMGYK1a9diy5Yt0j1hFQoFkpKSMG3aNOzbtw8fffRRkQZKRERERO9I3E3g75Zp70T0Rpg7EREREZHOunkTVr16ATe1KzcsVE+NcePG4erVq+jduzcsLS0BAH369MGzZ8+QmpqKjz76CB9++GFRxkla6If74TCJK6XpMKgwhIBx3CskJj0Bsrm3M2k5Hj/dx2Oo20rA8SsTfw09Hh3A1vsX8dQ8SdPhFD0h0MXIVtNRUAnB3ImIiIiIdNbLlzA6fBjq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CQkJSktLs58RdTHbtm1TvXr17AflktS8eXMFBwdr27ZtateunaSzBU9kZKTc3Ny0ZcsWWSyW825z3LhxGj16tP3n3Nxch+0DAICry1G/KL3VYaNsFqc7/wVwWdRO1E4AAAAu59prdWj3boXVqWN2EgflrlTHjBmj//3vfw6XNkuSm5ubRo4c6XD/1UvRs2dPNWjQQLNnz1ZERIRsNptatGihoqIi+zKenp72P5ccUJbkuP/++9WtWzctWbJE33//vSZNmqRp06bpscceU3BwsFq3bq2VK1cqOTlZt9xyi7p06aIBAwZox44d2rlzp/1so7y8PLm7u2vjxo1yd3d3yFhy1pMk+fr6XvCg9nKMGDFCX3/9tVatWqW6detW6LZ/++035efny83NTQcPHrQXOOfi7e193nvYAgCAq5DFTTaLl9kpgKsGtdNZ1E4AAAAuxs1N8vY+++5EypVm2rRpevXVV9W7d28lJyfrxIkTOnHihJKTk9W3b1+9+uqrevXVVy95u8eOHdP27dv1zDPP6Oabb1Z0dLSys7MveTv16tXTww8/rIULF2rMmDGaPXu2fV5cXJxWrFihVatWKT4+XtWrV1d0dLRefPFFhYeH288uio2NldVqVVZWlpo2berwql279iVnuhSGYWjEiBH64osv9OOPP17S2VvR0dHau3ev9u7da5+2detWnThxwn621vHjxzV8+HCNHz9ew4cP1+DBg3Xq1KkK3w8AAOCagk7t1p2b71HQqd1mRwFcHrUTtRMAAIDL2rFD1Xv3lnbsMDuJg3I1NWbPnq077rhDn3zyidq3b6/AwEAFBgaqffv2mj9/vnr27Km33377krcbEhKi0NBQzZo1S+np6frxxx8dLt0ti5EjR+q7775TRkaGfv31V61YsULR0dH2+fHx8fruu+/k4eGhqKgo+7R58+bZzzSSpMjISA0ePFhDhw7VwoULlZGRoV9++UWTJk3SkiVLLnnfShQVFSklJUUpKSkqKirS/v37lZKSovT0dPsyCQkJ+vDDD/XRRx8pICBAhw4d0qFDh8p08Ny1a1e1bNlSgwcP1q+//qpffvlFQ4cOVVxcnNq2bStJevjhh1WvXj0988wzeuWVV2S1WjV27Nhy7xMAALi6eFoLVCd3gzytBWZHAVwetRO1EwAAgMvKy5NXcrKUl2d2Egflamrs3r1b3bp1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Svv6c+fOVXBwsBYtWqTmzZvL29tbmZmZF9y/du3aacqUKRo4cKC8vb0v+fspLCzU448/rrCwMPn4+KhTp05av379BZfPzc11eAEAAABwbdRNF3apdVPJOtROAAAAleuqbGrk5+dr9OjR2rBhg5YvXy43NzfdddddDmfyjB8/XmPHjlVKSooiIyM1aNAgFRcXS5ISEhJUWFioVatWKTU1VZMnT5a/v78kKS4uzn5wbRiGVq9ereDgYP3000+SpKSkJNWpU0dNmzaVJI0YMULJycmaP3++Nm/erH79+ql79+7aufP/budQUFCgyZMna86cOdqyZUulP3jln//8pz7//HO99957+vXXX9W0aVN169ZNx48fP+fykyZNUlBQkP1Vr169Ss0HAAAAoPJRN13YpdZNErUTAADAleBhdoDK0KdPH4ef3333XdWsWVNbt261H2SPHTtWt99+uyTpueeeU0xMjNLT0xUVFaXMzEz16dNHLVu2lCQ1btzYvq34+Hi98847slqtSktLk5eXlwYMGKCVK1eqe/fuWrlypeLi4iRJmZmZSkxMVGZmpiIiIuyfu3TpUiUmJmrixImSpDNnzmjGjBlq3bp15X4xOlu4zJw5U3PnztVtt90mSZo9e7aWLVumd955R08++WSpdcaNG6fRo0fbf87NzeXgHAAAAHBx1E3nV566SaJ2AgAAuBKuyis1du7cqUGDBqlx48YKDAxUw4YNJcnh8uRWrVrZ/xweHi5JysrKkiQ9/vjjeuGFF9SxY0dNmDBBmzdvti/buXNnnTx5Ups2bVJSUpLi4uIUHx9vPwspKSlJ8fHxkqTU1FRZrVZFRkbK39/f/kpKSrJf1i1JXl5eDnkq065du3TmzBl17NjRPs3T01PXX3+9tm3bds51vL29FRgY6PACAABXr2N+zTT7hmQd82tmdhQAlYi66fzKUzdJ1E4AAOAq07q1Du/YIV2Bk0ouxVV5pUbPnj3VoEEDzZ49WxEREbLZbGrRooWKiorsy3h6etr/bLFYJMl+mfX999+vbt26acmSJfr+++81adIkTZs2TY899piCg4PVunVrrVy5UsnJybrlllvUpUsXDRgwQDt27NDOnTvtZxzl5eXJ3d1dGzdulLu7u0PGkjOfJMnX19eeAQAAwGyGxV1nPPwvviAAl0bdBAAAgAtyd5cRECD95RjNbFfd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b9+uBx980D7tp59+0iOPPKI777xTzz77rH744Qc9+eSTDuvNnj1bOTk5GjNmzDm3+9BDD+ntt9/WyZMnKzU/AAAAcCV16tRJ0tlj5j/Lzc1VWlqaPDw8tGbNGod5e/fu1d69e+3ruqKdO3dq/fr1atiwoebNm2d2HNMMGjRIH3zwgRITE/XII4/o559/1k033aTU1NRyba8ymxpTpkzRwIEDFRQUZJ82bNgw/fHHH5o8ebKuu+469evXT7t377bPP336tMaOHasXXnjBYb0Sd955pwIDAzVjxoxKyQxUFTQ1AKCKy8jI0Nq1a/XKK6+oZs2aTn2AnZ+fb3aEUhITE9WxY0fVqVPHPu3rr79WfHy8pk+frscff1yTJk3SokWL7PNPnDihZ555RlOnTpW3t/c5t9unTx8VFhbq008/rfR9AAAAAK6UiIgINWrUqFRTIzk5WYZhqF+/fqXmlfx8oaZGQUFBxYetQB9++KHCwsI0bdo0rV271uEfwq8WZanXrrvuOt19990aNmyYXnzxRX388ccqLCx0uqtXNm3apN9++039+/e3Tzt16pR+/PFHvf3223rkkUf0wQcfKCIiQt999519malTpyooKEj333//Obfr5uamvn376v3335dhGJW+H8DViqYGAFRx8+bNU0hIiG6//Xb17dv3vE2NEydOaNSoUWrYsKG8vb1Vt25dDR06VEePHrUvc/r0aT377LOKjIyUj4+PwsPD1bt3b+3atUuStHLlSlksFq1cudJh2yWXIv/5DJvhw4fL399fu3bt0t///ncFBARo8ODBkqTVq1erX79+ql+/vry9vVWvXj2NGjVKp06dKpX7999/V//+/VWzZk35+vqqWbNmGj9+vCRpxYoV5730/aOPPpLFYrngpdCnT5/W0qVL1bVrV4fpp06dUkhIiP3n6tWrOxRZzz77rFq2bKnevXufd9thYWFq1aqVvvrqq/MuAwAAALiiTp06adOmTQ7H72vWrFFMTIxuu+02/fzzz7LZbA7zLBaLOnbsKEmKj49XixYttHHjRnXp0kXVqlXT008/LUnKysrSfffdp1q1asnHx0etW7fWe++95/D5JfXH1KlTNWvWLDVp0kTe3t5q166d1q9fXyrvp59+qubNm8vHx0ctWrTQF198oeHDh6thw4Zl3uePPvpIffv2VY8ePRQUFKSPPvqo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dOlSSdLixYtVWFioRYsWOVy1cq4rHs534lyTJk2Ul5dX7v2IiopSRkbGRZf773//q0aNGmnw4MGSzt6y7M8P/46IiFBKSorDOvv371dRUZH9CiIAl47bTwFAFXTq1CktXLhQPXr0UN++fUu9RowYoZMnT2rRokWSpD59+ui3337TF198UWpbJWcL9enTR0ePHj3nFQ4lyzRo0EDu7u6l7l86Y8aMMmcvOWvpz2dPGYah//3vfw7L1axZU126dNG7776rzMzMc+YpUaNGDd1222368MMPNW/ePHXv3r1MZ820adNGXl5e2rBhwwWXe+qpp9SlSxd1795dklSrVi1J/1dcbdu2TZJUu3Zth/U2btyoG2+88aI5AAAAAFfTtm1b+fj4aN68edq/f7/DlRre3t667rrr9Oabbyo/P7/UrafO5+9//7sOHTqkBQsW2KcVFxfr9ddfl7+/v/2WtWUVERGhFi1a6P3331deXp59elJSklJTUy+6/hdffKH8/HwlJCScs+7q0aOHPv/8cxUWFl5SruPHj5eadu2110qSw7Y6d+6swsJCTZ8+XZ06dbI3ADp37qwPPvhABw4csD9PQ5LCwsIUHx+vt99+WwcPHiz1GUeOHLmknGURHByshx56SN999539H//PVfPl5OQoMTGx1Pp+fn6lTpqTzl4Zk5ycrO+++67UvBMnTqi4uPiCuW688UalpaVdcGx27NihN954Q//73//s322tWrXsdZ50ttY7V50nyeF3HsCl4UoNAKiCFi1apJMnT+qOO+445/wbbrhBNWvW1Lx58zRgwAA9+eST+uyzz9SvXz/de++9atOmjY4fP65FixbprbfeUuvWrTV06FC9//77Gj16tH755Rd17txZ+fn5+uGHH/Too4/qzjvvVFBQkPr166fXX39dFotFTZo00ddff12m+5mWiIqKUpMmTTR27Fjt379fgYGB+vzzz895afBrr72mTp066brrrtODDz6oRo0aaffu3VqyZEmps2WGDh1qP3vq+eefL1MWHx8f3Xrrrfrhhx/03//+95zL/PLLL1qwYIE2b95sn9awYUO1bdtWw4cP13333ac5c+aoffv2DmeOZWVlafPmzUpISChTFgAAAMCVeHl5qV27dlq9erW8vb3Vpk0bh/kdOnTQtGnTJJV+nsb5PPjgg3r77bc1fPhwbdy4UQ0b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eLagmPKPObOzs4127doVGceIESOK/G5uu+22y9q4uLgYixYtsrlRJ+/l4eFR7HHl5MmTbdq++eabxe7D3bt3G9WrVy/y2p577jmbNo4oagQFBRkREREFft7LL79strlSnlXSokblypWN5s2bF3iuIUOGmG0+++wzc7unp6dx4sQJm3Pm/70cNGhQsb/vPIUVNQzDMBo3bmzue/7552325S96uLq6GkeOHDEM4/K/Gdx9990FXuODDz5oU6TIzc01evfuXeR3/Oijj16WZwHOjAeFA7guZWZm6p133tGJEyfMbY899pjNMYsWLdLEiRPN9+3bt9err76quLg4+fr6SpLWrVun4cOHm8fMnz9f2dnZkqTq1avrxRdf1GuvvaZnnnlGUVFRcnV1LbVratGihaZOnarmzZub2+rUqaOpU6ear7p16zrkswYMGGDzPjEx8YptZs2aZT5cvEGDBnr55Zc1fvx4Pfnkk7rttttksVjMY6dOnaqBAwfatP/nP/9pXkf37t0L/Ix169apUaNGevHFF/XCCy9c9ryPK1mxYoVuvfVWvfzyy+rSpYu5/fjx45fFU1Ldu3fX1KlTbZZEuvfee23650rWrl2rESNGyGq1SpJq1KihF154QXFxcfL29pZ08aF/Xbt2LXCNXEnasWOHKlSooOHDh2vgwIHm76RhGMWKoSDLli1T27Zt9corr+iee+4xt//yyy964YUXJEmenp42y2rNmTPH5hyfffaZ+fPjjz9erCUHiuvJJ580v58jR45o2bJl5r7vv/9ehw8fliRVqFBBvXv3LvAciYmJuu222674u3Hw4EH16NHD/H+gUaNGGjNmjP75z3+qZs2akqTff/9dXbt2Nf89AAAAlGebNm2yeV+lSpUCjytsrD906FCtXbvWPO6+++7T2LFj1b59e3Pb+vXrNXTo0EJjKM549kqGDx+u1atXS5Lc3d3Vp08fvfbaa3rsscfMXOdf//qXPv7440LPsXXrVnXr1k0vvfSS/Pz8JF18xmH37t118OBB9e7dW8OHD1eFChdXe8/JydHbb79drPjWrFlj/myxWNSvX79itbtw4YK6dOmi3377TZLk6uqqfv36acyYMTbLJb399ttasGBBsc5ZXMePH9fevXvVp08fvfjii7rppptsPu/cuXOS7M8fC/Pnn38qNTVVAwcO1Isvvqjq1aub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9thj6t69u1JTUzVu3Di9/PLLly3J9Oabb6p58+bavn27Bg0apGeffVZ79+6VJJ0/f17t27eXn5+f1q1bpw0bNsjX11exsbE6d+7ctbjMq0LuBAAAADiWXUWNf/zjHwoICNDPP/+sjz766LL1cjt27Kh169Y5JEAAAAAA168uXbrolltu0dixYy/b969//Uv33HOPXn75ZYWHh6tfv34aPHiwpk6danPc/fffr0GDBqlevXp64YUXdNNNNykxMVGS9Omnn8pqtWrOnDlq0qSJIiIiNG/ePKWlpSkpKelaXOJVIXcCAAAAHMuuosbatWv17LPPKjg4WBaL5bL9NWrU0O+//37VwQEAAAC4/k2ZMkXz58/Xnj17bLbv2bNHUVFRNtuioqK0b98+5ebmmtuaNm1q/myxWFSlShWlp6dLkn788Uft379ffn5+8vX1la+vrypVqqSzZ8/qwIEDpXhVjkHuBAAAADhWBXsaWa1WeXt7F7r/2LFj8vDwsDsoAAAAAM6jTZs2at++vV566SX169evxO3d3Nxs3lssFlmtVknSmTNndNttt2nhwoWXtQsODrYr3muJ3AkAAABwLLtmatx6661atmxZgfsuXLigRYsW6Y477riqwAAAAAA4j8mTJ+t///ufNm3aZG6LiIjQhg0bbI7bsGGDwsPD5erqWqzz3nrrrdq3b59CQkJUr149m1fFihUdeg2lgdwJAAAAcCy7ihovvfSSVq5cqWeffVY7d+6UJP35559avXq17rvvPu3Zs0cvvviiQwMFAAAAcP1q0qSJevbsqXfeecfcNnLkSK1Zs0avvfaafv75Z82fP1/Tp0/XqFGjin3enj176qabbtJDDz2kdevW6eDBg0pKStLQoUMLfDj59YbcCQAAAHAsu4oaHTp0UEJCgj799FPdfffdkqRevXrpvvvu07Zt27RgwQK1adPGoYECAAAAuL69+uqr5rJR0sVZCv/5z3+0aNEiNW7cWK+88opeffXVEi1R5e3trbVr16pGjRp6+OGHFRERoSeffFJnz56Vv79/KVyFY5E7AQAAAI5lMQzDsLdxVlaWvv76a+3fv19Wq1V169ZV+/bt5efn58gYcZ3JzMxUxYoVFZ+6UV7+9LVTMgx5ZmbrrL+3VMADK3Gdo/+cH33o3Og/52cYetgjWCEhIXJxsesenxLJGztlZGRc9kf4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llxcXHT06FEzySmIh4dHoevYAgAAALGxsTp37pwsFovat29/xeMrVKigdu3aqV27dho7dqwCAgL07bff6uGHH5bFYlFUVJSioqL0yiuvqGbNmlqyZIlGjBhR4rjq16+vX3/9VX/++acqV64sSdqyZUuJz3O1SiN3Im/6P6WZN5UUuRMAAEDps2umxptvvqm33npLDz/8sDZt2qRTp07p1KlT2rRpkx555BG99dZbeuutt0p83uPHj2vv3r0aM2aM7rnnHkVEROjkyZMlPk9YWJgGDhyoxYsXa+TIkZo9e7a5Lzo6WomJiVq7dq1iYmJUqVIlRUREaMKECQoNDVV4eLgkKTIyUrm5uUpPT1e9evVsXvmnr5cGwzA0ePBgLVmyRN9++61q165d7LYRERH69ddfbe4I2r17t06dOmU+M+PEiRPq16+fRo8erX79+qlnz576+++/HX4dAAAAKB9cXV21Z88e7d69+7I/bF/qq6++0jvvvKOUlBQdPnxYCxYskNVqVf369bV582ZNnDhRP/zwg9LS0rR48WIdO3ZMERERdsV17733qm7duurbt6927NihDRs2aMyYMZJUan9gv1Rp5E7kTReVdt4UERGhDRs22LTbsGFDoc8iBAAAwLVh10yN2bNn68EHH9R//vMfm+0tW7bUokWLdPbsWb3//vsaPnx4ic4bGBiooKAgzZo1S6GhoUpLS9OLL75YonMMGzZMHTp0UHh4uE6ePKnExESbJCgmJkbvvvuugoOD1aBBA3Pb9OnT9eijj5rHhYeHq2fPnurTp4/efPNNRUZG6tixY1qzZo2aNm1qrk1bUufOndPu3bvNn3///XelpKTI19fXfNBeXFycPv74Y3355Zfy8/PTH3/8IUmqWLGivLy8ijx/u3bt1KRJE/Xs2VPTpk3ThQsXNGjQIEVHR6t58+aSpIEDByosLExjxoxRTk6OIiMjNWrUKP373/+265oAAADgeHdEBpd1CCXi7+9frOMCAgK0ePFijRs3TmfPntXNN9+sTz75RI0aNdKePXu0du1aTZs2TZmZmapZs6befPNNdejQwa6YXF1d9cUXX2jAgAFq0aKF6tSpo6lTp6pTp07y9PS065wlVRq5E3nTtcmbnn/+eT322GOKjIxUu3bt9L///U+LFy/W6tWr7bomAAAAOIZdRY1Dhw7pueeeK3R/+/bt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DVxP79699eGHH2rYsGHavHmzGjVqpKysLH3zzTcaMGCA2rVrp+joaD399NNKSEhQSkqKmjdvrhIlSmj//v1atGiR3nzzTXXq1OmWYv/b3/4mR0dHTZw4Uenp6XJxcVGTJk308MMPy8/PT3369NGgQYNksVg0b968PE0bZ2dnvfjiixo4cKCaNGmiLl266PDhw0pMTFSlSpXsrsjo1auXFi5cqGeeeUbJyclq0KCBcnJy9PPPP2vhwoX66quvrnuLL+nKQ/CcnJz0zTff6KmnnrrmnOeff141atRQ586dbWMdO3bUuHHj9K9//UsVKlTQzJkz89wCKykpSe7u7mrWrNktfX8AAABAUfHcc89p3rx52rt3ryIiIuyW9e/fXxMmTFD//v0VGRmpdevW2c78vxf8/f3VsGFD9e3bV8ePH9fUqVNVuXJlPfnkk5KunOU/Z84ctWrVShEREerbt6/KlCmjo0ePKjk5Wd7e3vriiy9u67NHjRql//73v2rVqpUGDRokf39/ffDBBzp06JAWL15cKM98KFGihCZOnKi+ffsqOjpa3bt31/Hjx/Xmm2+qYsWKGjp0qN18V1dXrVy5Un369FFUVJRWrFihZcuWafTo0dd9xqEkTZgwQcnJyYqKitKTTz6patWq6fTp09q2bZu++eabazYjbse4ceO0bt06tW7dWhUqVFBaWpreffddlS1b1u4B7QDuPZoaAFCMjRo1SmFhYXrjjTf00ksvSbryjIjmzZvn65ZGjo6OWr58ucaPH6+PP/5YixcvVkBAgBo2bKgaNWrY5s2YMUN16tTRzJkzNXr0aNsDuXv27KkGDRrcctylSpXSjBkzlJCQoH79+iknJ0fJycmKiYnRl19+qeHDh2vMmDHy8/NTz549FRsbqxYtWthtIz4+XoZhaMqUKRoxYoRq1aqlzz//XIMGDbJdLSFdKTz+97//6Y033tCHH36opUuXyt3dXaGhoRo8ePBNb90VFBSkf/zjH1q4cOE1mxo7duzQnDlztGnTJrvxGjVqaO7cuXrxxReVmZmpAQMG5Fl/0aJF6tChg7y8vG71KwQAAACKhMqVK6tnz5764IMP8ix74YUXdOLECX366adauHChWrVqpRUrVigwMPCexDJ69Ght375dCQkJyszMVGxsrN599125u7vb5sTExGjjxo16+eWXNW3aNJ07d06lSpVSVFSUnn766dv+7KCgIH333XcaOXKk3n77bV24cEE1a9bUF198cc0rIgrK448/Lnd3d02YMEEjR46Uh4eHHnvsMU2cOFG+vr52cx0dHbVy5Ur961//0rPPPisvLy+NHTtWL7zwwg0/IygoSJs3b9a4ceO0ZMkSvfvuuwoICFBERMQ1b012u9q2bavDhw/r/fff18mTJ/XAAw8oOjpaL730ku1h4wAKhsW4nScbAQBQBFmtVpUsWVIdOnS45u2mbtf69esVExOjn3/++a491DslJUV///vftW3btus+ZBAAAAAAAKCo4ZkaAIBi6cKFC3luS/Xhhx/q9OnTiomJuauf1ahRIzVv3lyvvfbaXdvmhAkT1KlTJxoaAAAAAACgWOFKDQBAsbRmzRoNHTpUnTt3VkBAgLZt26b33ntP4eHh2rp1q5ydnQs7RAAAAAAAAFyFZ2oAAIqlihUrqly5cnrrrbd0+vRp+fv7q3fv3powYQINDQAAAAAAgPsUV2oAAAAAAAAAAABT4JkaAAAAAAAAAADAFGhqAAAAAAAAAAAAU6CpAQAAAAAAAAAATIGmBgAAAAAAAAAAMAWaGgAAAAAAAAAAwBRoagAAAAAAAAAAAFOgqQEAAAAAAAAAAEyBpgYAAAAAAAAAADCF/wcpDAfQH7YrogAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import matplotlib\n", + "matplotlib.rcParams['font.family'] = 'DejaVu Sans'\n", + "matplotlib.rcParams['axes.unicode_minus'] = False\n", + "\n", + "if merged_df['problem_type'].notna().sum() > 0:\n", + " fig, axes = plt.subplots(2, 2, figsize=(16, 12))\n", + " fig.suptitle('Type-based Analysis', fontsize=16, fontweight='bold')\n", + " \n", + " # 1. ์œ ํ˜•๋ณ„ ์ •ํ™•๋„ ๋ง‰๋Œ€ ๊ทธ๋ž˜ํ”„\n", + " ax1 = axes[0, 0]\n", + " type_stats_sorted = type_stats.sort_values('accuracy', ascending=True)\n", + " colors = ['#FF6B6B' if acc < 80 else '#4ECDC4' if acc < 90 else '#95E1D3' \n", + " for acc in type_stats_sorted['accuracy']]\n", + " type_stats_sorted['accuracy'].plot(kind='barh', ax=ax1, color=colors)\n", + " ax1.set_xlabel('Accuracy (%)', fontsize=12)\n", + " ax1.set_ylabel('Problem Type', fontsize=12)\n", + " ax1.set_title('Accuracy by Problem Type', fontsize=14, fontweight='bold')\n", + " ax1.axvline(x=90, color='orange', linestyle='--', linewidth=1, label='90% threshold')\n", + " ax1.legend()\n", + " ax1.grid(axis='x', alpha=0.3)\n", + " \n", + " # 2. ์œ ํ˜•๋ณ„ ์˜ค๋‹ต๋ฅ  ๋ง‰๋Œ€ ๊ทธ๋ž˜ํ”„\n", + " ax2 = axes[0, 1]\n", + " type_stats_sorted_wrong = type_stats.sort_values('wrong_rate', ascending=False)\n", + " colors_wrong = ['#FF6B6B' if rate > 10 else '#FFE66D' if rate > 5 else '#95E1D3' \n", + " for rate in type_stats_sorted_wrong['wrong_rate']]\n", + " type_stats_sorted_wrong['wrong_rate'].plot(kind='barh', ax=ax2, color=colors_wrong)\n", + " ax2.set_xlabel('Wrong Answer Rate (%)', fontsize=12)\n", + " ax2.set_ylabel('Problem Type', fontsize=12)\n", + " ax2.set_title('Wrong Answer Rate by Type', fontsize=14, fontweight='bold')\n", + " ax2.axvline(x=10, color='red', linestyle='--', linewidth=1, label='10% threshold')\n", + " ax2.legend()\n", + " ax2.grid(axis='x', alpha=0.3)\n", + " \n", + " # 3. ์œ ํ˜•๋ณ„ ๊ฒฐ๊ณผ ๋ถ„ํฌ (์Šคํƒ ๋ฐ” ์ฐจํŠธ)\n", + " ax3 = axes[1, 0]\n", + " type_result_pct = type_stats[['correct', 'wrong', 'none', 'missing']].div(type_stats['total'], axis=0) * 100\n", + " type_result_pct.plot(kind='barh', stacked=True, ax=ax3, \n", + " color=['#95E1D3', '#FF6B6B', '#FFE66D', '#C7CEEA'])\n", + " ax3.set_xlabel('Percentage (%)', fontsize=12)\n", + " ax3.set_ylabel('Problem Type', fontsize=12)\n", + " ax3.set_title('Result Distribution by Type', fontsize=14, fontweight='bold')\n", + " ax3.legend(['Correct', 'Wrong', 'None', 'Missing'], loc='center left', bbox_to_anchor=(1, 0.5))\n", + " ax3.grid(axis='x', alpha=0.3)\n", + " \n", + " # 4. ์œ ํ˜•๋ณ„ ๋ฌธ์ œ ์ˆ˜\n", + " ax4 = axes[1, 1]\n", + " type_stats['total'].sort_values(ascending=True).plot(kind='barh', ax=ax4, color='#B4A7D6')\n", + " ax4.set_xlabel('Number of Problems', fontsize=12)\n", + " ax4.set_ylabel('Problem Type', fontsize=12)\n", + " ax4.set_title('Problem Count by Type', fontsize=14, fontweight='bold')\n", + " ax4.grid(axis='x', alpha=0.3)\n", + " \n", + " plt.tight_layout()\n", + " type_viz_path = output_dir / \"type_analysis_visualization.png\"\n", + " plt.savefig(type_viz_path, dpi=300, bbox_inches='tight')\n", + " print(f\"\\n๐Ÿ’พ ์œ ํ˜•๋ณ„ ๋ถ„์„ ์‹œ๊ฐํ™” ์ €์žฅ: {type_viz_path}\")\n", + " plt.show()\n", + "else:\n", + " print(\"โš ๏ธ ์œ ํ˜• ์ •๋ณด๊ฐ€ ์—†์–ด ์‹œ๊ฐํ™”๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. ์ „์ฒด ์‹œ๊ฐํ™”" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ’พ ์‹œ๊ฐํ™” ์ €์žฅ: accuracy_visualization.png\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABdEAAAPZCAYAAAD+1mNdAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Xd8E/X/B/BX0jajE0qhA1r2pixBUEZB9kZABZGl4B6IKKCCbMSBoKgoyhKcLEGGE7AgyF5Sdpmle6dN0iSf3x/99b69pulur+P1fDzyaHOfz92975JL7t753OejEkIIEBERERERERERERGRHbXSARARERERERERERERlVdMohMREREREREREREROcAkOhERERERERERERGRA0yiExERERERERERERE5wCQ6EREREREREREREZEDTKITERERERERERERETnAJDoRERERERERERERkQNMohMREREREREREREROcAkOhERERERERERERGRA0yiExERFYPZbEarVq2gUqmkx6BBgxzWf/rpp2V1/f39ER8fL5XHxMRgyZIl6N27N2rXrg2dTgcPDw/Ur18fI0eOxNdffw2TyeRw+RMnTpQtf+7cuYXaHqvVip9++glPPPEEGjduDC8vL2i1Wvj7+6Nbt254++23cePGjUItMy9Tp06VxatSqdChQ4cSWz7lr0ePHnavgUqlglqthru7Oxo1aoRRo0Zh69atEEIoHW6Ft27dumIdo1lu3LghW06PHj1KNM6ytHz5crv3n7+/PywWi9KhUQnZvn273Wus1Wpl33/lyf79+2WxTpw4UdF46tWrJ4uHiIiIyh6T6ERERMWg0Wiwbt06ODk5SdN2796Nb7/91q7u/v378dVXX8mmrVq1Ct7e3gCAZcuWoW7dunjzzTfx559/IiIiAiaTCampqbhx4wa2bt2KyZMno0GDBvjzzz9LfFtOnTqFli1b4tFHH8WmTZtw9epVJCcnw2w2IzIyEgcPHsSiRYvQuHFjzJgxo9gJroyMDGzatMlu+okTJ3D+/PliLZuKTwgBg8GAa9euYcuWLRg5ciRGjRrFRHopK6kke0Wybt06u2mRkZHYu3dv2QdDpWLt2rV208xmc67flURERETlkbPSARAREVV0HTp0wIwZM7B48WJp2iuvvIK+ffvCx8cHAGA0GvH000/LEpBjx47FsGHD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hM8//xxHjx7FM888g5YtW8LDwwMuLi7w9fVF586dMWvWLLtBAGfMmIGzZ8/ixRdfRKtWreDh4QFnZ2f4+PggJCQEy5Ytw/nz5+0GzgUyB+I7ePAgBg4cCC8vL+j1erRt2xYrV67EN998IxvctiQHbS2onTt3YsqUKQgMDISzs3ORl1OcfVQaIiMj8euvv0rPVSoVHnvsMYf1dTodhg0bJpuWvbuPzp0748KFC1i5ciX69u0LPz8/aDQauLu7o2HDhhg9erRdV0i+vr44cOAAtm7dikceeQT16tWDXq+HVqtFnTp10K9fP7zxxhuyeapVq4ZDhw5h4sSJ8PX1hYuLC+rWrYuXX34ZZ8+ezfWzoiiqV6+Ow4cP45lnnkFAQABcXFwQEBCAiRMn4vTp03bjZ+Tk5uaGbdu24Y8//sC4cePQuHFjuLm5QaPRwN/fHz169MD8+fMdzj9x4kTZ4J0+Pj4YNWpUobYht+568hskM+d7oKS6dBk+fDj+/PNP9OrVC+7u7tDr9QgODsaHH36ILVu2lNhYEoXZb2+//TYWLFiAgQMHonHjxvD29oaTkxNcXV3RpEkTPPHEE9i/fz9mzpxZ4PUvX74cb7/9Nnr37o0GDRrAy8sLarUa7u7uaNmyJaZMmYLjx4/jiSeeKPa2EhERVWUqIUpoWHciIiIiogogIiICPj4+dgNGAsBbb72FxYsXS88nT56M1atXl2V4RIqIiYlBvXr1kJaWBiDzR5jsP5ZR7rjfiIiIqgYm0YmIiIioSpk7dy6WLVuGnj17IigoCNWrV0dMTAxCQ0Px33//SfXc3d1x9uxZ1K9fX8FoiUrP7du38cMPPyA1NRU//vijNDirq6srrly5osidGBUB9xsREVHVU/T7Q4mIiIiIKqiUlBS7rmWyCwgIwPfff88EOlVq165dw+uvv243/YMPPmAiOA/cb0RERFUPk+hEREREVKUMHz4cSUlJ+Oeff3D79m3ExcVBrVbDx8cHwcHBGDRoEMaPHw8PDw+lQyUqM15eXmjZsiVef/11DB8+XOlwKgzuNyIioqqB3bkQERERERERERERETlQMkOSExERERERERERERFVQkyiExERERERERERERE5wCQ6EREREREREREREZEDTKITERERERERERERETnAJDoRERERERERERERkQNMohMREREREREREREROcAkOhERERERERERERGRA0yiExERERERERERERE5wCQ6EREREREREREREZEDTKITEZWCHj16QKVSQaVS4caNGwCAGzduSNN69OihaHylKWsb69Wrp3Qo+VIy1v3790vrnzhxojR94sSJ0vT9+/eXeVwV6fUjIiIiKqjly5ejWbNm0Gq1UKlUaNu2rdIhUTlTr1496VyYiCgnJtGJSFFRUVGYNWsW2rRpAw8PD+j1ejRo0ACTJk3CmTNnlA5PUdmTqVkPFxcXBAQEYMSIEThy5IjSIRbK3LlzMXfuXCxfvrzEl51zX7m4uMDb2xvBwcGYNGkS/vnnnxJfZ2JiorRN69atK/Hll5bt27dLcWf9wENEREQV19y5c3P9YR4ANm3aBCcnJ+n8aMeOHYrEmD05mf18rXbt2njsscdw6tSpUl3/999/j1dffRWXLl2C2Wwu1XXR/+R83b/99lu7Oi+99JKszujRo4u8vnXr1knnuYmJicWInIjInrPSARBR1fX333/j4YcfRnx8vGx6eHg4wsPDsWHDBnz00Ud4+eWXFYqw/LFYLLh37x62bduGXbt24eDBg+jYsaPSYRXIvHnzAAB169bF1KlTS3VdFosFCQkJSEhIwPnz57Fu3TpMnjwZn332GVxcXKR6oaGhAACdTlfodSQmJkrbFBISYnfRmp927dpJ6/f19S30+otq+/btWL9+PYDMOyZytjgvzj4hIiKi8mP79u2YOHEibDYb1Go1NmzYgKFDhyodlsRisSAiIgI//vgjtm3bht27d6N3796lsq5ffvlF+n/OnDno06cP3N3dS2Vd5NhXX32Fxx9/XHqenp6OjRs3ltjy161bhwMHDgDIbGRTrVq1Qs2/efNmGI3GEouHiCoXJtGJSBF37tzB8OHDkZCQAADo1q0bXnnlFbi7u+PHH3/EmjVrYLPZMHXqVDRq1AgDBw5ULFaDwQA3NzfF1g8AkyZNwpNPPok7d+5g5syZuHnzJsxmM7744osKk0QvK5MmTcKkSZMQHR2NnTt3YsOGDRBC4KuvvoKbm5usJXzXrl3LPD6bzQaz2QwvLy9F1p+f8hgTERERFc7vv/+O0aNHw2KxAAC++OILjBkzRuGoMn388cdo164doqKiMGfOHFy4cAEZGRmYOnUqzp8/X2LryTrn0ul0iIiIkKZPnDgR9evXL7H15FwXObZ//35cu3YNDRs2BJCZtC4PLcazrvc6dOigdChEVI6xOxciUsR7770nJdCbNm2K33//HSNHjkS/fv3w9ddfS616hRCYOXMmAGDr1q3SbX6vvPKKbHn//POPVPboo49K01NTUzF37ly0atUKer0enp6e6NGjB/bs2SObP2d/5X///TceeOAB6PV6vPDCCwCAr7/+Gv369UNQUBDc3Nyg0+nQuHFjvPTSS4iNjS2tXQUACAoKQteuXTF69GhZy/zbt2/b1Q0NDcXQoUNRs2ZNaDQa1K9fH9OmTZP2d5a4uDg8++yzqFu3LjQaDTw8PNCkSROMGTNGasEBOO4bsKB9d2fdYpzl5s2bdv1u22w2LFq0SHqddDodgoKCMGjQIHz99deF2VUICgpCt27dMHLkSKxbtw4ff/yxVPbJJ5/g8uXL0vPc+v8uSCw5L74OHDhg19999lur16xZg4ULF6Ju3bpwcXHBkSNHHPaJnp3FYsG8efMQGBgIvV6P7t274+TJk7I6BX19st7jWa3QAaBnz552r6GjPtHNZjOWLl2Ktm3bws3NDa6urmjTpg3effddu9uis8cUGRmJcePGoXr16vDw8MBjjz1md/cJERERlZyDBw9i+PDhMJlMAICPPvoIkydPtqtXkHPGcePGSd/p+/btk83/6quvSmVbtmwpcHzBwcHo2rUrRo4cic8++0ya/t9//8nWffbsWYwZMwb+/v7QaDSoXbs2Jk+ejDt37siWl985V87YGzRoYHf+9ddff2HQoEHw8fGBRqNBYGAgJk6ciCtXrhRqXTnP73766Sc0b94crq6u6NatG86dOwebzYb58+ejdu3acHV1xYABA3Dz5k3Zegpz3ZF9LKazZ8/ipZdeQq1ataDX63NdNgAcOXIEjzzyCAICAqDRaODn54eBAwfi9OnTsno///wzevfujerVq0Or1aJp06aYN28e0tPT836Rc+Hh4QEhhOzcfvXq1VKZIwW5nsva79mvYerXry8bo6og13t59Yn+3XffoWfPntK+qFevHsaNG4ekpCQAJXs9Q0TllCAiUkCdOnUEAAFArFy50q783LlzUjkAce3aNWE0GkW1atUEAFGnTh1hs9mk+q+++qpU9+effxZCCJGYmCiCg4Nly8n++PTTT6X5w8PDpekBAQFCp9NJzydMmCCEEKJfv34Ol9W8eXORnp4uLS8kJEQqCw8Pt1tHSEhIvvtowoQJUv133nlHmv7BBx9I0ydOnCibZ/Xq1UKtVucaY9OmTUV8fLxU96GHHnK4PW+99ZZUr27dutJ0R/Ht27dPmp41rW7dukIIId555x2H68mqM3/+fId1unTpUuR9JYQQVqtVNG3aVCpfsGCBw1gLGkv29eV8ZL222be7QYMGsjr79u0T+/bts3uP5Vx269at7Zbv6ekpLl26VOjXJ/v7L7dH1muY2z4xGo2ie/fuDuft3r27MJlMucaUc9sBiLFjx+b7mhIREVHBZD/n6Nixo/Dy8pKez58/P9d5CnrOmP185amnnpIto2HDhtK5Sfbz4NxkPzfIft546tQp2bojIyOFEELs3r1baLXaXOPz8/MT169fz3X7czvncnT+knX+9emnnwqVSpVrHQ8PD3H06NECryv7+urXr2+3XD8/PzFlypR8z3eLet2R23lXzmWvWbNGODk55brstWvXSvVmz57tMIZu3brJzv0K8rpnbXdAQICwWCwiLCxMKnv66ael/x977DFp/oJez+X1OgOZ12MFud5zdF795JNP5rlsIYp/PUNE5R9bohNRmUtJSZG1IGnbtq1dnZYtW8r6rr5w4QK0Wi1GjRoFILM7mOwDa2a1fqlRowYGDBgAAHjrrbdw7tw5AMDAgQOxa9cubNiwAX5+fgAyW8/k1pI7IiICderUwcaNG7F7924MHz4cAPDYY49hzZo12LVrF/bv349du3Zh/PjxAICwsDBs3bq1qLskX7du3cLBgwfxww8/SC2rnZycZK2K7t69ixdffBE2mw0eHh745JNP8Ouvv2LSpEkAgEuXLuHNN98EkPkaZLXIadeuHXbs2IE9e/Zg1apVGDlyZIl2X/Pkk09K/WwDgJ+fH0JDQxEaGorNmzcDyGzlAgDVqlXDxo0b8ccff2DDhg149tln4e/vX6z1q9Vq3H///dLznC1scipILG+99RZ++uknaZ62bdtK2/TJJ5/YLfP69esYO3as9B6sXbt2gWK/evUqVqxYge3bt0u3lyYnJ2PWrFkFmj87f39/hIaGSscHkHk7dVbc7dq1czjv8uXL8ffffwMAAgMD8e233+K7775DUFAQgMzxDT766KNc583q6/Kzzz6DRqMBkDm4V1arHSIiIio5x44dk75jX3/9dcyePduuTmHOGUNCQqSuN7Zs2SK1bv/v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398fWq0WXbt2xb59+9CsWTOpTmFfn8GDB+ODDz5Aw4YNC9yHqVarxe+//453330XrVu3hl6vh06nQ3BwMJYsWYLffvsNGo2mRLaZiIiISoa/vz/++OMP1K5dGwBw5coV9O3bFwkJCYU6Z8yS1aVLltK8C23gwIE4fvw4xo0bhzp16sDFxQU+Pj5o27Ytpk2bJjtXLa7nn38ev//+OwYMGABvb284OzsjICAA48ePx4kTJ9CxY8cSW1dBlPZ1x+TJkxEaGip77WvVqoUBAwbIxg6aP38+fvnlF/Tv3x81atSAi4sLateuja5du+Ldd9/FvHnzSiSevBT2eu6ZZ57BjBkzEBQUJLtWLK5169bhm2++QUhICLy8vKDRaBAUFISxY8dK1wElfT1DROWPSgiO7EVEREREREREeWvQoAHCw8PRvHnzEulOhYiIqKJgn+hERERERERElCuLxYK0tDT89ttv0vg5WQPdExERVRVsiU5EREREREREuVq3bh0mTZokPa9VqxYuXbqEatWqKRcUERFRGWOf6ERERERERESUJ51Oh65du2LPnj1MoBMRUZXDluhERERERERERERERA6wJToRERERERERERERkQNMohMREREREREREREROeCsdABERERERFR+2Ww2REREwMPDAyqVSulwiIiIiIhKjBACKSkpCAgIgFrtuL05k+hERERERORQREQEAgMDlQ6DiIiIiKjU3L59G3Xq1HFYziQ6ERERERE55OHhASDzwsLT01PhaIiIiIiISk5ycjICAwOlc15HmEQnIiIiIiKHsrpw8fT0ZBKdiIiIiCql/Lot5MCiRERERERERER5+PvvvzFw4EDUrFkTKpUKKpUKq1atktXJyMjAvHnz0KBBA2g0GtSpUwevvvoqUlNTZfWuXr2KUaNGwdvbG3q9Hu3bt8cPP/xQoDhOnDiB/v37w9PTE66urujatSv++OMPqdxqtWLq1KmoVasWvL29MX78eNn6k5KSEBAQgMWLFxdjbxARVT1siU5ERERERERElIeTJ0/i999/R4MGDRAbG5trnSeffBIbN26EWq1G48aNcf36dSxfvhynTp3CX3/9BbVajXv37qFLly6Ijo6Gp6cn/P39cerUKYwePRoGgwFPPvmkwxjOnj2L7t27Iy0tDT4+PvD09MShQ4fQv39/7N69G3379sWaNWuw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Pg0gczDR06dP49atW1CpVJg6dSoWLlyIHTt24Ny5cxg/fjwCAgIwfPhwAEDz5s3Rv39/TJkyBUePHsWhQ4fw4osvYvTo0QgICFBuw4iIiIiIKhi2RCcionKpR48eWLNmDc6cOQMXFxc0a9YMPXr0wP79+5GQkICQkBCprl6vL9JtX1ndumRRqVQQQhQ7diKiknD8+HFZ91FZ/ZRPmDAB69atwxtvvAGDwYCnn34aiYmJ6Nq1K/bu3Svr13HTpk148cUX0atXL6jVaowcORIff/xxmW9LSej3+072w0wVnjXdiF/7DFE6DCKqBPi9SJVBRfpeZBKdiIjKpax+0T/66CMpYd6jRw+8++67SEhIwGuvveZw3ubNm8NiseDff/+VunOJi4vDpUuX0KJFiwKt38vLC76+vjh27Bi6d+8OALBarTh58qTUdQIRUWnq0aNHnj/sqVQqzJ8/X9YNVU7e3t749ttvSyO8Muek18GZ/TATEREB4PciUVljdy5ERFQuVa9eHa1bt8amTZvQo0cPAED37t1x8uRJXL58WdYSPafGjRtj2LBhmDJlCg4ePIgzZ87giSeeQO3atTFs2LACx/DSSy9hyZIl+Pnnn3Hp0iW88sorSEhIqDCDgBERERERERFR8TGJTkRE5VZISAisVquURPf29kaLFi3g5+eHpk2b5jnv2rVrcd9992Hw4MF44IEHIITA7t277bpwycuMGTMwZswYjB8/Hg888ADc3d3Rr18/WVcJRERERERERFS5qQQ7fyUiIioQm82G5s2b49FHH8WCBQuUDoeIqEwkJyfDy8sLSUlJ8PT0LNN1GwwGuLu7AwAGHvydt61ThWdJT8furn0AZA4e7ObmpnBEBcNjkSobHotE5UN5OBYLeq7LPtGJiIgcuHnzJn777TeEhITAZDJh5cqVCA8Px+OPP650aERERERERERURtidCxERkQNqtRrr1q1Dx44d0aVLF5w7dw5//PEHmjdvrnRoRERERERERFRG2BKdiIjIgcDAQBw6dEjpMIiIiIiIiIhIQWyJTkRERERERERERETkAJPoREREREREREREREQOMIlOREREREREREREROQAk+hERERERERERERERA4wiU5ERERERERERERE5ACT6EREREREREREREREDjCJTkRERERERERERETkAJPoREREREREREREREQOOCsdABERVT4WYUOGzYaMbH8twgYhAAEBAcAvIhpaoxFQqQAnJ8DZOfPh4gJoNIBWC+h0mc+JiIiIiIiIiBTCJDoREeXLJgQM1gykWS0wWC1Ik/2f+TzdZkWGzYoMYYOtAMt8avteIPxGvvWEqyvWvfwkdE5O0KkzH3onZ7g7ucDD2QXuTv//cHaBk4o3WBERERERERFRyWISnYiIJKmWDCRZTEjMMCPRYkKSxYzEDDOSLWbYIBSJSbi4IN1mQbrNkm9dvdoZ7s4u8HLWoLqLFt4uWlR30cLLWQsnlaoMoiUiIiIiIiKiyoZJdCKiKsgqBBIyjIgxGxFjTkeMOR1xGSZYREHakJctm15f4LrpNgvSzRbEmNNl09VQyRLrPho9fLV6uDmxqxgiIiIiIiIiyhuT6EREVUBChgn3TAZEm9MRYzYi3myEVaGW5YVl1euKvQwbBBIsJiRYTLieLb/u5uQMX40rfLV6+GpcUVOjh4uaXcIQERERERER0f8wiU5EVMkIIZCQYUKEyYC7JgMijGkF6gqlvLLqip9Ed8RgteB6ejKupycDAFQAvF10CNC6IVDnhgCdGzRqp1JbPxERERERERGVf0yiExFVAikWM26mp+CO0YB7JgPSbValQyoxGSXQEr2gBIC4DCPiMow4lxoHNYBaGlfU0bmhjs4dvlpX9q1OREREREREVMUwiU5EVAEJIRBlTseN9GTcSE9BfIZJ6ZBKjVmrVWzdNgCR5jREmtNwPDkGLio1ArRuqO/qgXp6T7g68WuUiIiIiIiIqLLj1T8RUQWRYbPhljEFN9MzH5WptXlezHrlkug5ZQgbbhpTcNOYAhUi4Kd1RQO9Jxq4esLDWaN0eERERERERERUCphEJyIqx6xC4LYxBZcNSbiRngyLqBiDgZYkk4It0fMiANwzpeGeKQ2HEiPh46JDA1dPNHL1QjWX8hkzERERERERERUek+hEROWMEAKRpjRcTkvCtbQkGKtIi3NH0nUVo4V3bIYRsUlGHE2Khq9Gj6Zu1dHYzQtaDkxKREREREREVKExiU5EVE4kZZgQZkjAFUMSUqwZSodTbqRrK0YSPbsoczqizOk4lHAP9Vw90NStOoJ07lBzUFIiIiIiIiKiCodJdCIiBVmFDdfTUnAhNR53TQalwymX0jQuSodQZFYIXEtLxrW0ZLiqndHErRpauleHF7t7ISIiIiIiIqowmEQnIlJAisWM/1ITEJYaX2UGCC0qg7biJtGzS7NZcDolFmdSYhGk80CwhzcCde5QsXU6ERERERERUbnGJDoRURm6azTgbEocbqQno+oNEVo0qRW4JXpuBICbxhTcNKagmrMWwR7eaOZWDS7sO52IiIiIiIioXGISnYiolAkhEJ6eglPJMYgypysdToWTUsmS6NklWkwITbiHfxOj0My9Olp71ICnc8XrA56IiIiIiIioMmMSnYiolFiFwGVDIk4nxyLBYlI6nApJqNUwulT+FtpmYcPZlDicT4lDI1cvtPeqCW8XndJhERERERERERGYRCciKnEZNisupCbgdEosDFaL0uFUbK6uSkdQpmwALqcl4XJaEurrPdHBqyZqavRKh0VEBAC4Hn8dHhYP6bm7xh2+7r4wW824nXTbrn5D74YAgLvJd2G0GGVltdxqwUPrgSRjEmLTYmVlehc9AjwCYBM2XE+8DlTPnG5Ii4CzTQe93hdqtTOMxlhYrfIfqTUaT7i4eMBiSYPJlCArU6udodf7Zi7LcNcuXr2+FtRqF5hMCbBY0mRlLi7u0Gi8YLWaYDTK41Wp1HB19QcApKXdgxA2WblO5wMnJy3M5iRkZKTKypydXaHVVofNloH09Gi7mNzcagMA0tOjYLPJzym02upwdnZFRkYKzOZkWZmTkxY6nQ9sNgvS06Psluvq6g+VSu1gH3rBxcXdwT7UQK+vCSDvfWg0xcNqkd995+LiAY3GExaLESZTnKxMpXKCq6sfgLz3ocmUCItFPhB71j60Ws0wGmPsYsp7H3rD2VkPszkZGRkpsjInJx10uhp57MMAqFQqpKfHwGYzy8o0mmpwcXFDRoYBZnOirEyY/7dt1xOvw9UkP9epW60unNXOiEyNhMEs31ZvvTeq66vDYDYgMjVSvk4nDQK9AjOXm3AdQsg7DqzjWQdaZy1iDDFINsnfL146L/i4+sBoMeJusvx1dVI7oV61ev9fEYD6f8ciAGi1NeDsrMt9HzrrodN6F+D9bb8P//f+ToXZnCRf7v+/v4WwIS3tnt1y+RmRiZ8RmRx9RliMxszvl//fhNtJt2G2yt+Hfu5+cNO4ISE9AfHp8bIyN40b/Nz9YLFZcDPxpt22NqjeACqVKtfvwJpuNeGp9USyKRkxBvnnls5Zh9qetSGEwPWE63bL9XHxyfzHXX4sAtn3YTpMJnm8+b2/dbqacHLS5Pr+dnZ2g1ZbrQDv70gIIR/vi58RmfgZkSm3zwjpWARgtprhBjdEpUYh1Szf1ur66vDWeyMtIw33UuSvq4uTC4K8ggAANxJvwJpj3LnanrWhc9YhNi0WSUb5+8VT6wkttHbbmBsm0YmISohF2HA+JR4nk2Ng5GChJcKmr7qtscPTkxGenox6eg909KrFZDoRKW7mnzPh4vq/LrZ61O2B1x58DXFpcZj661S7+jvH7AQAfHTkI1yKuyQrm9Z5GnrW74mDtw5i1YlVsrJ2fu0wv+d8GC1GzPhrBtA/c3rY5c+hclKjfbs5UKvdcfPWL0hMvCCbNyhwMPz9uyMp6QquXtskK3N1DUBwq8w4/7uw0u5CP7jVNLi6+uHu3T8QE3tMVubv3xNBgQNgMNxB2MUvZGUaFy+0a/cWAODSpTUwZ8gvzpo3ewaeng0RGfUP7t3bJyur6dMRDRo8AqMxDuf/WyErU6mccH/HJQCAq9e+Q1pahKy8UcOxqFGjDWJjT+HW7V9kZdWqtUDTJhNhtRrtlgsA97WfD2dnHW7c2I6k5Muysnp1h8PX90EkJl7Etevfy8rc3YLQsuWLAJDrctu0fgM6nQ/u3PkVcXGnZGW1A3qjTp2+SE29iUuXv5aV6bQ10KbNDABA2MUv7ZJgLZq/AA+PuoiMDEVkVKisrFatB1C/3sMwGmPsYnJSa9GhwwIAwJUr3yDdKE8wNGk8AdWrt0Rs7HHcvrNXVuZdPRiNG49DRkZqrtvascNiqFTOCL+xBSkp8kRX/XqjUKvW/UhI+A/hNzbLytz0mRf5UAMz/poBJ2f5HXdrh62Fj6sP1p1eh0O3D8nKxrcej0daPoLz0eexMHShrCzQMxCfDfoMADDzj5lIz5GgXN5vORp6N8TmC5ux++puWdmwpsMwuf1k3Ei8gdd/f11W5qn1xKYR/38sdQfg/r9jEQCaNnkK1ao1RXT0EdyN+EM2b40a7dCo4RiYzUm57sNO978HALh+/QekGm7Jyho2GA0fn/aIjz+LGze3y8q8PJugWbPJsFrNuS6XnxGZ+BmRydFnhLDagN4Afsp8vuTgEtxOlv8g/Ha3t9GpTif8cf0PbDi7QVbWJbALZnadiURjYq7fgVsf3QoXJxesPLoS52POy8peuv8l9G3YF0fuHMEnRz+RlbWq2QpLei+BxWbJdbkre6/M/Ket/FgEgMA6/REQ8BBSUq7j8pX1svn0ulpo3Xo6ACAsbBWsNnnis1XLV+DmVhsR9/YjOvqwrMzPtxvq1h2CtLRIXAj7VFbm7OyG+9q/AwC4cmU9jDl+AOFnRCZ+RmTK7TNCWG3SuV58ejyqe1bHxrMbsf/mftm8Y1qNwePBj+Ni7EW8s/8dWZm/uz++HPIlAOCtv96y+7H4/T7vo5lPM2y/uB0/X/pZVjaw0UCMbTrWbhtzoxI5f6ImIqJCsQmBi4YEHEuKZsvzQnjqp73Qht/Is05GUCBWjx5UNgGVc/X1HuhczQ/VXQr2KzkRUUlJTk6Gl5cXToWfgodn2bZE/y/iP7QObg0ACPlhPZx1bImepby0IMuuPLUyzVIeW6L/1XsMAODsnbNw1VeMlugGgwHutd0B9f+Oxcx9yFamAD8jslSkzwiL0YgDj00AEoDU1FTEW+IrTEv0ap7VAHcgZOv/jkX5PmRLdH5GZKoInxHSsQgg/kZmEr3MW6JbtfDy8kJSUhI8PT3ttjcLk+hEREUkhMC19GQcTYxCosWc/wwkU5AkenqTxlg7vFfZBFQBqAE0d/dGR69acHXizWREVDaykuj5XViUBoPBAHd3dwDAwIO/w1nPu3KoYrOkp2N31z4AMhN3bm5uCkdUMDwWqbLhsUhUPpSHY7Gg57q8AiciKoLbxlQcSYxEjNmYf2UqMouu6nbnkhsbgP9S43HZkIh2nj5o4+EDF7U63/mIiIiIiIiIqOiYRCciKoRkixmHEu4hPD0l/8pUbOYq3Cd6XjKEDUeTonE+NR73e9VCM7fqUKtUSodFREREREREVCkxiU5EVAAWmw0nk2NwKiUWVvaCVWbMOvb/nZc0qwX74yNwLiUe3b0D4K91zX8mIiIiIiIiIioUJtGJiPJxLS0J/yREIsWaoXQoVY5Jq1E6hAohLsOIbVHX0dytOh6o5gsd+0snIiIiIiIiKjG8yiYiciAhw4TQhAjcMRryr0ylwqRlS/TCCDMkIDw9GQ9U80Mzt2pQsYsXIiIiIiIiomJjEp2IKAebEDiZHIPjSTGwgV23KCldx5bohWW0WbEv/i4uGhLQvXoAamjYrzwRERERERFRcTCJTkSUTazZiH1xdxCTYVQ6FAKQpnFROoQK654pDT9FXkVbz5ro6FUTTiq10iERERERERERVUhMohMRAbAKgRNJ0TiZHMvW5+WIQcckenHYAJxMjsHN9BT0qlEHPmyVTkRERERERFRoTKITUZUXbU7HX3F3EJ9hUjoUysHAluglIi7DiM2R19DRqxbaefpAzb7SiYiIiIiIiAqMSXQiqrJsQuB4UjROJsfApnQwlKsUJtFLjA0C/yZF4UZ6MnrVqINqLhy0lYiIiIiIiKgg2EEqEVVJqZYM/BwdjuNMoJdbQqVCqoa/9Za0KHM6foy8inMpcUqHQkRERERERFQhMDtBRFVOeFoy/oq/C5PNqnQolBedDoLdjpQKixAITbiH28ZUPFSjDnRqJ6VDIiIiIiIiIiq32BKdiKoMi7Dh7/gI7Im9xQR6BSB0HASztN1IT8FP964iypSmdChERERERERE5RaT6ERUJSRkmLAl8jrOp8YrHQoVkM1Vr3QIVUKKNQPbosJxlt27EBEREREREeWK3bkQUaV3LS0Jf8bdhUWw9/OKxMqW6GXGBoGDCfdwz2hAzxq1oWH3LkREREREREQSJtGJqNISQuBoUjROJMcoHQoVQYaeSfSydi09GbGRRvTzCYKPhvufiIiIiIiICGB3LkRUSZltVuyJvcUEegVmYUt0RSRZzNgadR3haclKh0JERERERERULjCJTkSVTmKGCZsjr+NGeorSoVAxmHVapUOosizChr2xt3CSP0IRERERERERsTsXIqpcbqan4PfY2zCz//MKz6RlEl1JAsCRxCgkZJjQwzsATir+7k5ERERERERVE5PoRFRpnEuJw8GEexBKB0IlwqjTKB0CAbhkSESSxYwBPkHQO/G0gYiIiIiIiKoeNisjogpPCIHDiZEIZQK9UjGyJXq5EWlKw+bIa4gzG5UOhYiIiIiIiKjMMYlORBWaVQj8GXcXp5JjlQ6FSli61kXpECibFGsGtkddxz2jQelQiIiIiIiIiMoUk+hEVGFl2KzYHXMTl9MSlQ6FSoGBSfRyxyRs2BlzAzc5aC8RERERERFVIUyiE1GFlGa1YHtUOG4bU5UOhUqJQcM+0csjixDYE3MTlwyJSodCREREREREVCY4QhgRVThJFjN2Rocj2ZKhdChUilI1/Ioqr2wA/oy7A5PNitYeNZQOh4iIiIiIiKhUsSU6EVUoiRkmbI+6zgR6FZCiYXcu5d3BhHs4mhildBhEREREREREpYpJdCKqMOLNRmyPCofBalE6FCplwsUFGc78iqoIjifHIDT+ntJhEBEREREREZUa3itPRBVCnNmIn6PDYbRZlQ6FyoDQ65UOgQrhXGoc1CqgS3V/pUMhIiIiIiIiKnFs5kdE5R4T6FWPjUn0CudMShz+SYhUOgwiIiIiIiKiEsckOhGVa0ygV01MoldMp1NicSSRiXQiIiIiIiKqXJhEJ6JyKzHDhB1MoFdJFr1W6RCoiE4mx3KwUSIiIiIiIqpUmEQnonIp1ZKBndE3kM4EepWUodMpHQIVw/HkGBxLilY6DCIiIiIiIqISwSQ6EZU7RqsFO6NvIMWaoXQopBAm0Su+Y0nROJMcq3QYRJWa1WrF7NmzUb9+fej1ejRs2BALFiyAEEKqI4TAnDlz4O/vD71ej969e+PKlSsKRk1EREREVPEwiU5E5UqGzYpfYm4iwWJSOhRSkEmnUToEKgGHEiNx2ZCodBhEldbSpUvx+eefY+XKlQgLC8PSpUvx3nvv4ZNPPpHqvPfee/j444+xatUq/Pvvv3Bzc0O/fv1gNBoVjJyIiIiIqGJxVjoAIqIsVmHDnthbiDanKx0KKcysY5/olcVfcXehVzsjUO+udChElc4///yDYcOGYdCgQQCAevXq4bvvvsPRo0cBZLZCX758Od5++20MGzYMALBhwwb4+vpi+/btGD16tGKxExERERFVJGyJTkTlghACf8TdwR2jQelQqBxI17IlemVhg8De2FuI4Y9jRCXuwQcfxJ9//onLly8DAM6cOYODBw9iwIABAIDw8HBERkaid+/e0jxeXl7o1KkTDh8+rEjMREREREQVEVuiE1G58E9iJK6lJSsdBpUTTKJXLhnChl0xNzHStwE8nPnaEpWUmTNnIjk5Gc2aNYOTkxOsVisWLVqEsWPHAgAiIyMBAL6+vrL5fH19pbLcmEwmmEz/61YtOTnz+9lms8Fms5X0ZuTJZrNBrc5s96MSAqps/b0TVUQqIaT3tBLHVFHxWKTKhsciUflQHo7Fgq6TSXQiUtyF1HicSYlTOgwqR9K0LkqHQCUszWrBLzE3McK3AbRqJ6XDIaoUfvzxR2zatAnffvstWrZsidOnT2Pq1KkICAjAhAkTirzcJUuWYN68eXbTY2JiyrwvdaPRiPvuuw8AEGi2wkllLtP1E5U0q9kqvafj4uJgMFSMuzB5LFJlw2ORqHwoD8diSkpKgeoxiU5EirprTMXf8feUDoPKGYOGrZUro4QME36NuYXBtepBrVIpHQ5Rhff6669j5syZUt/mwcHBuHnzJpYsWYIJEybAz88PABAVFQV/f39pvqioKLRt29bhcmfNmoVp06ZJz5OTkxEYGIiaNWvC09OzdDbGAYPBgBMnTgAAammc4MyBp6mCswir9J6uUaMG3NzcFI6oYHgsUmXDY5GofCgPx6JOpytQPSbRiUgxSRkm7I29DRt4CxrJGTRsiV5Z3TEZcDgxEl2q++dfmYjylJaWJt3+msXJyUm6JbV+/frw8/PDn3/+KSXNk5OT8e+//+K5555zuFytVgut1n6AZ7Vabbe+0qZWq6XtESoVBH+AowpOqFTSe1qJY6qoeCxSZcNjkah8KA/HYkHXWTE+JYio0jHZrNgVcwsmm1XpUKgEXPn3OD5/8kW82fEhvFA3GGd+/TPfeQ5cvYb2P/wA7eefo9E332BdWJhUlqJxxtFtv+Ctzr0xPfhBbJn/nmzeuNt3Ma/HYKSnpJb4tlDpO5MSh0uGBKXDIKrwhgwZgkWLFmHXrl24ceMGtm3bhmXLluHhhx8GAKhUKkydOhULFy7Ejh07cO7cOYwfPx4BAQEYPny4ssETEREREVUgbIlORGXOJgR+i72NRIsp/8pUIZjT0lGneRM88OjDWP3M1Hzrx966g9e//hrPtmiBTX364M87dzB53z74u7mhb716iE5Nwbcz5mLchwvhE1QHn016AU26dEJwrxAAwPdvL8SwGVOh93Av5S2j0rI/PgLVnLXw1boqHQpRhfXJJ59g9uzZeP755xEdHY2AgAA888wzmDNnjlTnjTfegMFgwNNPP43ExER07doVe/fuLfBtq0RERERExCQ6ESngSGIUbhvZgrgyadmzG1r27Fbg+gc3/Yh63t74sGtXAEBzb28cvHcPH505g77NmyP21h3oPN1x35D+AIAmD3RE5JXrCO4VguM/74aTizPaDuhdKttCZcMqBPbG3sIjfo3g6sTTEaKi8PDwwPLly7F8+XKHdVQqFebPn4/58+eXXWBERERERJUMu3MhojIVnpaM0ymxSodBCrt+8gweatJYNq1fUBAOR0bCptejVv0gZKQbcft8GAyJSbh55jxqN2+CtKQk7PxwJR6b/5ZCkVNJMlgt2Bt7C1ZhUzoUIiIiIiIiIofY9IuIykyyxYy/4u4oHQaVAykxcajVzFc2zVevR7LZDIOzM1y9vDDuw0XYMO1NmI0mdBo5FC1CumDj63MQMmEMYm/fwaqnXoLVYsHAqc+h/aC+Cm0JFVekKQ2HEiLR3TtA6VCIiIiIiIiIcsUkOhGVCauw4bfY2zCxxSnlw6LVAADa9u+Ftv17SdOvHDmGuxcv49H5szC3+yBM+mQpPGv64L1hj6Nxp/vg4VNDqZCpmM6nxqOOzh0NXD2VDoWIiIiIiIjIDrtzIaIy8U9CJKLN6UqHQeWER80aiE5NkU2LSk+Hp0YDFy8vu/oZJjO+f3sRxiyeg5gbt2C1WtG4c0f4NqyPWvXr4sbpc2UVOpWSffF3kWIxKx0GERERERERkR0m0Ymo1F1NS8K51Hilw6BypEH7Nth35aps2u+3b+MBPz9k6LR29fd+8gVahHRBUHAL2Kw22CwWqcxqscBmtZZ6zFS6TDYr/oi7A5sQSodCREREREREJMMkOhGVqiSLGfvj7iodBpUyoyENt/+7iNv/XQQAxN2+i9v/XUT83XsAgJ+XLsf6V9+U6ncd+yjC4+Lwxj//4GJCAj47dw4/Xr2KV9u0gTlHEv3e5Ws4+cuvGPzaCwAA30b1oVKr8c/3W3H+z78RdS0cddu0KqMtpdJ0z5SG40nRSodBREREREREJMM+0Ymo1Agh8FfcHZjZD3qld+vsf1gx+knp+ZYF7wMAOo0aivEfLkJSdAwSIu5J5T5BdbDtqacwY/NmrDhzBnXc3fFVz57oFxSEm9mS6EIIfDtrHkbMfh1aV1cAgEanw7gPF+KH2YtgMZvx6Lw3Uc1PPkgpVVwnkmNQW+eG2jp3pUMhIiIiIiIiAsAkOhGVotMpsbhnSlM6DCoDTR7oiE9vOu6XfPyHi+ymhTRqiFOPPWY33ajTSP+rVCq8tmWDXZ3gXiEI7hVSxGipPBMA/oi7g8f8GkHnxNMUIiIiIiIiUh67cyGiUhFvNuJoIrtloMJL12jyr0SVmsFqQWjCvfwrEhEREREREZUBJtGJqMRZhcCfcXdgBQcIpMJL17ooHQKVA1fSkhCelqx0GERERERERERMohNRyTuRFI2YDKPSYVAFZdCyJTplOhAfAaPNqnQYREREREREVMUxiU5EJSralI6TyTFKh0EVWKqGLdEpU5rNgkPs1oWIiIiIiIgUxiQ6EZUYqxD4K/4ObEoHQhWagd25UDaXDIm4mZ6idBhERERERERUhTGJTkQl5kxKLOIzTEqHQRWYUKmQ4uKkdBhUzuyPvwszu3UhIiIiIiIihTCJTkQlIsVixvGkaKXDoIpOo4FNza8mkjNYLfgnMVLpMIiIiIiIiKiKYqaCiEpEaMI9WIRQOgyq4ISrq9IhUDkVlpqAaFO60mEQERERERFRFcQkOhEVW3haMm6wz2IqATa9TukQqJwSAEITIiD4Yx0RERERERGVMSbRiahYMmw2hCbcUzoMqiSsOibRybEoczouGhKVDoOIiIiIiIiqGCbRiahYjidFI9WaoXQYVElY9HqlQ6By7khiJEwcZJSIiIiIiIjKEJPoRFRkSRkmnEmJUzoMqkQy2BKd8pFus+IYBzEmIiIiIiKiMsQkOhEV2ZHEKNjA/omp5Jh1GqVDoArgfEoc4s1GpcMgIiIiIiKiKoJJdCIqkkhTGq6lJysdBlUyZp1W6RCoArABOMixGIiIiIiIiKiMMIlOREXyT2Kk0iFQJWRkEp0K6I7JgNvGVKXDICIiIiIioiqASXQiKrTracmINKUpHQZVQukadudCBXckMUrpEIiIiIiIiKgKYBKdiArFJgSOsBU6lRKjlkl0KrgYczqupSUpHQYRERERERFVckyiE1GhXEiNR6LFrHQYVEkZmESnQvo3MRo2wQGOiYiIiIiIqPQwiU5EBWYRNhxPilE6DKrEDBpnpUOgCibRYsIlQ6LSYRAREREREVElxiQ6ERXYhdQEpNksSodBlViqzkXpEKgCOpYUDauwKR0GERERERERVVJMohNRgViFDaeS2QqdSlcKW6JTEaRaM/BfaoLSYRAREREREVElxSQ6ERXIRUMiDFa2QqfSI5ydYXZyUjoMqqBOJ8fCyr7RiYiIiIiIqBQwiU5E+bIJgVPsC51Km6te6QioAku1ZuAK+0YnIiIiIiKiUsAkOhHl67IhEcnWDKXDoErOpmcSnYrnVEosBFujExERERERUQljEp2I8mQTAifYFzqVAauOSXQqnoQME26kpygdBhEREREREVUyTKITUZ6upyUjyWJWOgyqAix6ndIhUCVwkj/6ERERERERUQljEp2I8nQmJVbpEKiKsOi0SodAlUCUOR0RRoPSYRAREREREVElwiQ6ETkUaUpDlDld6TCoisjQsSU6lQy2RiciIiIiIqKSxCQ6ETl0NiVO6RCoCjGxJTqVkFvGVCRlmJQOg4iIiIiIiCoJJtGJKFcGSwaupyUpHQZVISadRukQqBL5LzVB6RCIiIiIiIiokmASnYhy9V9qPGxKB0FVilHLJDqVnIuGBFgEP8WIiIiIiIio+JhEJyI7ViFwga04qYyla9mdC5Uco82Ka7ybhoiIiIiIiEoAk+hEZOd6WjLSbBalw6AqJk3ronQIVMmcT4lXOgQiIiIiIiKqBJhEJyI7YQYmnqjspWmYRKeSFWVOR6w5XekwiIiIiIiIqIJjEp2IZFItGbhrNCgdBlVBqWyJTqWAA4wSERERERFRcTGJTkQylw2JEEoHQVVSisZZ6RCoErpsSESGjQOMEhERERERUdExiU5EMhcNiUqHQFWQUKlgcGESnUpehrAhPD1Z6TCIiIiIiIioAmPGgogkUaY0JFpMSodBVZFeD6hUSkdBldRlQyKauFVTOgyqIuLi4nD06FHcu3cP6enpqFGjBpo2bYq2bdtCxc85IiIiIqIKiUl0IpKwFTopxabXKx0CVWK3jalIs2bA1Yn97lPpSEpKwvr167F+/XqcPn0aQsg7RlOpVHB3d8fDDz+MKVOmoEuXLgpFSkRERERERcHuXIgIAGAVNlxNS1I6DKqimESn0iQAXDHw841Kx+LFi1G/fn2sWLECffr0wbZt2xAeHo6UlBSYzWZER0fj33//xdKlS5GQkIBevXqhd+/euHDhgtKhExERERFRAbElOhEBAG6mp8JksyodBlVRVr1O6RCokrualoQ2nj5Kh0GV0P79+7F161b06NEj13IfHx/4+PigQ4cOePbZZ5GQkICVK1di//79aNGiRdkGS0RERERERcIkOhEBAK6nceA9Uo5FxyQ6la4oczqSLWZ4OmuUDoUqmd9++61Q9atXr47Zs2eXUjRERERERFQa2J0LEcEqBG4aU5QOg6qwDL1W6RCoCrjKLl2IiIiIiIioCJhEJyJEGA3syoUUZdYxiU6lLzydd9xQ2YmLi8PYsWNRq1Yt1KxZE2PGjEFUVJTSYRERERERUREwiU5EuM7EEinMqGUSnUpflDkdaVaL0mFQFTF58mSkpaVh7dq1WLlyJS5evIjJkycrHRYRERERERUB+0QnquKEEGydSYozsSU6lZGb6Slo7l5d6TCoEvn5558xbNgwu+mhoaG4ffs29Ho9AMDb2xujRo0q6/CIiIiIiKgEsCU6URXHlplUHqRrOdgjlY0b6Rz/gUrWzJkz0a9fP1y6dEk2vX79+vj888+Rnp6O2NhYfPPNN2jYsKFCURIRERERUXEwiU5UxV1PYyt0Ul66xkXpEKiKuGNMhVXYlA6DKpFz586hd+/e6NKlC6ZPn46UlMwfalauXImPPvoI7u7u8PX1xb59+/DZZ58pHC0RERERERUFk+hEVdwtI1tlkvIMbIlOZSRD2HDXaFA6DKpEnJ2d8frrr+P8+fOIiYlB06ZNsW7dOnTq1AnXr1/H6dOncfr0aVy7dg2dO3dWOlwiIiIiIioCJtGJqrA0awbiM0xKh0EEg5Yt0anssEsXKg1+fn5Yv349tm7dis8//xydOnXC6dOnERwcjODgYGg0/LGQiIiIiKiiYhKdqAq7zdaYVE6kajjONZWdm0yiUwmzWq24ePEizpw5gzZt2uDff//F008/jaFDh2LSpEmIiYlROkQiIiIiIioGJtGJqrA7xlSlQyACAKQwiU5lKMWagWSLWekwqJI4fvw4GjdujBYtWqBdu3aoXbs2vv/+ezz11FO4ePEiqlWrhhYtWmDZsmWwWq1Kh0tEREREREXAJDpRFcYkOpUHQquFVc2vIypbEbwTh0rIlClT0LlzZ0RGRiIpKQnTpk3DpEmTYDAY4OXlhY8++gh///03fv31V7Rq1UrpcImIiIiIqAiYtSCqohIyTDBYLUqHQQSh1ysdAlVBd01MolPJCA8Px6RJk1CrVi14eHjg+eefh8lkQmRkpFSnefPm+PXXX7FkyRIFIyUiIiIioqLi/fNEVRRboVN5YWMSnRTAluhUUgYOHIgZM2YgOTkZer0eX375JZo0aYIGDRrY1R0+fHjZB0hERERERMXGJDpRFcUkOpUXVr1O6RCoCkqxZiDFYoaHs0bpUKiCW716NRYtWoSlS5fCZDKhY8eO+O2336BSqZQOjYiIiIiISgiT6ERVVKQpTekQiAAAFh2T6KSMu0YDmrkziU7F4+bmhsWLF2Px4sVKh0JERERERKWEfaITVUHJFjPSbValwyACwCQ6KSeC/aITERERERFRATCJTlQFRZvSlQ6BSGLWa5UOgaqoe7wjh0pAp06dsH37dthstgLVv337NqZPn45ly5aVcmRERERERFRS2J0LURUUZWbiiMoPk5bdaZAykixmmGxWaNVOSodCFdj48ePx/PPP4+mnn8awYcPQpUsXtG7dGjVr1oRWq0ViYiLCw8Nx4sQJ7NmzB0eOHMHQoUPx3HPPKR06EREREREVEFuiE1VBUWa2RKfyw8TuXEhBsfw8pGJ64YUXcO3aNSxduhRXr17FM888g44dO6JevXrw9/dH8+bNMWDAAHz66ado3749Tp48iS1btqBhw4Ylsv67d+/iiSeeQI0aNaDX6xEcHIzjx49L5UIIzJkzB/7+/tDr9ejduzeuXLlSIusmIiIiIqoq2BKdqIqxCcGkEZUr6WyJTgqKMRtRW+eudBhUwen1ekyaNAmTJk2C0WjE6dOnce/ePRiNRnh7e6Np06aoV69eia83ISEBXbp0Qc+ePbFnzx7UrFkTV65cQfXq1aU67733Hj7++GOsX78e9evXx+zZs9GvXz9cuHABOv6ISURERERUIEyiE1UxcRlGWIRQOgwiSbrGRekQqAqL4Y+KVMJ0Oh06d+5cJutaunQpAgMDsXbtWmla/fr1pf+FEFi+fDnefvttDBs2DACwYcMG+Pr6Yvv27Rg9enSZxElEREREVNGxOxeiKiaaCSMqZ9J1bIlOyokxG5UOgajIduzYgQ4dOuCRRx5BrVq10K5dO6xevVoqDw8PR2RkJHr37i1N8/LyQqdOnXD48GElQiYiIiIiqpDYEp2oiolnwojKmVQtW6KTcpIsJmTYbHBRs10BVTzXr1/H559/jmnTpuHNN9/EsWPH8PLLL0Oj0WDChAmIjIwEAPj6+srm8/X1lcpyYzKZYDKZpOfJyckAAJvNBpvNVgpb4pjNZoP6/49PlRBQ8W46quBUQkjvaSWOqaLisUiVDY9FovKhPByLBV0nk+hEVUx8hin/SkRlyKDhVxEpRwCIzUiHv9ZN6VCICs1ms6FDhw5YvHgxAKBdu3Y4f/48Vq1ahQkTJhR5uUuWLMG8efPspsfExMBoLNsf441GI+677z4AQKDZCieVuUzXT1TSrGar9J6Oi4uDwWBQOKKC4bFIlQ2PRaLyoTwciykpKQWqx8wFURWTYGESncqXZCbRSWFxZiOT6FQh+fv7o0WLFrJpzZs3x5YtWwAAfn5+AICoqCj4+/tLdaKiotC2bVuHy501axamTZsmPU9OTkZgYCBq1qwJT0/PEtyC/BkMBpw4cQIAUEvjBGd2AUYVnEVYpfd0jRo14OZWMb5/eCxSZcNjkah8KA/Hok6nK1A9Zi6IqhCTzYo0q0XpMIgkwtkJJmd+FZGyEi1swUMVU5cuXXDp0iXZtMuXL6Nu3boAMgcZ9fPzw59//iklzZOTk/Hvv//iueeec7hcrVYLrVZrN12tVku325YVtVot3WIrVCoIlapM109U0oRKJb2nlTimiorHIlU2PBaJyofycCwWdJ0V41OCiEoEu3KhckenVzoCIiTys5FK2N69e7FgwQI8/fTTuHXrFgDg77//RkRERImu59VXX8WRI0ewePFiXL16Fd9++y2+/PJLvPDCCwAAlUqFqVOnYuHChdixYwfOnTuH8ePHIyAgAMOHDy/RWIiIiIiIKjM2/yOqQhIyOKgolS82VybRSXlJbIlOJSQmJgbDhw/HkSNHEBgYiNu3b+PZZ59FUFAQ1qxZAzc3N3z66acltr6OHTti27ZtmDVrFubPn4/69etj+fLlGDt2rFTnjTfegMFgwNNPP43ExER07doVe/fuLfBtq0RERERExCQ6UZWSwNaWVM5Y9Uyik/JSLGbYhICat8NSMU2dOhUxMTE4f/48GjduDI3mf/2U9u7dGwsXLizxdQ4ePBiDBw92WK5SqTB//nzMnz+/xNdNRERERFRVMIlOVIUwiU7ljZUtIakcsAFItphRzcW+D2iiwti1axdWr16N5s2bw2q1ysoCAwNx584dhSIjIiIiIqLiYJ/oRFVIqjVD6RCIZCx6JtGpfODgolQSLBYL3Nzcci1LSEiQtUwnIiIiIqKKg0l0oiok1cIkOpUvZh1b/lL5kMQ7dagEdOrUCWvWrMm17Pvvv0eXLl3KOCIiIiIiIioJ7M6FqIow26wwC5vSYRDJmLVMolP5kMyW6FQCFi5ciJ49e6J79+4YNWoUVCoVtm/fjiVLlmDXrl04ePCg0iESEREREVERsCU6URXBVuhUHpnYEp3KiTSrRekQqBJ44IEHsG/fPqhUKrz22msQQmDRokW4d+8e/vzzT7Rv317pEImIiIiIqAjYEp2oikhhf+hUDhnZEp3KCYONSXQqGQ888AAOHDiA9PR0JCQkoFq1anB1dVU6LCIiIiIiKgYm0YmqCA4qSuVRutZF6RCIAABp/IykEqbX66HX65UOg4iIiIiISgCT6ERVBLtzofIoTatROgQiAOzOhUrGk08+6bBMrVbDy8sL7dq1w4gRI9g6nYiIiIioAmESnaiKMLCVJZVDBrZEp3LCIgTMNis0aielQ6EK7NSpU4iIiEBMTAy8vb1Rq1YtREdHIz4+HjVr1oSbmxtWrFiBt956C3/99RcaNmyodMhERERERFQAHFiUqIow2axKh0Bkx6Dhb7lUfhjYGp2K6f3334enpydCQ0MRGxuLCxcuIDY2FgcOHICnpyc+/fRThIWFQavV4o033lA6XCIiIiIiKiAm0YmqCCbRqTxK1bAlOpUf7Bedimv69OmYO3cuunTpIpverVs3zJkzB6+//joaN26MWbNmYd++fQpFSUREREREhcUkOlEVYWQSncoblRopbIlO5Ug6PyepmC5duoRq1arlWla9enVcu3YNANCwYUOkp6eXYWRERERERFQcTKITVRFmm03pEIhkLFoNoFIpHQaRJIOfk1RMzZo1wwcffIC0tDTZdIPBgPfffx8tWrQAAERERMDX11eJEImIiIiIqAjYBJCoimB3LlTeWPQ6pUMgkskQTKJT8XzyyScYMGAA6tSpg549e6JmzZqIiYnBX3/9BYvFgr179wIAzp49i1GjRikcLRERERERFRST6ERVgE0IJoeo3DHrtEqHQCRj5o+NVExdu3bFlStXsGzZMhw/fhwXLlyAv78/nn76abz66qvw8/MDACxevFjhSImIiIiIqDCYRCeqAtgKncojs5ZJdCpf+GMjlQQ/Pz+89957SodBREREREQliH2iE1UBbF1J5ZFJzyQ6lS/sE52IiIiIiIhyw5boRFWARQilQyCyk67VKB0CkQxbolNJ+Pvvv/Hll1/i8uXLMBqNduVnz55VICoiIiIiIioOtkQnqgJsYBKdyh8m0am8YUt0Kq5ff/0VDz30EGJjY3H8+HEEBgbCx8cHly5dgsFgQIcOHZQOkYiIiIiIioBJdKIqwMqW6FQOpWldlA6BSMbCluhUTO+88w6mTp2KXbt2AQAWLFiAv/76C5cvX4aLiwseeughhSMkIiIiIqKiYBKdqAqwMYlO5ZBBwyQ6EVUuYWFhGDBgANRqNVQqFQwGAwCgbt26mDt3LhYuXKhwhEREREREVBRMohNVAYLduVA5lMokOhFVMjqdDjabDSqVCv7+/rh27ZpU5uHhgdu3bysYHRERERERFRUHFiWqAphCp/IohUl0Iqpk2rRpg0uXLqFPnz7o1asXFi1aBB8fH7i4uODtt99GcHCw0iESEREREVERsCU6URXA3lyoPDK6OCkdAhFRiZo6dSpUKhUAYPHixfDw8MDQoUMxYMAAxMXF4dNPP1U4QiIiIiIiKgq2RCeqAtidCxERUekbOHCg9H/t2rVx4sQJXL16Fenp6WjWrBk0Go2C0RERERERUVGxJTpRFeCk4qFORERU2ubPn4+IiAjpuUqlQuPGjdG6dWvExcVh/vz5CkZHRERERERFxcwaURXg/P+3lhMREVHpmTdvHu7cuZNrWUREBObNm1fGERERERERUUlgEp2oCnBiEp2IKF8q8LOSikcIIfWJntO9e/dQrVq1sg2IiIiIiIhKBPtEJ6oCnNmdCxFRvlzU/Kykwvvuu+/w3XffAcjsvuW1116zS5YbjUYcP34cXbp0USBCIiIiIiIqLibRiaoAtkQnIsofu76iojCbzUhJSQGQ2RLdYDDAyclJVkej0WD8+PF44403lAiRiIiIiIiKiUl0oiqAA4sSEeXPhZ+VVAQTJkzAhAkTAAA9e/bE559/jmbNmikcFRERERERlSQm0YmqALauJCLKnzO7c6Fi2rdvn9IhEBERERFRKWASnagKYJ/oRET506ic8q9ElI9Lly5hy5YtuHPnDoxGo6xMpVLh66+/VigyIiIiIiIqKibRiaoAtUoFjUoNs7ApHQoRUbmlYUt0KqZvvvkGkyZNgk6nQ926daHRaGTlKt4ZRkRERERUITGJTlRF6JycYbaYlQ6DiKjc0qjZEp2KZ8GCBRg1ahTWrFkDV1dXpcMhIiIiIqISwiZXRFWEnskhIqI8afk5ScUUERGBKVOmMIFORERERFTJMIlOVEXo1LzxhIgoL25O/Jyk4unevTvOnz+vdBhERERERFTCeLVIVEXondjCkogoL65MolMxLV68GE888QR0Oh369OmDatWq2dXx9vYu+8CIiIiIiKhYeLVIVEXo2RKdiMghFfg5ScXXvn17AMBzzz3ncBBRq9ValiEREREREVEJ4NUiURWhYwtLIiKH9GpnqB0kPYkKas2aNQ6T50REREREVHExq0ZURXBgUSIix9iVC5WEiRMnKh0CERERERGVAg4sSlRFeDi7KB0CEVG5xSQ6laSEhASEhobi22+/RUJCAgDAaDTCZrMpHBkRERERERUFk+hEVYSns0bpEIiIyi03J/7QSMVns9nw5ptvIjAwECEhIRg3bhzCw8MBACNGjMCCBQsUjpCIiIiIiIqCSXSiKsLdyQVqsJ9WIqLcuLElOpWAOXPmYOXKlfjwww9x+fJlCCGksqFDh2Lnzp0KRkdEREREREXFK0aiKkKlUsHd2QXJFrPSoRARlTteLlqlQ6BKYN26/2PvvsOjqN42jt+7m2TTKykkhNAhSOgtCNJBQAUEFQTpYMFCURBQqooNRcWCiKD+AAUVFVF6EalSQi/SpPcSkpCEJPP+gezLmoSaZFO+n+tayJ45c+aZk0zKs2efmao33nhDTz75pFJTU+22lSxZUvv27XNQZAAAAADuBivRgQLEm7roAJAhX0peIQucPXtWkZGRGW5LTU3VlStXcjgiAAAAAFmBJDpQgFAXHQAy5stKdGSBMmXKaOHChRluW7ZsmSpUqJDDEQEAAADICpRzAQoQbwtJdAD4L1ezRVazxdFhIB/o37+/evfuLWdnZ7Vv316SdOTIEa1evVoffvihpk6d6tgAAQAAANwRkuhAAeLtTBIdAP7L14lV6Mga3bp107lz5zRy5Ei98cYbkqQ2bdrIw8NDr732mh599FEHRwgAAADgTpBEBwoQf8oVAEA6PrzAiCw0YMAA9enTR6tWrdKZM2fk7++v6Oho+fj4ODo0AAAAAHeIJDpQgPg6WWWRSakyHB0KAOQa3FQUWc3T01PNmjVzdBgAAAAAsgg3FgUKELPJJD9WowOAHT9nV0eHgHzio48+0ssvv5zhtpdfflkff/xxDkcEAAAAICuQRAcKmAAXkkUAcL1Avi8ii3zyyScqWbJkhtvKlCmjTz75JIcjAgAAAJAVSKIDBUwhVlwCgI2r2SIvyrkgi/zzzz8qXbp0httKlCihgwcP5mxAAAAAALIESXSggGElOgD8v0J8T0QW8vb21oEDBzLctn//frm7u+dwRAAAAACyAkl0oIAJYCU6ANgEurg5OgTkI82aNdOoUaN0+PBhu/YjR45ozJgxatGihYMiAwAAAHA3nBwdAICc5WZxkofFSfGpKY4OBQAcjiQ6stKbb76p2rVrq2zZsmrUqJFCQ0N17NgxLVmyRIGBgRo7dqyjQwQAAABwB1iJDhRAIS68nRwAJJLoyFqhoaGKiYlR//79dfbsWS1btkxnz57VwIEDtWnTJoWFhTk6RAAAAAB3gJXoQAEUYnXXvsuxjg4DABzKajLLh5uKIoskJiZq0KBBeuKJJ/T66687OhwAAAAAWYiV6EABFGJlJToABPG9EFnI1dVVX375pRISEhwdCgAAAIAsRhIdKIACXdzkZDI5OgwAcKhQq4ejQ0A+U6dOHa1Zs8bRYQAAAADIYpRzAQogs8mkIBd3HUuKd3QoAOAwoa4k0ZG1Ro8erU6dOslisahly5YKDg6W6T8vWvv7+zsoOgAAAAB3iiQ6UEAVtpJEB1BwOZlMCuKmoshiderUkSQNGjRIgwcPzrBPampqToYEAAAAIAuQRAcKKOqiAyjIQqzuslDWClnsyy+/TLfyHAAAAEDeRxIdKKBCrO4yS0pzdCAA4ADUQ0d26Natm6NDAAAAAJANuLEoUEBZzRYFsRodQAEVRhId2ej8+fNasWKFpk+frvPnz0uSEhMTlZbGS9cAAABAXkQSHSjAirp6OjoEAMhxTiaTgqzUQ0fWS0tL09ChQxUeHq769evriSee0IEDByRJDz/8sMaMGePgCAEAAADcCZLoQAFW1M3L0SEAQI4LtXrIYuJXIGS94cOHa8KECRo3bpz27NkjwzBs2x566CHNmTPHgdEBAAAAuFP8BQkUYIHOrnIzWxwdBgDkqGK8gIhsMnXqVL3xxht68sknVbx4cbttJUuW1L59+7L1+G+++aZMJpP69etna0tMTFTfvn0VEBAgT09PtWvXTidPnszWOAAAAID8hiQ6UICZTCaFU9IFQAETQRId2eTs2bOKjIzMcFtqaqquXLmSbcf+66+/NHHiRFWsWNGuvX///pozZ45mzZql5cuX69ixY3r44YezLQ4AAAAgPyKJDhRwlHQBUJAUcnaVl5OLo8NAPlWmTBktXLgww23Lli1ThQoVsuW4cXFx6tSpkyZNmiQ/Pz9b+8WLFzV58mS99957atSokapVq6YpU6Zo1apVWrNmTbbEAgAAAORHTo4OAIBjhbt6yiTJuGlPAMj7KOWC7NS/f3/17t1bzs7Oat++vSTpyJEjWr16tT788ENNnTo1W47bt29ftWrVSk2aNNFrr71ma9+wYYOuXLmiJk2a2NrKlSunokWLavXq1apdu3aG4yUlJSkpKcn2PDY2VtLVG6empaVlyzlkJi0tTWbz1XU/JsOQyeA3FuRtJsOwfU074pq6U1yLyG+4FoHcITdci7d6TJLoQAHnZnFSiNVdx5MSHB0KAGQ7SrkgO3Xr1k3nzp3TyJEj9cYbb0iS2rRpIw8PD7322mt69NFHs/yY3377rTZu3Ki//vor3bYTJ07IxcVFvr6+du3BwcE6ceJEpmOOHTtWo0aNStd++vRpJSYm3nXMtyMxMVHVqlWTJIUnp8piSs7R4wNZLTU51fY1ffbsWcXHxzs4olvDtYj8hmsRyB1yw7V46dKlW+pHEh2ASrr7kEQHkO+5m50U5OLm6DCQzw0YMEB9+vTRypUrdfbsWfn7+ys6Olo+Pj5ZfqzDhw/rhRde0MKFC+Xq6ppl4w4ZMkQDBgywPY+NjVV4eLgCAwPl7e2dZce5FfHx8dqwYYMkKcjFIidXyjEhb0sxUm1f0wEBAfLw8HBwRLeGaxH5DdcikDvkhmvxVn+PJokOQCXdvLXy/HFKugDI1yLcvGQymRwdBvKhHTt26LPPPtOBAwcUFham9u3bq3nz5tl+3A0bNujUqVOqWrWqrS01NVV//PGHJkyYoPnz5ys5OVkXLlywW41+8uRJhYSEZDqu1WqV1WpN1242m21vt80pZrPZ9hZbw2SSwTWMPM4wmWxf0464pu4U1yLyG65FIHfIDdfirR6TJDoAeTg5U9IFQL5X2iPrVwIDf/75p5o0aaIrV64oMDBQ8+bN06RJk/Txxx/rqaeeytZjN27cWFu3brVr6969u8qVK6fBgwcrPDxczs7OWrx4sdq1aydJ2r17tw4dOqTo6OhsjQ0AAADIT0iiA5AklaKkC4B8zMPipDBr3nibLvKWESNGqFy5cpozZ47Cw8MVGxur7t2765VXXsn2JLqXl5cqVKhg1+bh4aGAgABbe8+ePTVgwAD5+/vL29tbzz33nKKjozO9qSgAAACA9EiiA5AklXT31p+UdAGQT5Vy96GUC7LF1q1b9dlnnyk8PFyS5O3trXHjxqlEiRI6fPiwrd1R3n//fZnNZrVr105JSUlq3ry5PvnkE4fGBAAAAOQ1JNEBSJLcLc4qbHXXMVajA8iHSnv4OjoE5FNnzpxRkSJF7NquJc7PnDmT40n0ZcuW2T13dXXVxx9/rI8//jhH4wAAAADyk7xx5wQAOaKUO/WCAeQ/vk4uCnJxc3QYyMd4lwMAAACQv7ESHYBNKXcfrTx/QqkUdQGQj7AKHdmtYcOGMpvTr02pV6+eXbvJZNLFixdzMjQAAAAAWYAkOgAbV4uTirl7aV9CrKNDAYAsU4Z32SAbjRgxwtEhAAAAAMhmJNEB2In08COJDiDfCLG6y8fZ6ugwkI+RRAcAAADyP2qiA7AT7uopT4uzo8MAgCxRwdPf0SEAAAAAAPI4kugA7JhMJkV6+jk6DAC4a65mi0q6ezs6DAAAAABAHkcSHUA6kR5+Mjk6CAC4S5EefrKY+FUHAAAAAHB3+MsSQDqeTs6KcPNydBgAcFfKe1HKBQAAAABw90iiA8gQdYQB5GXhrp7ycXJxdBgAAAAAgHyAJDqADBV185K/s9XRYQDAHeGFQAAAAABAViGJDiBTlbwKOToEALhtnhZKUgEAAAAAsg5JdACZKuPhIzezk6PDAIDbUtErQGYTt0cGAAAAAGQNkugAMmUxmRXFjfkA5CEuJrPKe/o5OgwAAAAAQD5CEh3ADd3j6S8nVnQCyCPu8fSXi9ni6DAAAAAAAPkISXQAN+RmcVJZD1Z1Asj9LDKpoleAo8MAAAAAAOQzJNEB3FQlrwCxFh1AblfW01ceTs6ODgMAAAAAkM+QRAdwU77OVpV293F0GACQKZOkqt6Bjg4DAAAAAJAPkUQHcEtq+ASxGh1ArlXK3UfeTi6ODgMAAAAAkA+RRAdwS3ycrSrr4evoMAAgHbOuvtAHAAAAAEB2IIkO4JZV8wnimwaAXKesh598na2ODgMAAAAAkE+RDwNwy3ycXFTWw8/RYQCAjcVkYhU6AAAAACBbkUQHcFuq+wTKTHV0ALlEBU9/eTo5OzoMAAAAAEA+RhIdwG3xcnJRpCer0QE4novJrKregY4OAwAAAACQz5FEB3DbavgEycXEtw8AjlXJu5DcLE6ODgMAAAAAkM+RBQNw29wtTqrqw+pPAI7jZraosleAo8MAAAAAABQAJNEB3JFKXgHypg4xAAep4RMkZ7PF0WEAAAAAAAoAkugA7ojFZFa0b4ijwwBQABVydtU9nv6ODgMAAAAAUECQRAdwx0q6+yjU6u7oMAAUMPX8Q2UymRwdBgAAAACggCCJDuCu3OtXWKSyAOSUMu6+KsyLdwAAAACAHEQSHcBdCXRxUzkPP0eHAaAAcDaZVccv2NFhAAAAAAAKGJLoAO5atG+w3LjBH4BsVsMnSO4WbmgMAAAAAMhZJNEB3DVXi5Pq+hV2dBgA8jE/J6uivAIcHQYAAAAAoAAiiQ4gS5T28FVRV09HhwEgn6rvHyoLNxMFAAAAADgASXQAWaa+f6icTHxbAZC1ojz9Ferq4egwAAAAAAAFFNkuAFnGy8lFtXyCHB0GgHzE28lZtX1DHB0GAAAAAKAAI4kOIEtFeQUo0MXN0WEAyCca+ofJ2cyvKwAAAAAAx+GvUgBZymwyqaF/mMyidjGAu3OPp7/CuNcCAAAAAMDBSKIDyHKFXFxVy5eyLvlBYly8vh/1ll6p00z9ylTXu20765/N22zbY0+f0dcDh2lojUbqV7aGJnR5SqcO/HPTcTfOna/RjR7UC2Wq6fVmbbVtyR922xdNnKrBVetrcNX6WvT5V3bbDmzaojdbParUlJSsOUnkSp4WZ0X7Bjs6DAAAAAAASKIDyB6VvQopzMqNAPO6aYNHaOeK1er6/hsauuBHRd5XRx926q0LJ07KMAx93vsFnTl0RE9+8aGG/DZT/mGF9WGn3kpKSMh0zP3rYzTlucGKfvRhDZk7SxWbNdLnfV7Qsd1/S5KO7tytX9/7WD0+elvdP3xLv777kY7u2iNJSk1J0bdDx6jjG8NlcXLKkTmAYzT0D5OL2eLoMAAAAAAAIIkOIHuYTCY1DigiK0mwPCs5MVExvy9S2yEDVLpWdQUVK6pW/Z9RYES4VnzznU4d+EcHNm1Rh9dfVUSlCgouWVwdXn9VVxKTtP7n3zMdd+mU/6l8/XvV9KnuCildQg+++JzCK5TX8q9mSJJO7DugsMgyKntvLZWrW1uhkWV0ct8BSVdXqJeqVU0RlSrkyBzAMSp5BSjcjTIuAAAAAIDcgSQ6gGzj6eSs+n6hjg4DdygtJVVpqalysrrYtTu7umrf+k1KSU6++txqtW0zm81ycnHWvvUbMx33wMbNKlu3tl1b5H11dGDjZklSWNkyOrX/oM4dPa6zR47p1P6DCi1TWqf/Oaw1s37Sgy8+l1WniFwo0MVVtSnjAgAAAADIRUiiA8hWpTx8VNbD19Fh4A64enqoeNVKmvfRRF04eUppqala9+McHdi4WRdPnVFIyeLyCyusn98ar4SLF5WSfEULPp2sC8dPKvbUmUzHjT19Rt6FAuzavAsFKPb01X1CSpfQQ4Ne0Eed+2jCE0+q9eB+CildQjOGjFKbIf21Y/lKvda0rca2eER/r12frXOAnOVsMqtZQLgsJn49AQAAAADkHhSUBZDt6vkV1vHEeMWmXnF0KLhNXceP1f9eelXDajaW2WJReIVIVX+ohQ5t3SGLs7P6THxf/xs0Qi9VrCuzxaKydWurfIO6kmHc1XHrdX5U9To/anu+5vufbUn90Y0e0qBfZujC8ZOa8uwgjfpznpz/s1oeeVN9/1D5OFtv3hEAAAAAgBxEEh1AtnMxW9S0ULh+OnlAqbq75CpyVmBEuPrPnKqkhAQlXoqXT3CgJvd9UYWKFpEkFY26R0N//16XYy8p5coVeQX46+3WjysiqnymY3oHFlLsmbN2bbFnzso7sFCG/ePOnddv4z9V/1lTdTBmq4KKR9geqSkpOnXgoMLKlcm6k4ZDlPXwVRnetQIAAAAAyIV4vzSAHBFsdVdd/8KODgN3yOruLp/gQCVcvKidf6xSxWYN7ba7eXvJK8Bfpw78o0Nbtqtis0aZjlW8aiXtXrnWrm3XitUqXrVShv2/H/22GvV8Qn6FQ5SWmqbUKym2bakpKUpLTbuLM0Nu4Ovkovu4fwIAAAAAIJdiJTqAHHOPp79OJiVoV/wFR4eCW7Rj+UoZhqHgEsV0+p9Dmv3GewouWVzRj7SRJG2cO1+e/v7yDwvR0V1/6/tRb6lSs0aKvK+ObYyv+g+Vb0iQWg/uJ0lq2L2z3n+suxZ9/pUqNKqnDXPm6dDW7Xr8zRHpjr9zxSqdOvCPurz3uiQpotI9OrnvgLYvXaHzx0/IbLEouGSx7J4GZCMnk1nNChWVs5nX9QEAAAAAuRNJdAA56j7/UJ1NTtTpK4mODgW34PKlS/rlrQ904cRJufv4qHKLJnropedlcXaWJF08dUY/jHlHl86clXdQoGo9/KBaPP+U3Rjnjx2XyWyyPS9RvbK6f/im5rw7QXPe+UCBxSLU5/MPFFq2tN1+yYmJmjl8rHpMeEfmfxOsfoVD9MioIfrmpVfl5OKiLuNel4urazbPArJTo4AwFXLhcwgAAAAAyL1MhnGXd38DgNsUm5KsWSf2KSkt1dGhAHCgqt6Bqu0b7OgwANxEbGysfHx8dPHiRXl7e+fosePj4+Xp6SlJavnnQjm5ueXo8YGslnL5sn6r21SSFBcXJw8PDwdHdGu4FpHfcC0CuUNuuBZv9Xdd3jsNIMd5O7moaUARmW7eFUA+FeHqpVo+QY4OAwAAAACAmyKJDsAhirp5qZYPK1CBgsjXyUVNCxWRycRLaQAAAACA3I8kOgCHqeoTqEgPP0eHASAHuZjMahEYIRezxdGhAAAAAABwS0iiA3Co+v6hKuKaN+rPAbg7ZklNC4XLz9nq6FAAAAAAALhlJNEBOJTZZNL9hYrKn6QakO/d5x+qCDcvR4cBAAAAAMBtIYkOwOFczBa1CoyQu8XJ0aEAyCY1fIJU3tPf0WEAAAAAAHDbSKIDyBW8nFzUKjBCTia+LQH5TXlPP9XwCXJ0GAAAAAAA3BGyVQByjUAXNzUrFM43JiAfKebmpfv8Qh0dBgAAAAAAd4xcFYBcpZiblxoFFJHJ0YEAuGvBLm5qFhAus4krGgAAAACQd5FEB5DrlPHwVT2/wo4OA8Bd8He2Xi3RZOZXDQAAAABA3sZftgBypQpeAYr2DXZ0GADugJ+TVQ8FFZcrNwsGAAAAAOQDJNEB5FpVvANV3TvQ0WEAuA2+Ti5qHVxM7iTQAQAAAAD5BEl0ALlaTd9gVfEu5OgwANwCHycXtQ4qLneLs6NDAQAAAAAgy5BEB5DrRfuGqLIXiXQgN/N2clbroOLycCKBDgAAAADIX0iiA8gT6viFqIZPkKPDAJABL8vVBLonCXQAAAAAQD5EEh1AnlHDJ0h1fEMcHQaA6/g4uahNcHF5Obk4OhQAAAAAALIFd/0CkKdU9i4kZ5NZy88fc3QoQIEX4OyqB4O4iSgAAAAAIH/jr14Aec49Xv5yMpu05OxRGY4OBiiggl3c9EBQMVnNFkeHAgAAAABAtiKJDiBPKuvhJyeTWQvPHFEaqXQgRxV19VTzQkXlbKYqHAAAAAAg/+OvXwB5Vkl3Hz3ESlggR5Vx91XLwAgS6AAAAACAAoO/gAHkaaGuHmoXXELe3NQQyHaVvQqpcUCYzCaTo0MB8K+xY8eqRo0a8vLyUlBQkNq0aaPdu3fb9UlMTFTfvn0VEBAgT09PtWvXTidPnnRQxAAAAEDeQxIdQJ7n62xVu+ASCnZxc3QoQL5klkkN/cNUxy9EJhLoQK6yfPly9e3bV2vWrNHChQt15coVNWvWTPHx8bY+/fv315w5czRr1iwtX75cx44d08MPP+zAqAEAAIC8hZroAPIFN4uTWgcX1+KzR7QvIdbR4QD5hqvZovsLFVWoq4ejQwGQgXnz5tk9nzp1qoKCgrRhwwbdd999unjxoiZPnqzp06erUaNGkqQpU6YoMjJSa9asUe3atR0RNgAAAJCnkEQHkG84mcxqFhCuNZaT2nTpjKPDAfI8PyerWgZFyIdySUCecfHiRUmSv7+/JGnDhg26cuWKmjRpYutTrlw5FS1aVKtXr84wiZ6UlKSkpCTb89jYqy9Op6WlKS0tLTvDTyctLU3mf+/BYDIMmQxuJo68zWQYtq9pR1xTd4prEfkN1yKQO+SGa/FWj0kSHUC+YjKZFO0XIj9nq/44f0wp/FIB3JGirp5qWiicG/cCeUhaWpr69eune++9VxUqVJAknThxQi4uLvL19bXrGxwcrBMnTmQ4ztixYzVq1Kh07adPn1ZiYmKWx30jiYmJqlatmiQpPDlVFlNyjh4fyGqpyam2r+mzZ8/alV7KzbgWkd9wLQK5Q264Fi9dunRL/UiiA8iXynn6qZCLq+adOaTYlCuODgfIUyp6BaiObwg3EAXymL59+2rbtm36888/72qcIUOGaMCAAbbnsbGxCg8PV2BgoLy9ve82zNsSHx+vDRs2SJKCXCxycuWdMcjbUoxU29d0QECAPDzyRrk0rkXkN1yLQO6QG65FV1fXW+pHEh1AvlXIxU2PhJTSojNH9E/irb2yCBRkziazGviHqbSHj6NDAXCbnn32Wf3666/6448/VKRIEVt7SEiIkpOTdeHCBbvV6CdPnlRISEiGY1mtVlmt1nTtZrPZ9nbbnGI2m21vsTVMJhm8uIc8zjCZbF/Tjrim7hTXIvIbrkUgd8gN1+KtHjNvfJcAgDtkNVvUMrCoavgEiV8vgMwFOLvqkZCSJNCBPMYwDD377LOaPXu2lixZouLFi9ttr1atmpydnbV48WJb2+7du3Xo0CFFR0fndLgAAABAnsRKdAD5nslkUg2fIAW5uGnR2SNKSkt1dEhArhLp4ad6/oXlZOK1dSCv6du3r6ZPn66ff/5ZXl5etjrnPj4+cnNzk4+Pj3r27KkBAwbI399f3t7eeu655xQdHZ3hTUUBAAAApEcSHUCBEeHmpUdDSmrx2SM6lpTg6HAAh3MymVXfv7DKevg5OhQAd+jTTz+VJDVo0MCufcqUKerWrZsk6f3335fZbFa7du2UlJSk5s2b65NPPsnhSAEAAIC8iyQ6gALFy8lFrYOKa1PsGa27eEppMhwdEuAQ/s5WNSsULn/nW7uJCoDcyTBu/nPM1dVVH3/8sT7++OMciAgAAADIf0iiAyhwTCaTqvoEqoibpxadOawLKcmODgnIMSZJlb0LqaZPkCyUbwEAAAAA4Kb46xlAgRXk4qZHQkrpHk9/R4cC5AgfJxe1CS6haN8QEugAAAAAANwiVqIDKNCczWbV9w9VhKunlp07poS0FEeHBGSLCp7+ivYNkbOZ5DkAAAAAALeDJDoASCrm7q2Orh5aff6EdsSfd3Q4QJbxsDipkX8Rhbt5OjoUAAAAAADyJJLoAPAvq9miBgFhKu3hq+XnjlIrHXmaSdI9nv6q5Rssq9ni6HAAAAAAAMizSKIDwH+EuXroscKltP7iaW2KPaM0GY4OCbgtgS6uqu8XpiCrm6NDAQAAAAAgzyOJDgAZsJjMquUbrFLuPlp27qhOJl92dEjATbn8+3VbwdNfJpPJ0eEAAAAAAJAvkEQHgBsIcHHVw8EltDv+gtZcPKmEVG48ityptLuP7vULkbvF2dGhAAAAAACQr5BEB4CbMJlMKufpp5Lu3toYe0Yxl84o1aDEC3KHQs6uquMXoiKu3DgUAAAAAIDsQBIdAG6Rs9miWr7BKu/pp1UXTmhfQqyjQ0IB5mlxVk2fIJX18KV0CwAAAAAA2YgkOgDcJi8nFzUvVFTHk+L15/kTOk29dOQgF5NZVX0CVdErQE4ms6PDAQAAAAAg3yOJDgB3qLDVQ+2DS2j/5Vj9dfGUzl1JcnRIyMfMMqmCl7+qewfK1cKPbwAAAAAAcgp/hQPAXTCZTCrp7qMSbt7alxCrv2JP6TzJdGQhs0wq6+Grqj6B8nFycXQ4AAAAAAAUOCTRASALmEwmlfLwUUl3b/2dcFHrL57ShZRkR4eFPMwikyI9/VTFu5C8SJ4DAAAAAOAwJNEBIAuZTCaV8fBVKXcf/Z1wQRsvntH5FFam49Y5mUwq7+mvKl6F5OHk7OhwAAAAAAAo8EiiA0A2MJtMKuvhpzLuvvrn8iVtunRGx5MSHB0WcjEXk1n3ePmrklchuVPzHAAAAACAXIO/0gEgG5lMJhVz91Yxd2+dTErQ5ktntT/hotIcHRhyDT8nq6K8/FXWw0/OZrOjwwEAAAAAAP9BEh0Ackiw1V3NrO66lBKsbZfOaUf8eSWlpTo6LDiASVJRVy9V9ApQEVcPmUwmR4cEAAAAAAAyQRIdAHKYl5OLov1CVMM3SPsTYrUj7ryOJcU7OizkABeTWeU8/RTl6S8fZ6ujwwEAAAAAALeAJDoAOIiTyawyHr4q4+Gri1eStCP+vHbHX1BCaoqjQ0MWC7N6KNLTTyXcvOVEyRYAAAAAAPIUkugAkAv4OFsV7RuiWj7B+ufyJe2MP69Dl+OUJsPRoeEO+Ti5qOy/L5J4O7k4OhwAAAAAAHCHSKIDQC5iNplU3N1bxd29lZiaogOXL2lvwkUdTYzjZqR5gLvZSSXcvVXWw1fBVndHhwMAAAAAALIASXQAyKVcLU6K9PRTpKefElNTtP9yrPYmXNSxxHgS6rmIt5Ozirt5q4S7t0Jc3LlJKAAAAAAA+QxJdADIA1wtTirv6a/ynv66nJqiA5djdehynI4kxinZIKWe0wKcXVXczUsl3L1VyMXN0eEAAAAAAIBsRBIdAPIYt+sS6mmGoRNJCTqUeEmHLsfpzJVER4eXL7maLQqzeqiIq6eKuHnKhxrnAAAAAAAUGCTRASAPM5tMCnX1UKirh2r7SgmpV/5doR6vE8nxik254ugQ8yQnk0mFrR4q4no1cV7I2ZUyLQAAAAAAFFAk0QEgH3G3OKucp5/KefpJuppUP56UoBNJCTqelKAzyYlKk+HgKHMfT4uzgl3cFGR1U7CLu4KtbrKYzI4OCwAAAAAA5AIk0QEgH3O3OKuku49KuvtIklLS0nQy+bJOJ1/W2SuJOpucqPNXkpRagBLrVpNZhVzcFGx1U9C/CXMPi7OjwwIAAAAAALkUSXQAKECczGaFuXoozNXD1pZmGDp/JelqUv3fxPrFlGRdSrmSp1etu5kt8nO2ys/ZVX7OVvk7W+XnbCVhDgAAAAAAbgtJdAAo4MwmkwJcXBXg4mrXbhiG4lKvKDYlWbEp1/6/mlxPSL2iy2mpumKkOShqyd3iJE+L89WHk/3/Pk4ucrPwIw4AAAAAANw9MgwAgAyZTCZ5ObnIy8lFYZn0STHSdDk1RYlpqXb/JxtpSklLU4qRpitGmlINQ6mGoTRd/V+SzDLJbLr6v8lkkllXE/pmmeRkNstqtvz7MMtqstieu5gtcrM4ycKNPgEAAAAAQA4giQ4AuGNOJvPVRLujAwEAAAAAAMgmZkcHAAAAAAAAAABAbkUSHQAAAAAAAACATJBEBwAAAAAAAAAgEyTRAQAAAAAAAADIBEl0AAAAAAAAAAAyQRIdAAAAAAAAAIBMkEQHAAAAAAAAACATTo4OAAAAAEDel5qaqitXrmTpmElJSYqIiJAkFTKZZTFMWTo+7owhKU6Gkvl0AACAAoIkOgAAAIA7ZhiGTpw4oQsXLmT52Glpafrss88kSW7ufpKJrG3uYCglzdCmtGStUKrEpwUAAORzJNEBAFlm5MiR+umnnxQTE+PoUAAAOeRaAj0oKEju7u4yZWGiOzU1VZcvX5YkeYaHZ+nYuAuGlJqUKOuZM9KVy1cT6QAAAPkYSXQAKGCSk5Pl4uKSrv3KlStydnZ2QEQAgLwqNTXVlkAPCAjIlvGvsVhdZDJxS6fcwuJqlb+kKidPam3aZUq7AACAfI3fQgEgD0hLS9Pbb7+tUqVKyWq1qmjRonr99dclSVu3blWjRo3k5uamgIAA9enTR3FxcbZ9u3XrpjZt2uj1119XaGioypYtq4MHD8pkMum7775T/fr15erqqmnTpkmSvvjiC0VGRsrV1VXlypXTJ598YhfLkSNH1LFjR/n7+8vDw0PVq1fX2rVrNXXqVI0aNUqbN2+WyWSSyWTS1KlTc2yOAAA571oNdHd3dwdHAkewWF3lZDbJk3ouAAAgn2MlOgDkAUOGDNGkSZP0/vvvq27dujp+/Lh27dql+Ph4NW/eXNHR0frrr7906tQp9erVS88++6xdAnvx4sXy9vbWwoUL7cZ9+eWXNW7cOFWpUsWWSB8+fLgmTJigKlWqaNOmTerdu7c8PDzUtWtXxcXFqX79+goLC9Mvv/yikJAQbdy4UWlpaXrssce0bds2zZs3T4sWLZIk+fj45OQ0AQAchDIrBZTp6j989gEAQH5HEh0AcrlLly7pgw8+0IQJE9S1a1dJUsmSJVW3bl1NmjRJiYmJ+vrrr+Xh4SFJmjBhgh588EG99dZbCg4OliR5eHjoiy++sJVxOXjwoCSpX79+evjhh23HGjFihMaNG2drK168uHbs2KGJEyeqa9eumj59uk6fPq2//vpL/v7+kqRSpUrZ9vf09JSTk5NCQkKyd1IAAAAAAAByCEl0AMjldu7cqaSkJDVu3DjDbZUqVbIl0CXp3nvvVVpamnbv3m1LokdFRWVYB7169eq2j+Pj47Vv3z717NlTvXv3trWnpKTYVpTHxMSoSpUqtgQ6AAAAAABAfkdNdADI5dzc3O56jOuT7Jm1X6ujPmnSJMXExNge27Zt05o1a7IsFgAAHC3u0iW9Nmiw6keWV4VCgXq0cWNt2bDBro9hGBo/5jXVKVlKFQoFqusDD+rg3r227UlJSXqxV29VLhyqppUra+XSpXb7Txo/XqMHvnjDOBqUv0elPb0yfQx68smsO+nb1KD8PZry8ccOOz4AAEBuQhIdAHK50qVLy83NTYsXL063LTIyUps3b1Z8fLytbeXKlTKbzSpbtuxtHSc4OFihoaHav3+/SpUqZfcoXry4JKlixYqKiYnRuXPnMhzDxcVFqampt3VcAABy2rC+z2rlkiV6Z9Lnmrt2jeo2aqyuDz6kE8eO2fp8/v77+vqzzzT6g/H6ftlSuXm4q3ubtkpKTJQkffflFG3btEmzFi/WY927a0D3HjIMQ5J0+OBBzZw6Vf1HDL9hHD8sX6ZV+/Zq1b69mjDtf5KkBZs22tpeffvt2zqv5OTk2+oPAACAW0MSHQByOVdXVw0ePFiDBg3S119/rX379mnNmjWaPHmyOnXqJFdXV3Xt2lXbtm3T0qVL9dxzz+mJJ56wlXK5HaNGjdLYsWP14Ycfas+ePdq6daumTJmi9957T5LUsWNHhYSEqE2bNlq5cqX279+vH374QatXr5YkFStWTAcOHFBMTIzOnDmjpKSkLJ0LAADuVuLly5r/888a9NoY1axbVxElS+r5YUMVUaKEpk/6QtLVVehfffyJnhn0kpo88IDKVaigdz7/XKeOH9fCOb9Kkvbt3q3GrVqqdPlIde7TR+fOnNG5M2ckSSP69ddLo0fLy9v7hrEEBAYqMDhYgcHB8vXzt2tzcnLSqy/0U93SZRQVGKRWNWtpzsxZdvt3ur+FRg0YqNcGDVbNohHq0bqNJGnx3LlqUqmy7gkopM4tWurHadNU2tNLsRcu2PZdv2qVOjZtpgqFAlWvbDmNfvElJfz7onyn+1vo6KFDemPwy7ZV8QAAAAUZSXQAyANeffVVDRw4UMOHD1dkZKQee+wxnTp1Su7u7po/f77OnTunGjVqqH379mrcuLEmTJhwR8fp1auXvvjiC02ZMkVRUVGqX7++pk6daluJ7uLiogULFigoKEgtW7ZUVFSU3nzzTVksFklSu3btdP/996thw4YKDAzUjBkzsmwOAADICikpKUpNTZXV6mrX7urmqg3/vih8+OBBnT55UnUaNrRt9/LxUaXq1bVp3TpJUrmoKG1YvVqJly9rxaJFCgoJkX+hQvr5u+9kdbWq2UMP3VWcSUlJqlClsj7/4XvNXbdWj3Xvrpd699bm9evt+s2ePl3OLs76dtFCjf5gvA4fPKjnOj+hJg+00pzVq9ShRw+9N2q03T7/7N+vnm0fVrM2rfXrmtX64Kup2rB6tUYNHChJ+nj6NIWEhemFV16xrYoHAAAoyLixKADkAWazWcOGDdOwYcPSbYuKitKSJUsy3Xfq1Knp2ooVK2Z7y/l/Pf7443r88cczHS8iIkLff/99htusVmum2wAABce5y+d0/vJ5uzZPF08FewYrOTVZhy8eTrdPSf+SkqSjsUeVmHK1ZEpqaqqOxB+Rn9VPPpIuJV3Uuctn7fZzdXJTsGfhW47N08tLVWrV1MdvvaWS5cqqUFCQfp01S5vWrlNEyRKSpDMnT0qSCgUF2e1bKCjItq19lye0e9s2taheQ34BAfrg66908fx5ffDa65r2+296b9Rozf3hBxUtXlxjP/1EIaGhtxyjJIWEhqrXCy/Ynnd5+imtWLxIv//4oypdd2PwiJIlNfi112zP3xk+XMVLl9bLr78uSSpRpoz27NihT995x9Zn4rhxevDRR9W9b19JUrFSpfTqO2+r0/0tNHr8ePn6+8tiscjDy1OBd/DONgAAgPyGJDoAAACALDVv7zzN2Gb/bqQGEQ00sM5AnU04q37z+6XbZ07HOZKk99e8r91nd0u6Wlbl4sWL6lS8k0JVReuPrNaMzZPt9isfVEn96r5yW/G9M2mShjz9jOqWLiOLxaJ7KlfWA488om2bNt3yGM7Ozhr5/nt2bYOfekpdnnpKOzZv1qJff9Wc1as06f3xGvPiS/p4+rTbijE1NVWfvvOufv/xR508flxXkpOVnJQkNzd3u34VqlS2e35gz9+KqlbVrq1S9Wp2z3dt3aZd27ZpzsyZtjbDMJSWlqbDBw+qVLlytxUrAABAfkcSHQAAAECWur/U/aoVVsuuzdPFU5IU4B6g8c3HZ7pv/9r97Vai79ixQ35WP0lS9SLRKhFQxq6/q5PbbccXUaKEps+fp4T4eMVduqSgkBC90KWrwosXkyQV+nf19ZlTpxQUEmLb78ypU4qsWDHDMdcs/0N7d+7SGx9/rLeGDVP95s3k7uGhlg8/rP99PvG2Y/xi/Hh9/cknGvb2Wypzzz1yd3fXa4MH68oV+5uHurl73PbY8XFx6tCjh7o+/VS6bYXDw297PAAAgPyOJDoAAACALOXv5i9/N/8Mt7lYXGylWzIS5h1m+zg1NVWxHrG2515WH3lZfbIsTncPD7l7eOji+fNasXixBo25Wjs8vFgxBQYHa/WyZSr/b9L8UmysNq9fr8d79Uo3TlJiokYOGKBxX06WxWJRamqaDCNFknQl5YpSU9NuO7YNa9ao8QOt1LpDB0lSWlqaDu7de9NV4sXLlNby+Qvs2rZs2Gj3/J7KlbVv1y5FlMz88+Ds4qy01NTbjhsAACA/4saiAAAAAAqUFYsW6Y+FC3X44EH9uWSJOrdspRJlSqvdE09Ikkwmk7r2fUafvP2OFs+dq93btmtQnz4KKlxYTR98IN14H7/5lho0b6Z7KlWSJFWrXVsLfvlFu7Zt0/8mTlTV2rXS7XMzxUqW1MolS7VxzRrt3bVLrz7/vM6cOn3T/Tr06KH9e/bo7Vdf1YG//9ZvP/yoH6dNs52XJPUZ0F8b167VqAEDtWPLFh3cu1eLfv1VowYMtI0TVjRCf61cqRPHjuncmTO3HT8AAEB+wkp0AAAAAAXKpYuxenfkSJ04elS+fn5q3rq1BowYLmdnZ1ufPv3763J8gl557nnFXryo6tHR+nL2j7K6utqNtWf7Dv02e7Z+WbXS1nZ/2zZau2KFOjZrrhKlS+u9L+3ruN+KZwYN0uGDB9WjTVu5urnpse7d1fSBVroUG3vD/cKLFdNH//tGY4cO01effKoqNWvq6Zde0oh+/eRitUqSylWooGnzftd7o0br8WbNZRiGihYvrpbtHraN88IrwzT8+RfUOKqikpOS9Hfcpds+BwAAgPzCZBiG4eggAAAAAOROsbGx8vHx0cWLF+Xt7W23LTExUQcOHFDx4sXl+p/kclZITU3Vpn9v9ulTroxMJt5Ieyc+efsdzZg8WSt278rScVOTknTi8GF9lZKgsyb+rLwVKZcv67e6TSVJcXFx8vC4/Zr2jhAfHy9Pz6v3NWj550I5ud3+vQiA3IRrEcgdcsO1eKPfda/HSnQAAAAAyEemfT5JUdWqytffXxvXrNEXH3ygzn36ODosAACAPIskOgAAAADkIwf37dMnb7+tC+fPKzS8iHo895yeenHgzXcEAABAhkiiAwAAAEA+MuytNzXsrTcdHQYAAEC+QVFBAAAAAAAAAAAyQRIdAAAAwF0xDG4qWSAZV//hsw8AAPI7kugAAAAA7oizs7MkKSEhwcGRwBFSkxKVkmYojjQ6AADI56iJDgAAAOCOWCwW+fr66tSpU5Ikd3d3mUymLBs/NTX1/z9OSs7SsXEXjKsJ9HNnzmhTWrKS+bQAAIB8jiQ6AAAAgDsWEhIiSbZEelZKS0vTmTNnJEnxThaJJHouYSglzdCmtGStUOrNuwMAAORxJNEBAAAA3DGTyaTChQsrKChIV65cydKxExIS1KpVK0lS/elfymJ1zdLxcWcMSXEyWIEOAAAKDJLoAAAAAO6axWKRxWLJ0jFTU1P1zz//SJLOGGlyMlF7GwAAADmPG4sCAAAA+dzHH3+sYsWKydXVVbVq1dK6descHRIAAACQZ5BEBwAAAPKx7777TgMGDNCIESO0ceNGVapUSc2bN8+WGuYAAABAfkQ5FwAAACAfe++999S7d291795dkvTZZ59p7ty5+vLLL/Xyyy87OLpbl3o50dEhAHctP3wd54dzAPLD13F+OAcgL30dk0QHAAAA8qnk5GRt2LBBQ4YMsbWZzWY1adJEq1evznCfpKQkJSUl2Z5fvHhRknThwgWlpaVlb8D/ER8fL5Pp6t0rFzR7KEePDWSXa1/TFy5cyPKb8WYXrkXkR1yLQO7g6GsxNjZWkmQYN773Dkl0AAAAIJ86c+aMUlNTFRwcbNceHBysXbt2ZbjP2LFjNWrUqHTtERER2RIjUFAVKVLE0SEAENcikFs4+lq8dOmSfHx8Mt1OEh0AAACAzZAhQzRgwADb87S0NJ07d04BAQG2lULIf2JjYxUeHq7Dhw/L29vb0eEABRbXIpA7cC0WHIZh6NKlSwoNDb1hP5LoAAAAQD5VqFAhWSwWnTx50q795MmTCgkJyXAfq9Uqq9Vq1+br65tdISKX8fb2JlkA5AJci0DuwLVYMNxoBfo15hyIAwAAAIADuLi4qFq1alq8eLGtLS0tTYsXL1Z0dLQDIwMAAADyDlaiAwAAAPnYgAED1LVrV1WvXl01a9bU+PHjFR8fr+7duzs6NAAAACBPIIkOAAAA5GOPPfaYTp8+reHDh+vEiROqXLmy5s2bl+5moyjYrFarRowYka6UD4CcxbUI5A5ci/gvk2EYhqODAAAAAAAAAAAgN6ImOgAAAAAAAAAAmSCJDgAAAAAAAABAJkiiAwAAAAAAAACQCZLoAAAAAIAs06BBA/Xr18/2vFixYho/frzD4gHys5EjR6py5co37HPw4EGZTCbFxMTkSEwAstdPP/2kUqVKyWKx2P28RfYiiQ4AAAAAecjhw4fVo0cPhYaGysXFRREREXrhhRd09uxZR4cG5BndunWTyWSSyWSSs7OzihcvrkGDBikxMdHRod2WF198UYsXL7Y979atm9q0aWPXJzw8XMePH1eFChVyODrg1q1evVoWi0WtWrVydCi53pNPPqn27dvr8OHDGjNmjKPDKTBIogMAAABAHrF//35Vr15df//9t2bMmKG9e/fqs88+0+LFixUdHa1z585l27GvXLmSbWMDjnD//ffr+PHj2r9/v95//31NnDhRI0aMcHRYt8XT01MBAQE37GOxWBQSEiInJ6ccigq4fZMnT9Zzzz2nP/74Q8eOHXNoLMnJyQ49/o3ExcXp1KlTat68uUJDQ+Xl5eXokAoMkugAAAAAkEf07dtXLi4uWrBggerXr6+iRYuqRYsWWrRokY4ePaphw4Zp6NChqlWrVrp9K1WqpNGjR9uef/HFF4qMjJSrq6vKlSunTz75xLbtWvmH7777TvXr15erq6umTZums2fPqmPHjgoLC5O7u7uioqI0Y8aMHDl3IKtZrVaFhIQoPDxcbdq0UZMmTbRw4UJJUlpamsaOHavixYvLzc1NlSpV0vfff2+3//bt2/XAAw/I29tbXl5eqlevnvbt22fbf/To0SpSpIisVqsqV66sefPm2e2/atUqVa5cWa6urqpevbp++uknu7Iry5Ytk8lk0uLFi1W9enW5u7urTp062r17t22M68u5jBw5Ul999ZV+/vln2yr7ZcuWZVjOZfny5apZs6asVqsKFy6sl19+WSkpKbbtDRo00PPPP69BgwbJ399fISEhGjlyZBbNPGAvLi5O3333nZ5++mm1atVKU6dOTddnzpw5qlGjhlxdXVWoUCG1bdvWti0pKUmDBw9WeHi4rFarSpUqpcmTJ0uSpk6dKl9fX7uxrl1r11y7jr744gsVL15crq6ukqR58+apbt268vX1VUBAgB544AHbNX7NkSNH1LFjR/n7+8vDw0PVq1fX2rVrdfDgQZnNZq1fv96u//jx4xUREaG0tLQM5+L8+fPq0qWL/Pz85O7urhYtWujvv/+WdPV7wrWkeaNGjWzXOHIGSXQAAAAAyAPOnTun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vCSpbNmy2rp1q5KSkmzb//rrr7s+DxcXF6Wmpt6wT2RkpK3W8vWxeXl5qUiRIncdA3CrUlJS9PXXX2vcuHGKiYmxPTZv3qzQ0FDbjasrVqyoxYsXZzhGVFSU0tLSbPcr+K/AwEBdunRJ8fHxtrbrb7KbmbNnz2r37t165ZVX1LhxY0VGRur8+fN2fSpWrKiYmBidO3cu03F69eqlRYsW6ZNPPlFKSooefvjhTPtGRkYqJSVFa9euTRfHte8dcByS6AAAAACQR0yYMEFJSUlq3ry5/vjjDx0+fFjz5s1T06ZNFRYWptdff93Wt1OnTvr22281a9YsWymXa0aNGqWxY8fqww8/1J49e7R161ZNmTJF77333g2PX7p0aS1cuFCrVq3Szp079eSTT+rkyZPZcq5ATnvkkUdksVg0ceJEvfjii+rfv7+++uor7du3Txs3btRHH31ku/nus88+q9jYWHXo0EHr16/X33//rW+++cZ207+XXnpJb731lr777jvt3r1bL7/8smJiYvTCCy9Ikh5//HGlpaWpT58+2rlzp+bPn693331XkuzKrNyuYsWKacuWLdq9e7fOnDmTYZL/mWee0eHDh/Xcc89p165d+vnnnzVixAgNGDAg05sdAtnh119/1fnz59WzZ09VqFDB7tGuXTtbSZcRI0ZoxowZGjFihHbu3KmtW7fqrbfeknT1a75r167q0aOHfvrpJx04cEDLli3TzJkzJUm1atWSu7u7hg4dqn379mn69OmaOnXqTWPz8/NTQECAPv/8c+3du1dLlizRgAED7Pp07NhRISEhatOmjVauXKn9+/frhx9+0OrVq219IiMjVbt2bQ0ePFgdO3a84er10qVLq3Xr1urdu7f+/PNPbd68WZ07d1ZYWJhat259u9OLLMZ3RwAAAADII0qXLq3169erRIkSevTRR1WyZEn16dNHDRs21OrVq+3qsrZv315nz55VQkKC2rRpYzdOr1699MUXX2jKlCmKiopS/fr1NXXq1JuuRH/llVdUtWpVNW/eXA0aNLAlD4D8wMnJSc8++6zefvttDRkyRK+++qrGjh2ryMhI3X///Zo7d67tGgkICNCSJUsUFxen+vXrq1q1apo0aZKtBMrzzz+vAQMGaODAgYqKitK8efP0yy+/qHTp0pKurlafM2eOYmJiVLlyZQ0bNkzDhw+XJLs6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Zctq69atSkpKsm3/66+/7vo8Vq9erV69emnixImqXbu23babXcclS5aUs7Oz1q5da9vn/Pnz6b5HIOeQRAcAAACAXOLXX3/V+fPn1bNnT1WoUMHu0a5dO02ePFkjRozQjBkzNGLECO3cuVNbt261rWQrVqyYunbtqh49euinn37SgQMHtGzZMs2cOVOSVKtWLbm7u2vo0KHat2+fpk+frqlTp940Lj8/PwUEBOjzzz/X3r17tWTJEg0YMMCuT8eOHRUSEqI2bdpo5cqV2r9/v3744QetXr3a1icyMlK1a9fW4MGD1bFjxxxdPQjkBo888ogsFos+/vhjlS5dWgsXLtSqVau0c+dOPfnkkzp58qRd/2LFimnt2rU6ePCgrYxS3759de7cOXXs2FF//fWX9u3bp/nz56t79+7pEu5AXnXtWpk4caJefPFF9e/fX1999ZX27dunjRs36qOPPtJXX30lSXr22WcVGxurDh06aP369fr777/1zTffaPfu3ZKu3qDzrbfe0nfffafdu3fr5ZdfVkxMjF544QVJ0uOPP660tDT16dNHO3fu1Pz58/Xuu+9K+v/V5rfrxIkTatu2rTp06KDmzZvrxIkTOnHihE6fPi1JN72OPT091bNnT7300ktasmSJtm3bxo24HYyZBwAAAIBcYvLkyWrSpIl8fHzSbWvXrp3Wr18vf39/zZo1S7/88osqV66sRo0aad26dbZ+n376qdq3b69nnnlG5cqVU+/evW0rz/39/fW///1Pv/32m6KiojRjxgyNHDnypnGZzWZ9++232rBhgypUqKD+/fvrnXfesevj4uKiBQsWKCgoSC1btlRUVJTefPNNWSwWu349e/ZUcnKyevTocQczBORtTk5OevbZZ/X2229r4MCBqlq1qpo3b64GDRrYXoS63osvviiLxaLy5csrMDBQhw4dsq2qTU1NVbNmzRQVFaV+/frJ19eXBBvyjeuvlSFDhujVV1/V2LFjFRkZqfvvv19z585V8eLFJUkBAQFasmSJ4uLiVL9+fVWrVk2TJk2ylV55/vnnNWDAAA0cOFBRUVGaN2+efvnlF5UuXVrS1dXqc+bMUUxMjCpXrqxhw4Zp+PDhkmRXJ/127Nq1SydPntRXX32lwoUL2x41atSQpFu6jt955x3Vq1dPDz74oJo0aaK6deuqWrVqdzWvuHMm478F8QAAAAAAyCZjxozRrFmztGXLFkeHAgBAhqZNm6bu3bvr4sWLvGsKkrixKAAAAAAgB8TFxengwYOaMGGCXnvtNUeHAwCAzddff60SJUooLCxMmzdv1uDBg/Xoo4+SQIcN7/MBgDysWLFiMplMd1yn7U5069bNdsxly5bl2HEBAEDe9uyzz6patWpq0KABpVwAALnKiRMn1LlzZ0VGRqp///565JFH9Pnnnzs6LOQilHMBAEkjR47UqFGj7NosFov8/f1VtWpVvfDCC2rRooWDostcsWLF9M8//0iSrv92Pn78eF24cEGSbqnO6e3o1q2b7QYuS5cuVYMGDbJ0/Bv566+/9Mknn+iPP/7QsWPH5ObmpoiICDVt2lTdu3dXZGTkbY8ZExOjn376SZLUoEGDHD0fAAAAAACQ+1HOBQAykZqaqtOnT2v+/PlasGCBZs+erdatWzs6rFsyfvx4W3I9q5PojvLyyy/rrbfesmtLTEzU+fPnFRMToz179tiS4bcjJibG7gUUkugAAAAAAOB6lHMBgP9o0aKFVqxYodmzZ6tSpUqSrq7y/uijjxwcWcH17rvv2iXQH3vsMf34449atGiRPv30U9WtW9eB0TlefHy8o0MAAAAAACDfIokOAP8RFBSkunXrqk2bNho+fLit/fDhw+n6btmyRR07dlThwoXl4uKisLAw9erVS0eOHLHrd/nyZb300ksqXbq0rFarPDw8VLx4cT388MOaPXu2rV+DBg1s9cYPHjxoax85cqStferUqZnGPnXqVJlMJtsqdEm2/a6vmz5x4kRVr15dnp6eslqtCgsLU5MmTfT222/fzlQpJSVFo0aNUnh4uNzc3HTfffdp48aNtu316tWzHXv//v12+7Zt29a2bcOGDZke49y5c3YrxQcOHKhvv/1Wbdu2VePGjfXUU09pxYoVGjt2rK3P5MmT1bx5cxUtWlQeHh5ydXVV6dKl9dxzz+nMmTO2fsWKFVP37t1tz0eNGmWL6foV/AcOHFDv3r0VEREhq9WqoKAgPfbYY9q5c2e6eP/55x+1adNGnp6eCgoK0gsvvKAdO3bYxv3vSvfY2FgNGzZMkZGRcnNzk5eXl2rVqqWJEyfqvxXXro1RrFgxbd26VU2bNpWnp6datWqVJXMNAAAAAADSo5wLANzA9UnM0NBQu22///672rZtq6SkJFvbsWPHNHnyZM2dO1erVq1S8eLFJV29kdaXX35p65ecnKyDBw/q4MGDcnd3V9u2bbP5TP7fN998o6eeesqu7dixYzp27Jh27dqlQYMG3fJYAwcO1JYtW2zPV6xYoYYNG+qvv/5SmTJl1LNnT/3555+SpOnTp+uVV16RdLUMy8KFCyVJZcqUUbVq1TI9xty5cxUXFydJ8vHxsXth43rX10OfNWuWFixYYLd97969mjBhghYvXqyNGzfK1dX1ls5x48aNaty4sa3GvCSdPn1aM2fO1G+//abFixerZs2akqQLFy6ofv36thcx4uPj9eGHH2r58uUZjn3+/HnVqVNHu3btsmtft26d1q1bp2XLlmnGjBnp9rtw4YIaNmyos2fP2tqyYq4BAAAAAEB6rEQHgP84deqU/vzzT/30008aM2aMrf3JJ5+0fZyQkKCuXbsqKSlJTk5Oev3117VgwQJbAvrEiRN65plnbP1//vlnSVJERIS+//57LViwQJMnT1aXLl3k5+eXZbG3bNlSK1asUEhIiK1txYoVtsf1sTg5Oemzzz7T4sWLNW3aNA0cONCW9L9Ve/fu1QcffKCffvpJ1atXl3R1ZfWQIUMkSY888oi8vLwkSdOmTbPtt3jxYlsJko4dO97wGJs3b7Z9XLFiRXl7e980rscee0xffvml5s6dq2XLlmnu3Lnq0qWLJGnnzp368ccfJUnff/+9hg4datuve/futrnq0aOHDMNQ165dbQn0gQMHasGCBXrrrbdksVgUFxen7t27215sefvtt20J9KJFi+rbb7/VlClT0r0z4ZqhQ4faEuhRUVH68ccf9cUXX9i+Jr799lt999136fa7ePGiLBaLPv/8c82fP1+9evXKkrkGAAAAAADpsRIdAP7j999/1++//257HhQUpHfeeUcdOnSwtS1YsECnT5+WJDVt2lT33XefJOnBBx/UzJkzdfDgQc2fP19nzpxRoUKF5OzsLEny9fVVyZIlFRkZKavVqh49emRp7EFBQQoKCpLVarW1/bde+LVYXFxcVKpUKVWvXl3e3t56/PHHb/t4/fv31/PPPy9JKl++vMqUKSNJ+u2333TlyhV5eHioQ4cOmjRpknbt2qWNGzeqatWqmjNnjm2MmyV2L168aPv4v+8GyEyTJk00ZswYLVq0SMeOHbN7t4AkrV+/Xo8//riqV6+ubdu22dqL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hFxcXOTr66sKFSroqaee0uLFi219fX19tXz5cj300ENyd3dXQECAnnnmGX366ae2Pu7u7raP/f39tWbNGg0ZMkRly5aV1WqVh4eHatSooU8//VTTp0+/rdrq19ztXAMAAAAAgP9nMgzDcHQQAID8LyUlRR4eHkpOTlaLFi3022+/OTqkbGEYRrrE92effaann35akvT888/rgw8+yNYYCspcAwAAAACQE6iJDgDIVsnJyUpISNDUqVOVnJwsSerSpYuDo8o+rVq1Uvv27VWrVi25ubnpzz//1CuvvGLbnp03+Cxocw0AAAAAQE5gJToAIFuNHDlSo0aNsj2PjIzUli1b5OSUP1/HLVasmP75558Mt7300kt6++23s+3YBW2uAQAAAADICdREBwDkCE9PT7Vo0UK//vprvk7q9urVS9WrV5efn5+cnJwUGBioFi1a6Oeff87WBPr1CspcAwAAAACQE1iJDgAAAAAAAABAJliJDgAAAAAAAABAJhyeRP/0009VsWJFeXt7y9vbW9HR0fr9999t2xMTE9W3b18FBATI09NT7dq108mTJ+3GOHTokFq1aiV3d3cFBQXppZdeUkpKSk6fCgAAAAAAAAAgn3F4Er1IkSJ68803tWHDBq1fv16NGjVS69attX37dklS//79NWfOHM2aNUvLly/XsWPH9PDDD9v2T01NVatWrZScnKxVq1bpq6++0tSpUzV8+HBHnRIAAAAAAAAAIJ/IlTXR/f399c4776h9+/YKDAzU9OnT1b59e0nSrl27FBkZqdWrV6t27dr6/fff9cADD+jYsWMKDg6WJH322WcaPHiwTp8+LRcXl1s6Zlpamo4dOyYvLy+ZTKZsOzcAAAAgpxmGoUuXLik0NFRms8PX0QAAAAB5ipOjA7heamqqZs2apfj4eEVHR2vDhg26cuWKmjRpYutTrlw5FS1a1JZEX716taKiomwJdElq3ry5nn76aW3fvl1VqlTJ8FhJSUlKSkqyPT969KjKly+ffScHAAAAONjhw4dVpEgRR4cBAAAA5Cm5Iom+detWRUdHKzExUZ6enpo9e7bKly+vmJgYubi4yNfX165/cHCwTpw4IUk6ceKEXQL92vZr2zIzduxYjRo1Kl37xo0b5enpeZdnBAAAAOQecXFxqlq1qry8vBwdCgAAAJDn5IoketmyZRUTE6OLFy/q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DAzM8ZXoGzZs0P+xd99RUV1bHMe/gIh0BFHsAvaKvffea+zd2KKxxRJ7711j7xp7jzUau4m9F+wtothQEEQE4f1BnOcEUEAixvw+a816zjnnnrPvdVbeuOfcfQEaWVtoJ7oAEPQKw+fCyclJO9FFRETkk+gHeRERERGR2PtikuidO3dm69atHDx4kFSpoq6vBVCwYPgDF2/cuIG7uzsuLi4cP37caMyjR48AoqyjbmFhgUUku77fPUzjczE1Nf3/AzBMTMJfIiYmhs/F5/5MioiIyNdH3yVERERERGIv3r9Nh4WF0blzZzZu3MjevXtxdXX96DHvap8nT54cgMKFC3PhwgUeP35sGLN7927s7OzImjXrPxK3iIiIiIiIiIiIiHz94n0neqdOnVixYgWbN2/G1tYWb+/wh0HY29tjaWnJzZs3WbFiBVWqVMHJyYnz58/TvXt3SpQoQc6cOQGoUKECWbNmpVmzZowbNw5vb28GDBhAp06dIt1tLiIiIiIiIiIiIiISHfG+E33WrFn4+vpSqlQpkidPbnitXr0agIQJE/Lbb79RoUIFMmfOzA8//EDdunXZsmWLYQ4zMzO2bt2KmZkZhQsXpmnTpjRv3pxhw4bF12mJiIiIiIiIiIiIyFcg3neih4WFfbA/derUHDhw4KPzpE2blu3bt8dVWCIiIiIiIiIiIiIi8b8TXURERERERERERETkS6UkuoiIiIiIiIiIiIhIFJREFxERERERERERERGJgpLoIiIiIiIiIiIiIiJRUBJdRERERERERERERCQKSqKLiIiIiIiIiIiIiERBSXQRERERERERERERkSgoiS4iIiIiIiIiIiIiEgUl0UVEREREREREREREoqAkuoiIiIiIiIiIiIhIFJREFxERERERERERERGJgpLoIiIiIiIiIiIiIiJRUBJdRERERERERERERCQKSqKLiIiIiIiIiIiIiERBSXQRERERERERERERkSgoiS4iIiIiIiIiIiIiEgUl0UVEREREREREREREoqAkuoiIiIiISCy0btcFc2uXKF/ps+SL8ZwHDv7O1J/mxjqm9Ru3GMVw4ODvsZ6rbKXahnks7VORJWdhfuw/DH//gFjPGZVhI8d/9Hp16dHX6Ny+JmvXb6ZStfqkTJedJCkyUrZSbf44eiLCuA2btuKRryTWidPgnjkvY8ZPJSws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lCxbPdJ1F82bTrvvulO5RkNCQkI48cdveOTK/o+ea2SqVq7AonnTGTN+Kkt/Xk2K5MkYN3oI7b9tYTTOJZkzHdq3olOX3gS8ekWdWtUYPXxAhPlcXJKycO5U+g8aycLFy7G3t+Ppg2tA+MNJf9uxnv6DR9Gn31Be+PqROlUKSpcqTubMGWIUd6GCeVn682omT5uNqakpHrmy88uG5Yad8HFp776DBAUF0ahZO6P2tGlSccPzJABmZqYcPXaSmXMWEhISQm6PnOz4ZRXFihQ0jDcxMWHDmiV07tqHhs3aYmNtTdfO7enTs0ucxywiIvJfYhIWFhYW30F8Cfz8/LC3t8fX1xe7GNQl/FQBAQHY2ITfwjjJ8xgW8bAzRL48Qa9e0SNL+Jdhf39/rK2t4zkiERER+TeLr++6XwtPT0/u37lC6ZJF4jsUERGJA/e9HnD+0i2q1aht9IBhEZGo6L8UIiIiIiIiIiIiIiJRUBJdRERERERERERERCQKSqKLiIiIiIiIiIiIiERBSXQRERERERERERERkSgoiS4iIiIiIiIiIiIiEgUl0UVEREREREREREREoqAkuoiIiIiIiIiIiIhIFJREFxERERERERERERGJgpLoIiIiIiIiIiIiIiJRUBJdRERERERERERERCQKSqKLiIiIiIiIiIiIiERBSXQRERERERERERERkSgoiS4iIiIiIiIiIiIiEgUl0UVEREREREREREREoqAkuoiIiIiIiIiIiIhIFJREFxERERERERERERGJgpLoIiIiIiIiIiIiIiJRUBJdRERERERERERERCQKSqKLiIiIiIiIiIiIiERBSXQRERERERERERERkSgoiS4iIiIiIiIiIiIiEgUl0UVEREREREREREREoqAkuoiIiIiISCylz5IPc2sXzK1dsHd2JW+hssxbuIywsLDPHsv6jVsMsZhbu3Dg4O9Rjn3xwpdhI8dz5+69zxihiIiIyL+TkugiIiIiIiKfoG7tahzat411KxeRNUsmvvu+FzPnLPzscZQuWYxD+7axduXH137h68vwURO5e/fPzxCZiIiIyL9bgvgOQERERERE5N8saVJnChXIC0DZMiU4c/Y8c+YtplOHNp81DkfHxBQqkFe7y0VERETimHaii4iIiIiIxBFTU1Ny5sjKnbv3DW1nzl6gUrX62Du7kjRVZjp368Pr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iIiIREFJdBERERERERERERGRKCiJLiIiIiIiIiIiIiISBSXRRURERERERERERESioCS6iIiIiIiIiIiIiEgUlEQXEREREREREREREYmCkugiIiIiIiIiIiIiIlFQEl1EREREREREREREJApKoouIiIiIiIiIiIiIREFJdBERERERERERERGRKCiJLiIiIiIiIiIiIiISBSXRRURERERERERERESioCS6iIiIiIiIiIiIiEgUlEQXEREREREREREREYmCkugiIiIiIiIiIiIiIlFQEl1EREREREREREREJApKoouIiIiIiIiIiIiIREFJdBERERERERERERGRKCiJLiIiIiIiIiIiIiISBSXRRURERERERERERESioCS6iIiIiIiIiIiIiEgUlEQXEREREREREREREYmCkugiIiIiIiIiIiIiIlFQEl1ERERERCSWzK1dmDRlplHbth27SGSXktHjpnz2eNJnyYe5tQsrVq03tF25eh1zaxfMrV14+vRZjOccNnI8Z89djLP4ho0cHydziYiIiHwuSqKLiIiIiIjEkROnztC4eXtatWhM397d4iUGOztbtmzbaXj/y5ad2NnZxnq+4aMmcu583CTR165cROuWTeJkLhEREZHPRUl0ERERERGROHDr9l1q1W1G6ZLF+GnKmHiLo0K5Uuzec4A3b94AsHnrDipXKBtv8bwvt0cOUqVMEd9hiIiIiMRIvCfRDx48SPXq1UmRIgUmJiZs2rTJqD8sLIxBgwaRPHlyLC0tKVeuHNevXzca4+PjQ5MmTbCzs8PBwYE2bdrg7+//Gc9CRERERET+y54986F67cakSZOKFUvnYGZmZtR/5uwFKlWrj72zK0lTZaZztz68fv3a0F+0VBUaNWsbYd7CJSrRpEX7GMXi7JyEbFkzs2//YR4+fMTVazcoWbKo0ZiQkBCGj5pA+iz5sE6chnyFy7H/wGFD/4GDvxtKwAB826Gb4f3fy7EsWbYKc2sXzl+4TPXajbF3diVluuwsX7kOgNevXxuOjez4981buAyPfCWxcUyLW6a8dO85gODgYEP/pctXqFqzEc4pM+GUPANFS1Vhx87fIp3rytXr3Lx1J0bXTkRERCQy8Z5EDwgIIFeuXMyYMSPS/nHjxjFt2jRmz57NsWPHsLa2pmLFikZfOJs0acKlS5fYvXs3W7du5eDBg7Rr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ycAkOhERERERERERERGRDEyiExERERERERERERHJwCQ6EREREREREREREZEMTKITEREREREREREREcnAJDoRERERERERERERkQxMohMRERERERERERERycAkOhERERERERERERGRDEyiExERERERERERERHJwCQ6EREREREREREREZEMTKITEREREREREREREcnAJDoRERERERERERERkQxMohMRERERERERERERycAkOhERERERERERERGRDEyiExERERERERERERHJwCQ6EREREREREREREZEMTKITEREREREREdFXQxAEeYdAROUMk+hERERERETvoaioiJycXHmHQUREn0hubi4kEgUoKDAtRkTFw78WRERERERE76GlpYU32blIS0uTdyhERPQJJCa+gpaOjrzDIKJyhEl0IiIiIiKi96hcuTKUlFXxIOIxSwAQEZVzyckpiI1PQpUqFvIOhYjKESV5B0BERERERFSWKSoqolYdF1y9EoqM0MuoUsUUmhoakEgk8g6NiIiKKTs7G/EJL/E8Kg46+sawtraWd0hEVI4wiU5ERERERPQBFhYWUFZWxsOHEbgV9gQQ8gBwVzoRUfmhAFU1dVjaVEf16tWhrKws74CIqBxhEp2IiIiIiKgYTExMYGJiguzsbGRlZSEvL0/eIRERUTEpKSlBTU2N3yIiolJhEp2IiIiIiKgElJWVuYORiIiI6CvCB4sSEX3AwoULUbt2bejq6kJFRQXm5ubo1q0bbt68Ke/QiIiIiIiIiIjoM2MSnYjoA06dOoX4+HjY2trCzs4O0dHR2LVrFzw8PJCWlibv8IiIiIiIiIiI6DNiEp2I6AO2bduGqKgoXL16FXfv3sWkSZMAAImJibh3756coyMiIiIiIiIios+JNdGJiD5AVVUVe/bswezZs5GcnIzw8HAAgJGREapVqybn6IiIiIiIiIiI6HNiEp2IqBhiY2MRGhoqvrexscH+/fuhpaUlx6iIiIiIiIiIiOhzYzkXIqJiGDx4MPLy8vD06VP06NEDjx8/Ro8ePZCSkiLv0OgrFxAQABcXF6ipqUFfXx9du3bFw4cP5R0WEdcmERERERFVGEyiExEVk0QigaWlpVgT/c6dO9i2bZuco6Kv2d9//42ePXvi2rVrMDU1RW5uLgIDA9G0aVPExMTIOzz6inFtEhERERFRRcIk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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import matplotlib\n", + "\n", + "# ํ•œ๊ธ€ ํฐํŠธ ์„ค์ • (์‹œ์Šคํ…œ์— ๋”ฐ๋ผ ์กฐ์ • ํ•„์š”)\n", + "matplotlib.rcParams['font.family'] = 'DejaVu Sans'\n", + "matplotlib.rcParams['axes.unicode_minus'] = False\n", + "\n", + "# ์‹œ๊ฐํ™” ์„ค์ •\n", + "fig, axes = plt.subplots(2, 2, figsize=(15, 10))\n", + "fig.suptitle('YOLO Answer Recognition Accuracy Analysis', fontsize=16, fontweight='bold')\n", + "\n", + "# 1. ์ „์ฒด ๊ฒฐ๊ณผ ํŒŒ์ด ์ฐจํŠธ\n", + "result_counts = merged_df['result'].value_counts()\n", + "colors = {'correct': '#95E1D3', 'wrong': '#FF6B6B', 'none': '#FFE66D', 'missing': '#C7CEEA'}\n", + "result_colors = [colors.get(x, '#CCCCCC') for x in result_counts.index]\n", + "\n", + "axes[0, 0].pie(result_counts.values, labels=result_counts.index, autopct='%1.1f%%',\n", + " colors=result_colors, startangle=90)\n", + "axes[0, 0].set_title('Overall Results Distribution', fontweight='bold')\n", + "\n", + "# 2. ์ •ํ™•๋„ ์ง€ํ‘œ ๋ง‰๋Œ€ ๊ทธ๋ž˜ํ”„\n", + "metrics = ['Overall\\nAccuracy', 'Recognition\\nRate', 'Accuracy of\\nRecognized']\n", + "values = [accuracy, recognition_rate, accuracy_of_recognized]\n", + "bar_colors = ['#4ECDC4' if v >= 90 else '#FFE66D' if v >= 80 else '#FF6B6B' for v in values]\n", + "\n", + "bars = axes[0, 1].bar(metrics, values, color=bar_colors, edgecolor='black', linewidth=1.5)\n", + "axes[0, 1].set_ylabel('Percentage (%)', fontsize=11)\n", + "axes[0, 1].set_title('Key Performance Metrics', fontweight='bold')\n", + "axes[0, 1].set_ylim(0, 105)\n", + "axes[0, 1].axhline(y=90, color='green', linestyle='--', linewidth=1, alpha=0.7, label='90% Target')\n", + "axes[0, 1].legend()\n", + "\n", + "# ๋ง‰๋Œ€ ์œ„์— ๊ฐ’ ํ‘œ์‹œ\n", + "for bar, value in zip(bars, values):\n", + " height = bar.get_height()\n", + " axes[0, 1].text(bar.get_x() + bar.get_width()/2., height + 1,\n", + " f'{value:.1f}%', ha='center', va='bottom', fontweight='bold')\n", + "\n", + "axes[0, 1].grid(axis='y', alpha=0.3)\n", + "\n", + "# 3. ๊ฒฐ๊ณผ ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ๊ฐœ์ˆ˜\n", + "categories = ['Correct', 'Wrong', 'None', 'Missing']\n", + "counts = [correct_count, wrong_count, none_count, missing_count]\n", + "cat_colors = ['#95E1D3', '#FF6B6B', '#FFE66D', '#C7CEEA']\n", + "\n", + "bars = axes[1, 0].bar(categories, counts, color=cat_colors, edgecolor='black', linewidth=1.5)\n", + "axes[1, 0].set_ylabel('Count', fontsize=11)\n", + "axes[1, 0].set_title('Results by Category', fontweight='bold')\n", + "\n", + "# ๋ง‰๋Œ€ ์œ„์— ๊ฐ’ ํ‘œ์‹œ\n", + "for bar, count in zip(bars, counts):\n", + " height = bar.get_height()\n", + " axes[1, 0].text(bar.get_x() + bar.get_width()/2., height + 0.5,\n", + " f'{count}', ha='center', va='bottom', fontweight='bold')\n", + "\n", + "axes[1, 0].grid(axis='y', alpha=0.3)\n", + "\n", + "# 4. ๋ˆ„์  ํ†ต๊ณ„ ํ‘œ\n", + "axes[1, 1].axis('off')\n", + "stats_text = f\"\"\"\n", + "SUMMARY STATISTICS\n", + "{\"=\"*40}\n", + "\n", + "Total Problems: {total_count}\n", + "\n", + "Results:\n", + " โ€ข Correct: {correct_count} ({correct_count/total_count*100:.2f}%)\n", + " โ€ข Wrong: {wrong_count} ({wrong_count/total_count*100:.2f}%)\n", + " โ€ข None: {none_count} ({none_count/total_count*100:.2f}%)\n", + " โ€ข Missing: {missing_count} ({missing_count/total_count*100:.2f}%)\n", + "\n", + "{\"=\"*40}\n", + "\n", + "Key Metrics:\n", + " ๐ŸŽฏ Overall Accuracy: {accuracy:.2f}%\n", + " ๐Ÿ“ Recognition Rate: {recognition_rate:.2f}%\n", + " โœจ Accuracy (Recognized): {accuracy_of_recognized:.2f}%\n", + "\n", + "{\"=\"*40}\n", + "\"\"\"\n", + "\n", + "axes[1, 1].text(0.1, 0.5, stats_text, fontsize=11, family='monospace',\n", + " verticalalignment='center', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.3))\n", + "\n", + "plt.tight_layout()\n", + "\n", + "# ์ €์žฅ\n", + "viz_path = output_dir / \"accuracy_visualization.png\"\n", + "plt.savefig(viz_path, dpi=300, bbox_inches='tight')\n", + "print(f\"\\n๐Ÿ’พ ์‹œ๊ฐํ™” ์ €์žฅ: {viz_path}\")\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 9. ๋ˆ„๋ฝ ๋ฌธ์ œ (Missing)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "๐Ÿ” ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ถ„์„ (์ด 0๊ฐœ)\n", + "============================================================\n", + "\n", + "โœ… ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!\n" + ] + } + ], + "source": [ + "# ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ (results์— ์—†์Œ)\n", + "missing_df = merged_df[merged_df['result'] == 'missing'].copy()\n", + "\n", + "print(\"=\"*60)\n", + "print(f\"๐Ÿ” ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ถ„์„ (์ด {len(missing_df)}๊ฐœ)\")\n", + "print(\"=\"*60)\n", + "\n", + "if len(missing_df) > 0:\n", + " print(\"\\n๋ˆ„๋ฝ ๋ชฉ๋ก:\")\n", + " display(missing_df[['page_number', 'problem_number', 'correct_answer', 'problem_type']].sort_values(['page_number', 'problem_number']))\n", + " \n", + " # ํŽ˜์ด์ง€๋ณ„ ๋ˆ„๋ฝ ํ†ต๊ณ„\n", + " print(\"\\n๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ ๋ˆ„๋ฝ ํ†ต๊ณ„:\")\n", + " page_missing = missing_df.groupby('page_number').size().reset_index(name='missing_count')\n", + " page_missing = page_missing.sort_values('missing_count', ascending=False)\n", + " display(page_missing.head(10))\n", + "else:\n", + " print(\"\\nโœ… ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 10. None ๋‹ต์•ˆ ๋ถ„์„" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "โš ๏ธ None ๋‹ต์•ˆ ๋ถ„์„ (์ด 0๊ฐœ)\n", + "============================================================\n", + "\n", + "โœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค!\n" + ] + } + ], + "source": [ + "# None ๋‹ต์•ˆ\n", + "none_df = merged_df[merged_df['result'] == 'none'].copy()\n", + "\n", + "print(\"=\"*60)\n", + "print(f\"โš ๏ธ None ๋‹ต์•ˆ ๋ถ„์„ (์ด {len(none_df)}๊ฐœ)\")\n", + "print(\"=\"*60)\n", + "\n", + "if len(none_df) > 0:\n", + " print(\"\\nNone ๋‹ต์•ˆ ๋ชฉ๋ก:\")\n", + " display(none_df[['page_number', 'problem_number', 'correct_answer', 'problem_type']].sort_values(['page_number', 'problem_number']))\n", + " \n", + " # ํŽ˜์ด์ง€๋ณ„ None ํ†ต๊ณ„\n", + " print(\"\\n๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ None ๋‹ต์•ˆ ํ†ต๊ณ„:\")\n", + " page_none = none_df.groupby('page_number').size().reset_index(name='none_count')\n", + " page_none = page_none.sort_values('none_count', ascending=False)\n", + " display(page_none.head(10))\n", + "else:\n", + " print(\"\\nโœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 11. ์˜ค๋‹ต ๋ถ„์„" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "โŒ ์˜ค๋‹ต ๋ถ„์„ (์ด 3๊ฐœ)\n", + "============================================================\n", + "\n", + "์˜ค๋‹ต ๋ชฉ๋ก:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberproblem_numbercorrect_answerpredicted_answerproblem_type
1131050445answer_1_o
1191061041answer_1_o
1341122542answer_1_o
\n", + "
" + ], + "text/plain": [ + " page_number problem_number correct_answer predicted_answer problem_type\n", + "113 105 04 4 5 answer_1_o\n", + "119 106 10 4 1 answer_1_o\n", + "134 112 25 4 2 answer_1_o" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ ์˜ค๋‹ต ํ†ต๊ณ„:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberwrong_count
01051
11061
21121
\n", + "
" + ], + "text/plain": [ + " page_number wrong_count\n", + "0 105 1\n", + "1 106 1\n", + "2 112 1" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ์˜ค๋‹ต\n", + "wrong_df = merged_df[merged_df['result'] == 'wrong'].copy()\n", + "\n", + "print(\"=\"*60)\n", + "print(f\"โŒ ์˜ค๋‹ต ๋ถ„์„ (์ด {len(wrong_df)}๊ฐœ)\")\n", + "print(\"=\"*60)\n", + "\n", + "if len(wrong_df) > 0:\n", + " print(\"\\n์˜ค๋‹ต ๋ชฉ๋ก:\")\n", + " display(wrong_df[['page_number', 'problem_number', 'correct_answer', 'predicted_answer', 'problem_type']].sort_values(['page_number', 'problem_number']))\n", + " \n", + " # ํŽ˜์ด์ง€๋ณ„ ์˜ค๋‹ต ํ†ต๊ณ„\n", + " print(\"\\n๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ ์˜ค๋‹ต ํ†ต๊ณ„:\")\n", + " page_wrong = wrong_df.groupby('page_number').size().reset_index(name='wrong_count')\n", + " page_wrong = page_wrong.sort_values('wrong_count', ascending=False)\n", + " display(page_wrong.head(10))\n", + "else:\n", + " print(\"\\nโœ… ์˜ค๋‹ต์ด ์—†์Šต๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 12. ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "๐Ÿ“Š ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„\n", + "============================================================\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
totalcorrectwrongnonemissingaccuracy
page_number
1011000100.0
10022000100.0
10122000100.0
10222000100.0
10322000100.0
.....................
9522000100.0
9922000100.0
1055410080.0
1065410080.0
1122110050.0
\n", + "

147 rows ร— 6 columns

\n", + "
" + ], + "text/plain": [ + " total correct wrong none missing accuracy\n", + "page_number \n", + "10 1 1 0 0 0 100.0\n", + "100 2 2 0 0 0 100.0\n", + "101 2 2 0 0 0 100.0\n", + "102 2 2 0 0 0 100.0\n", + "103 2 2 0 0 0 100.0\n", + "... ... ... ... ... ... ...\n", + "95 2 2 0 0 0 100.0\n", + "99 2 2 0 0 0 100.0\n", + "105 5 4 1 0 0 80.0\n", + "106 5 4 1 0 0 80.0\n", + "112 2 1 1 0 0 50.0\n", + "\n", + "[147 rows x 6 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "โš ๏ธ ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ํŽ˜์ด์ง€ (80% ๋ฏธ๋งŒ):\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
totalcorrectwrongnonemissingaccuracy
page_number
1122110050.0
\n", + "
" + ], + "text/plain": [ + " total correct wrong none missing accuracy\n", + "page_number \n", + "112 2 1 1 0 0 50.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„ ๊ณ„์‚ฐ\n", + "page_stats = merged_df.groupby('page_number').agg({\n", + " 'result': 'count',\n", + "}).rename(columns={'result': 'total'})\n", + "\n", + "page_stats['correct'] = merged_df[merged_df['result'] == 'correct'].groupby('page_number').size()\n", + "page_stats['wrong'] = merged_df[merged_df['result'] == 'wrong'].groupby('page_number').size()\n", + "page_stats['none'] = merged_df[merged_df['result'] == 'none'].groupby('page_number').size()\n", + "page_stats['missing'] = merged_df[merged_df['result'] == 'missing'].groupby('page_number').size()\n", + "\n", + "page_stats = page_stats.fillna(0).astype(int)\n", + "page_stats['accuracy'] = (page_stats['correct'] / page_stats['total'] * 100).round(2)\n", + "page_stats = page_stats.sort_values('accuracy', ascending=False)\n", + "\n", + "print(\"=\"*60)\n", + "print(\"๐Ÿ“Š ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„\")\n", + "print(\"=\"*60)\n", + "display(page_stats)\n", + "\n", + "# ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ํŽ˜์ด์ง€\n", + "print(\"\\nโš ๏ธ ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ํŽ˜์ด์ง€ (80% ๋ฏธ๋งŒ):\")\n", + "low_accuracy_pages = page_stats[page_stats['accuracy'] < 80]\n", + "if len(low_accuracy_pages) > 0:\n", + " display(low_accuracy_pages)\n", + "else:\n", + " print(\"โœ… ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ 80% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋ณด์ž…๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 13. ๊ฒฐ๊ณผ ์ €์žฅ" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ’พ ์ƒ์„ธ ๋น„๊ต ๊ฒฐ๊ณผ ์ €์žฅ: detailed_comparison.csv\n", + "๐Ÿ’พ ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„ ์ €์žฅ: page_statistics.csv\n", + "๐Ÿ’พ ์œ ํ˜•๋ณ„ ํ†ต๊ณ„ ์ €์žฅ: type_statistics.csv\n", + "๐Ÿ’พ ์š”์•ฝ ๋ฆฌํฌํŠธ ์ €์žฅ: accuracy_summary.txt\n", + "\n", + "============================================================\n", + "โœ… ๋ชจ๋“  ๋ถ„์„์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\n", + "============================================================\n" + ] + } + ], + "source": [ + "# ์ƒ์„ธ ๊ฒฐ๊ณผ ์ €์žฅ\n", + "detailed_results_path = output_dir / \"detailed_comparison.csv\"\n", + "merged_df.to_csv(detailed_results_path, index=False, encoding='utf-8-sig')\n", + "print(f\"\\n๐Ÿ’พ ์ƒ์„ธ ๋น„๊ต ๊ฒฐ๊ณผ ์ €์žฅ: {detailed_results_path}\")\n", + "\n", + "# ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„ ์ €์žฅ\n", + "page_stats_path = output_dir / \"page_statistics.csv\"\n", + "page_stats.to_csv(page_stats_path, encoding='utf-8-sig')\n", + "print(f\"๐Ÿ’พ ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„ ์ €์žฅ: {page_stats_path}\")\n", + "\n", + "# ์œ ํ˜•๋ณ„ ํ†ต๊ณ„ ์ €์žฅ\n", + "if merged_df['problem_type'].notna().sum() > 0:\n", + " type_stats_path = output_dir / \"type_statistics.csv\"\n", + " type_stats.to_csv(type_stats_path, encoding='utf-8-sig')\n", + " print(f\"๐Ÿ’พ ์œ ํ˜•๋ณ„ ํ†ต๊ณ„ ์ €์žฅ: {type_stats_path}\")\n", + "\n", + "# ์š”์•ฝ ๋ฆฌํฌํŠธ ์ €์žฅ\n", + "summary_path = output_dir / \"accuracy_summary.txt\"\n", + "with open(summary_path, 'w', encoding='utf-8') as f:\n", + " f.write(\"=\"*60 + \"\\n\")\n", + " f.write(\"YOLO ๋‹ต์•ˆ ์ธ์‹ ์ •ํ™•๋„ ๋ถ„์„ ๋ณด๊ณ ์„œ\\n\")\n", + " f.write(\"(ํŽ˜์ด์ง€๋ฒˆํ˜ธ + ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ธฐ์ค€)\\n\")\n", + " f.write(\"=\"*60 + \"\\n\\n\")\n", + " \n", + " f.write(\"๐Ÿ“Š ์ „์ฒด ํ†ต๊ณ„\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " f.write(f\"์ด ๋ฌธ์ œ ์ˆ˜: {total_count}๊ฐœ\\n\")\n", + " f.write(f\"์ •๋‹ต: {correct_count}๊ฐœ ({correct_count/total_count*100:.2f}%)\\n\")\n", + " f.write(f\"์˜ค๋‹ต: {wrong_count}๊ฐœ ({wrong_count/total_count*100:.2f}%)\\n\")\n", + " f.write(f\"None: {none_count}๊ฐœ ({none_count/total_count*100:.2f}%)\\n\")\n", + " f.write(f\"๋ˆ„๋ฝ: {missing_count}๊ฐœ ({missing_count/total_count*100:.2f}%)\\n\\n\")\n", + " \n", + " f.write(\"=\"*60 + \"\\n\")\n", + " f.write(f\"๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: {accuracy:.2f}%\\n\")\n", + " f.write(f\"๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): {recognition_rate:.2f}%\\n\")\n", + " f.write(f\"โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„: {accuracy_of_recognized:.2f}%\\n\")\n", + " f.write(\"=\"*60 + \"\\n\\n\")\n", + " \n", + " # ์œ ํ˜•๋ณ„ ํ†ต๊ณ„ ์ถ”๊ฐ€\n", + " if merged_df['problem_type'].notna().sum() > 0:\n", + " f.write(\"\\n๐Ÿ“Š ์œ ํ˜•๋ณ„ ํ†ต๊ณ„\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for problem_type in type_stats.index:\n", + " stats = type_stats.loc[problem_type]\n", + " f.write(f\"\\n์œ ํ˜•: {problem_type}\\n\")\n", + " f.write(f\" ์ด ๋ฌธ์ œ: {stats['total']}๊ฐœ\\n\")\n", + " f.write(f\" ์ •๋‹ต: {stats['correct']}๊ฐœ ({stats['accuracy']:.2f}%)\\n\")\n", + " f.write(f\" ์˜ค๋‹ต: {stats['wrong']}๊ฐœ ({stats['wrong_rate']:.2f}%)\\n\")\n", + " f.write(f\" None: {stats['none']}๊ฐœ ({stats['none_rate']:.2f}%)\\n\")\n", + " f.write(f\" ๋ˆ„๋ฝ: {stats['missing']}๊ฐœ ({stats['missing_rate']:.2f}%)\\n\")\n", + " \n", + " if len(missing_df) > 0:\n", + " f.write(f\"\\n๐Ÿ” ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ: {len(missing_df)}๊ฐœ\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for _, row in missing_df.iterrows():\n", + " f.write(f\"ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}, ์ •๋‹ต {row['correct_answer']}\\n\")\n", + " \n", + " if len(none_df) > 0:\n", + " f.write(f\"\\nโš ๏ธ None ๋‹ต์•ˆ: {len(none_df)}๊ฐœ\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for _, row in none_df.head(20).iterrows():\n", + " f.write(f\"ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}, ์ •๋‹ต {row['correct_answer']}\\n\")\n", + " if len(none_df) > 20:\n", + " f.write(f\"... ์™ธ {len(none_df)-20}๊ฐœ\\n\")\n", + " \n", + " if len(wrong_df) > 0:\n", + " f.write(f\"\\nโŒ ์˜ค๋‹ต: {len(wrong_df)}๊ฐœ\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for _, row in wrong_df.head(20).iterrows():\n", + " f.write(f\"ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}, ์œ ํ˜• {row['problem_type']}, ์ •๋‹ต {row['correct_answer']}, ์˜ˆ์ธก {row['predicted_answer']}\\n\")\n", + " if len(wrong_df) > 20:\n", + " f.write(f\"... ์™ธ {len(wrong_df)-20}๊ฐœ\\n\")\n", + "\n", + "print(f\"๐Ÿ’พ ์š”์•ฝ ๋ฆฌํฌํŠธ ์ €์žฅ: {summary_path}\")\n", + "\n", + "print(\"\\n\" + \"=\"*60)\n", + "print(\"โœ… ๋ชจ๋“  ๋ถ„์„์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\")\n", + "print(\"=\"*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 14. ์ตœ์ข… ์š”์•ฝ" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "\n", + "# ๐Ÿ“Š ์ตœ์ข… ๋ถ„์„ ์š”์•ฝ\n", + "\n", + "## ๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: **98.97%**\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ˆ ์ฃผ์š” ์ง€ํ‘œ\n", + "- **๋งค์นญ ๊ธฐ์ค€**: ํŽ˜์ด์ง€๋ฒˆํ˜ธ + ๋ฌธ์ œ๋ฒˆํ˜ธ\n", + "- **์ธ์‹ ์„ฑ๊ณต๋ฅ **: 100.00% (๋ˆ„๋ฝ ์ œ์™ธ)\n", + "- **์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„**: 98.97%\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“Š ์ƒ์„ธ ํ†ต๊ณ„\n", + "| ๊ตฌ๋ถ„ | ๊ฐœ์ˆ˜ | ๋น„์œจ |\n", + "|------|------|------|\n", + "| โœ… ์ •๋‹ต | 287๊ฐœ | 98.97% |\n", + "| โŒ ์˜ค๋‹ต | 3๊ฐœ | 1.03% |\n", + "| โš ๏ธ None | 0๊ฐœ | 0.00% |\n", + "| ๐Ÿ” ๋ˆ„๋ฝ | 0๊ฐœ | 0.00% |\n", + "| **๐Ÿ“˜ ์ „์ฒด** | **290๊ฐœ** | **100.00%** |\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“Š ์œ ํ˜•๋ณ„ ์ •ํ™•๋„\n", + "\n", + "| ์œ ํ˜• | ๋ฌธ์ œ ์ˆ˜ | ์ •ํ™•๋„ | ์˜ค๋‹ต๋ฅ  |\n", + "|------|---------|--------|--------|\n", + "| answer_12_oo | 29.0๊ฐœ | 100.00% | 0.00% |\n", + "| answer_12_xo | 27.0๊ฐœ | 100.00% | 0.00% |\n", + "| answer_12_ox | 27.0๊ฐœ | 100.00% | 0.00% |\n", + "| answer_12_xx | 27.0๊ฐœ | 100.00% | 0.00% |\n", + "| answer_2_o | 45.0๊ฐœ | 100.00% | 0.00% |\n", + "| answer_1_x | 45.0๊ฐœ | 100.00% | 0.00% |\n", + "| answer_2_x | 45.0๊ฐœ | 100.00% | 0.00% |\n", + "| answer_1_o | 45.0๊ฐœ | 93.33% | 6.67% |\n", + "\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ’ก ๊ฐœ์„  ํฌ์ธํŠธ\n", + "\n", + "- โŒ **์˜ค๋‹ต ๋ถ„์„**: 3๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ž˜๋ชป ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n", + "\n", + "### ๐ŸŽ‰ ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ!\n", + "95% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค!\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ ์ƒ์„ฑ๋œ ํŒŒ์ผ\n", + "- `detailed_comparison.csv`: ์ „์ฒด ๋น„๊ต ๊ฒฐ๊ณผ\n", + "- `page_statistics.csv`: ํŒŒ์ผ๋ณ„ ํ†ต๊ณ„\n", + "- `type_statistics.csv`: ์œ ํ˜•๋ณ„ ํ†ต๊ณ„ โญ NEW\n", + "- `accuracy_summary.txt`: ์š”์•ฝ ๋ฆฌํฌํŠธ\n", + "- `accuracy_visualization.png`: ์ „์ฒด ์‹œ๊ฐํ™” ์ฐจํŠธ\n", + "- `type_analysis_visualization.png`: ์œ ํ˜•๋ณ„ ๋ถ„์„ ์‹œ๊ฐํ™” โญ NEW\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Markdown, display\n", + "\n", + "summary_md = f\"\"\"\n", + "# ๐Ÿ“Š ์ตœ์ข… ๋ถ„์„ ์š”์•ฝ\n", + "\n", + "## ๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: **{accuracy:.2f}%**\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ˆ ์ฃผ์š” ์ง€ํ‘œ\n", + "- **๋งค์นญ ๊ธฐ์ค€**: ํŽ˜์ด์ง€๋ฒˆํ˜ธ + ๋ฌธ์ œ๋ฒˆํ˜ธ\n", + "- **์ธ์‹ ์„ฑ๊ณต๋ฅ **: {recognition_rate:.2f}% (๋ˆ„๋ฝ ์ œ์™ธ)\n", + "- **์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„**: {accuracy_of_recognized:.2f}%\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“Š ์ƒ์„ธ ํ†ต๊ณ„\n", + "| ๊ตฌ๋ถ„ | ๊ฐœ์ˆ˜ | ๋น„์œจ |\n", + "|------|------|------|\n", + "| โœ… ์ •๋‹ต | {correct_count}๊ฐœ | {correct_count/total_count*100:.2f}% |\n", + "| โŒ ์˜ค๋‹ต | {wrong_count}๊ฐœ | {wrong_count/total_count*100:.2f}% |\n", + "| โš ๏ธ None | {none_count}๊ฐœ | {none_count/total_count*100:.2f}% |\n", + "| ๐Ÿ” ๋ˆ„๋ฝ | {missing_count}๊ฐœ | {missing_count/total_count*100:.2f}% |\n", + "| **๐Ÿ“˜ ์ „์ฒด** | **{total_count}๊ฐœ** | **100.00%** |\n", + "\"\"\"\n", + "\n", + "# ์œ ํ˜•๋ณ„ ์š”์•ฝ ์ถ”๊ฐ€\n", + "if merged_df['problem_type'].notna().sum() > 0:\n", + " summary_md += \"\\n---\\n\\n### ๐Ÿ“Š ์œ ํ˜•๋ณ„ ์ •ํ™•๋„\\n\\n\"\n", + " summary_md += \"| ์œ ํ˜• | ๋ฌธ์ œ ์ˆ˜ | ์ •ํ™•๋„ | ์˜ค๋‹ต๋ฅ  |\\n\"\n", + " summary_md += \"|------|---------|--------|--------|\\n\"\n", + " for problem_type in type_stats.sort_values('accuracy', ascending=False).index:\n", + " stats = type_stats.loc[problem_type]\n", + " summary_md += f\"| {problem_type} | {stats['total']}๊ฐœ | {stats['accuracy']:.2f}% | {stats['wrong_rate']:.2f}% |\\n\"\n", + "\n", + "summary_md += \"\"\"\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ’ก ๊ฐœ์„  ํฌ์ธํŠธ\n", + "\"\"\" \n", + "\n", + "if missing_count > 0:\n", + " summary_md += f\"\\n- ๐Ÿ” **๋ˆ„๋ฝ ๋ฌธ์ œ ํ•ด๊ฒฐ**: {missing_count}๊ฐœ ๋ฌธ์ œ๊ฐ€ results์— ์—†์Šต๋‹ˆ๋‹ค. Section ๊ฒ€์ถœ ๋ฌธ์ œ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\"\n", + "\n", + "if none_count > 0:\n", + " summary_md += f\"\\n- โš ๏ธ **None ๋‹ต์•ˆ ๊ฐœ์„ **: {none_count}๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ธ์‹๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.\"\n", + "\n", + "if wrong_count > 0:\n", + " summary_md += f\"\\n- โŒ **์˜ค๋‹ต ๋ถ„์„**: {wrong_count}๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ž˜๋ชป ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\"\n", + " if merged_df['problem_type'].notna().sum() > 0:\n", + " high_wrong_types = type_stats[type_stats['wrong_rate'] > 10]\n", + " if len(high_wrong_types) > 0:\n", + " summary_md += f\"\\n - ํŠนํžˆ ๋‹ค์Œ ์œ ํ˜•์˜ ์˜ค๋‹ต๋ฅ ์ด ๋†’์Šต๋‹ˆ๋‹ค: {', '.join(high_wrong_types.index.astype(str))}\"\n", + "\n", + "if accuracy >= 95:\n", + " summary_md += \"\\n\\n### ๐ŸŽ‰ ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ!\"\n", + " summary_md += \"\\n95% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค!\"\n", + "elif accuracy >= 90:\n", + " summary_md += \"\\n\\n### ๐Ÿ‘ ์–‘ํ˜ธํ•œ ์„ฑ๋Šฅ\"\n", + " summary_md += \"\\n90% ์ด์ƒ์˜ ์ •ํ™•๋„์ž…๋‹ˆ๋‹ค. ์กฐ๊ธˆ ๋” ๊ฐœ์„ ํ•˜๋ฉด ๋” ์ข‹์Šต๋‹ˆ๋‹ค!\"\n", + "else:\n", + " summary_md += \"\\n\\n### ๐Ÿ”ง ๊ฐœ์„  ํ•„์š”\"\n", + " summary_md += \"\\n์ •ํ™•๋„๊ฐ€ 90% ๋ฏธ๋งŒ์ž…๋‹ˆ๋‹ค. ์œ„์˜ ๊ฐœ์„  ํฌ์ธํŠธ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋ชจ๋ธ์„ ๊ฐœ์„ ํ•˜์„ธ์š”.\"\n", + "\n", + "summary_md += f\"\"\"\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ ์ƒ์„ฑ๋œ ํŒŒ์ผ\n", + "- `detailed_comparison.csv`: ์ „์ฒด ๋น„๊ต ๊ฒฐ๊ณผ\n", + "- `page_statistics.csv`: ํŒŒ์ผ๋ณ„ ํ†ต๊ณ„\n", + "- `type_statistics.csv`: ์œ ํ˜•๋ณ„ ํ†ต๊ณ„ โญ NEW\n", + "- `accuracy_summary.txt`: ์š”์•ฝ ๋ฆฌํฌํŠธ\n", + "- `accuracy_visualization.png`: ์ „์ฒด ์‹œ๊ฐํ™” ์ฐจํŠธ\n", + "- `type_analysis_visualization.png`: ์œ ํ˜•๋ณ„ ๋ถ„์„ ์‹œ๊ฐํ™” โญ NEW\n", + "\"\"\"\n", + "\n", + "display(Markdown(summary_md))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ocr", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.13" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/ai-service/test/Hierarchical_crop/answers/accuracy_summary.txt b/ai-service/test/Hierarchical_crop/answers/accuracy_summary.txt new file mode 100644 index 0000000..64c644a --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/accuracy_summary.txt @@ -0,0 +1,84 @@ +============================================================ +YOLO ๋‹ต์•ˆ ์ธ์‹ ์ •ํ™•๋„ ๋ถ„์„ ๋ณด๊ณ ์„œ +(ํŽ˜์ด์ง€๋ฒˆํ˜ธ + ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ธฐ์ค€) +============================================================ + +๐Ÿ“Š ์ „์ฒด ํ†ต๊ณ„ +------------------------------------------------------------ +์ด ๋ฌธ์ œ ์ˆ˜: 290๊ฐœ +์ •๋‹ต: 287๊ฐœ (98.97%) +์˜ค๋‹ต: 3๊ฐœ (1.03%) +None: 0๊ฐœ (0.00%) +๋ˆ„๋ฝ: 0๊ฐœ (0.00%) + +============================================================ +๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: 98.97% +๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): 100.00% +โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„: 98.97% +============================================================ + + +๐Ÿ“Š ์œ ํ˜•๋ณ„ ํ†ต๊ณ„ +------------------------------------------------------------ + +์œ ํ˜•: answer_1_o + ์ด ๋ฌธ์ œ: 45.0๊ฐœ + ์ •๋‹ต: 42.0๊ฐœ (93.33%) + ์˜ค๋‹ต: 3.0๊ฐœ (6.67%) + None: 0.0๊ฐœ (0.00%) + ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%) + +์œ ํ˜•: answer_12_oo + ์ด ๋ฌธ์ œ: 29.0๊ฐœ + ์ •๋‹ต: 29.0๊ฐœ (100.00%) + ์˜ค๋‹ต: 0.0๊ฐœ (0.00%) + None: 0.0๊ฐœ (0.00%) + ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%) + +์œ ํ˜•: answer_12_xo + ์ด ๋ฌธ์ œ: 27.0๊ฐœ + ์ •๋‹ต: 27.0๊ฐœ (100.00%) + ์˜ค๋‹ต: 0.0๊ฐœ (0.00%) + None: 0.0๊ฐœ (0.00%) + ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%) + +์œ ํ˜•: answer_12_ox + ์ด ๋ฌธ์ œ: 27.0๊ฐœ + ์ •๋‹ต: 27.0๊ฐœ (100.00%) + ์˜ค๋‹ต: 0.0๊ฐœ (0.00%) + None: 0.0๊ฐœ (0.00%) + ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%) + +์œ ํ˜•: answer_12_xx + ์ด ๋ฌธ์ œ: 27.0๊ฐœ + ์ •๋‹ต: 27.0๊ฐœ (100.00%) + ์˜ค๋‹ต: 0.0๊ฐœ (0.00%) + None: 0.0๊ฐœ (0.00%) + ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%) + +์œ ํ˜•: answer_1_x + ์ด ๋ฌธ์ œ: 45.0๊ฐœ + ์ •๋‹ต: 45.0๊ฐœ (100.00%) + ์˜ค๋‹ต: 0.0๊ฐœ (0.00%) + None: 0.0๊ฐœ (0.00%) + ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%) + +์œ ํ˜•: answer_2_o + ์ด ๋ฌธ์ œ: 45.0๊ฐœ + ์ •๋‹ต: 45.0๊ฐœ (100.00%) + ์˜ค๋‹ต: 0.0๊ฐœ (0.00%) + None: 0.0๊ฐœ (0.00%) + ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%) + +์œ ํ˜•: answer_2_x + ์ด ๋ฌธ์ œ: 45.0๊ฐœ + ์ •๋‹ต: 45.0๊ฐœ (100.00%) + ์˜ค๋‹ต: 0.0๊ฐœ (0.00%) + None: 0.0๊ฐœ (0.00%) + ๋ˆ„๋ฝ: 0.0๊ฐœ (0.00%) + +โŒ ์˜ค๋‹ต: 3๊ฐœ +------------------------------------------------------------ +ํŽ˜์ด์ง€ 105, ๋ฌธ์ œ 04, ์œ ํ˜• answer_1_o, ์ •๋‹ต 4, ์˜ˆ์ธก 5 +ํŽ˜์ด์ง€ 106, ๋ฌธ์ œ 10, ์œ ํ˜• answer_1_o, ์ •๋‹ต 4, ์˜ˆ์ธก 1 +ํŽ˜์ด์ง€ 112, ๋ฌธ์ œ 25, ์œ ํ˜• answer_1_o, ์ •๋‹ต 4, ์˜ˆ์ธก 2 diff --git a/ai-service/test/Hierarchical_crop/answers/answer.txt b/ai-service/test/Hierarchical_crop/answers/answer.txt new file mode 100644 index 0000000..db6a69c --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/answer.txt @@ -0,0 +1,290 @@ +9, 01, 4 +10, 02, 4 +11, 03, 3 +12, 04, 5 +13, 05, 4 +15, 01, 1 +16, 02, 3 +17, 03, 5 +18, 04, 5 +19, 05, 5 +21, 01, 3 +22, 02, 1 +23, 03, 1 +24, 04, 5 +25, 05, 5 +27, 01, 1 +28, 02, 5 +29, 03, 5 +30, 04, 1 +31, 05, 3 +33, 01, 3 +34, 02, 4 +35, 03, 3 +36, 04, 5 +37, 05, 2 +39, 01, 4 +40, 02, 4 +41, 03, 4 +42, 04, 3 +43, 05, 3 +45, 01, 3 +46, 02, 1 +47, 03, 4 +48, 04, 2 +49, 05, 2 +51, 01, 1 +52, 02, 3 +53, 03, 1 +54, 04, 2 +55, 05, 4 +57, 01, 4 +58, 02, 3 +59, 03, 4 +60, 04, 4 +61, 05, 3 +63, 01, 4 +64, 02, 3 +65, 03, 2 +66, 04, 4 +67, 05, 4 +69, 01, 3 +70, 02, 5 +71, 03, 5 +72, 04, 4 +73, 05, 3 +75, 01, 4 +76, 02, 4 +77, 03, 2 +78, 04, 3 +79, 05, 2 +83, 01, 5 +83, 02, 1 +85, 03, 4 +85, 04, 5 +85, 05, 2 +88, 01, 1 +88, 02, 3 +88, 03, 2 +88, 04, 5 +88, 05, 2 +89, 06, 3 +89, 07, 2 +89, 08, 3 +89, 09, 2 +89, 10, 4 +90, 11, 5 +90, 12, 1 +90, 13, 1 +90, 14, 3 +90, 15, 4 +91, 16, 5 +91, 17, 3 +91, 18, 5 +92, 19, 1 +92, 20, 2 +93, 21, 1 +93, 22, 1 +94, 23, 2 +94, 24, 1 +95, 25, 5 +95, 26, 4 +96, 27, 4 +96, 28, 5 +97, 29, 4 +97, 30, 3 +98, 31, 1 +98, 32, 3 +99, 33, 2 +99, 34, 1 +100, 35, 3 +100, 36, 4 +101, 37, 5 +101, 38, 4 +102, 39, 4 +102, 40, 1 +103, 41, 4 +103, 42, 5 +104, 43, 5 +104, 44, 3 +104, 45, 2 +105, 01, 2 +105, 02, 3 +105, 03, 3 +105, 04, 4 +105, 05, 2 +106, 06, 4 +106, 07, 5 +106, 08, 3 +106, 09, 5 +106, 10, 4 +107, 11, 2 +107, 12, 1 +107, 13, 1 +107, 14, 1 +107, 15, 3 +108, 16, 4 +108, 17, 4 +108, 18, 5 +109, 19, 1 +109, 20, 3 +110, 21, 5 +110, 22, 1 +111, 23, 5 +111, 24, 2 +112, 25, 4 +112, 26, 2 +113, 27, 4 +113, 28, 4 +114, 29, 3 +114, 30, 4 +115, 31, 2 +115, 32, 2 +116, 33, 1 +116, 34, 1 +117, 35, 3 +117, 36, 2 +118, 37, 5 +118, 38, 3 +119, 39, 3 +119, 40, 4 +120, 41, 4 +120, 42, 4 +121, 43, 4 +121, 44, 2 +121, 45, 5 +122, 01, 5 +122, 02, 3 +122, 03, 2 +122, 04, 5 +122, 05, 3 +123, 06, 3 +123, 07, 1 +123, 08, 4 +123, 09, 4 +123, 10, 3 +124, 11, 5 +124, 12, 4 +124, 13, 5 +124, 14, 3 +124, 15, 5 +125, 16, 3 +125, 17, 4 +125, 18, 1 +126, 19, 2 +126, 20, 1 +127, 21, 2 +127, 22, 1 +128, 23, 1 +128, 24, 1 +129, 25, 5 +129, 26, 4 +130, 27, 4 +130, 28, 5 +131, 29, 3 +131, 30, 4 +132, 31, 2 +132, 32, 2 +133, 33, 3 +133, 34, 1 +134, 35, 4 +134, 36, 4 +135, 37, 2 +135, 38, 5 +136, 39, 4 +136, 40, 1 +137, 41, 2 +137, 42, 5 +138, 43, 5 +138, 44, 3 +138, 45, 4 +139, 01, 1 +139, 02, 2 +139, 03, 5 +139, 04, 3 +139, 05, 1 +140, 06, 5 +140, 07, 2 +140, 08, 5 +140, 09, 5 +140, 10, 1 +141, 11, 1 +141, 12, 2 +141, 13, 4 +141, 14, 5 +141, 15, 2 +142, 16, 1 +142, 17, 3 +142, 18, 3 +143, 19, 2 +143, 20, 4 +144, 21, 4 +144, 22, 1 +145, 23, 4 +145, 24, 2 +146, 25, 5 +146, 26, 5 +147, 27, 4 +147, 28, 3 +148, 29, 4 +148, 30, 3 +149, 31, 4 +149, 32, 2 +150, 33, 4 +150, 34, 2 +151, 35, 4 +151, 36, 4 +152, 37, 3 +152, 38, 3 +153, 39, 3 +153, 40, 1 +154, 41, 1 +154, 42, 5 +155, 43, 2 +155, 44, 2 +155, 45, 2 +156, 01, 1 +156, 02, 1 +156, 03, 3 +156, 04, 3 +156, 05, 3 +157, 06, 2 +157, 07, 4 +157, 08, 4 +157, 09, 4 +157, 10, 4 +158, 11, 1 +158, 12, 2 +158, 13, 4 +158, 14, 5 +158, 15, 5 +159, 16, 4 +159, 17, 3 +159, 18, 5 +160, 19, 3 +160, 20, 1 +161, 21, 3 +161, 22, 2 +162, 23, 1 +162, 24, 1 +163, 25, 3 +163, 26, 4 +164, 27, 4 +164, 28, 5 +165, 29, 4 +165, 30, 5 +166, 31, 2 +166, 32, 5 +167, 33, 3 +167, 34, 2 +168, 35, 4 +168, 36, 5 +169, 37, 1 +169, 38, 3 +170, 39, 2 +170, 40, 2 +171, 41, 5 +171, 42, 5 +172, 43, 2 +172, 44, 2 +172, 45, 3 \ No newline at end of file diff --git a/ai-service/test/Hierarchical_crop/answers/answer_source_analysis.txt b/ai-service/test/Hierarchical_crop/answers/answer_source_analysis.txt new file mode 100644 index 0000000..97a2d00 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/answer_source_analysis.txt @@ -0,0 +1,85 @@ +================================================================================ +๋‹ต์•ˆ ์ถœ์ฒ˜(answer_source)๋ณ„ ํ†ต๊ณ„ +================================================================================ + +์ด Section ์ˆ˜: 292๊ฐœ + +๐Ÿ“Š ์ถœ์ฒ˜๋ณ„ ํ†ต๊ณ„: + - answer_2_resnet: 202๊ฐœ (69.2%) + - answer_1_resnet: 87๊ฐœ (29.8%) + - answer_1_yolo: 1๊ฐœ (0.3%) + - other: 2๊ฐœ (0.7%) + +โœ… ์ „์ฒด ์„ฑ๊ณต๋ฅ : 290/292 (99.3%) +โŒ ์ „์ฒด ์‹คํŒจ์œจ: 2/292 (0.7%) + +๐ŸŽฏ answer_2 ์šฐ์„  ์ „๋žต: + - answer_2๋กœ ํ•ด๊ฒฐ: 202๊ฐœ (69.2%) + - answer_2 ResNet ํ‰๊ท  ์‹ ๋ขฐ๋„: 0.9993 + + +================================================================================ +ANSWER_2_RESNET (202๊ฐœ) +================================================================================ + +[1] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, Section: 3, ๋ฌธ์ œ: 10, ๋‹ต: 1, ์‹ ๋ขฐ๋„: 0.9993 + +[2] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25, Section: 0, ๋ฌธ์ œ: 25, ๋‹ต: 2, ์‹ ๋ขฐ๋„: 0.9989 + +[3] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, Section: 0, ๋ฌธ์ œ: 04, ๋‹ต: 3, ์‹ ๋ขฐ๋„: 0.9924 + +[4] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, Section: 1, ๋ฌธ์ œ: 01, ๋‹ต: 4, ์‹ ๋ขฐ๋„: 1.0000 + +[5] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, Section: 2, ๋ฌธ์ œ: 02, ๋‹ต: 2, ์‹ ๋ขฐ๋„: 1.0000 + +[6] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, Section: 3, ๋ฌธ์ œ: 05, ๋‹ต: 2, ์‹ ๋ขฐ๋„: 0.9998 + +[7] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, Section: 4, ๋ฌธ์ œ: 03, ๋‹ต: 1, ์‹ ๋ขฐ๋„: 1.0000 + +[8] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36, Section: 0, ๋ฌธ์ œ: 06, ๋‹ต: 1, ์‹ ๋ขฐ๋„: 1.0000 + +[9] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36, Section: 1, ๋ฌธ์ œ: 09, ๋‹ต: 5, ์‹ ๋ขฐ๋„: 0.9635 + +[10] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36, Section: 2, ๋ฌธ์ œ: 07, ๋‹ต: 2, ์‹ ๋ขฐ๋„: 0.9999 + +... (์™ธ 192๊ฐœ) + +================================================================================ +ANSWER_1_RESNET (87๊ฐœ) +================================================================================ + +[1] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, Section: 0, ๋ฌธ์ œ: 04, ๋‹ต: 3, ์‹ ๋ขฐ๋„: 0.9710 + +[2] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, Section: 1, ๋ฌธ์ œ: 01, ๋‹ต: 4, ์‹ ๋ขฐ๋„: 0.9989 + +[3] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, Section: 2, ๋ฌธ์ œ: 02, ๋‹ต: 2, ์‹ ๋ขฐ๋„: 0.9952 + +[4] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, Section: 3, ๋ฌธ์ œ: 05, ๋‹ต: 3, ์‹ ๋ขฐ๋„: 0.9943 + +[5] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, Section: 4, ๋ฌธ์ œ: 03, ๋‹ต: 3, ์‹ ๋ขฐ๋„: 0.9990 + +[6] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10, Section: 0, ๋ฌธ์ œ: 29, ๋‹ต: 3, ์‹ ๋ขฐ๋„: 0.9648 + +[7] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10, Section: 1, ๋ฌธ์ œ: 30, ๋‹ต: 2, ์‹ ๋ขฐ๋„: 0.9939 + +[8] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11, Section: 0, ๋ฌธ์ œ: 32, ๋‹ต: 5, ์‹ ๋ขฐ๋„: 0.5118 + +[9] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11, Section: 1, ๋ฌธ์ œ: 31, ๋‹ต: 3, ์‹ ๋ขฐ๋„: 0.9581 + +[10] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12, Section: 0, ๋ฌธ์ œ: 34, ๋‹ต: 4, ์‹ ๋ขฐ๋„: 0.9895 + +... (์™ธ 77๊ฐœ) + +================================================================================ +ANSWER_1_YOLO (1๊ฐœ) +================================================================================ + +[1] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31, Section: 0, ๋ฌธ์ œ: 37, ๋‹ต: 5, ์‹ ๋ขฐ๋„: 0.6847 + +================================================================================ +OTHER (2๊ฐœ) +================================================================================ + +[1] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 50, Section: 1, ๋ฌธ์ œ: None, ๋‹ต: None + +[2] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 67, Section: 2, ๋ฌธ์ œ: None, ๋‹ต: None diff --git a/ai-service/test/Hierarchical_crop/answers/crop_failure_analysis.txt b/ai-service/test/Hierarchical_crop/answers/crop_failure_analysis.txt new file mode 100644 index 0000000..7da16d2 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/crop_failure_analysis.txt @@ -0,0 +1,12 @@ +================================================================================ +Section Crop ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„ +================================================================================ + +์ด 2๊ฐœ์˜ Section crop ์‹คํŒจ ๋ฐœ๊ฒฌ + +[1] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 50, Section: 1 + ์‹คํŒจ ์›์ธ: invalid_bbox + +[2] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 67, Section: 2 + ์‹คํŒจ ์›์ธ: invalid_bbox + diff --git a/ai-service/test/Hierarchical_crop/answers/detailed_comparison.csv b/ai-service/test/Hierarchical_crop/answers/detailed_comparison.csv new file mode 100644 index 0000000..41cbccc --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/detailed_comparison.csv @@ -0,0 +1,291 @@ +๏ปฟpage_number,problem_number,correct_answer,problem_type,file_name,predicted_answer,_merge,result +9,01,4,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1,4,both,correct +10,02,4,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2,4,both,correct +11,03,3,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3,3,both,correct +12,04,5,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4,5,both,correct +13,05,4,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5,4,both,correct +15,01,1,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6,1,both,correct +16,02,3,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7,3,both,correct +17,03,5,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8,5,both,correct +18,04,5,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9,5,both,correct +19,05,5,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10,5,both,correct +21,01,3,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11,3,both,correct +22,02,2,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 12,2,both,correct +23,03,4,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 13,4,both,correct +24,04,1,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14,1,both,correct +25,05,1,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 15,1,both,correct +27,01,3,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 16,3,both,correct +28,02,4,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 17,4,both,correct +29,03,4,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 18,4,both,correct +30,04,2,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 19,2,both,correct +31,05,1,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 20,1,both,correct +33,01,5,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 21,5,both,correct +34,02,1,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 22,1,both,correct +35,03,2,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 23,2,both,correct +36,04,1,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 24,1,both,correct +37,05,3,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 25,3,both,correct +39,01,2,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 26,2,both,correct +40,02,2,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 27,2,both,correct +41,03,5,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 28,5,both,correct +42,04,1,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 29,1,both,correct +43,05,1,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 30,1,both,correct +45,01,2,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 31,2,both,correct +46,02,5,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 32,5,both,correct +47,03,2,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 33,2,both,correct +48,04,3,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 34,3,both,correct +49,05,4,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 35,4,both,correct +51,01,5,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 36,5,both,correct +52,02,1,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 37,1,both,correct +53,03,3,answer_12_ox,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 38,3,both,correct +54,04,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 39,3,both,correct +55,05,2,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 40,2,both,correct +57,01,2,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 41,2,both,correct +58,02,4,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 42,4,both,correct +59,03,2,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 43,2,both,correct +60,04,2,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 44,2,both,correct +61,05,1,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 45,1,both,correct +63,01,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 46,3,both,correct +64,02,1,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 47,1,both,correct +65,03,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 48,3,both,correct +66,04,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 49,3,both,correct +67,05,2,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 50,2,both,correct +69,01,4,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 51,4,both,correct +70,02,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 52,3,both,correct +71,03,4,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 53,4,both,correct +72,04,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 54,3,both,correct +73,05,4,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 55,4,both,correct +75,01,2,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 56,2,both,correct +76,02,2,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 57,2,both,correct +77,03,4,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 58,4,both,correct +78,04,4,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 59,4,both,correct +79,05,4,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 60,4,both,correct +83,01,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62,3,both,correct +83,02,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62,3,both,correct +85,03,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64,3,both,correct +85,04,4,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64,4,both,correct +85,05,3,answer_12_xx,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64,3,both,correct +88,01,4,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,4,both,correct +88,02,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,2,both,correct +88,03,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,3,both,correct +88,04,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,3,both,correct +88,05,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,3,both,correct +89,06,4,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,4,both,correct +89,07,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,3,both,correct +89,08,1,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,1,both,correct +89,09,4,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,4,both,correct +89,10,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,2,both,correct +90,11,4,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,4,both,correct +90,12,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,3,both,correct +90,13,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,3,both,correct +90,14,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,2,both,correct +90,15,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,3,both,correct +91,16,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4,3,both,correct +91,17,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4,2,both,correct +91,18,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4,3,both,correct +92,19,4,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5,4,both,correct +92,20,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5,3,both,correct +93,21,5,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6,5,both,correct +93,22,4,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6,4,both,correct +94,23,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7,3,both,correct +94,24,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7,2,both,correct +95,25,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8,2,both,correct +95,26,5,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8,5,both,correct +96,27,5,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9,5,both,correct +96,28,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9,2,both,correct +97,29,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10,3,both,correct +97,30,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10,2,both,correct +98,31,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11,3,both,correct +98,32,5,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11,5,both,correct +99,33,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12,3,both,correct +99,34,4,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12,4,both,correct +100,35,4,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13,4,both,correct +100,36,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13,3,both,correct +101,37,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14,2,both,correct +101,38,5,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14,5,both,correct +102,39,3,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15,3,both,correct +102,40,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15,2,both,correct +103,41,5,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16,5,both,correct +103,42,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16,2,both,correct +104,43,4,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17,4,both,correct +104,44,2,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17,2,both,correct +104,45,1,answer_1_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17,1,both,correct +105,01,2,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,2,both,correct +105,02,3,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,3,both,correct +105,03,3,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,3,both,correct +105,04,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,5,both,wrong +105,05,2,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,2,both,correct +106,06,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,4,both,correct +106,07,5,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,5,both,correct +106,08,3,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,3,both,correct +106,09,5,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,5,both,correct +106,10,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,1,both,wrong +107,11,2,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,2,both,correct +107,12,1,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,1,both,correct +107,13,1,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,1,both,correct +107,14,1,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,1,both,correct +107,15,3,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,3,both,correct +108,16,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21,4,both,correct +108,17,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21,4,both,correct +108,18,5,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21,5,both,correct +109,19,1,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22,1,both,correct +109,20,3,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22,3,both,correct +110,21,5,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23,5,both,correct +110,22,1,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23,1,both,correct +111,23,5,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24,5,both,correct +111,24,2,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24,2,both,correct +112,25,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25,2,both,wrong +112,26,2,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25,2,both,correct +113,27,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26,4,both,correct +113,28,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26,4,both,correct +114,29,3,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27,3,both,correct +114,30,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27,4,both,correct +115,31,2,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28,2,both,correct +115,32,2,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28,2,both,correct +116,33,1,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29,1,both,correct +116,34,1,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29,1,both,correct +117,35,3,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30,3,both,correct +117,36,2,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30,2,both,correct +118,37,5,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31,5,both,correct +118,38,3,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31,3,both,correct +119,39,3,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32,3,both,correct +119,40,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32,4,both,correct +120,41,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33,4,both,correct +120,42,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33,4,both,correct +121,43,4,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34,4,both,correct +121,44,2,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34,2,both,correct +121,45,5,answer_1_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34,5,both,correct +122,01,4,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35,4,both,correct +122,02,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35,2,both,correct +122,03,1,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35,1,both,correct +122,04,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35,3,both,correct +122,05,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35,2,both,correct +123,06,1,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36,1,both,correct +123,07,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36,2,both,correct +123,08,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36,3,both,correct +123,09,5,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36,5,both,correct +123,10,4,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36,4,both,correct +124,11,4,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37,4,both,correct +124,12,5,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37,5,both,correct +124,13,4,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37,4,both,correct +124,14,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37,2,both,correct +124,15,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37,3,both,correct +125,16,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 38,2,both,correct +125,17,5,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 38,5,both,correct +125,18,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 38,2,both,correct +126,19,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 39,3,both,correct +126,20,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 39,2,both,correct +127,21,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 40,3,both,correct +127,22,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 40,2,both,correct +128,23,4,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 41,4,both,correct +128,24,5,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 41,5,both,correct +129,25,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 42,2,both,correct +129,26,5,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 42,5,both,correct +130,27,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 43,3,both,correct +130,28,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 43,2,both,correct +131,29,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 44,2,both,correct +131,30,5,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 44,5,both,correct +132,31,1,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 45,1,both,correct +132,32,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 45,3,both,correct +133,33,4,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 46,4,both,correct +133,34,5,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 46,5,both,correct +134,35,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 47,2,both,correct +134,36,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 47,3,both,correct +135,37,1,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 48,1,both,correct +135,38,4,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 48,4,both,correct +136,39,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 49,3,both,correct +136,40,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 49,2,both,correct +137,41,3,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 50,3,both,correct +137,42,1,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 50,1,both,correct +138,43,4,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 51,4,both,correct +138,44,2,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 51,2,both,correct +138,45,1,answer_2_x,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 51,1,both,correct +139,01,1,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52,1,both,correct +139,02,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52,2,both,correct +139,03,5,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52,5,both,correct +139,04,3,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52,3,both,correct +139,05,1,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52,1,both,correct +140,06,5,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53,5,both,correct +140,07,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53,2,both,correct +140,08,5,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53,5,both,correct +140,09,5,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53,5,both,correct +140,10,1,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53,1,both,correct +141,11,1,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54,1,both,correct +141,12,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54,2,both,correct +141,13,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54,4,both,correct +141,14,5,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54,5,both,correct +141,15,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54,2,both,correct +142,16,1,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 55,1,both,correct +142,17,3,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 55,3,both,correct +142,18,3,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 55,3,both,correct +143,19,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 56,2,both,correct +143,20,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 56,4,both,correct +144,21,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 57,4,both,correct +144,22,1,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 57,1,both,correct +145,23,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 58,4,both,correct +145,24,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 58,2,both,correct +146,25,5,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 59,5,both,correct +146,26,5,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 59,5,both,correct +147,27,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 60,4,both,correct +147,28,3,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 60,3,both,correct +148,29,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 61,4,both,correct +148,30,3,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 61,3,both,correct +149,31,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 62,4,both,correct +149,32,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 62,2,both,correct +150,33,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 63,4,both,correct +150,34,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 63,2,both,correct +151,35,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 64,4,both,correct +151,36,4,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 64,4,both,correct +152,37,3,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 65,3,both,correct +152,38,3,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 65,3,both,correct +153,39,3,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 66,3,both,correct +153,40,1,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 66,1,both,correct +154,41,1,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 67,1,both,correct +154,42,5,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 67,5,both,correct +155,43,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 68,2,both,correct +155,44,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 68,2,both,correct +155,45,2,answer_2_o,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 68,2,both,correct +156,01,1,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69,1,both,correct +156,02,1,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69,1,both,correct +156,03,3,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69,3,both,correct +156,04,3,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69,3,both,correct +156,05,3,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69,3,both,correct +157,06,2,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70,2,both,correct +157,07,4,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70,4,both,correct +157,08,4,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70,4,both,correct +157,09,4,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70,4,both,correct +157,10,4,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70,4,both,correct +158,11,1,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71,1,both,correct +158,12,2,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71,2,both,correct +158,13,4,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71,4,both,correct +158,14,5,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71,5,both,correct +158,15,5,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71,5,both,correct +159,16,4,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 72,4,both,correct +159,17,3,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 72,3,both,correct +159,18,5,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 72,5,both,correct +160,19,3,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 73,3,both,correct +160,20,1,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 73,1,both,correct +161,21,3,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 74,3,both,correct +161,22,2,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 74,2,both,correct +162,23,1,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 75,1,both,correct +162,24,1,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 75,1,both,correct +163,25,3,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 76,3,both,correct +163,26,4,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 76,4,both,correct +164,27,4,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 77,4,both,correct +164,28,5,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 77,5,both,correct +165,29,4,answer_12_oo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 78,4,both,correct +165,30,5,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 78,5,both,correct +166,31,2,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 79,2,both,correct +166,32,5,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 79,5,both,correct +167,33,3,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 80,3,both,correct +167,34,2,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 80,2,both,correct +168,35,4,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 81,4,both,correct +168,36,5,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 81,5,both,correct +169,37,1,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 82,1,both,correct +169,38,3,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 82,3,both,correct +170,39,2,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 83,2,both,correct +170,40,2,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 83,2,both,correct +171,41,5,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 84,5,both,correct +171,42,5,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 84,5,both,correct +172,43,2,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 85,2,both,correct +172,44,2,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 85,2,both,correct +172,45,3,answer_12_xo,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 85,3,both,correct diff --git a/ai-service/test/Hierarchical_crop/answers/file_statistics.csv b/ai-service/test/Hierarchical_crop/answers/file_statistics.csv new file mode 100644 index 0000000..0e84232 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/file_statistics.csv @@ -0,0 +1,148 @@ +๏ปฟimage_file,total,correct,wrong,none,missing,accuracy +10,1,0,0,0,1,0.0 +100,2,0,0,0,2,0.0 +101,2,0,0,0,2,0.0 +102,2,0,0,0,2,0.0 +103,2,0,0,0,2,0.0 +104,3,0,0,0,3,0.0 +105,5,0,0,0,5,0.0 +106,5,0,0,0,5,0.0 +107,5,0,0,0,5,0.0 +108,3,0,0,0,3,0.0 +109,2,0,0,0,2,0.0 +11,1,0,0,0,1,0.0 +110,2,0,0,0,2,0.0 +111,2,0,0,0,2,0.0 +112,2,0,0,0,2,0.0 +113,2,0,0,0,2,0.0 +114,2,0,0,0,2,0.0 +115,2,0,0,0,2,0.0 +116,2,0,0,0,2,0.0 +117,2,0,0,0,2,0.0 +118,2,0,0,0,2,0.0 +119,2,0,0,0,2,0.0 +12,1,0,0,0,1,0.0 +120,2,0,0,0,2,0.0 +121,3,0,0,0,3,0.0 +122,5,0,0,0,5,0.0 +123,5,0,0,0,5,0.0 +124,5,0,0,0,5,0.0 +125,3,0,0,0,3,0.0 +126,2,0,0,0,2,0.0 +127,2,0,0,0,2,0.0 +128,2,0,0,0,2,0.0 +129,2,0,0,0,2,0.0 +13,1,0,0,0,1,0.0 +130,2,0,0,0,2,0.0 +131,2,0,0,0,2,0.0 +132,2,0,0,0,2,0.0 +133,2,0,0,0,2,0.0 +134,2,0,0,0,2,0.0 +135,2,0,0,0,2,0.0 +136,2,0,0,0,2,0.0 +137,2,0,0,0,2,0.0 +138,3,0,0,0,3,0.0 +139,5,0,0,0,5,0.0 +140,5,0,0,0,5,0.0 +141,5,0,0,0,5,0.0 +142,3,0,0,0,3,0.0 +143,2,0,0,0,2,0.0 +144,2,0,0,0,2,0.0 +145,2,0,0,0,2,0.0 +146,2,0,0,0,2,0.0 +147,2,0,0,0,2,0.0 +148,2,0,0,0,2,0.0 +149,2,0,0,0,2,0.0 +15,1,0,0,0,1,0.0 +150,2,0,0,0,2,0.0 +151,2,0,0,0,2,0.0 +152,2,0,0,0,2,0.0 +153,2,0,0,0,2,0.0 +154,2,0,0,0,2,0.0 +155,3,0,0,0,3,0.0 +156,5,0,0,0,5,0.0 +157,5,0,0,0,5,0.0 +158,5,0,0,0,5,0.0 +159,3,0,0,0,3,0.0 +16,1,0,0,0,1,0.0 +160,2,0,0,0,2,0.0 +161,2,0,0,0,2,0.0 +162,2,0,0,0,2,0.0 +163,2,0,0,0,2,0.0 +164,2,0,0,0,2,0.0 +165,2,0,0,0,2,0.0 +166,2,0,0,0,2,0.0 +167,2,0,0,0,2,0.0 +168,2,0,0,0,2,0.0 +169,2,0,0,0,2,0.0 +17,1,0,0,0,1,0.0 +170,2,0,0,0,2,0.0 +171,2,0,0,0,2,0.0 +172,3,0,0,0,3,0.0 +18,1,0,0,0,1,0.0 +19,1,0,0,0,1,0.0 +21,1,0,0,0,1,0.0 +22,1,0,0,0,1,0.0 +23,1,0,0,0,1,0.0 +24,1,0,0,0,1,0.0 +25,1,0,0,0,1,0.0 +27,1,0,0,0,1,0.0 +28,1,0,0,0,1,0.0 +29,1,0,0,0,1,0.0 +30,1,0,0,0,1,0.0 +31,1,0,0,0,1,0.0 +33,1,0,0,0,1,0.0 +34,1,0,0,0,1,0.0 +35,1,0,0,0,1,0.0 +36,1,0,0,0,1,0.0 +37,1,0,0,0,1,0.0 +39,1,0,0,0,1,0.0 +40,1,0,0,0,1,0.0 +41,1,0,0,0,1,0.0 +42,1,0,0,0,1,0.0 +43,1,0,0,0,1,0.0 +45,1,0,0,0,1,0.0 +46,1,0,0,0,1,0.0 +47,1,0,0,0,1,0.0 +48,1,0,0,0,1,0.0 +49,1,0,0,0,1,0.0 +51,1,0,0,0,1,0.0 +52,1,0,0,0,1,0.0 +53,1,0,0,0,1,0.0 +54,1,0,0,0,1,0.0 +55,1,0,0,0,1,0.0 +57,1,0,0,0,1,0.0 +58,1,0,0,0,1,0.0 +59,1,0,0,0,1,0.0 +60,1,0,0,0,1,0.0 +61,1,0,0,0,1,0.0 +63,1,0,0,0,1,0.0 +64,1,0,0,0,1,0.0 +65,1,0,0,0,1,0.0 +66,1,0,0,0,1,0.0 +67,1,0,0,0,1,0.0 +69,1,0,0,0,1,0.0 +70,1,0,0,0,1,0.0 +71,1,0,0,0,1,0.0 +72,1,0,0,0,1,0.0 +73,1,0,0,0,1,0.0 +75,1,0,0,0,1,0.0 +76,1,0,0,0,1,0.0 +77,1,0,0,0,1,0.0 +78,1,0,0,0,1,0.0 +79,1,0,0,0,1,0.0 +83,2,0,0,0,2,0.0 +85,3,0,0,0,3,0.0 +88,5,0,0,0,5,0.0 +89,5,0,0,0,5,0.0 +9,1,0,0,0,1,0.0 +90,5,0,0,0,5,0.0 +91,3,0,0,0,3,0.0 +92,2,0,0,0,2,0.0 +93,2,0,0,0,2,0.0 +94,2,0,0,0,2,0.0 +95,2,0,0,0,2,0.0 +96,2,0,0,0,2,0.0 +97,2,0,0,0,2,0.0 +98,2,0,0,0,2,0.0 +99,2,0,0,0,2,0.0 diff --git a/ai-service/test/Hierarchical_crop/answers/missing_sections_analysis.txt b/ai-service/test/Hierarchical_crop/answers/missing_sections_analysis.txt new file mode 100644 index 0000000..4475365 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/missing_sections_analysis.txt @@ -0,0 +1,12 @@ +================================================================================ +๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ Section ๋ถ„์„ +================================================================================ + +์ด 2๊ฐœ ํŽ˜์ด์ง€์—์„œ ๋ถˆ์ผ์น˜ ๋ฐœ๊ฒฌ + +ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 50 + ์˜ˆ์ƒ: 2๊ฐœ, ์‹ค์ œ: 3๊ฐœ + +ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 67 + ์˜ˆ์ƒ: 2๊ฐœ, ์‹ค์ œ: 3๊ฐœ + diff --git a/ai-service/test/Hierarchical_crop/answers/none_debug_analysis.txt b/ai-service/test/Hierarchical_crop/answers/none_debug_analysis.txt new file mode 100644 index 0000000..20fa41d --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/none_debug_analysis.txt @@ -0,0 +1,48 @@ +================================================================================ +None ๋‹ต์•ˆ ๋””๋ฒ„๊น… ๋ถ„์„ (answer_2 ์šฐ์„  + ResNet) +================================================================================ + +์ด 2๊ฐœ์˜ None ๋‹ต์•ˆ ๋ฐœ๊ฒฌ + +๐Ÿ“Š ์›์ธ๋ณ„ ํ†ต๊ณ„: + - answer_1 ๋ฏธ๊ฒ€์ถœ: 2๊ฐœ + - answer_2 ๋ฏธ๊ฒ€์ถœ: 2๊ฐœ + - ResNet ์‹œ๋„: 0๊ฐœ (0.0%) + - ResNet๋„ ์‹คํŒจ: 0๊ฐœ (0.0%) + + +================================================================================ +[1] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 50 (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: 137) + Section: 1, ๋ฌธ์ œ๋ฒˆํ˜ธ: None +-------------------------------------------------------------------------------- + ๐Ÿ“‹ ๊ฒ€์ถœ ์ •๋ณด: + answer_1 ๊ฒ€์ถœ ๊ฐœ์ˆ˜: 0 + answer_2 ๊ฒ€์ถœ ๊ฐœ์ˆ˜: 0 + ResNet ์‹œ๋„: ์•„๋‹ˆ์˜ค + answer_source: None + + ๐Ÿ” ์›์ธ ๋ถ„์„: + โŒ answer_1๊ณผ answer_2 ๋ชจ๋‘ ๊ฒ€์ถœ๋˜์ง€ ์•Š์Œ (1104 ๋ชจ๋ธ ๋ฌธ์ œ) + โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: 1104 ๋ชจ๋ธ ์žฌํ•™์Šต ๋˜๋Š” confidence threshold ์กฐ์ • + + ๐Ÿ“ ๊ด€๋ จ ํŒŒ์ผ: + Section ์ด๋ฏธ์ง€: None + ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€: (๋ฏธ์ƒ์„ฑ - ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ) + +================================================================================ +[2] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 67 (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: 154) + Section: 2, ๋ฌธ์ œ๋ฒˆํ˜ธ: None +-------------------------------------------------------------------------------- + ๐Ÿ“‹ ๊ฒ€์ถœ ์ •๋ณด: + answer_1 ๊ฒ€์ถœ ๊ฐœ์ˆ˜: 0 + answer_2 ๊ฒ€์ถœ ๊ฐœ์ˆ˜: 0 + ResNet ์‹œ๋„: ์•„๋‹ˆ์˜ค + answer_source: None + + ๐Ÿ” ์›์ธ ๋ถ„์„: + โŒ answer_1๊ณผ answer_2 ๋ชจ๋‘ ๊ฒ€์ถœ๋˜์ง€ ์•Š์Œ (1104 ๋ชจ๋ธ ๋ฌธ์ œ) + โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: 1104 ๋ชจ๋ธ ์žฌํ•™์Šต ๋˜๋Š” confidence threshold ์กฐ์ • + + ๐Ÿ“ ๊ด€๋ จ ํŒŒ์ผ: + Section ์ด๋ฏธ์ง€: None + ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€: (๋ฏธ์ƒ์„ฑ - ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ) diff --git a/ai-service/test/Hierarchical_crop/answers/page_statistics.csv b/ai-service/test/Hierarchical_crop/answers/page_statistics.csv new file mode 100644 index 0000000..6faa691 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/page_statistics.csv @@ -0,0 +1,148 @@ +๏ปฟpage_number,total,correct,wrong,none,missing,accuracy +10,1,1,0,0,0,100.0 +100,2,2,0,0,0,100.0 +101,2,2,0,0,0,100.0 +102,2,2,0,0,0,100.0 +103,2,2,0,0,0,100.0 +104,3,3,0,0,0,100.0 +107,5,5,0,0,0,100.0 +109,2,2,0,0,0,100.0 +108,3,3,0,0,0,100.0 +110,2,2,0,0,0,100.0 +11,1,1,0,0,0,100.0 +115,2,2,0,0,0,100.0 +114,2,2,0,0,0,100.0 +111,2,2,0,0,0,100.0 +113,2,2,0,0,0,100.0 +116,2,2,0,0,0,100.0 +119,2,2,0,0,0,100.0 +118,2,2,0,0,0,100.0 +117,2,2,0,0,0,100.0 +22,1,1,0,0,0,100.0 +23,1,1,0,0,0,100.0 +24,1,1,0,0,0,100.0 +12,1,1,0,0,0,100.0 +120,2,2,0,0,0,100.0 +121,3,3,0,0,0,100.0 +122,5,5,0,0,0,100.0 +123,5,5,0,0,0,100.0 +124,5,5,0,0,0,100.0 +125,3,3,0,0,0,100.0 +126,2,2,0,0,0,100.0 +127,2,2,0,0,0,100.0 +128,2,2,0,0,0,100.0 +129,2,2,0,0,0,100.0 +13,1,1,0,0,0,100.0 +130,2,2,0,0,0,100.0 +131,2,2,0,0,0,100.0 +132,2,2,0,0,0,100.0 +133,2,2,0,0,0,100.0 +134,2,2,0,0,0,100.0 +135,2,2,0,0,0,100.0 +136,2,2,0,0,0,100.0 +137,2,2,0,0,0,100.0 +138,3,3,0,0,0,100.0 +139,5,5,0,0,0,100.0 +140,5,5,0,0,0,100.0 +141,5,5,0,0,0,100.0 +142,3,3,0,0,0,100.0 +143,2,2,0,0,0,100.0 +144,2,2,0,0,0,100.0 +145,2,2,0,0,0,100.0 +146,2,2,0,0,0,100.0 +147,2,2,0,0,0,100.0 +148,2,2,0,0,0,100.0 +149,2,2,0,0,0,100.0 +15,1,1,0,0,0,100.0 +150,2,2,0,0,0,100.0 +151,2,2,0,0,0,100.0 +152,2,2,0,0,0,100.0 +153,2,2,0,0,0,100.0 +154,2,2,0,0,0,100.0 +155,3,3,0,0,0,100.0 +156,5,5,0,0,0,100.0 +157,5,5,0,0,0,100.0 +158,5,5,0,0,0,100.0 +159,3,3,0,0,0,100.0 +16,1,1,0,0,0,100.0 +160,2,2,0,0,0,100.0 +161,2,2,0,0,0,100.0 +162,2,2,0,0,0,100.0 +163,2,2,0,0,0,100.0 +164,2,2,0,0,0,100.0 +165,2,2,0,0,0,100.0 +166,2,2,0,0,0,100.0 +167,2,2,0,0,0,100.0 +168,2,2,0,0,0,100.0 +169,2,2,0,0,0,100.0 +17,1,1,0,0,0,100.0 +170,2,2,0,0,0,100.0 +171,2,2,0,0,0,100.0 +172,3,3,0,0,0,100.0 +18,1,1,0,0,0,100.0 +19,1,1,0,0,0,100.0 +21,1,1,0,0,0,100.0 +60,1,1,0,0,0,100.0 +61,1,1,0,0,0,100.0 +63,1,1,0,0,0,100.0 +25,1,1,0,0,0,100.0 +27,1,1,0,0,0,100.0 +28,1,1,0,0,0,100.0 +29,1,1,0,0,0,100.0 +30,1,1,0,0,0,100.0 +31,1,1,0,0,0,100.0 +33,1,1,0,0,0,100.0 +34,1,1,0,0,0,100.0 +35,1,1,0,0,0,100.0 +36,1,1,0,0,0,100.0 +37,1,1,0,0,0,100.0 +39,1,1,0,0,0,100.0 +40,1,1,0,0,0,100.0 +41,1,1,0,0,0,100.0 +42,1,1,0,0,0,100.0 +43,1,1,0,0,0,100.0 +45,1,1,0,0,0,100.0 +46,1,1,0,0,0,100.0 +47,1,1,0,0,0,100.0 +48,1,1,0,0,0,100.0 +49,1,1,0,0,0,100.0 +51,1,1,0,0,0,100.0 +52,1,1,0,0,0,100.0 +53,1,1,0,0,0,100.0 +54,1,1,0,0,0,100.0 +55,1,1,0,0,0,100.0 +57,1,1,0,0,0,100.0 +58,1,1,0,0,0,100.0 +59,1,1,0,0,0,100.0 +79,1,1,0,0,0,100.0 +83,2,2,0,0,0,100.0 +85,3,3,0,0,0,100.0 +64,1,1,0,0,0,100.0 +65,1,1,0,0,0,100.0 +66,1,1,0,0,0,100.0 +67,1,1,0,0,0,100.0 +69,1,1,0,0,0,100.0 +70,1,1,0,0,0,100.0 +71,1,1,0,0,0,100.0 +72,1,1,0,0,0,100.0 +73,1,1,0,0,0,100.0 +75,1,1,0,0,0,100.0 +76,1,1,0,0,0,100.0 +77,1,1,0,0,0,100.0 +78,1,1,0,0,0,100.0 +92,2,2,0,0,0,100.0 +93,2,2,0,0,0,100.0 +94,2,2,0,0,0,100.0 +88,5,5,0,0,0,100.0 +89,5,5,0,0,0,100.0 +9,1,1,0,0,0,100.0 +90,5,5,0,0,0,100.0 +91,3,3,0,0,0,100.0 +96,2,2,0,0,0,100.0 +97,2,2,0,0,0,100.0 +98,2,2,0,0,0,100.0 +95,2,2,0,0,0,100.0 +99,2,2,0,0,0,100.0 +105,5,4,1,0,0,80.0 +106,5,4,1,0,0,80.0 +112,2,1,1,0,0,50.0 diff --git a/ai-service/test/Hierarchical_crop/answers/results_summary.txt b/ai-service/test/Hierarchical_crop/answers/results_summary.txt new file mode 100644 index 0000000..6514c1b --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/results_summary.txt @@ -0,0 +1,292 @@ +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10, 97, 29, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10, 97, 30, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11, 98, 32, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11, 98, 31, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12, 99, 34, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12, 99, 33, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13, 100, 35, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13, 100, 36, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14, 101, 37, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14, 101, 38, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15, 102, 40, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15, 102, 39, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16, 103, 41, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16, 103, 42, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17, 104, 43, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17, 104, 44, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17, 104, 45, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 04, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 02, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 05, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 09, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 06, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 07, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 10, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 08, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 09, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 06, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 07, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 10, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 08, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 14, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 11, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 12, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 13, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 15, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21, 108, 18, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21, 108, 16, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21, 108, 17, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22, 109, 20, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22, 109, 19, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23, 110, 21, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23, 110, 22, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24, 111, 24, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24, 111, 23, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25, 112, 25, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25, 112, 26, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26, 113, 27, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26, 113, 28, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27, 114, 30, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27, 114, 29, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28, 115, 32, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28, 115, 31, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29, 116, 34, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29, 116, 33, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 14, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 11, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 12, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 15, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 13, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30, 117, 35, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30, 117, 36, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31, 118, 37, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31, 118, 38, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32, 119, 39, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32, 119, 40, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33, 120, 41, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33, 120, 42, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34, 121, 43, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34, 121, 44, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34, 121, 45, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, 122, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, 122, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, 122, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, 122, 05, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 35, 122, 03, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36, 123, 06, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36, 123, 09, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36, 123, 07, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36, 123, 10, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 36, 123, 08, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37, 124, 14, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37, 124, 11, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37, 124, 12, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37, 124, 15, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 37, 124, 13, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 38, 125, 18, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 38, 125, 16, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 38, 125, 17, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 39, 126, 19, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 39, 126, 20, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4, 91, 18, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4, 91, 16, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4, 91, 17, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 40, 127, 21, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 40, 127, 22, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 41, 128, 24, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 41, 128, 23, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 42, 129, 25, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 42, 129, 26, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 43, 130, 28, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 43, 130, 27, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 44, 131, 30, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 44, 131, 29, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 45, 132, 32, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 45, 132, 31, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 46, 133, 34, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 46, 133, 33, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 47, 134, 35, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 47, 134, 36, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 48, 135, 37, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 48, 135, 38, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 49, 136, 40, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 49, 136, 39, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5, 92, 20, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5, 92, 19, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 50, 137, 41, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 50, 137, None, None +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 50, 137, 42, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 51, 138, 43, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 51, 138, 44, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 51, 138, 45, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52, 139, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52, 139, 01, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52, 139, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52, 139, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 52, 139, 03, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53, 140, 09, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53, 140, 06, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53, 140, 07, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53, 140, 10, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 53, 140, 08, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54, 141, 14, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54, 141, 11, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54, 141, 12, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54, 141, 15, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 54, 141, 13, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 55, 142, 18, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 55, 142, 16, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 55, 142, 17, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 56, 143, 19, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 56, 143, 20, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 57, 144, 21, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 57, 144, 22, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 58, 145, 23, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 58, 145, 24, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 59, 146, 26, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 59, 146, 25, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6, 93, 22, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6, 93, 21, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 60, 147, 27, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 60, 147, 28, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 61, 148, 30, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 61, 148, 29, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 62, 149, 32, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 62, 149, 31, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 63, 150, 34, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 63, 150, 33, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 64, 151, 35, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 64, 151, 36, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 65, 152, 37, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 65, 152, 38, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 66, 153, 39, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 66, 153, 40, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 67, 154, 41, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 67, 154, 42, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 67, 154, None, None +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 68, 155, 43, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 68, 155, 44, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 68, 155, 45, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69, 156, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69, 156, 01, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69, 156, 02, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69, 156, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 69, 156, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7, 94, 24, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7, 94, 23, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70, 157, 06, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70, 157, 09, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70, 157, 07, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70, 157, 10, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 70, 157, 08, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71, 158, 14, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71, 158, 11, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71, 158, 12, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71, 158, 15, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 71, 158, 13, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 72, 159, 18, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 72, 159, 16, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 72, 159, 17, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 73, 160, 19, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 73, 160, 20, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 74, 161, 21, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 74, 161, 22, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 75, 162, 24, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 75, 162, 23, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 76, 163, 25, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 76, 163, 26, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 77, 164, 28, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 77, 164, 27, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 78, 165, 29, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 78, 165, 30, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 79, 166, 32, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 79, 166, 31, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8, 95, 26, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8, 95, 25, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 80, 167, 33, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 80, 167, 34, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 81, 168, 35, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 81, 168, 36, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 82, 169, 37, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 82, 169, 38, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 83, 170, 40, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 83, 170, 39, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 84, 171, 41, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 84, 171, 42, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 85, 172, 43, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 85, 172, 44, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 85, 172, 45, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9, 96, 28, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9, 96, 27, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1, 9, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10, 19, 05, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11, 21, 01, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 12, 22, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 13, 23, 03, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14, 24, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 15, 25, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 16, 27, 01, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 17, 28, 02, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 18, 29, 03, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 19, 30, 04, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2, 10, 02, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 20, 31, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 21, 33, 01, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 22, 34, 02, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 23, 35, 03, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 24, 36, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 25, 37, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 26, 39, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 27, 40, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 28, 41, 03, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 29, 42, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3, 11, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 30, 43, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 31, 45, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 32, 46, 02, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 33, 47, 03, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 34, 48, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 35, 49, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 36, 51, 01, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 37, 52, 02, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 38, 53, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 39, 54, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4, 12, 04, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 40, 55, 05, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 41, 57, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 42, 58, 02, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 43, 59, 03, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 44, 60, 04, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 45, 61, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 46, 63, 01, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 47, 64, 02, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 48, 65, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 49, 66, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5, 13, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 50, 67, 05, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 51, 69, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 52, 70, 02, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 53, 71, 03, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 54, 72, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 55, 73, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 56, 75, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 57, 76, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 58, 77, 03, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 59, 78, 04, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6, 15, 01, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 60, 79, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62, 83, 01, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62, 83, 02, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64, 85, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64, 85, 04, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64, 85, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7, 16, 02, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8, 17, 03, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9, 18, 04, 5 diff --git a/ai-service/test/Hierarchical_crop/answers/student_answer.txt b/ai-service/test/Hierarchical_crop/answers/student_answer.txt new file mode 100644 index 0000000..5aa6a37 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/student_answer.txt @@ -0,0 +1,290 @@ +9, 01, 4 +10, 02, 4 +11, 03, 3 +12, 04, 5 +13, 05, 4 +15, 01, 1 +16, 02, 3 +17, 03, 5 +18, 04, 5 +19, 05, 5 +21, 01, 3 +22, 02, 2 +23, 03, 4 +24, 04, 1 +25, 05, 1 +27, 01, 3 +28, 02, 4 +29, 03, 4 +30, 04, 2 +31, 05, 1 +33, 01, 5 +34, 02, 1 +35, 03, 2 +36, 04, 1 +37, 05, 3 +39, 01, 2 +40, 02, 2 +41, 03, 5 +42, 04, 1 +43, 05, 1 +45, 01, 2 +46, 02, 5 +47, 03, 2 +48, 04, 3 +49, 05, 4 +51, 01, 5 +52, 02, 1 +53, 03, 3 +54, 04, 3 +55, 05, 2 +57, 01, 2 +58, 02, 4 +59, 03, 2 +60, 04, 2 +61, 05, 1 +63, 01, 3 +64, 02, 1 +65, 03, 3 +66, 04, 3 +67, 05, 2 +69, 01, 4 +70, 02, 3 +71, 03, 4 +72, 04, 3 +73, 05, 4 +75, 01, 2 +76, 02, 2 +77, 03, 4 +78, 04, 4 +79, 05, 4 +83, 01, 3 +83, 02, 3 +85, 03, 3 +85, 04, 4 +85, 05, 3 +88, 01, 4 +88, 02, 2 +88, 03, 3 +88, 04, 3 +88, 05, 3 +89, 06, 4 +89, 07, 3 +89, 08, 1 +89, 09, 4 +89, 10, 2 +90, 11, 4 +90, 12, 3 +90, 13, 3 +90, 14, 2 +90, 15, 3 +91, 16, 3 +91, 17, 2 +91, 18, 3 +92, 19, 4 +92, 20, 3 +93, 21, 5 +93, 22, 4 +94, 23, 3 +94, 24, 2 +95, 25, 2 +95, 26, 5 +96, 27, 5 +96, 28, 2 +97, 29, 3 +97, 30, 2 +98, 31, 3 +98, 32, 5 +99, 33, 3 +99, 34, 4 +100, 35, 4 +100, 36, 3 +101, 37, 2 +101, 38, 5 +102, 39, 3 +102, 40, 2 +103, 41, 5 +103, 42, 2 +104, 43, 4 +104, 44, 2 +104, 45, 1 +105, 01, 2 +105, 02, 3 +105, 03, 3 +105, 04, 4 +105, 05, 2 +106, 06, 4 +106, 07, 5 +106, 08, 3 +106, 09, 5 +106, 10, 4 +107, 11, 2 +107, 12, 1 +107, 13, 1 +107, 14, 1 +107, 15, 3 +108, 16, 4 +108, 17, 4 +108, 18, 5 +109, 19, 1 +109, 20, 3 +110, 21, 5 +110, 22, 1 +111, 23, 5 +111, 24, 2 +112, 25, 4 +112, 26, 2 +113, 27, 4 +113, 28, 4 +114, 29, 3 +114, 30, 4 +115, 31, 2 +115, 32, 2 +116, 33, 1 +116, 34, 1 +117, 35, 3 +117, 36, 2 +118, 37, 5 +118, 38, 3 +119, 39, 3 +119, 40, 4 +120, 41, 4 +120, 42, 4 +121, 43, 4 +121, 44, 2 +121, 45, 5 +122, 01, 4 +122, 02, 2 +122, 03, 1 +122, 04, 3 +122, 05, 2 +123, 06, 1 +123, 07, 2 +123, 08, 3 +123, 09, 5 +123, 10, 4 +124, 11, 4 +124, 12, 5 +124, 13, 4 +124, 14, 2 +124, 15, 3 +125, 16, 2 +125, 17, 5 +125, 18, 2 +126, 19, 3 +126, 20, 2 +127, 21, 3 +127, 22, 2 +128, 23, 4 +128, 24, 5 +129, 25, 2 +129, 26, 5 +130, 27, 3 +130, 28, 2 +131, 29, 2 +131, 30, 5 +132, 31, 1 +132, 32, 3 +133, 33, 4 +133, 34, 5 +134, 35, 2 +134, 36, 3 +135, 37, 1 +135, 38, 4 +136, 39, 3 +136, 40, 2 +137, 41, 3 +137, 42, 1 +138, 43, 4 +138, 44, 2 +138, 45, 1 +139, 01, 1 +139, 02, 2 +139, 03, 5 +139, 04, 3 +139, 05, 1 +140, 06, 5 +140, 07, 2 +140, 08, 5 +140, 09, 5 +140, 10, 1 +141, 11, 1 +141, 12, 2 +141, 13, 4 +141, 14, 5 +141, 15, 2 +142, 16, 1 +142, 17, 3 +142, 18, 3 +143, 19, 2 +143, 20, 4 +144, 21, 4 +144, 22, 1 +145, 23, 4 +145, 24, 2 +146, 25, 5 +146, 26, 5 +147, 27, 4 +147, 28, 3 +148, 29, 4 +148, 30, 3 +149, 31, 4 +149, 32, 2 +150, 33, 4 +150, 34, 2 +151, 35, 4 +151, 36, 4 +152, 37, 3 +152, 38, 3 +153, 39, 3 +153, 40, 1 +154, 41, 1 +154, 42, 5 +155, 43, 2 +155, 44, 2 +155, 45, 2 +156, 01, 1 +156, 02, 1 +156, 03, 3 +156, 04, 3 +156, 05, 3 +157, 06, 2 +157, 07, 4 +157, 08, 4 +157, 09, 4 +157, 10, 4 +158, 11, 1 +158, 12, 2 +158, 13, 4 +158, 14, 5 +158, 15, 5 +159, 16, 4 +159, 17, 3 +159, 18, 5 +160, 19, 3 +160, 20, 1 +161, 21, 3 +161, 22, 2 +162, 23, 1 +162, 24, 1 +163, 25, 3 +163, 26, 4 +164, 27, 4 +164, 28, 5 +165, 29, 4 +165, 30, 5 +166, 31, 2 +166, 32, 5 +167, 33, 3 +167, 34, 2 +168, 35, 4 +168, 36, 5 +169, 37, 1 +169, 38, 3 +170, 39, 2 +170, 40, 2 +171, 41, 5 +171, 42, 5 +172, 43, 2 +172, 44, 2 +172, 45, 3 diff --git a/ai-service/test/Hierarchical_crop/answers/test_answer.txt b/ai-service/test/Hierarchical_crop/answers/test_answer.txt new file mode 100644 index 0000000..b528196 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/test_answer.txt @@ -0,0 +1,290 @@ +9, 01, 4, answer_12_xo +10, 02, 4, answer_12_xo +11, 03, 3, answer_12_xo +12, 04, 5, answer_12_xo +13, 05, 4, answer_12_xo +15, 01, 1, answer_12_xo +16, 02, 3, answer_12_xo +17, 03, 5, answer_12_xo +18, 04, 5, answer_12_xo +19, 05, 5, answer_12_xo +21, 01, 3, answer_12_xo +22, 02, 2, answer_12_ox +23, 03, 4, answer_12_ox +24, 04, 1, answer_12_ox +25, 05, 1, answer_12_ox +27, 01, 3, answer_12_ox +28, 02, 4, answer_12_ox +29, 03, 4, answer_12_ox +30, 04, 2, answer_12_ox +31, 05, 1, answer_12_ox +33, 01, 5, answer_12_ox +34, 02, 1, answer_12_ox +35, 03, 2, answer_12_ox +36, 04, 1, answer_12_ox +37, 05, 3, answer_12_ox +39, 01, 2, answer_12_ox +40, 02, 2, answer_12_ox +41, 03, 5, answer_12_ox +42, 04, 1, answer_12_ox +43, 05, 1, answer_12_ox +45, 01, 2, answer_12_ox +46, 02, 5, answer_12_ox +47, 03, 2, answer_12_ox +48, 04, 3, answer_12_ox +49, 05, 4, answer_12_ox +51, 01, 5, answer_12_ox +52, 02, 1, answer_12_ox +53, 03, 3, answer_12_ox +54, 04, 3, answer_12_xx +55, 05, 2, answer_12_xx +57, 01, 2, answer_12_xx +58, 02, 4, answer_12_xx +59, 03, 2, answer_12_xx +60, 04, 2, answer_12_xx +61, 05, 1, answer_12_xx +63, 01, 3, answer_12_xx +64, 02, 1, answer_12_xx +65, 03, 3, answer_12_xx +66, 04, 3, answer_12_xx +67, 05, 2, answer_12_xx +69, 01, 4, answer_12_xx +70, 02, 3, answer_12_xx +71, 03, 4, answer_12_xx +72, 04, 3, answer_12_xx +73, 05, 4, answer_12_xx +75, 01, 2, answer_12_xx +76, 02, 2, answer_12_xx +77, 03, 4, answer_12_xx +78, 04, 4, answer_12_xx +79, 05, 4, answer_12_xx +83, 01, 3, answer_12_xx +83, 02, 3, answer_12_xx +85, 03, 3, answer_12_xx +85, 04, 4, answer_12_xx +85, 05, 3, answer_12_xx +88, 01, 4, answer_1_x +88, 02, 2, answer_1_x +88, 03, 3, answer_1_x +88, 04, 3, answer_1_x +88, 05, 3, answer_1_x +89, 06, 4, answer_1_x +89, 07, 3, answer_1_x +89, 08, 1, answer_1_x +89, 09, 4, answer_1_x +89, 10, 2, answer_1_x +90, 11, 4, answer_1_x +90, 12, 3, answer_1_x +90, 13, 3, answer_1_x +90, 14, 2, answer_1_x +90, 15, 3, answer_1_x +91, 16, 3, answer_1_x +91, 17, 2, answer_1_x +91, 18, 3, answer_1_x +92, 19, 4, answer_1_x +92, 20, 3, answer_1_x +93, 21, 5, answer_1_x +93, 22, 4, answer_1_x +94, 23, 3, answer_1_x +94, 24, 2, answer_1_x +95, 25, 2, answer_1_x +95, 26, 5, answer_1_x +96, 27, 5, answer_1_x +96, 28, 2, answer_1_x +97, 29, 3, answer_1_x +97, 30, 2, answer_1_x +98, 31, 3, answer_1_x +98, 32, 5, answer_1_x +99, 33, 3, answer_1_x +99, 34, 4, answer_1_x +100, 35, 4, answer_1_x +100, 36, 3, answer_1_x +101, 37, 2, answer_1_x +101, 38, 5, answer_1_x +102, 39, 3, answer_1_x +102, 40, 2, answer_1_x +103, 41, 5, answer_1_x +103, 42, 2, answer_1_x +104, 43, 4, answer_1_x +104, 44, 2, answer_1_x +104, 45, 1, answer_1_x +105, 01, 2, answer_1_o +105, 02, 3, answer_1_o +105, 03, 3, answer_1_o +105, 04, 4, answer_1_o +105, 05, 2, answer_1_o +106, 06, 4, answer_1_o +106, 07, 5, answer_1_o +106, 08, 3, answer_1_o +106, 09, 5, answer_1_o +106, 10, 4, answer_1_o +107, 11, 2, answer_1_o +107, 12, 1, answer_1_o +107, 13, 1, answer_1_o +107, 14, 1, answer_1_o +107, 15, 3, answer_1_o +108, 16, 4, answer_1_o +108, 17, 4, answer_1_o +108, 18, 5, answer_1_o +109, 19, 1, answer_1_o +109, 20, 3, answer_1_o +110, 21, 5, answer_1_o +110, 22, 1, answer_1_o +111, 23, 5, answer_1_o +111, 24, 2, answer_1_o +112, 25, 4, answer_1_o +112, 26, 2, answer_1_o +113, 27, 4, answer_1_o +113, 28, 4, answer_1_o +114, 29, 3, answer_1_o +114, 30, 4, answer_1_o +115, 31, 2, answer_1_o +115, 32, 2, answer_1_o +116, 33, 1, answer_1_o +116, 34, 1, answer_1_o +117, 35, 3, answer_1_o +117, 36, 2, answer_1_o +118, 37, 5, answer_1_o +118, 38, 3, answer_1_o +119, 39, 3, answer_1_o +119, 40, 4, answer_1_o +120, 41, 4, answer_1_o +120, 42, 4, answer_1_o +121, 43, 4, answer_1_o +121, 44, 2, answer_1_o +121, 45, 5, answer_1_o +122, 01, 4, answer_2_x +122, 02, 2, answer_2_x +122, 03, 1, answer_2_x +122, 04, 3, answer_2_x +122, 05, 2, answer_2_x +123, 06, 1, answer_2_x +123, 07, 2, answer_2_x +123, 08, 3, answer_2_x +123, 09, 5, answer_2_x +123, 10, 4, answer_2_x +124, 11, 4, answer_2_x +124, 12, 5, answer_2_x +124, 13, 4, answer_2_x +124, 14, 2, answer_2_x +124, 15, 3, answer_2_x +125, 16, 2, answer_2_x +125, 17, 5, answer_2_x +125, 18, 2, answer_2_x +126, 19, 3, answer_2_x +126, 20, 2, answer_2_x +127, 21, 3, answer_2_x +127, 22, 2, answer_2_x +128, 23, 4, answer_2_x +128, 24, 5, answer_2_x +129, 25, 2, answer_2_x +129, 26, 5, answer_2_x +130, 27, 3, answer_2_x +130, 28, 2, answer_2_x +131, 29, 2, answer_2_x +131, 30, 5, answer_2_x +132, 31, 1, answer_2_x +132, 32, 3, answer_2_x +133, 33, 4, answer_2_x +133, 34, 5, answer_2_x +134, 35, 2, answer_2_x +134, 36, 3, answer_2_x +135, 37, 1, answer_2_x +135, 38, 4, answer_2_x +136, 39, 3, answer_2_x +136, 40, 2, answer_2_x +137, 41, 3, answer_2_x +137, 42, 1, answer_2_x +138, 43, 4, answer_2_x +138, 44, 2, answer_2_x +138, 45, 1, answer_2_x +139, 01, 1, answer_2_o +139, 02, 2, answer_2_o +139, 03, 5, answer_2_o +139, 04, 3, answer_2_o +139, 05, 1, answer_2_o +140, 06, 5, answer_2_o +140, 07, 2, answer_2_o +140, 08, 5, answer_2_o +140, 09, 5, answer_2_o +140, 10, 1, answer_2_o +141, 11, 1, answer_2_o +141, 12, 2, answer_2_o +141, 13, 4, answer_2_o +141, 14, 5, answer_2_o +141, 15, 2, answer_2_o +142, 16, 1, answer_2_o +142, 17, 3, answer_2_o +142, 18, 3, answer_2_o +143, 19, 2, answer_2_o +143, 20, 4, answer_2_o +144, 21, 4, answer_2_o +144, 22, 1, answer_2_o +145, 23, 4, answer_2_o +145, 24, 2, answer_2_o +146, 25, 5, answer_2_o +146, 26, 5, answer_2_o +147, 27, 4, answer_2_o +147, 28, 3, answer_2_o +148, 29, 4, answer_2_o +148, 30, 3, answer_2_o +149, 31, 4, answer_2_o +149, 32, 2, answer_2_o +150, 33, 4, answer_2_o +150, 34, 2, answer_2_o +151, 35, 4, answer_2_o +151, 36, 4, answer_2_o +152, 37, 3, answer_2_o +152, 38, 3, answer_2_o +153, 39, 3, answer_2_o +153, 40, 1, answer_2_o +154, 41, 1, answer_2_o +154, 42, 5, answer_2_o +155, 43, 2, answer_2_o +155, 44, 2, answer_2_o +155, 45, 2, answer_2_o +156, 01, 1, answer_12_oo +156, 02, 1, answer_12_oo +156, 03, 3, answer_12_oo +156, 04, 3, answer_12_oo +156, 05, 3, answer_12_oo +157, 06, 2, answer_12_oo +157, 07, 4, answer_12_oo +157, 08, 4, answer_12_oo +157, 09, 4, answer_12_oo +157, 10, 4, answer_12_oo +158, 11, 1, answer_12_oo +158, 12, 2, answer_12_oo +158, 13, 4, answer_12_oo +158, 14, 5, answer_12_oo +158, 15, 5, answer_12_oo +159, 16, 4, answer_12_oo +159, 17, 3, answer_12_oo +159, 18, 5, answer_12_oo +160, 19, 3, answer_12_oo +160, 20, 1, answer_12_oo +161, 21, 3, answer_12_oo +161, 22, 2, answer_12_oo +162, 23, 1, answer_12_oo +162, 24, 1, answer_12_oo +163, 25, 3, answer_12_oo +163, 26, 4, answer_12_oo +164, 27, 4, answer_12_oo +164, 28, 5, answer_12_oo +165, 29, 4, answer_12_oo +165, 30, 5, answer_12_xo +166, 31, 2, answer_12_xo +166, 32, 5, answer_12_xo +167, 33, 3, answer_12_xo +167, 34, 2, answer_12_xo +168, 35, 4, answer_12_xo +168, 36, 5, answer_12_xo +169, 37, 1, answer_12_xo +169, 38, 3, answer_12_xo +170, 39, 2, answer_12_xo +170, 40, 2, answer_12_xo +171, 41, 5, answer_12_xo +171, 42, 5, answer_12_xo +172, 43, 2, answer_12_xo +172, 44, 2, answer_12_xo +172, 45, 3, answer_12_xo \ No newline at end of file diff --git a/ai-service/test/Hierarchical_crop/answers/type_statistics.csv b/ai-service/test/Hierarchical_crop/answers/type_statistics.csv new file mode 100644 index 0000000..2cae431 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/answers/type_statistics.csv @@ -0,0 +1,9 @@ +๏ปฟproblem_type,total,correct,wrong,none,missing,accuracy,wrong_rate,none_rate,missing_rate +answer_1_o,45,42,3,0,0,93.33,6.67,0.0,0.0 +answer_12_oo,29,29,0,0,0,100.0,0.0,0.0,0.0 +answer_12_xo,27,27,0,0,0,100.0,0.0,0.0,0.0 +answer_12_ox,27,27,0,0,0,100.0,0.0,0.0,0.0 +answer_12_xx,27,27,0,0,0,100.0,0.0,0.0,0.0 +answer_1_x,45,45,0,0,0,100.0,0.0,0.0,0.0 +answer_2_o,45,45,0,0,0,100.0,0.0,0.0,0.0 +answer_2_x,45,45,0,0,0,100.0,0.0,0.0,0.0 diff --git a/ai-service/test/Hierarchical_crop/hierarchical_crop.py b/ai-service/test/Hierarchical_crop/hierarchical_crop.py new file mode 100644 index 0000000..f06821e --- /dev/null +++ b/ai-service/test/Hierarchical_crop/hierarchical_crop.py @@ -0,0 +1,1296 @@ +# hierarchical_crop.py +import logging +import time +import os +from pathlib import Path +from typing import Dict, List, Tuple, Optional +import cv2 +import numpy as np +import torch +import torch.nn as nn +from torchvision import transforms +from models.Detection.legacy.Model_routing_1104.run_routed_inference import RoutedInference as RoutedInference_1104 +from models.Detection.legacy.Model_routing_1004.run_routed_inference import RoutedInference as RoutedInference_1004 +from models.Recognition.ocr import OCRModel + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + + +class ResNetClassifier: + """ResNet ๊ธฐ๋ฐ˜ ๋‹ต์•ˆ ๋ถ„๋ฅ˜ ๋ชจ๋ธ (1-5 ๋ถ„๋ฅ˜)""" + + def __init__(self, model_path: str, model_type: str = 'answer', device: str = 'cuda'): + """ + Args: + model_path: ResNet ๋ชจ๋ธ ๊ฐ€์ค‘์น˜ ํŒŒ์ผ ๊ฒฝ๋กœ (.pth) + model_type: ๋ชจ๋ธ ํƒ€์ž… ('answer_1' ๋˜๋Š” 'answer_2') + device: 'cuda' ๋˜๋Š” 'cpu' + """ + self.device = torch.device(device if torch.cuda.is_available() else 'cpu') + self.model_type = model_type + self.model = self._load_model(model_path) + self.transform = self._get_transform() + + logger.info(f"โœ… ResNet ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ ({model_type}): {model_path}") + logger.info(f" ๋””๋ฐ”์ด์Šค: {self.device}") + + def _load_model(self, model_path: str): + """ResNet ๋ชจ๋ธ ๋กœ๋“œ - ์ปค์Šคํ…€ ๊ตฌ์กฐ""" + import torch.nn as nn + + # ์ปค์Šคํ…€ ResNet18 ๊ตฌ์กฐ (shortcut ์‚ฌ์šฉ, grayscale ์ž…๋ ฅ) + class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, in_channels, out_channels, stride=1): + super(BasicBlock, self).__init__() + self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(out_channels) + self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(out_channels) + + self.shortcut = nn.Sequential() + if stride != 1 or in_channels != out_channels: + self.shortcut = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(out_channels) + ) + + def forward(self, x): + out = torch.relu(self.bn1(self.conv1(x))) + out = self.bn2(self.conv2(out)) + out += self.shortcut(x) + out = torch.relu(out) + return out + + class CustomResNet18(nn.Module): + def __init__(self, num_classes=5): + super(CustomResNet18, self).__init__() + # Grayscale ์ž…๋ ฅ (1 ์ฑ„๋„) + self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(64) + + # ResNet18 ๊ตฌ์กฐ + self.layer1 = self._make_layer(64, 64, 2, stride=1) + self.layer2 = self._make_layer(64, 128, 2, stride=2) + self.layer3 = self._make_layer(128, 256, 2, stride=2) + self.layer4 = self._make_layer(256, 512, 2, stride=2) + + self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(512, num_classes) + + def _make_layer(self, in_channels, out_channels, num_blocks, stride): + layers = [] + layers.append(BasicBlock(in_channels, out_channels, stride)) + for _ in range(1, num_blocks): + layers.append(BasicBlock(out_channels, out_channels, 1)) + return nn.Sequential(*layers) + + def forward(self, x): + out = torch.relu(self.bn1(self.conv1(x))) + out = self.layer1(out) + out = self.layer2(out) + out = self.layer3(out) + out = self.layer4(out) + out = self.avgpool(out) + out = out.view(out.size(0), -1) + out = self.fc(out) + return out + + # ๋ชจ๋ธ ์ƒ์„ฑ + model = CustomResNet18(num_classes=5) + + # ๊ฐ€์ค‘์น˜ ๋กœ๋“œ (PyTorch 2.6+ ํ˜ธํ™˜) + try: + checkpoint = torch.load(model_path, map_location=self.device, weights_only=False) + except TypeError: + checkpoint = torch.load(model_path, map_location=self.device) + + # state_dict ์ถ”์ถœ + if isinstance(checkpoint, dict): + if 'model_state_dict' in checkpoint: + state_dict = checkpoint['model_state_dict'] + elif 'state_dict' in checkpoint: + state_dict = checkpoint['state_dict'] + else: + state_dict = checkpoint + else: + state_dict = checkpoint + + model.load_state_dict(state_dict) + model.to(self.device) + model.eval() + + return model + + def _get_transform(self): + """์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ ๋ณ€ํ™˜ - MNIST ์Šคํƒ€์ผ""" + return transforms.Compose([ + transforms.ToPILImage(), + transforms.Grayscale(num_output_channels=1), # Grayscale ๋ณ€ํ™˜ + transforms.Resize((28, 28)), # MNIST ํฌ๊ธฐ + transforms.ToTensor(), + transforms.Normalize(mean=[0.1307], std=[0.3081]) # MNIST ์ •๊ทœํ™” + ]) + + def predict(self, image_path: str) -> Tuple[Optional[str], float]: + """ + ์ด๋ฏธ์ง€์—์„œ ๋‹ต์•ˆ ๋ฒˆํ˜ธ ์˜ˆ์ธก + + Args: + image_path: ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ + + Returns: + Tuple[Optional[str], float]: (์˜ˆ์ธก๋œ ๋‹ต์•ˆ ๋ฒˆํ˜ธ '1'-'5', ์‹ ๋ขฐ๋„) + """ + try: + # ์ด๋ฏธ์ง€ ๋กœ๋“œ (BGR) + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return None, 0.0 + + # RGB๋กœ ๋ณ€ํ™˜ (PIL์€ RGB๋ฅผ ๊ธฐ๋Œ€) + image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + + # ์ „์ฒ˜๋ฆฌ (Grayscale ๋ณ€ํ™˜ ํฌํ•จ) + input_tensor = self.transform(image_rgb).unsqueeze(0).to(self.device) + + # ์ถ”๋ก  + with torch.no_grad(): + outputs = self.model(input_tensor) + probabilities = torch.softmax(outputs, dim=1) + confidence, predicted = torch.max(probabilities, 1) + + # ๊ฒฐ๊ณผ ๋ณ€ํ™˜ (0-4 โ†’ 1-5) + answer = str(predicted.item() + 1) + conf = confidence.item() + + # logger.info(f"ResNet ({self.model_type}) ์˜ˆ์ธก: ๋‹ต์•ˆ={answer}, ์‹ ๋ขฐ๋„={conf:.4f}") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + + return answer, conf + + except Exception as e: + logger.error(f"ResNet ({self.model_type}) ์˜ˆ์ธก ์‹คํŒจ: {e}", exc_info=True) + return None, 0.0 + + +class HierarchicalCropPipeline: + """๊ณ„์ธต์  ํฌ๋กญ ํŒŒ์ดํ”„๋ผ์ธ: ํŽ˜์ด์ง€ โ†’ Section โ†’ ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ ์ •๋‹ต (answer_2 ์šฐ์„ , answer_1 fallback)""" + + def __init__(self, model_dir_1104: str, model_dir_1004: str, + section_padding: int = 50, + answer_key_path: Optional[str] = None, + resnet_answer_1_path: Optional[str] = None, + resnet_answer_2_path: Optional[str] = None): + """ + Args: + model_dir_1104: 1104 ๋ชจ๋ธ ๊ฒฝ๋กœ + model_dir_1004: 1004 ๋ชจ๋ธ ๊ฒฝ๋กœ + section_padding: Section crop ์‹œ ์ถ”๊ฐ€ํ•  ์—ฌ๋ฐฑ (ํ”ฝ์…€). ๊ธฐ๋ณธ๊ฐ’ 50 + answer_key_path: ๋‹ต์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ (txt ํŒŒ์ผ) + resnet_answer_1_path: answer_1์šฉ ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ (.pth ํŒŒ์ผ) + resnet_answer_2_path: answer_2์šฉ ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ (.pth ํŒŒ์ผ) + """ + self.router_1104 = RoutedInference_1104(model_dir_1104) # ๋‹ต์•ˆ ์ถ”๋ก ์šฉ + self.router_1004 = RoutedInference_1004(model_dir_1004) # ํฌ๋กญ์šฉ (ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section) + self.ocr = OCRModel() + self.section_padding = section_padding + + # โœจ answer_1๊ณผ answer_2์šฉ ResNet ๋ชจ๋ธ ์ดˆ๊ธฐํ™” + self.resnet_answer_1 = None + self.resnet_answer_2 = None + + # answer_1 ResNet ๋กœ๋“œ + if resnet_answer_1_path and os.path.exists(resnet_answer_1_path): + try: + self.resnet_answer_1 = ResNetClassifier(resnet_answer_1_path, model_type='answer_1') + logger.info("โœ… answer_1 ResNet ๋ถ„๋ฅ˜ ๋ชจ๋ธ ๋กœ๋“œ ์„ฑ๊ณต") + except Exception as e: + logger.error(f"โŒ answer_1 ResNet ๋ชจ๋ธ ๋กœ๋“œ ์‹คํŒจ: {e}") + logger.warning("answer_1 ResNet ๋ถ„๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + else: + if resnet_answer_1_path: + logger.warning(f"answer_1 ResNet ๋ชจ๋ธ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {resnet_answer_1_path}") + logger.info("answer_1 ResNet ๋ถ„๋ฅ˜ ์—†์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.") + + # answer_2 ResNet ๋กœ๋“œ + if resnet_answer_2_path and os.path.exists(resnet_answer_2_path): + try: + self.resnet_answer_2 = ResNetClassifier(resnet_answer_2_path, model_type='answer_2') + logger.info("โœ… answer_2 ResNet ๋ถ„๋ฅ˜ ๋ชจ๋ธ ๋กœ๋“œ ์„ฑ๊ณต") + except Exception as e: + logger.error(f"โŒ answer_2 ResNet ๋ชจ๋ธ ๋กœ๋“œ ์‹คํŒจ: {e}") + logger.warning("answer_2 ResNet ๋ถ„๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + else: + if resnet_answer_2_path: + logger.warning(f"answer_2 ResNet ๋ชจ๋ธ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {resnet_answer_2_path}") + logger.info("answer_2 ResNet ๋ถ„๋ฅ˜ ์—†์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.") + + # ๋‹ต์ง€ ๋กœ๋“œ + self.answer_key = self._load_answer_key(answer_key_path) if answer_key_path else None + + logger.info("HierarchicalCropPipeline ์ดˆ๊ธฐํ™” (๋‘ ๊ฐœ์˜ ๋ชจ๋ธ + OCR ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ)") + logger.info(" - 1104 ๋ชจ๋ธ: ๋‹ต์•ˆ ์ถ”๋ก ์šฉ (answer_1, answer_2 ๊ฒ€์ถœ)") + logger.info(" - 1004 ๋ชจ๋ธ: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ํฌ๋กญ์šฉ") + logger.info(f" - Section padding: {section_padding}px") + logger.info(f" - answer_1 ResNet: {'์‚ฌ์šฉ ๊ฐ€๋Šฅ' if self.resnet_answer_1 else '์‚ฌ์šฉ ๋ถˆ๊ฐ€'}") + logger.info(f" - answer_2 ResNet: {'์‚ฌ์šฉ ๊ฐ€๋Šฅ' if self.resnet_answer_2 else '์‚ฌ์šฉ ๋ถˆ๊ฐ€'}") + if self.answer_key: + logger.info(f" - ๋‹ต์ง€ ๋กœ๋“œ ์™„๋ฃŒ: {len(self.answer_key)}๊ฐœ ํŽ˜์ด์ง€") + + def _load_answer_key(self, answer_key_path: str) -> Dict[str, List[Dict]]: + """๋‹ต์ง€ ํŒŒ์ผ ๋กœ๋“œ + + ํŒŒ์ผ ํ˜•์‹: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต + ์˜ˆ: 1, 1, 3 + + Returns: + Dict[str, List[Dict]]: {ํŽ˜์ด์ง€๋ฒˆํ˜ธ: [{'problem': ๋ฌธ์ œ๋ฒˆํ˜ธ, 'answer': ์ •๋‹ต}, ...]} + """ + answer_key = {} + try: + with open(answer_key_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line: + continue + + parts = [p.strip() for p in line.split(',')] + if len(parts) >= 3: + page_num = parts[0] + problem_num = parts[1] + answer = parts[2] + + if page_num not in answer_key: + answer_key[page_num] = [] + + answer_key[page_num].append({ + 'problem': problem_num, + 'answer': answer + }) + + logger.info(f"๋‹ต์ง€ ๋กœ๋“œ ์™„๋ฃŒ: {answer_key_path}") + for page, problems in answer_key.items(): + logger.info(f" ํŽ˜์ด์ง€ {page}: {len(problems)}๊ฐœ ๋ฌธ์ œ") + + except Exception as e: + logger.error(f"๋‹ต์ง€ ๋กœ๋“œ ์‹คํŒจ: {e}") + return {} + + return answer_key + + def is_valid_page(self, page_number: Optional[str]) -> bool: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๊ฐ€ ๋‹ต์ง€์— ์žˆ๋Š”์ง€ ํ™•์ธ + + Args: + page_number: OCR๋กœ ์ธ์‹๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ + + Returns: + bool: ๋‹ต์ง€์— ์žˆ์œผ๋ฉด True, ๋‹ต์ง€๊ฐ€ ์—†๊ฑฐ๋‚˜ ํŽ˜์ด์ง€๊ฐ€ ์—†์œผ๋ฉด True (๊ธฐ๋ณธ ์ฒ˜๋ฆฌ) + """ + if self.answer_key is None: + # ๋‹ต์ง€๊ฐ€ ์—†์œผ๋ฉด ๋ชจ๋“  ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ + return True + + if page_number is None: + logger.warning("ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + return False + + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ •๊ทœํ™” (๊ณต๋ฐฑ ์ œ๊ฑฐ, ๋ฌธ์ž์—ด ๋ณ€ํ™˜) + page_number_normalized = str(page_number).strip() + + is_valid = page_number_normalized in self.answer_key + + if not is_valid: + logger.warning(f"ํŽ˜์ด์ง€ {page_number}๋Š” ๋‹ต์ง€์— ์—†์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + else: + logger.info(f"ํŽ˜์ด์ง€ {page_number}๋Š” ๋‹ต์ง€์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜๋ฆฌ๋ฅผ ๊ณ„์†ํ•ฉ๋‹ˆ๋‹ค.") + + return is_valid + + def get_missing_problem_number(self, page_number: Optional[str], + recognized_numbers: set) -> Optional[str]: + """๋‹ต์ง€ ๊ธฐ๋ฐ˜์œผ๋กœ ํŽ˜์ด์ง€์—์„œ ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ค‘ ๊ฐ€์žฅ ์ž‘์€ ๊ฒƒ์„ ๋ฐ˜ํ™˜ + + Args: + page_number: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ + recognized_numbers: ์ด๋ฏธ ์ธ์‹๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ set + + Returns: + Optional[str]: ๋ˆ„๋ฝ๋œ ๊ฐ€์žฅ ์ž‘์€ ๋ฌธ์ œ ๋ฒˆํ˜ธ, ๋˜๋Š” None (๋‹ต์ง€๊ฐ€ ์—†๊ฑฐ๋‚˜ ๋ˆ„๋ฝ ์—†์Œ) + """ + if self.answer_key is None or page_number is None: + return None + + page_number_normalized = str(page_number).strip() + + if page_number_normalized not in self.answer_key: + return None + + # ๋‹ต์ง€์— ์žˆ๋Š” ๋ฌธ์ œ ๋ฒˆํ˜ธ๋“ค + expected_problems = {item['problem'] for item in self.answer_key[page_number_normalized]} + + # ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ๋“ค + missing = expected_problems - recognized_numbers + + if not missing: + return None + + # ๋ˆ„๋ฝ๋œ ๋ฒˆํ˜ธ ์ค‘ ๊ฐ€์žฅ ์ž‘์€ ๊ฒƒ (๋ฌธ์ž์—ด์„ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ •๋ ฌ) + try: + missing_sorted = sorted(missing, key=lambda x: int(x) if x.isdigit() else float('inf')) + smallest_missing = missing_sorted[0] + logger.info(f"๐Ÿ“‹ ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ค‘ ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’: {smallest_missing}") + logger.info(f" ์ „์ฒด ๋ˆ„๋ฝ: {sorted(missing_sorted)}") + return smallest_missing + except Exception as e: + logger.error(f"๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ •๋ ฌ ์‹คํŒจ: {e}") + return None + + def calculate_iou(self, bbox1: List[float], bbox2: List[float]) -> float: + """๋‘ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค์˜ IoU(Intersection over Union) ๊ณ„์‚ฐ + + Args: + bbox1: [x1, y1, x2, y2] + bbox2: [x1, y1, x2, y2] + + Returns: + float: IoU ๊ฐ’ (0.0 ~ 1.0) + """ + x1_1, y1_1, x2_1, y2_1 = bbox1 + x1_2, y1_2, x2_2, y2_2 = bbox2 + + # ๊ฒน์น˜๋Š” ์˜์—ญ ๊ณ„์‚ฐ + x1_i = max(x1_1, x1_2) + y1_i = max(y1_1, y1_2) + x2_i = min(x2_1, x2_2) + y2_i = min(y2_1, y2_2) + + if x2_i <= x1_i or y2_i <= y1_i: + return 0.0 + + # Intersection ๋ฉด์  + intersection = (x2_i - x1_i) * (y2_i - y1_i) + + # ๊ฐ ๋ฐ•์Šค์˜ ๋ฉด์  + area1 = (x2_1 - x1_1) * (y2_1 - y1_1) + area2 = (x2_2 - x1_2) * (y2_2 - y1_2) + + # Union ๋ฉด์  + union = area1 + area2 - intersection + + if union == 0: + return 0.0 + + return intersection / union + + def expand_bbox_with_padding(self, bbox: List[float], padding: int, img_width: int, img_height: int) -> List[int]: + """๋ฐ”์šด๋”ฉ ๋ฐ•์Šค์— padding์„ ์ถ”๊ฐ€ํ•˜๋˜, ์ด๋ฏธ์ง€ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์ง€ ์•Š๋„๋ก ์ฒ˜๋ฆฌ + + Args: + bbox: [x1, y1, x2, y2] + padding: ์ถ”๊ฐ€ํ•  ์—ฌ๋ฐฑ (ํ”ฝ์…€) + img_width: ์ด๋ฏธ์ง€ ๋„ˆ๋น„ + img_height: ์ด๋ฏธ์ง€ ๋†’์ด + + Returns: + List[int]: ํ™•์žฅ๋œ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + """ + x1, y1, x2, y2 = bbox + + # Padding ์ถ”๊ฐ€ + x1_expanded = max(0, int(x1 - padding)) + y1_expanded = max(0, int(y1 - padding)) + x2_expanded = min(img_width, int(x2 + padding)) + y2_expanded = min(img_height, int(y2 + padding)) + + return [x1_expanded, y1_expanded, x2_expanded, y2_expanded] + + def is_bbox_near_section_boundary(self, bbox: List[float], section_bbox: List[float], threshold: int = 30) -> bool: + """๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ•์Šค๊ฐ€ section ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์žˆ๋Š”์ง€ ํ™•์ธ + + Args: + bbox: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + section_bbox: Section ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + threshold: ๊ฒฝ๊ณ„๋กœ ๊ฐ„์ฃผํ•  ๊ฑฐ๋ฆฌ (ํ”ฝ์…€) + + Returns: + bool: ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์žˆ์œผ๋ฉด True + """ + bx1, by1, bx2, by2 = bbox + sx1, sy1, sx2, sy2 = section_bbox + + # ์ƒํ•˜์ขŒ์šฐ ๊ฒฝ๊ณ„์™€์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ + dist_top = abs(by1 - sy1) + dist_bottom = abs(by2 - sy2) + dist_left = abs(bx1 - sx1) + dist_right = abs(bx2 - sx2) + + # ํ•˜๋‚˜๋ผ๋„ threshold ์ด๋‚ด์ด๋ฉด ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜๋กœ ํŒ๋‹จ + return min(dist_top, dist_bottom, dist_left, dist_right) < threshold + + def visualize_section_detection(self, image_path: str, section_bbox: List[float], + section_idx: int, output_dir: Path, page_name: str, + detections_1104: List[Dict], section_padding: int = 50): + """Section ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐํ™”ํ•˜์—ฌ ์ €์žฅ (๋””๋ฒ„๊น…์šฉ) + โœจ section, answer_1, answer_2, 1-5 ๋ชจ๋“  ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐํ™” + + Args: + image_path: ์›๋ณธ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + section_bbox: Section ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + section_idx: Section ์ธ๋ฑ์Šค + output_dir: ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ + page_name: ํŽ˜์ด์ง€ ์ด๋ฆ„ + detections_1104: 1104 ๋ชจ๋ธ์˜ ๊ฒ€์ถœ ๊ฒฐ๊ณผ (answer_1, answer_2, 1-5) + section_padding: Section padding ๊ฐ’ + """ + image = cv2.imread(image_path) + if image is None: + return + + h, w = image.shape[:2] + sx1, sy1, sx2, sy2 = section_bbox + + # Section ํ™•์žฅ ์˜์—ญ ๊ณ„์‚ฐ + sx1_exp = max(0, int(sx1 - section_padding)) + sy1_exp = max(0, int(sy1 - section_padding)) + sx2_exp = min(w, int(sx2 + section_padding)) + sy2_exp = min(h, int(sy2 + section_padding)) + + # Section bbox ๊ทธ๋ฆฌ๊ธฐ (์›๋ณธ - ์ดˆ๋ก์ƒ‰) + x1, y1, x2, y2 = map(int, section_bbox) + cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 3) + label = f"Section {section_idx}" + cv2.putText(image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) + + # Section ํ™•์žฅ ์˜์—ญ ๊ทธ๋ฆฌ๊ธฐ (์ ์„  - ์—ฐ๋‘์ƒ‰) + cv2.rectangle(image, (sx1_exp, sy1_exp), (sx2_exp, sy2_exp), (100, 255, 100), 2) + cv2.putText(image, f"Expanded (+{section_padding}px)", + (sx1_exp, sy1_exp - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (100, 255, 100), 2) + + # ์ƒ‰์ƒ ์ •์˜ + colors = { + 'answer_1': (255, 0, 0), # ๋นจ๊ฐ• + 'answer_2': (255, 0, 255), # โœจ ์žํ™ (answer_2 ์ถ”๊ฐ€) + '1': (0, 0, 255), # ํŒŒ๋ž‘ + '2': (255, 165, 0), # ์ฃผํ™ฉ + '3': (255, 255, 0), # ๋…ธ๋ž‘ + '4': (128, 0, 128), # ๋ณด๋ผ + '5': (0, 255, 255) # ์ฒญ๋ก + } + + # Section ๋‚ด์˜ answer_1, answer_2, ์ˆซ์ž ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ + for det in detections_1104: + class_name = det['class_name'] + if class_name not in colors: + continue + + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + + # ํ™•์žฅ๋œ Section ์˜์—ญ ๋‚ด์— ์žˆ๋Š”์ง€ ํ™•์ธ + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ๊ทธ๋ฆฌ๊ธฐ + color = colors[class_name] + x1, y1, x2, y2 = map(int, det['bbox']) + cv2.rectangle(image, (x1, y1), (x2, y2), color, 2) + + # ๋ผ๋ฒจ (ํด๋ž˜์Šค๋ช… + ์‹ ๋ขฐ๋„) + conf = det['confidence'] + label = f"{class_name}: {conf:.2f}" + + # ํ…์ŠคํŠธ ๋ฐฐ๊ฒฝ + (text_w, text_h), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2) + cv2.rectangle(image, (x1, y1 - text_h - 5), (x1 + text_w, y1), color, -1) + + # ํ…์ŠคํŠธ + cv2.putText(image, label, (x1, y1 - 5), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2) + + # ๋ฒ”๋ก€ ์ถ”๊ฐ€ + legend_y = 30 + legend_x = w - 200 + cv2.rectangle(image, (legend_x - 10, 10), (w - 10, 220), (255, 255, 255), -1) # ๋†’์ด ์ฆ๊ฐ€ + cv2.rectangle(image, (legend_x - 10, 10), (w - 10, 220), (0, 0, 0), 2) + + cv2.putText(image, "Legend:", (legend_x, legend_y), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2) + legend_y += 25 + + for class_name, color in colors.items(): + cv2.rectangle(image, (legend_x, legend_y - 10), (legend_x + 15, legend_y + 5), color, -1) + cv2.putText(image, class_name, (legend_x + 20, legend_y), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1) + legend_y += 20 + + # ์ €์žฅ + debug_dir = output_dir / page_name / "debug" + debug_dir.mkdir(parents=True, exist_ok=True) + + save_path = debug_dir / f"section_{section_idx:02d}_detection_visual.jpg" + cv2.imwrite(str(save_path), image) + logger.info(f"โœจ Section ๊ฒ€์ถœ ์‹œ๊ฐํ™” ์ €์žฅ (answer_1 + answer_2 + 1-5 ํฌํ•จ): {save_path}") + + def crop_page_number(self, image_path: str, detections_1004: List[Dict], output_dir: Path) -> Tuple[Optional[str], Optional[str]]: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ํฌ๋กญํ•˜๊ณ  OCR๋กœ ์ธ์‹ (1004 ๋ชจ๋ธ ์‚ฌ์šฉ) + โœจ ์ด๋ฏธ์ง€ ์ €์žฅ ์—†์ด OCR๋งŒ ์ˆ˜ํ–‰ + + Returns: + Tuple[Optional[str], Optional[str]]: (None, ์ธ์‹๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ) + """ + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return None, None + + page_num_detections = [d for d in detections_1004 if d['class_name'] == 'page_number'] + + if not page_num_detections: + logger.warning(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ: {image_path}") + return None, None + + # ์‹ ๋ขฐ๋„ ๊ฐ€์žฅ ๋†’์€ ๊ฒƒ ์„ ํƒ + best_det = max(page_num_detections, key=lambda x: x['confidence']) + x1, y1, x2, y2 = map(int, best_det['bbox']) + + h, w = image.shape[:2] + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 <= x1 or y2 <= y1: + logger.warning(f"์ž˜๋ชป๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐ•์Šค: {best_det['bbox']}") + return None, None + + # ํฌ๋กญ (์ €์žฅํ•˜์ง€ ์•Š๊ณ  OCR๋งŒ ์ˆ˜ํ–‰) + cropped = image[y1:y2, x1:x2] + + # ์ž„์‹œ ํŒŒ์ผ๋กœ OCR ์ˆ˜ํ–‰ + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=True) as tmp: + cv2.imwrite(tmp.name, cropped) + recognized_number = self.ocr.extract_number(tmp.name) + + # logger.info(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ OCR ๊ฒฐ๊ณผ: '{recognized_number}' (์ด๋ฏธ์ง€ ์ €์žฅ ์•ˆ ํ•จ)") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + + return None, recognized_number + + def classify_answer_with_resnet(self, answer_crop_path: str, section_idx: int, + answer_type: str = "answer_1") -> Tuple[Optional[str], float, bool]: + """ + โœจ answer crop ์ด๋ฏธ์ง€๋ฅผ ํ•ด๋‹น ํƒ€์ž…์˜ ResNet์œผ๋กœ ๋ถ„๋ฅ˜ + + Args: + answer_crop_path: answer crop ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + section_idx: Section ์ธ๋ฑ์Šค + answer_type: ๋‹ต์•ˆ ํƒ€์ž… ('answer_1' ๋˜๋Š” 'answer_2') + + Returns: + Tuple[Optional[str], float, bool]: (์˜ˆ์ธก ๋‹ต์•ˆ, ์‹ ๋ขฐ๋„, ์‹คํŒจ ์—ฌ๋ถ€) + """ + # answer_type์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋ชจ๋ธ ์„ ํƒ + if answer_type == 'answer_2': + resnet_model = self.resnet_answer_2 + else: # 'answer_1' ๋˜๋Š” ๊ธฐํƒ€ + resnet_model = self.resnet_answer_1 + + if resnet_model is None: + logger.warning(f"Section {section_idx}: {answer_type} ResNet ๋ชจ๋ธ์ด ์—†์–ด ๋ถ„๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + return None, 0.0, True + + if not os.path.exists(answer_crop_path): + logger.error(f"Section {section_idx}: {answer_type} ์ด๋ฏธ์ง€๊ฐ€ ์—†์–ด ResNet์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {answer_crop_path}") + return None, 0.0, True + + # logger.info(f"Section {section_idx}: โœจ {answer_type} ResNet ๋ถ„๋ฅ˜ ์‹œ๋„ ์ค‘...") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + + try: + answer, confidence = resnet_model.predict(answer_crop_path) + + if answer is None: + logger.warning(f"Section {section_idx}: {answer_type} ResNet ์˜ˆ์ธก ์‹คํŒจ") + return None, 0.0, True + + # logger.info(f"Section {section_idx}: โœ… {answer_type} ResNet ์˜ˆ์ธก ์„ฑ๊ณต - ๋‹ต์•ˆ={answer}, ์‹ ๋ขฐ๋„={confidence:.4f}") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + return answer, confidence, False + + except Exception as e: + logger.error(f"Section {section_idx}: {answer_type} ResNet ์˜ˆ์ธก ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ: {e}") + return None, 0.0, True + + def process_single_section(self, original_image_path: str, section_idx: int, + page_name: str, output_dir: Path, + section_bbox: List[float], detections_1004: List[Dict], + detections_1104: List[Dict], page_number_ocr: Optional[str] = None, + recognized_problem_numbers: Optional[set] = None) -> Dict: + """์„น์…˜ ๋‚ด์˜ ๋ฌธ์ œ๋ฒˆํ˜ธ์™€ ์ •๋‹ต์„ ์ถ”๋ก  + โœจ ์ƒˆ๋กœ์šด ๋กœ์ง: + 1. YOLO๋กœ answer_2 ๊ฒ€์ถœ ์—ฌ๋ถ€ ํ™•์ธ + 2. answer_2 ์žˆ์œผ๋ฉด โ†’ answer_2 ResNet๋งŒ ์‚ฌ์šฉ (์ตœ์ข… ๋‹ต) + 3. answer_2 ์—†์œผ๋ฉด โ†’ answer_1 ResNet + YOLO IoU ๊ฒ€์ฆ (๊ธฐ์กด ๋กœ์ง) + 4. ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ 2๊ฐœ ๊ฒ€์ถœ๋œ ๊ฒฝ์šฐ โ†’ ๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ๋œ ๊ฐ€์žฅ ์ž‘์€ ๋ฒˆํ˜ธ ํ• ๋‹น + โœจ Section ์ด๋ฏธ์ง€๋งŒ ์ €์žฅ, ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋“ค์€ ์ €์žฅํ•˜์ง€ ์•Š์Œ + + Args: + page_number_ocr: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (OCR ์ธ์‹ ๊ฒฐ๊ณผ) + recognized_problem_numbers: ์ด๋ฏธ ์ธ์‹๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ๋“ค์˜ ์ง‘ํ•ฉ + + Returns: + Dict: {'section_idx', 'problem_number_ocr', 'answer_number', 'section_crop_path', 'problem_crop_path', + 'answer_1_crop_path', 'answer_2_crop_path', 'crop_success', 'crop_failure_reason', + 'used_resnet', 'resnet_confidence', 'resnet_failed', 'answer_source'} + """ + if recognized_problem_numbers is None: + recognized_problem_numbers = set() + + sx1, sy1, sx2, sy2 = section_bbox + image = cv2.imread(original_image_path) + h, w = image.shape[:2] + + # Section bbox ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if sx2 <= sx1 or sy2 <= sy1: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ์ž˜๋ชป๋œ bbox [{sx1:.1f}, {sy1:.1f}, {sx2:.1f}, {sy2:.1f}]") + logger.error(f" bbox ๋„ˆ๋น„: {sx2 - sx1:.1f}, ๋†’์ด: {sy2 - sy1:.1f}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'answer_2_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'invalid_bbox', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False, + 'answer_source': None, + 'debug_info': { + 'original_bbox': section_bbox, + 'bbox_width': sx2 - sx1, + 'bbox_height': sy2 - sy1, + 'image_size': (w, h) + } + } + + # Section ์ด๋ฏธ์ง€ ํฌ๋กญ ์‹œ padding ์ถ”๊ฐ€ + expanded_section_bbox = self.expand_bbox_with_padding( + [sx1, sy1, sx2, sy2], + self.section_padding, + w, h + ) + sx1_exp, sy1_exp, sx2_exp, sy2_exp = expanded_section_bbox + + # ํ™•์žฅ๋œ bbox ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if sx2_exp <= sx1_exp or sy2_exp <= sy1_exp: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ์ž˜๋ชป๋œ ํ™•์žฅ bbox [{sx1_exp}, {sy1_exp}, {sx2_exp}, {sy2_exp}]") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'answer_2_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'invalid_expanded_bbox', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False, + 'answer_source': None, + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'padding': self.section_padding, + 'image_size': (w, h) + } + } + + # Crop ์‹คํ–‰ - โœจ Section ์ด๋ฏธ์ง€๋งŒ ์ €์žฅ + try: + section_cropped = image[sy1_exp:sy2_exp, sx1_exp:sx2_exp] + + # Crop๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ํ™•์ธ + crop_h, crop_w = section_cropped.shape[:2] + if crop_h == 0 or crop_w == 0: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ํฌ๋กญ๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ๊ฐ€ 0") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'answer_2_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'zero_size_crop', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False, + 'answer_source': None, + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h) + } + } + + section_dir = output_dir / page_name / "sections" + section_dir.mkdir(parents=True, exist_ok=True) + + section_crop_path = section_dir / f"section_{section_idx:02d}.jpg" + + # ํŒŒ์ผ ์ €์žฅ + write_success = cv2.imwrite(str(section_crop_path), section_cropped) + + if not write_success or not section_crop_path.exists(): + logger.error(f"โŒ Section {section_idx} ํŒŒ์ผ ์ €์žฅ ์‹คํŒจ: {section_crop_path}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'answer_2_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'file_write_failed', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False, + 'answer_source': None + } + + # logger.info(f"โœ… Section {section_idx} ์ด๋ฏธ์ง€ ์ €์žฅ ์„ฑ๊ณต (padding {self.section_padding}px ์ถ”๊ฐ€): {section_crop_path}") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + + except Exception as e: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: {e}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'answer_2_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': f'exception: {str(e)}', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False, + 'answer_source': None + } + + # 1004 ๋ชจ๋ธ์—์„œ ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ (ํ™•์žฅ๋œ ์˜์—ญ ๊ธฐ์ค€) + section_dets_1004 = [] + for det in detections_1004: + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + # ํ™•์žฅ๋œ ์˜์—ญ ๋‚ด์—์„œ ๊ฒ€์ถœ (padding ๊ณ ๋ ค) + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + if det['class_name'] == 'problem_number': + section_dets_1004.append(det) + # ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜ ์—ฌ๋ถ€ ์ฒดํฌ + if self.is_bbox_near_section_boundary(det['bbox'], [sx1, sy1, sx2, sy2]): + logger.warning(f"Section {section_idx}: ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์œ„์น˜ (padding์œผ๋กœ ๋ณด์ •)") + + # ๋””๋ฒ„๊น…: ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ ๊ฒฐ๊ณผ (์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™”) + # logger.info(f"Section {section_idx}: 1004 ๋ชจ๋ธ ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ ๊ฐœ์ˆ˜ = {len(section_dets_1004)}") + # if section_dets_1004: + # for i, det in enumerate(section_dets_1004): + # logger.info(f" ๋ฌธ์ œ๋ฒˆํ˜ธ {i+1}: confidence={det['confidence']:.3f}, bbox={det['bbox']}") + + # 1104 ๋ชจ๋ธ์—์„œ answer_1, answer_2, ์ˆซ์ž(1-5) ๊ฒ€์ถœ (ํ™•์žฅ๋œ ์˜์—ญ ๊ธฐ์ค€) + section_dets_1104 = [] + for det in detections_1104: + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + if det['class_name'] in ['answer_1', 'answer_2', '1', '2', '3', '4', '5']: + section_dets_1104.append(det) + + # ๋””๋ฒ„๊น…: answer_1๊ณผ answer_2 ๊ฒ€์ถœ ๊ฒฐ๊ณผ (์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™”) + answer_1_dets = [d for d in section_dets_1104 if d['class_name'] == 'answer_1'] + answer_2_dets = [d for d in section_dets_1104 if d['class_name'] == 'answer_2'] + + # logger.info(f"Section {section_idx}: 1104 ๋ชจ๋ธ answer_1 ๊ฒ€์ถœ ๊ฐœ์ˆ˜ = {len(answer_1_dets)}") + # if answer_1_dets: + # for i, det in enumerate(answer_1_dets): + # logger.info(f" answer_1 {i+1}: confidence={det['confidence']:.3f}, bbox={det['bbox']}") + # + # logger.info(f"Section {section_idx}: 1104 ๋ชจ๋ธ answer_2 ๊ฒ€์ถœ ๊ฐœ์ˆ˜ = {len(answer_2_dets)}") + # if answer_2_dets: + # for i, det in enumerate(answer_2_dets): + # logger.info(f" answer_2 {i+1}: confidence={det['confidence']:.3f}, bbox={det['bbox']}") + + # โœจ ๋ฌธ์ œ๋ฒˆํ˜ธ OCR (์ด๋ฏธ์ง€ ์ €์žฅ ์—†์ด OCR๋งŒ ์ˆ˜ํ–‰) + problem_ocr = None + problem_crop_path = None + problem_ocr_override = False # โœจ ๋‹ต์ง€ ๊ธฐ๋ฐ˜ ํ• ๋‹น ์—ฌ๋ถ€ + + if section_dets_1004: + # โœจ ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ 2๊ฐœ ๊ฒ€์ถœ๋œ ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ + if len(section_dets_1004) == 2: + logger.warning(f"โš ๏ธ Section {section_idx}: ๋ฌธ์ œ๋ฒˆํ˜ธ 2๊ฐœ ๊ฒ€์ถœ๋จ!") + logger.warning(f" ๋‹ต์ง€ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ˆ„๋ฝ๋œ ๊ฐ€์žฅ ์ž‘์€ ๋ฒˆํ˜ธ๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.") + + # ๋‹ต์ง€์—์„œ ๋ˆ„๋ฝ๋œ ๊ฐ€์žฅ ์ž‘์€ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ฐพ๊ธฐ + missing_number = self.get_missing_problem_number(page_number_ocr, recognized_problem_numbers) + + if missing_number: + problem_ocr = missing_number + problem_ocr_override = True + logger.info(f"โœ… Section {section_idx}: ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ํ• ๋‹น โ†’ {problem_ocr}") + else: + logger.warning(f"Section {section_idx}: ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ, ์‹ ๋ขฐ๋„ ๋†’์€ ๊ฒƒ ์‚ฌ์šฉ") + best_det = max(section_dets_1004, key=lambda x: x['confidence']) + else: + best_det = max(section_dets_1004, key=lambda x: x['confidence']) + + # ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ์ˆ˜ํ–‰ (์ด๋ฏธ์ง€ ์ €์žฅ ์•ˆ ํ•จ) + if not problem_ocr_override: + x1, y1, x2, y2 = map(int, best_det['bbox']) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped = image[y1:y2, x1:x2] + + # ์ž„์‹œ ํŒŒ์ผ๋กœ OCR ์ˆ˜ํ–‰ (์ €์žฅํ•˜์ง€ ์•Š์Œ) + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=True) as tmp: + cv2.imwrite(tmp.name, cropped) + problem_ocr = self.ocr.extract_number(tmp.name) + + # logger.info(f"Section {section_idx} ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ๊ฒฐ๊ณผ: '{problem_ocr}' (์ด๋ฏธ์ง€ ์ €์žฅ ์•ˆ ํ•จ)") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + else: + logger.warning(f"Section {section_idx}: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ") + + # โœจโœจโœจ ์ƒˆ๋กœ์šด ๋กœ์ง: YOLO ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๊ธฐ๋ฐ˜ ์ฒ˜๋ฆฌ โœจโœจโœจ + best_answer = None + used_resnet = False + resnet_confidence = 0.0 + resnet_failed = False + answer_1_crop_path = None + answer_2_crop_path = None + answer_source = None # 'answer_2_resnet', 'answer_1_resnet', 'answer_1_yolo' + yolo_iou_verification = None + + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + # 1๋‹จ๊ณ„: YOLO๋กœ answer_2 ๊ฒ€์ถœ ์—ฌ๋ถ€ ํ™•์ธ + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + if answer_2_dets: + # logger.info(f"Section {section_idx}: ๐ŸŽฏ answer_2 ๊ฒ€์ถœ๋จ - answer_2 ResNet๋งŒ ์‚ฌ์šฉ") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + + # answer_2๋ฅผ crop (์ž„์‹œ ํŒŒ์ผ, ์ €์žฅํ•˜์ง€ ์•Š์Œ) + best_det = max(answer_2_dets, key=lambda x: x['confidence']) + answer_2_bbox = best_det['bbox'] + x1, y1, x2, y2 = map(int, answer_2_bbox) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped_answer_2 = image[y1:y2, x1:x2] + + # โœจ ์ž„์‹œ ํŒŒ์ผ๋กœ ResNet ๋ถ„๋ฅ˜ (์ €์žฅํ•˜์ง€ ์•Š์Œ) + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmp: + cv2.imwrite(tmp.name, cropped_answer_2) + answer_2_temp_path = tmp.name + + try: + # answer_2 ResNet์œผ๋กœ ๋ถ„๋ฅ˜ + answer, conf, failed = self.classify_answer_with_resnet(answer_2_temp_path, section_idx, "answer_2") + + if not failed and answer is not None: + best_answer = answer + resnet_confidence = conf + used_resnet = True + answer_source = 'answer_2_resnet' + # logger.info(f"Section {section_idx}: โœ… answer_2 ResNet ์„ฑ๊ณต - ๋‹ต์•ˆ={best_answer}, ์‹ ๋ขฐ๋„={conf:.4f} (์ตœ์ข… ๋‹ต)") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + else: + resnet_failed = True + used_resnet = True + answer_source = 'answer_2_failed' + logger.error(f"Section {section_idx}: โŒ answer_2 ResNet ์‹คํŒจ") + finally: + # ์ž„์‹œ ํŒŒ์ผ ์‚ญ์ œ + os.unlink(answer_2_temp_path) + else: + logger.warning(f"Section {section_idx}: answer_2 bbox๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Œ") + answer_source = 'answer_2_invalid_bbox' + + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + # 2๋‹จ๊ณ„: answer_2๊ฐ€ ์—†๊ฑฐ๋‚˜ ์‹คํŒจ โ†’ answer_1 ์ฒ˜๋ฆฌ (๊ธฐ์กด ๋กœ์ง) + # โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” + if best_answer is None: + # logger.info(f"Section {section_idx}: ๐Ÿ”„ answer_2 ์—†์Œ ๋˜๋Š” ์‹คํŒจ โ†’ answer_1 ์ฒ˜๋ฆฌ") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + + if answer_1_dets: + # answer_1์„ crop (์ž„์‹œ ํŒŒ์ผ, ์ €์žฅํ•˜์ง€ ์•Š์Œ) + best_det = max(answer_1_dets, key=lambda x: x['confidence']) + answer_1_bbox = best_det['bbox'] + x1, y1, x2, y2 = map(int, answer_1_bbox) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped_answer_1 = image[y1:y2, x1:x2] + + # โœจ ์ž„์‹œ ํŒŒ์ผ๋กœ ResNet ๋ถ„๋ฅ˜ (์ €์žฅํ•˜์ง€ ์•Š์Œ) + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmp: + cv2.imwrite(tmp.name, cropped_answer_1) + answer_1_temp_path = tmp.name + + try: + # ResNet์œผ๋กœ ๋ถ„๋ฅ˜ + answer, conf, failed = self.classify_answer_with_resnet(answer_1_temp_path, section_idx, "answer_1") + + if not failed and answer is not None: + # โœจ YOLO IoU๋กœ ๊ฒ€์ฆ + number_dets = [d for d in section_dets_1104 if d['class_name'] in ['1', '2', '3', '4', '5']] + + if number_dets: + # ๊ฐ ์ˆซ์ž์™€์˜ IoU ๊ณ„์‚ฐ + iou_results = [] + for det in number_dets: + iou = self.calculate_iou(answer_1_bbox, det['bbox']) + iou_results.append({ + 'number': det['class_name'], + 'iou': iou, + 'confidence': det['confidence'] + }) + + # IoU๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ์ˆซ์ž + best_iou_result = max(iou_results, key=lambda x: x['iou']) + yolo_best_number = best_iou_result['number'] + yolo_best_iou = best_iou_result['iou'] + + # YOLO IoU ๊ฒ€์ฆ ๋กœ๊ทธ (์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™”) + # logger.info(f"Section {section_idx}: YOLO IoU ๊ฒ€์ฆ") + # logger.info(f" ResNet ์˜ˆ์ธก: {answer} (์‹ ๋ขฐ๋„: {conf:.4f})") + # logger.info(f" YOLO ์ตœ๊ณ  IoU: {yolo_best_number} (IoU: {yolo_best_iou:.4f})") + # + # # IoU ๊ฒฐ๊ณผ ์ €์žฅ + # for result in sorted(iou_results, key=lambda x: x['iou'], reverse=True): + # logger.info(f" - {result['number']}: IoU={result['iou']:.4f}, Conf={result['confidence']:.3f}") + + yolo_iou_verification = { + 'yolo_best': yolo_best_number, + 'yolo_iou': yolo_best_iou, + 'resnet_pred': answer, + 'resnet_conf': conf, + 'all_ious': iou_results + } + + # โœจ ๋ถˆ์ผ์น˜ ์‹œ ๊ฒฝ๊ณ  + ResNet ์‹ ๋ขฐ๋„๊ฐ€ ๋‚ฎ์œผ๋ฉด YOLO ์‚ฌ์šฉ + if answer != yolo_best_number: + logger.warning(f"โš ๏ธ Section {section_idx}: ResNet({answer}) โ‰  YOLO IoU({yolo_best_number})") + + # ResNet ์‹ ๋ขฐ๋„๊ฐ€ ๋‚ฎ๊ณ (70% ์ดํ•˜) IoU๊ฐ€ ๋†’์œผ๋ฉด(0.3 ์ด์ƒ) YOLO ๊ฒฐ๊ณผ ์‚ฌ์šฉ + if conf < 0.70 and yolo_best_iou > 0.3: + # logger.warning(f" โ†’ ResNet ์‹ ๋ขฐ๋„ ๋‚ฎ์Œ({conf:.2f}), YOLO ๊ฒฐ๊ณผ({yolo_best_number}) ์‚ฌ์šฉ") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + best_answer = yolo_best_number + answer_source = 'answer_1_yolo' + else: + # logger.info(f" โ†’ ResNet ์‹ ๋ขฐ๋„ ๋†’์Œ({conf:.2f}), ResNet ๊ฒฐ๊ณผ({answer}) ์œ ์ง€") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + best_answer = answer + answer_source = 'answer_1_resnet' + else: + # logger.info(f"โœ… Section {section_idx}: ResNet๊ณผ YOLO IoU ์ผ์น˜ ({answer})") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + best_answer = answer + answer_source = 'answer_1_resnet' + else: + # ์ˆซ์ž ๊ฒ€์ถœ ์•ˆ ๋จ - ResNet๋งŒ ์‚ฌ์šฉ + logger.warning(f"Section {section_idx}: YOLO ์ˆซ์ž ๋ฏธ๊ฒ€์ถœ, ResNet๋งŒ ์‚ฌ์šฉ") + best_answer = answer + answer_source = 'answer_1_resnet' + + resnet_confidence = conf + used_resnet = True + resnet_failed = False + # logger.info(f"Section {section_idx}: โœ… ์ตœ์ข… ๋‹ต์•ˆ={best_answer} (์ถœ์ฒ˜: {answer_source})") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + else: + resnet_failed = True + used_resnet = True + answer_source = 'answer_1_failed' + logger.warning(f"Section {section_idx}: โŒ ResNet ๋ถ„๋ฅ˜ ์‹คํŒจ") + finally: + # ์ž„์‹œ ํŒŒ์ผ ์‚ญ์ œ + os.unlink(answer_1_temp_path) + else: + logger.warning(f"Section {section_idx}: answer_1 bbox๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Œ") + resnet_failed = True + answer_source = 'answer_1_invalid_bbox' + else: + logger.warning(f"Section {section_idx}: answer_1๊ณผ answer_2 ๋ชจ๋‘ ๊ฒ€์ถœ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.") + resnet_failed = True + answer_source = 'no_answer_detected' + + # Section ๊ฒ€์ถœ ์‹œ๊ฐํ™” ์ €์žฅ (โœจ ๋ชจ๋“  ๊ฒ€์ถœ ์ •๋ณด ํฌํ•จ) - ๋น„ํ™œ์„ฑํ™” + # self.visualize_section_detection(original_image_path, section_bbox, section_idx, + # output_dir, page_name, section_dets_1104, self.section_padding) + + return { + 'section_idx': section_idx, + 'problem_number_ocr': problem_ocr, + 'problem_number_override': problem_ocr_override, # โœจ ๋‹ต์ง€ ๊ธฐ๋ฐ˜ ํ• ๋‹น ์—ฌ๋ถ€ ํ”Œ๋ž˜๊ทธ + 'answer_number': best_answer, + 'section_crop_path': str(section_crop_path), + 'problem_crop_path': None, # โœจ ๋” ์ด์ƒ ์ €์žฅํ•˜์ง€ ์•Š์Œ + 'answer_1_crop_path': None, # โœจ ๋” ์ด์ƒ ์ €์žฅํ•˜์ง€ ์•Š์Œ + 'answer_2_crop_path': None, # โœจ ๋” ์ด์ƒ ์ €์žฅํ•˜์ง€ ์•Š์Œ + 'crop_success': True, + 'is_boundary_issue': len(section_dets_1004) > 0 and any( + self.is_bbox_near_section_boundary(d['bbox'], [sx1, sy1, sx2, sy2]) + for d in section_dets_1004 + ), + 'used_resnet': used_resnet, + 'resnet_confidence': resnet_confidence, + 'resnet_failed': resnet_failed, + 'answer_source': answer_source, # โœจ ๋‹ต์•ˆ ์ถœ์ฒ˜ ์ถ”๊ฐ€ + 'yolo_iou_verification': yolo_iou_verification, + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h), + 'answer_1_count': len(answer_1_dets), + 'answer_2_count': len(answer_2_dets), # โœจ answer_2 ๊ฐœ์ˆ˜ ์ถ”๊ฐ€ + 'problem_number_count': len(section_dets_1004) # โœจ ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ ๊ฐœ์ˆ˜ + } + } + + def filter_duplicate_sections(self, image_path: str, section_detections: List[Dict], + detections_1004: List[Dict]) -> List[Dict]: + """ + ์ค‘๋ณต๋œ section์„ ํ•„ํ„ฐ๋ง (๊ฐ™์€ problem_number๋ฅผ ๊ฐ€์ง„ section ์ค‘ ๋” ํฐ ๊ฒƒ ์„ ํƒ) + + Args: + image_path: ์›๋ณธ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + section_detections: section ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ + detections_1004: 1004 ๋ชจ๋ธ์˜ ์ „์ฒด ๊ฒ€์ถœ ๊ฒฐ๊ณผ + + Returns: + ํ•„ํ„ฐ๋ง๋œ section ๋ฆฌ์ŠคํŠธ + """ + if len(section_detections) <= 1: + return section_detections + + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return section_detections + + h, w = image.shape[:2] + + # ๊ฐ section์— ๋Œ€ํ•ด problem_number ์ฐพ๊ธฐ + section_with_problem = [] + + for idx, section in enumerate(section_detections): + sx1, sy1, sx2, sy2 = section['bbox'] + section_area = (sx2 - sx1) * (sy2 - sy1) + + # ํ•ด๋‹น section ๋‚ด์˜ problem_number ์ฐพ๊ธฐ + problem_numbers = [] + for det in detections_1004: + if det['class_name'] != 'problem_number': + continue + + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + + # Section ์˜์—ญ ๋‚ด์— ์žˆ๋Š”์ง€ ํ™•์ธ + if sx1 <= cx <= sx2 and sy1 <= cy <= sy2: + problem_numbers.append(det) + + # ๊ฐ€์žฅ ์‹ ๋ขฐ๋„ ๋†’์€ problem_number ์‚ฌ์šฉ + if problem_numbers: + best_problem = max(problem_numbers, key=lambda x: x['confidence']) + + # OCR๋กœ ๋ฌธ์ œ๋ฒˆํ˜ธ ์ธ์‹ (์ž„์‹œ) + x1, y1, x2, y2 = map(int, best_problem['bbox']) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped = image[y1:y2, x1:x2] + # โœจ ์ž„์‹œ ํŒŒ์ผ๋กœ OCR (์ €์žฅํ•˜์ง€ ์•Š์Œ) + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=True) as tmp: + cv2.imwrite(tmp.name, cropped) + problem_ocr = self.ocr.extract_number(tmp.name) + else: + problem_ocr = None + else: + problem_ocr = None + + section_with_problem.append({ + 'section': section, + 'original_index': idx, + 'problem_number_ocr': problem_ocr, + 'section_area': section_area, + 'bbox': section['bbox'] + }) + + # problem_number๋ณ„๋กœ ๊ทธ๋ฃนํ™” + problem_groups = {} + no_problem_sections = [] + + for item in section_with_problem: + problem_num = item['problem_number_ocr'] + + if problem_num is None or problem_num == '': + # ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ ์—†๋Š” section์€ ๋ณ„๋„ ์ฒ˜๋ฆฌ + no_problem_sections.append(item) + else: + if problem_num not in problem_groups: + problem_groups[problem_num] = [] + problem_groups[problem_num].append(item) + + # ์ค‘๋ณต ์ œ๊ฑฐ: ๊ฐ ๊ทธ๋ฃน์—์„œ ๊ฐ€์žฅ ํฐ section ์„ ํƒ + filtered_sections = [] + removed_count = 0 + + for problem_num, items in problem_groups.items(): + if len(items) > 1: + # ๋ฉด์ ์ด ๊ฐ€์žฅ ํฐ section ์„ ํƒ + largest = max(items, key=lambda x: x['section_area']) + filtered_sections.append(largest['section']) + + removed_count += len(items) - 1 + + logger.warning(f"โš ๏ธ ๋ฌธ์ œ๋ฒˆํ˜ธ '{problem_num}': {len(items)}๊ฐœ section ๊ฒ€์ถœ๋จ") + logger.warning(f" ๊ฐ€์žฅ ํฐ section ์„ ํƒ (๋ฉด์ : {largest['section_area']:.1f})") + + # ์ œ๊ฑฐ๋œ section๋“ค ๋กœ๊ทธ + for item in items: + if item != largest: + logger.warning(f" - ์ œ๊ฑฐ: Section index {item['original_index']}, " + f"๋ฉด์ ={item['section_area']:.1f}, bbox={item['bbox']}") + else: + filtered_sections.append(items[0]['section']) + + # ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ ์—†๋Š” section๋“ค ์ถ”๊ฐ€ + for item in no_problem_sections: + filtered_sections.append(item['section']) + logger.warning(f"โš ๏ธ Section index {item['original_index']}: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ (ํฌํ•จ)") + + if removed_count > 0: + logger.info(f"โœ‚๏ธ ์ค‘๋ณต ํ•„ํ„ฐ๋ง: {removed_count}๊ฐœ section ์ œ๊ฑฐ๋จ") + logger.info(f" ํ•„ํ„ฐ๋ง ์ „: {len(section_detections)}๊ฐœ โ†’ ํ•„ํ„ฐ๋ง ํ›„: {len(filtered_sections)}๊ฐœ") + + # y ์ขŒํ‘œ ๊ธฐ์ค€์œผ๋กœ ์žฌ์ •๋ ฌ + filtered_sections = sorted(filtered_sections, key=lambda x: x['bbox'][1]) + + return filtered_sections + + def process_page(self, image_path: str, output_dir: Path) -> Optional[Dict]: + """ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ: 1104 ๋ชจ๋ธ๋กœ answer_1/answer_2 ๊ฒ€์ถœ, answer_2 ์šฐ์„  ์ฒ˜๋ฆฌ + + Returns: + Optional[Dict]: ํŽ˜์ด์ง€๊ฐ€ ๋‹ต์ง€์— ์žˆ์œผ๋ฉด ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜, ์—†์œผ๋ฉด None + """ + start_time = time.time() + + # 1004 ๋ชจ๋ธ: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ๊ฒ€์ถœ + logger.info("1004 ๋ชจ๋ธ ์‹คํ–‰ ์ค‘ (ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ๊ฒ€์ถœ)...") + result_1004 = self.router_1004.route_infer_single_image(image_path) + detections_1004 = result_1004['detections'] + + # Section ๊ฒ€์ถœ ํ†ต๊ณ„ + section_detections = [d for d in detections_1004 if d['class_name'] == 'section'] + logger.info(f"1004 ๋ชจ๋ธ Section ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {len(section_detections)}") + + if not section_detections: + logger.error(f"โŒ Section์ด ํ•˜๋‚˜๋„ ๊ฒ€์ถœ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค!") + logger.error(f" 1004 ๋ชจ๋ธ ์ „์ฒด ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {len(detections_1004)}") + logger.error(f" ๊ฒ€์ถœ๋œ ํด๋ž˜์Šค: {set(d['class_name'] for d in detections_1004)}") + + # ๊ฒ€์ถœ๋œ ํด๋ž˜์Šค๋ณ„ ๊ฐœ์ˆ˜ ์ถœ๋ ฅ + class_counts = {} + for det in detections_1004: + class_name = det['class_name'] + class_counts[class_name] = class_counts.get(class_name, 0) + 1 + + logger.error(f" ํด๋ž˜์Šค๋ณ„ ๊ฒ€์ถœ ๊ฐœ์ˆ˜:") + for class_name, count in sorted(class_counts.items()): + logger.error(f" - {class_name}: {count}๊ฐœ") + # else: # Section ์ƒ์„ธ ์ •๋ณด ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + # for i, det in enumerate(section_detections): + # bbox = det['bbox'] + # conf = det['confidence'] + # logger.info(f" Section {i}: confidence={conf:.3f}, bbox=[{bbox[0]:.1f}, {bbox[1]:.1f}, {bbox[2]:.1f}, {bbox[3]:.1f}]") + + page_name = Path(image_path).stem + page_output_dir = output_dir / page_name + page_output_dir.mkdir(parents=True, exist_ok=True) + + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ OCR (1004 ๋ชจ๋ธ ์‚ฌ์šฉ, ์ด๋ฏธ์ง€ ์ €์žฅ ์•ˆ ํ•จ) + page_num_path, page_num_ocr = self.crop_page_number(image_path, detections_1004, page_output_dir) + + # ๋‹ต์ง€ ํ•„ํ„ฐ๋ง: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๊ฐ€ ๋‹ต์ง€์— ์—†์œผ๋ฉด ๊ฑด๋„ˆ๋›ฐ๊ธฐ + if not self.is_valid_page(page_num_ocr): + logger.info(f"ํŽ˜์ด์ง€ '{page_name}' (ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ: {page_num_ocr})๋Š” ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") + return None + + # 1104 ๋ชจ๋ธ: answer_1, answer_2 ๊ฒ€์ถœ์šฉ + logger.info("1104 ๋ชจ๋ธ ์‹คํ–‰ ์ค‘ (answer_1, answer_2 ๊ฒ€์ถœ)...") + result_1104 = self.router_1104.route_infer_single_image(image_path) + detections_1104 = result_1104['detections'] + + # Section ์˜์—ญ ๊ฒ€์ถœ (1004 ๋ชจ๋ธ ์‚ฌ์šฉ) + logger.info(f"ํŽ˜์ด์ง€ '{page_name}': {len(section_detections)}๊ฐœ Section ๊ฒ€์ถœ (ํ•„ํ„ฐ๋ง ์ „)") + + # ์ค‘๋ณต section ํ•„ํ„ฐ๋ง + section_detections = self.filter_duplicate_sections(image_path, section_detections, detections_1004) + + # ์ •๋ ฌ (y ์ขŒํ‘œ ๊ธฐ์ค€) + section_detections = sorted(section_detections, key=lambda x: x['bbox'][1]) + + logger.info(f"ํŽ˜์ด์ง€ '{page_name}': {len(section_detections)}๊ฐœ Section ์ฒ˜๋ฆฌ (ํ•„ํ„ฐ๋ง ํ›„)") + + # โœจ ํŽ˜์ด์ง€ ๋‚ด ์ธ์‹๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ถ”์ ์šฉ set + recognized_problem_numbers = set() + + page_result = [] + crop_failure_count = 0 + + for idx, det in enumerate(section_detections): + section_bbox = det['bbox'] + section_result = self.process_single_section( + image_path, idx, page_name, output_dir, section_bbox, + detections_1004, detections_1104, page_num_ocr, recognized_problem_numbers + ) + page_result.append(section_result) + + # โœจ ์ธ์‹๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ๋ฅผ set์— ์ถ”๊ฐ€ + if section_result.get('problem_number_ocr'): + recognized_problem_numbers.add(section_result['problem_number_ocr']) + # logger.info(f"๐Ÿ“ ์ธ์‹๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ถ”๊ฐ€: {section_result['problem_number_ocr']}") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + # logger.info(f" ํ˜„์žฌ๊นŒ์ง€ ์ธ์‹๋œ ๋ฌธ์ œ: {sorted(recognized_problem_numbers)}") # ์ƒ์„ธ ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” + + if not section_result.get('crop_success', True): + crop_failure_count += 1 + + end_time = time.time() + + # Crop ์‹คํŒจ ํ†ต๊ณ„ + if crop_failure_count > 0: + logger.warning(f"โš ๏ธ ํŽ˜์ด์ง€ '{page_name}': {crop_failure_count}๊ฐœ Section crop ์‹คํŒจ") + + return { + "image_path": image_path, + "page_name": page_name, + "page_number_ocr": page_num_ocr, + "sections": page_result, + "processing_time": end_time - start_time, + "total_sections": len(section_detections), + "crop_failure_count": crop_failure_count + } \ No newline at end of file diff --git a/ai-service/test/Hierarchical_crop/hierarchical_crop_test.py b/ai-service/test/Hierarchical_crop/hierarchical_crop_test.py new file mode 100644 index 0000000..ba4e433 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/hierarchical_crop_test.py @@ -0,0 +1,536 @@ +# yolo_test.py +import logging +import time +from pathlib import Path +from test.Hierarchical_crop.hierarchical_crop import HierarchicalCropPipeline + +# === ๋กœ๊น… ์„ค์ • === +current_dir = Path(__file__).parent +log_file = current_dir / "ocr_results.log" + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + +# ํŒŒ์ผ ์ถœ๋ ฅ ์ถ”๊ฐ€ (utf-8 ์ธ์ฝ”๋”ฉ) +file_handler = logging.FileHandler(log_file, encoding="utf-8") +file_handler.setLevel(logging.INFO) +file_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") +file_handler.setFormatter(file_formatter) +logger.addHandler(file_handler) + +logger.info(f"โœ… ๋กœ๊ทธ ํŒŒ์ผ์ด '{log_file}'๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.") + + +def main(): + """๋ฉ”์ธ ์‹คํ—˜ ํ•จ์ˆ˜""" + total_start_time = time.time() + + # ๊ฒฝ๋กœ ์„ค์ • + input_images_dir = current_dir / "images" / "exp_images" + output_dir = current_dir / "images" / "test_results" + model_dir_1104 = current_dir.parent.parent / "models" / "Detection" / "legacy" / "Model_routing_1104" + model_dir_1004 = current_dir.parent.parent / "models" / "Detection" / "legacy" / "Model_routing_1004" + + # โœจ answer_1๊ณผ answer_2์šฉ ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ ๋ถ„๋ฆฌ + resnet_answer_1_path = current_dir.parent.parent / "models" / "Recognition" / "models" / "answer_1_resnet.pth" + resnet_answer_2_path = current_dir.parent.parent / "models" / "Recognition" / "models" / "answer_2_resnet.pth" + + # ๋‹ต์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ + answer_key_path = current_dir / "answers" / "answer.txt" + + # ๋‹ต์ง€ ํŒŒ์ผ์ด ์—†์œผ๋ฉด None์œผ๋กœ ์„ค์ • (๋ชจ๋“  ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ) + if not answer_key_path.exists(): + logger.warning(f"๋‹ต์ง€ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {answer_key_path}") + logger.warning("๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.") + answer_key_path = None + + logger.info("=" * 60) + logger.info("๊ณ„์ธต์  ํฌ๋กญ ํŒŒ์ดํ”„๋ผ์ธ (answer_2 ์šฐ์„  + ResNet ๋ถ„๋ฅ˜) ์‹คํ—˜ ์‹œ์ž‘") + logger.info("=" * 60) + logger.info(f"์ž…๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ: {input_images_dir}") + logger.info(f"์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ: {output_dir}") + logger.info(f"1104 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ: {model_dir_1104}") + logger.info(f"1004 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ: {model_dir_1004}") + logger.info(f"answer_1 ResNet ๋ชจ๋ธ: {resnet_answer_1_path}") # โœจ + logger.info(f"answer_2 ResNet ๋ชจ๋ธ: {resnet_answer_2_path}") # โœจ + logger.info(f"๋‹ต์ง€ ํŒŒ์ผ: {answer_key_path}") + + # ํŒŒ์ดํ”„๋ผ์ธ ์ดˆ๊ธฐํ™” (๋‘ ๊ฐœ์˜ ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ ์ „๋‹ฌ) + pipeline = HierarchicalCropPipeline( + str(model_dir_1104), + str(model_dir_1004), + section_padding=50, + answer_key_path=str(answer_key_path) if answer_key_path else None, + resnet_answer_1_path=str(resnet_answer_1_path) if resnet_answer_1_path.exists() else None, # โœจ + resnet_answer_2_path=str(resnet_answer_2_path) if resnet_answer_2_path.exists() else None # โœจ + ) + + # ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ˆ˜์ง‘ + image_extensions = [".jpg", ".jpeg", ".png", ".bmp"] + image_files = [] + for ext in image_extensions: + image_files.extend(input_images_dir.glob(f"*{ext}")) + image_files.extend(input_images_dir.glob(f"*{ext.upper()}")) + + image_files = sorted(image_files) + logger.info(f"\n์ฒ˜๋ฆฌํ•  ์ด๋ฏธ์ง€: {len(image_files)}๊ฐœ") + + if not image_files: + logger.warning(f"์ž…๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ์— ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค: {input_images_dir}") + return + + # ๊ฐ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ + all_results = [] + skipped_pages = [] + + for idx, image_path in enumerate(image_files): + logger.info(f"\n\n{'#' * 60}") + logger.info(f"[{idx + 1}/{len(image_files)}] ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘: {Path(image_path).name}") + logger.info(f"{'#' * 60}") + + try: + result = pipeline.process_page(str(image_path), output_dir) + + if result is None: + # ๋‹ต์ง€์— ์—†๋Š” ํŽ˜์ด์ง€ + skipped_pages.append(Path(image_path).name) + logger.info(f"โญ๏ธ ํŽ˜์ด์ง€ ๊ฑด๋„ˆ๋œ€ (๋‹ต์ง€์— ์—†์Œ)") + else: + all_results.append(result) + logger.info(f"โœ… ํŽ˜์ด์ง€ '{result['page_name']}' ์ฒ˜๋ฆฌ ์™„๋ฃŒ: {result['processing_time']:.2f}์ดˆ") + except Exception as e: + logger.error(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์‹คํŒจ: {image_path}") + logger.error(f"์—๋Ÿฌ: {e}", exc_info=True) + continue + + total_end_time = time.time() + total_processing_time = total_end_time - total_start_time + + # ์š”์•ฝ ๋ฐ ๊ฒฐ๊ณผ ์ €์žฅ + print_summary(all_results, skipped_pages, output_dir, total_processing_time) + save_results_txt(all_results, output_dir) + save_none_analysis(all_results, output_dir) + save_answer_source_analysis(all_results, output_dir) # โœจ answer_source ํ†ต๊ณ„ ์ถ”๊ฐ€ + save_crop_failure_analysis(all_results, output_dir) + check_missing_sections_against_answer_key(all_results, output_dir, pipeline.answer_key) + + +def save_results_txt(all_results: list, output_dir: Path): + """ + TXT ํŒŒ์ผ์— ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ์ธ์‹๋œ ๋‹ต์„ ํ•œ ์ค„์”ฉ ์ €์žฅ + """ + txt_path = output_dir.parent.parent / "answers" / "results_summary.txt" + output_dir.mkdir(parents=True, exist_ok=True) + + if not all_results: + logger.warning("โš ๏ธ ์ €์žฅํ•  ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.") + return + + with open(txt_path, "w", encoding="utf-8") as f: + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + for section in sections: + problem_number = section.get("problem_number_ocr", "") + answer_number = section.get("answer_number", "") + + # ์ด๋ฏธ์ง€ ํŒŒ์ผ๋ช…, ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ๋‹ต ๋ฒˆํ˜ธ๋ฅผ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ํ•œ ์ค„์— ์ž‘์„ฑ + line = f"{page_name}, {page_num_ocr}, {problem_number}, {answer_number}\n" + f.write(line) + + logger.info(f"\n๐Ÿ“„ TXT ๊ฒฐ๊ณผ ์ €์žฅ ์™„๋ฃŒ: {txt_path}") + + # ์ด ๋ผ์ธ ์ˆ˜ ๊ณ„์‚ฐ + total_lines = sum(len(r.get("sections", [])) for r in all_results) + logger.info(f"์ด {total_lines}๊ฐœ ๋ฌธ์ œ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") + + # None ๋‹ต์•ˆ ํ†ต๊ณ„ + none_count = 0 + resnet_used_count = 0 # โœจ ResNet ์‚ฌ์šฉ ํšŸ์ˆ˜ + answer_2_count = 0 # โœจ answer_2 ์‚ฌ์šฉ ํšŸ์ˆ˜ + + for result in all_results: + for section in result.get("sections", []): + if section.get("answer_number") is None: + none_count += 1 + if section.get("used_resnet", False): # โœจ ResNet ์‚ฌ์šฉ ์—ฌ๋ถ€ + resnet_used_count += 1 + answer_source = section.get("answer_source", "") + # None ์ฒดํฌ ์ถ”๊ฐ€ + if answer_source and answer_source.startswith("answer_2"): + answer_2_count += 1 + + logger.info(f"None ๋‹ต์•ˆ: {none_count}๊ฐœ ({none_count/total_lines*100:.1f}%)") + logger.info(f"ResNet ์‚ฌ์šฉ: {resnet_used_count}๊ฐœ ({resnet_used_count/total_lines*100:.1f}%)") # โœจ + logger.info(f"answer_2 ์‚ฌ์šฉ: {answer_2_count}๊ฐœ ({answer_2_count/total_lines*100:.1f}%)") # โœจ + + +def save_none_analysis(all_results: list, output_dir: Path): + """ + None์œผ๋กœ ์ €์žฅ๋œ ๋‹ต์•ˆ์˜ ์ƒ์„ธ ๋””๋ฒ„๊น… ์ •๋ณด๋ฅผ ๋ณ„๋„ ํŒŒ์ผ๋กœ ์ €์žฅ + """ + analysis_path = output_dir.parent.parent / "answers" / "none_debug_analysis.txt" + + none_cases = [] + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + for section in sections: + if section.get("answer_number") is None: + debug_info = section.get("debug_info", {}) + none_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'section_idx': section.get('section_idx'), + 'problem_number': section.get('problem_number_ocr'), + 'debug_info': debug_info, + 'section_crop_path': section.get('section_crop_path'), + 'problem_crop_path': section.get('problem_crop_path'), + 'used_resnet': section.get('used_resnet', False), # โœจ + 'resnet_failed': section.get('resnet_failed', False), # โœจ + 'answer_source': section.get('answer_source', '') # โœจ + }) + + if not none_cases: + logger.info("โœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค!") + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("None ๋‹ต์•ˆ ๋””๋ฒ„๊น… ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write("โœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค! ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n") + return + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("None ๋‹ต์•ˆ ๋””๋ฒ„๊น… ๋ถ„์„ (answer_2 ์šฐ์„  + ResNet)\n") + f.write("=" * 80 + "\n\n") + f.write(f"์ด {len(none_cases)}๊ฐœ์˜ None ๋‹ต์•ˆ ๋ฐœ๊ฒฌ\n\n") + + # ์›์ธ๋ณ„ ํ†ต๊ณ„ + answer_1_missing = sum(1 for case in none_cases if case['debug_info'].get('answer_1_count', 0) == 0) + answer_2_missing = sum(1 for case in none_cases if case['debug_info'].get('answer_2_count', 0) == 0) + resnet_tried = sum(1 for case in none_cases if case['used_resnet']) # โœจ + resnet_failed = sum(1 for case in none_cases if case['resnet_failed']) # โœจ + + f.write("๐Ÿ“Š ์›์ธ๋ณ„ ํ†ต๊ณ„:\n") + f.write(f" - answer_1 ๋ฏธ๊ฒ€์ถœ: {answer_1_missing}๊ฐœ\n") + f.write(f" - answer_2 ๋ฏธ๊ฒ€์ถœ: {answer_2_missing}๊ฐœ\n") + f.write(f" - ResNet ์‹œ๋„: {resnet_tried}๊ฐœ ({resnet_tried/len(none_cases)*100:.1f}%)\n") # โœจ + f.write(f" - ResNet๋„ ์‹คํŒจ: {resnet_failed}๊ฐœ ({resnet_failed/len(none_cases)*100:.1f}%)\n") # โœจ + f.write("\n") + + for i, case in enumerate(none_cases, 1): + f.write(f"\n{'='*80}\n") + f.write(f"[{i}] ํŽ˜์ด์ง€: {case['page_name']} (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: {case['page_num']})\n") + f.write(f" Section: {case['section_idx']}, ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['problem_number']}\n") + f.write(f"{'-'*80}\n") + + debug = case['debug_info'] + answer_1_count = debug.get('answer_1_count', 0) + answer_2_count = debug.get('answer_2_count', 0) + + f.write(f" ๐Ÿ“‹ ๊ฒ€์ถœ ์ •๋ณด:\n") + f.write(f" answer_1 ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {answer_1_count}\n") + f.write(f" answer_2 ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {answer_2_count}\n") + f.write(f" ResNet ์‹œ๋„: {'์˜ˆ' if case['used_resnet'] else '์•„๋‹ˆ์˜ค'}\n") # โœจ + f.write(f" answer_source: {case['answer_source']}\n") # โœจ + if case['used_resnet']: + f.write(f" ResNet ๊ฒฐ๊ณผ: {'์‹คํŒจ' if case['resnet_failed'] else '์„ฑ๊ณตํ–ˆ์œผ๋‚˜ None'}\n") # โœจ + f.write("\n") + + # ์›์ธ ๋ถ„์„ + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + if answer_2_count == 0 and answer_1_count == 0: + f.write(f" โŒ answer_1๊ณผ answer_2 ๋ชจ๋‘ ๊ฒ€์ถœ๋˜์ง€ ์•Š์Œ (1104 ๋ชจ๋ธ ๋ฌธ์ œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: 1104 ๋ชจ๋ธ ์žฌํ•™์Šต ๋˜๋Š” confidence threshold ์กฐ์ •\n") + elif answer_2_count > 0 and case['answer_source'] == 'answer_2_failed': + f.write(f" โŒ answer_2๋Š” ๊ฒ€์ถœ๋˜์—ˆ์œผ๋‚˜ ResNet ๋ถ„๋ฅ˜ ์‹คํŒจ\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: answer_2 ResNet ๋ชจ๋ธ ์žฌํ•™์Šต\n") + elif answer_1_count > 0 and case['answer_source'] == 'answer_1_failed': + f.write(f" โŒ answer_1์€ ๊ฒ€์ถœ๋˜์—ˆ์œผ๋‚˜ ResNet ๋ถ„๋ฅ˜ ์‹คํŒจ\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: answer_1 ResNet ๋ชจ๋ธ ์žฌํ•™์Šต\n") + else: + f.write(f" โš ๏ธ ์›์ธ ๋ถˆ๋ช… (๋””๋ฒ„๊น… ํ•„์š”)\n") + + # ํŒŒ์ผ ๊ฒฝ๋กœ + f.write(f"\n ๐Ÿ“ ๊ด€๋ จ ํŒŒ์ผ:\n") + f.write(f" Section ์ด๋ฏธ์ง€: {case['section_crop_path']}\n") + if case['problem_crop_path']: + f.write(f" ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€: {case['problem_crop_path']}\n") + else: + f.write(f" ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€: (๋ฏธ์ƒ์„ฑ - ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ)\n") + + logger.info(f"๐Ÿ“Š None ๋””๋ฒ„๊น… ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + logger.info(f" ์ด {len(none_cases)}๊ฐœ None ์ผ€์ด์Šค ๋ถ„์„") + + +def save_answer_source_analysis(all_results: list, output_dir: Path): + """ + โœจ answer_source๋ณ„ ํ†ต๊ณ„๋ฅผ ๋ณ„๋„ ํŒŒ์ผ๋กœ ์ €์žฅ + """ + analysis_path = output_dir.parent.parent / "answers" / "answer_source_analysis.txt" + + source_stats = { + 'answer_2_resnet': [], + 'answer_1_resnet': [], + 'answer_1_yolo': [], + 'answer_2_failed': [], + 'answer_1_failed': [], + 'no_answer_detected': [], + 'other': [] + } + + total_sections = 0 + + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + total_sections += len(sections) + + for section in sections: + answer_source = section.get("answer_source", "") + answer_number = section.get("answer_number") + + case = { + 'page_name': page_name, + 'page_num': page_num_ocr, + 'section_idx': section.get('section_idx'), + 'problem_number': section.get('problem_number_ocr'), + 'answer': answer_number, + 'confidence': section.get('resnet_confidence', 0.0) + } + + if answer_source in source_stats: + source_stats[answer_source].append(case) + else: + source_stats['other'].append(case) + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("๋‹ต์•ˆ ์ถœ์ฒ˜(answer_source)๋ณ„ ํ†ต๊ณ„\n") + f.write("=" * 80 + "\n\n") + + f.write(f"์ด Section ์ˆ˜: {total_sections}๊ฐœ\n\n") + + f.write("๐Ÿ“Š ์ถœ์ฒ˜๋ณ„ ํ†ต๊ณ„:\n") + for source, cases in source_stats.items(): + if cases: + percentage = len(cases) / total_sections * 100 + f.write(f" - {source}: {len(cases)}๊ฐœ ({percentage:.1f}%)\n") + f.write("\n") + + # ์„ฑ๊ณต๋ฅ  ๊ณ„์‚ฐ + success_sources = ['answer_2_resnet', 'answer_1_resnet', 'answer_1_yolo'] + success_count = sum(len(source_stats[s]) for s in success_sources) + success_rate = success_count / total_sections * 100 if total_sections > 0 else 0 + + f.write(f"โœ… ์ „์ฒด ์„ฑ๊ณต๋ฅ : {success_count}/{total_sections} ({success_rate:.1f}%)\n") + f.write(f"โŒ ์ „์ฒด ์‹คํŒจ์œจ: {total_sections - success_count}/{total_sections} ({100 - success_rate:.1f}%)\n\n") + + # answer_2 ์šฐ์„  ์ „๋žต ํšจ๊ณผ + answer_2_count = len(source_stats['answer_2_resnet']) + if answer_2_count > 0: + f.write(f"๐ŸŽฏ answer_2 ์šฐ์„  ์ „๋žต:\n") + f.write(f" - answer_2๋กœ ํ•ด๊ฒฐ: {answer_2_count}๊ฐœ ({answer_2_count/total_sections*100:.1f}%)\n") + f.write(f" - answer_2 ResNet ํ‰๊ท  ์‹ ๋ขฐ๋„: ") + avg_conf = sum(c['confidence'] for c in source_stats['answer_2_resnet']) / len(source_stats['answer_2_resnet']) + f.write(f"{avg_conf:.4f}\n\n") + + # ์ƒ์„ธ ์ผ€์ด์Šค + for source, cases in source_stats.items(): + if cases: + f.write(f"\n{'='*80}\n") + f.write(f"{source.upper()} ({len(cases)}๊ฐœ)\n") + f.write(f"{'='*80}\n") + + for i, case in enumerate(cases[:10], 1): # ์ตœ๋Œ€ 10๊ฐœ๋งŒ ํ‘œ์‹œ + f.write(f"\n[{i}] ํŽ˜์ด์ง€: {case['page_name']}, ") + f.write(f"Section: {case['section_idx']}, ") + f.write(f"๋ฌธ์ œ: {case['problem_number']}, ") + f.write(f"๋‹ต: {case['answer']}") + if case['confidence'] > 0: + f.write(f", ์‹ ๋ขฐ๋„: {case['confidence']:.4f}") + f.write("\n") + + if len(cases) > 10: + f.write(f"\n... (์™ธ {len(cases) - 10}๊ฐœ)\n") + + logger.info(f"๐Ÿ“Š answer_source ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + logger.info(f" answer_2 ResNet: {len(source_stats['answer_2_resnet'])}๊ฐœ") + logger.info(f" answer_1 ResNet: {len(source_stats['answer_1_resnet'])}๊ฐœ") + logger.info(f" answer_1 YOLO: {len(source_stats['answer_1_yolo'])}๊ฐœ") + + +def save_crop_failure_analysis(all_results: list, output_dir: Path): + """ + Section crop ์‹คํŒจ ์ผ€์ด์Šค๋ฅผ ๋ถ„์„ํ•˜์—ฌ ๋ณ„๋„ ํŒŒ์ผ๋กœ ์ €์žฅ + """ + analysis_path = output_dir.parent.parent / "answers" / "crop_failure_analysis.txt" + + crop_failure_cases = [] + total_expected_sections = 0 + total_actual_files = 0 + + for result in all_results: + page_name = result.get("page_name", "") + sections = result.get("sections", []) + total_expected_sections += len(sections) + + # ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ ํ™•์ธ + sections_dir = output_dir / page_name / "sections" + if sections_dir.exists(): + actual_files = sorted(sections_dir.glob("section_*.jpg")) + total_actual_files += len(actual_files) + + for section in sections: + if not section.get("crop_success", True): + crop_failure_cases.append({ + 'page_name': page_name, + 'section_idx': section.get('section_idx'), + 'failure_reason': section.get('crop_failure_reason', 'unknown'), + 'debug_info': section.get('debug_info', {}) + }) + + logger.info(f"\n๐Ÿ“Š Section ํŒŒ์ผ ๊ฒ€์ฆ:") + logger.info(f" ์˜ˆ์ƒ section ์ด ๊ฐœ์ˆ˜: {total_expected_sections}") + logger.info(f" ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ ๊ฐœ์ˆ˜: {total_actual_files}") + + if not crop_failure_cases: + logger.info("โœ… Section crop ์‹คํŒจ ์ผ€์ด์Šค๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!") + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("โœ… ๋ชจ๋“  Section์ด ์ •์ƒ์ ์œผ๋กœ crop๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\n") + return + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("Section Crop ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write(f"์ด {len(crop_failure_cases)}๊ฐœ์˜ Section crop ์‹คํŒจ ๋ฐœ๊ฒฌ\n\n") + + for i, case in enumerate(crop_failure_cases, 1): + f.write(f"[{i}] ํŽ˜์ด์ง€: {case['page_name']}, Section: {case['section_idx']}\n") + f.write(f" ์‹คํŒจ ์›์ธ: {case['failure_reason']}\n\n") + + logger.info(f"๐Ÿ“Š Crop ์‹คํŒจ ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + + +def check_missing_sections_against_answer_key(all_results: list, output_dir: Path, answer_key: dict): + """ + ๋‹ต์ง€์™€ ์‹ค์ œ ์ฒ˜๋ฆฌ๋œ section์„ ๋น„๊ตํ•˜์—ฌ ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋ƒ„ + """ + if not answer_key: + logger.info("๋‹ต์ง€๊ฐ€ ์—†์–ด ๋ˆ„๋ฝ ๊ฒ€์ถœ์„ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + return + + analysis_path = output_dir.parent.parent / "answers" / "missing_sections_analysis.txt" + + missing_cases = [] + + for result in all_results: + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + if page_num_ocr not in answer_key: + continue + + expected_problems = answer_key[page_num_ocr] + expected_count = len(expected_problems) + actual_count = len(sections) + + if expected_count != actual_count: + missing_cases.append({ + 'page_name': result.get("page_name"), + 'page_num': page_num_ocr, + 'expected_count': expected_count, + 'actual_count': actual_count + }) + + if not missing_cases: + logger.info("โœ… ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ๋ฌธ์ œ ์ˆ˜๊ฐ€ ๋‹ต์ง€์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค!") + return + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ Section ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write(f"์ด {len(missing_cases)}๊ฐœ ํŽ˜์ด์ง€์—์„œ ๋ถˆ์ผ์น˜ ๋ฐœ๊ฒฌ\n\n") + + for case in missing_cases: + f.write(f"ํŽ˜์ด์ง€: {case['page_name']}\n") + f.write(f" ์˜ˆ์ƒ: {case['expected_count']}๊ฐœ, ์‹ค์ œ: {case['actual_count']}๊ฐœ\n\n") + + logger.info(f"๐Ÿ“Š ๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + + +def print_summary(all_results: list, skipped_pages: list, output_dir: Path, total_processing_time: float): + """์‹คํ—˜ ๊ฒฐ๊ณผ ์š”์•ฝ ์ถœ๋ ฅ""" + logger.info("\n\n" + "=" * 60) + logger.info("์ „์ฒด ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์š”์•ฝ (answer_2 ์šฐ์„  + ResNet)") + logger.info("=" * 60) + + total_pages = len(all_results) + total_sections = sum(len(r.get("sections", [])) for r in all_results) + total_crop_failures = sum(r.get("crop_failure_count", 0) for r in all_results) + + # โœจ answer_source ํ†ต๊ณ„ + source_counts = { + 'answer_2_resnet': 0, + 'answer_1_resnet': 0, + 'answer_1_yolo': 0, + 'failed': 0 + } + + for result in all_results: + for section in result.get("sections", []): + answer_source = section.get("answer_source", "") + + # None ์ฒดํฌ ์ถ”๊ฐ€ + if not answer_source: + source_counts['failed'] += 1 + elif answer_source.startswith("answer_2"): + if answer_source == "answer_2_resnet": + source_counts['answer_2_resnet'] += 1 + else: + source_counts['failed'] += 1 + elif answer_source.startswith("answer_1"): + if answer_source == "answer_1_resnet": + source_counts['answer_1_resnet'] += 1 + elif answer_source == "answer_1_yolo": + source_counts['answer_1_yolo'] += 1 + else: + source_counts['failed'] += 1 + else: + source_counts['failed'] += 1 + + logger.info(f" ์ฒ˜๋ฆฌ๋œ ํŽ˜์ด์ง€ ์ˆ˜: {total_pages}") + logger.info(f" ๊ฑด๋„ˆ๋›ด ํŽ˜์ด์ง€ ์ˆ˜: {len(skipped_pages)}") + logger.info(f" ์ด Section ์ˆ˜: {total_sections}") + logger.info(f" Section crop ์‹คํŒจ: {total_crop_failures}๊ฐœ") + logger.info(f"\n ๐Ÿ“Š ๋‹ต์•ˆ ์ถœ์ฒ˜ ํ†ต๊ณ„:") + logger.info(f" answer_2 ResNet: {source_counts['answer_2_resnet']}๊ฐœ ({source_counts['answer_2_resnet']/total_sections*100:.1f}%)") + logger.info(f" answer_1 ResNet: {source_counts['answer_1_resnet']}๊ฐœ ({source_counts['answer_1_resnet']/total_sections*100:.1f}%)") + logger.info(f" answer_1 YOLO: {source_counts['answer_1_yolo']}๊ฐœ ({source_counts['answer_1_yolo']/total_sections*100:.1f}%)") + logger.info(f" ์‹คํŒจ: {source_counts['failed']}๊ฐœ ({source_counts['failed']/total_sections*100:.1f}%)") + logger.info(f"\n ์ „์ฒด ์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {total_processing_time:.2f}์ดˆ ({total_processing_time / 60:.2f}๋ถ„)") + + logger.info(f"\n๐Ÿ“ ๊ฒฐ๊ณผ ํŒŒ์ผ:") + logger.info(f" - results_summary.txt") + logger.info(f" - none_debug_analysis.txt") + logger.info(f" - answer_source_analysis.txt") + logger.info(f" - crop_failure_analysis.txt") + logger.info(f" - missing_sections_analysis.txt") + logger.info("=" * 60) + + +if __name__ == "__main__": + main() + +# ํŒŒ์ผ ์‹คํ–‰: python -m test.Hierarchical_crop.hierarchical_crop_test \ No newline at end of file diff --git "a/ai-service/test/Hierarchical_crop/images/service_test/\341\204\222\341\205\241\341\206\250\341\204\211\341\205\242\341\206\274\341\204\213\341\205\265 \341\204\221\341\205\256\341\206\253 \341\204\206\341\205\256\341\206\253\341\204\214\341\205\246(\341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\206\341\205\251\341\204\213\341\205\264\341\204\200\341\205\251\341\204\211\341\205\241) - 1_detailed.json" "b/ai-service/test/Hierarchical_crop/images/service_test/\341\204\222\341\205\241\341\206\250\341\204\211\341\205\242\341\206\274\341\204\213\341\205\265 \341\204\221\341\205\256\341\206\253 \341\204\206\341\205\256\341\206\253\341\204\214\341\205\246(\341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\206\341\205\251\341\204\213\341\205\264\341\204\200\341\205\251\341\204\211\341\205\241) - 1_detailed.json" new file mode 100644 index 0000000..b252ca6 --- /dev/null +++ "b/ai-service/test/Hierarchical_crop/images/service_test/\341\204\222\341\205\241\341\206\250\341\204\211\341\205\242\341\206\274\341\204\213\341\205\265 \341\204\221\341\205\256\341\206\253 \341\204\206\341\205\256\341\206\253\341\204\214\341\205\246(\341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\206\341\205\251\341\204\213\341\205\264\341\204\200\341\205\251\341\204\211\341\205\241) - 1_detailed.json" @@ -0,0 +1,385 @@ +{ + "image_path": "./test/Hierarchical_crop/images/exp_images/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1.jpg", + "page_name": "แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1", + "page_number_ocr": "88", + "sections": [ + { + "section_idx": 0, + "problem_number_ocr": "04", + "problem_number_override": false, + "answer_number": "3", + "correction": true, + "section_crop_path": "test/Hierarchical_crop/images/service_test/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1/section_00.jpg", + "problem_crop_path": null, + "answer_1_crop_path": null, + "answer_2_crop_path": null, + "crop_success": true, + "is_boundary_issue": true, + "used_resnet": true, + "resnet_confidence": 0.9710263013839722, + "resnet_failed": false, + "answer_source": "answer_1_resnet", + "yolo_iou_verification": { + "yolo_best": "3", + "yolo_iou": 0.3301303223734631, + "resnet_pred": "3", + "resnet_conf": 0.9710263013839722, + "all_ious": [ + { + "number": "4", + "iou": 0.0, + "confidence": 0.7046958804130554 + }, + { + "number": "3", + "iou": 0.3301303223734631, + "confidence": 0.6537873148918152 + }, + { + "number": "1", + "iou": 0.0, + "confidence": 0.5980609655380249 + }, + { + "number": "5", + "iou": 0.0, + "confidence": 0.5793555378913879 + }, + { + "number": "2", + "iou": 0.0, + "confidence": 0.5525653958320618 + } + ] + }, + "debug_info": { + "original_bbox": [ + 1188.9056396484375, + 438.5601501464844, + 2178.552978515625, + 1473.1458740234375 + ], + "expanded_bbox": [ + 1138, + 388, + 2228, + 1523 + ], + "crop_size": [ + 1090, + 1135 + ], + "image_size": [ + 2332, + 3212 + ], + "answer_1_count": 3, + "answer_2_count": 0, + "problem_number_count": 1 + } + }, + { + "section_idx": 1, + "problem_number_ocr": "01", + "problem_number_override": false, + "answer_number": "4", + "correction": true, + "section_crop_path": "test/Hierarchical_crop/images/service_test/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1/section_01.jpg", + "problem_crop_path": null, + "answer_1_crop_path": null, + "answer_2_crop_path": null, + "crop_success": true, + "is_boundary_issue": true, + "used_resnet": true, + "resnet_confidence": 0.998916506767273, + "resnet_failed": false, + "answer_source": "answer_1_resnet", + "yolo_iou_verification": { + "yolo_best": "4", + "yolo_iou": 0.4874873402916174, + "resnet_pred": "4", + "resnet_conf": 0.998916506767273, + "all_ious": [ + { + "number": "1", + "iou": 0.0, + "confidence": 0.74174565076828 + }, + { + "number": "5", + "iou": 0.0, + "confidence": 0.7329201102256775 + }, + { + "number": "2", + "iou": 0.0, + "confidence": 0.730426549911499 + }, + { + "number": "4", + "iou": 0.4874873402916174, + "confidence": 0.7164048552513123 + }, + { + "number": "3", + "iou": 0.02179378124835689, + "confidence": 0.6971093416213989 + } + ] + }, + "debug_info": { + "original_bbox": [ + 164.2495880126953, + 949.6358642578125, + 1143.997314453125, + 1602.7301025390625 + ], + "expanded_bbox": [ + 114, + 899, + 1193, + 1652 + ], + "crop_size": [ + 1079, + 753 + ], + "image_size": [ + 2332, + 3212 + ], + "answer_1_count": 1, + "answer_2_count": 0, + "problem_number_count": 1 + } + }, + { + "section_idx": 2, + "problem_number_ocr": "02", + "problem_number_override": false, + "answer_number": "2", + "correction": true, + "section_crop_path": "test/Hierarchical_crop/images/service_test/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1/section_02.jpg", + "problem_crop_path": null, + "answer_1_crop_path": null, + "answer_2_crop_path": null, + "crop_success": true, + "is_boundary_issue": true, + "used_resnet": true, + "resnet_confidence": 0.9951686859130859, + "resnet_failed": false, + "answer_source": "answer_1_resnet", + "yolo_iou_verification": { + "yolo_best": "2", + "yolo_iou": 0.49082206216425295, + "resnet_pred": "2", + "resnet_conf": 0.9951686859130859, + "all_ious": [ + { + "number": "1", + "iou": 0.048102261792376554, + "confidence": 0.7521883845329285 + }, + { + "number": "4", + "iou": 0.0, + "confidence": 0.7521127462387085 + }, + { + "number": "2", + "iou": 0.49082206216425295, + "confidence": 0.7308573126792908 + }, + { + "number": "5", + "iou": 0.0, + "confidence": 0.7134376764297485 + }, + { + "number": "3", + "iou": 0.0, + "confidence": 0.6956141591072083 + } + ] + }, + "debug_info": { + "original_bbox": [ + 164.3761749267578, + 1751.6217041015625, + 1136.717041015625, + 2289.0126953125 + ], + "expanded_bbox": [ + 114, + 1701, + 1186, + 2339 + ], + "crop_size": [ + 1072, + 638 + ], + "image_size": [ + 2332, + 3212 + ], + "answer_1_count": 1, + "answer_2_count": 0, + "problem_number_count": 1 + } + }, + { + "section_idx": 3, + "problem_number_ocr": "05", + "problem_number_override": false, + "answer_number": "3", + "correction": true, + "section_crop_path": "test/Hierarchical_crop/images/service_test/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1/section_03.jpg", + "problem_crop_path": null, + "answer_1_crop_path": null, + "answer_2_crop_path": null, + "crop_success": true, + "is_boundary_issue": true, + "used_resnet": true, + "resnet_confidence": 0.9942670464515686, + "resnet_failed": false, + "answer_source": "answer_1_resnet", + "yolo_iou_verification": { + "yolo_best": "3", + "yolo_iou": 0.5397937398667206, + "resnet_pred": "3", + "resnet_conf": 0.9942670464515686, + "all_ious": [ + { + "number": "2", + "iou": 0.0, + "confidence": 0.7569021582603455 + }, + { + "number": "4", + "iou": 0.0, + "confidence": 0.7479438781738281 + }, + { + "number": "1", + "iou": 0.0, + "confidence": 0.7274431586265564 + }, + { + "number": "5", + "iou": 0.0, + "confidence": 0.7234012484550476 + }, + { + "number": "3", + "iou": 0.5397937398667206, + "confidence": 0.7024614810943604 + } + ] + }, + "debug_info": { + "original_bbox": [ + 1189.266357421875, + 1908.6044921875, + 2079.3076171875, + 2455.135009765625 + ], + "expanded_bbox": [ + 1139, + 1858, + 2129, + 2505 + ], + "crop_size": [ + 990, + 647 + ], + "image_size": [ + 2332, + 3212 + ], + "answer_1_count": 1, + "answer_2_count": 0, + "problem_number_count": 1 + } + }, + { + "section_idx": 4, + "problem_number_ocr": "03", + "problem_number_override": false, + "answer_number": "3", + "correction": true, + "section_crop_path": "test/Hierarchical_crop/images/service_test/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1/section_04.jpg", + "problem_crop_path": null, + "answer_1_crop_path": null, + "answer_2_crop_path": null, + "crop_success": true, + "is_boundary_issue": true, + "used_resnet": true, + "resnet_confidence": 0.9990137815475464, + "resnet_failed": false, + "answer_source": "answer_1_resnet", + "yolo_iou_verification": { + "yolo_best": "3", + "yolo_iou": 0.4491942594848505, + "resnet_pred": "3", + "resnet_conf": 0.9990137815475464, + "all_ious": [ + { + "number": "3", + "iou": 0.4491942594848505, + "confidence": 0.7411296367645264 + }, + { + "number": "2", + "iou": 0.0723123795466424, + "confidence": 0.7395511865615845 + }, + { + "number": "1", + "iou": 0.0, + "confidence": 0.7378852963447571 + }, + { + "number": "4", + "iou": 0.0, + "confidence": 0.7266397476196289 + }, + { + "number": "5", + "iou": 0.0, + "confidence": 0.7245199680328369 + } + ] + }, + "debug_info": { + "original_bbox": [ + 173.43507385253906, + 2497.14013671875, + 1156.8624267578125, + 3125.3095703125 + ], + "expanded_bbox": [ + 123, + 2447, + 1206, + 3175 + ], + "crop_size": [ + 1083, + 728 + ], + "image_size": [ + 2332, + 3212 + ], + "answer_1_count": 1, + "answer_2_count": 0, + "problem_number_count": 1 + } + } + ], + "processing_time": 3.7145259380340576, + "total_sections": 5, + "crop_failure_count": 0 +} \ No newline at end of file diff --git "a/ai-service/test/Hierarchical_crop/images/service_test/\341\204\222\341\205\241\341\206\250\341\204\211\341\205\242\341\206\274\341\204\213\341\205\265 \341\204\221\341\205\256\341\206\253 \341\204\206\341\205\256\341\206\253\341\204\214\341\205\246(\341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\206\341\205\251\341\204\213\341\205\264\341\204\200\341\205\251\341\204\211\341\205\241) - 1_result.json" "b/ai-service/test/Hierarchical_crop/images/service_test/\341\204\222\341\205\241\341\206\250\341\204\211\341\205\242\341\206\274\341\204\213\341\205\265 \341\204\221\341\205\256\341\206\253 \341\204\206\341\205\256\341\206\253\341\204\214\341\205\246(\341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\206\341\205\251\341\204\213\341\205\264\341\204\200\341\205\251\341\204\211\341\205\241) - 1_result.json" new file mode 100644 index 0000000..122a924 --- /dev/null +++ "b/ai-service/test/Hierarchical_crop/images/service_test/\341\204\222\341\205\241\341\206\250\341\204\211\341\205\242\341\206\274\341\204\213\341\205\265 \341\204\221\341\205\256\341\206\253 \341\204\206\341\205\256\341\206\253\341\204\214\341\205\246(\341\204\211\341\205\265\341\206\257\341\204\214\341\205\245\341\206\253 \341\204\206\341\205\251\341\204\213\341\205\264\341\204\200\341\205\251\341\204\211\341\205\241) - 1_result.json" @@ -0,0 +1,31 @@ +{ + "image_path": "./test/Hierarchical_crop/images/exp_images/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1.jpg", + "page_number": "88", + "sections": [ + { + "problem_number": "04", + "answer": "3", + "correction": true + }, + { + "problem_number": "01", + "answer": "4", + "correction": true + }, + { + "problem_number": "02", + "answer": "2", + "correction": true + }, + { + "problem_number": "05", + "answer": "3", + "correction": true + }, + { + "problem_number": "03", + "answer": "3", + "correction": true + } + ] +} \ No newline at end of file diff --git a/ai-service/test/Hierarchical_crop/services_hierarchical_crop_test.py b/ai-service/test/Hierarchical_crop/services_hierarchical_crop_test.py new file mode 100644 index 0000000..9d2eb35 --- /dev/null +++ b/ai-service/test/Hierarchical_crop/services_hierarchical_crop_test.py @@ -0,0 +1,402 @@ +#!/usr/bin/env python3 +""" +HierarchicalCropPipeline ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ +๋‹จ์ผ ์ด๋ฏธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. +""" + +import sys +import os +from pathlib import Path +import json +import logging + +# ๋กœ๊น… ์„ค์ • +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + + +def print_section_result(section: dict, section_idx: int): + """Section ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ธฐ ์ข‹๊ฒŒ ์ถœ๋ ฅ""" + print(f"\n{'='*60}") + print(f"Section {section_idx}") + print(f"{'='*60}") + + # ๋ฌธ์ œ๋ฒˆํ˜ธ + problem_num = section.get('problem_number_ocr', 'N/A') + problem_override = section.get('problem_number_override', False) + if problem_override: + print(f"๐Ÿ“‹ ๋ฌธ์ œ๋ฒˆํ˜ธ: {problem_num} (๋‹ต์ง€ ๊ธฐ๋ฐ˜ ํ• ๋‹น)") + else: + print(f"๐Ÿ“‹ ๋ฌธ์ œ๋ฒˆํ˜ธ: {problem_num}") + + # ๋‹ต์•ˆ + answer = section.get('answer_number', 'N/A') + answer_source = section.get('answer_source', 'N/A') + print(f"โœ… ์ •๋‹ต: {answer} (์ถœ์ฒ˜: {answer_source})") + + # ์ฑ„์  ๊ฒฐ๊ณผ + correction = section.get('correction') + if correction is not None: + if correction: + print(f"โญ• ์ฑ„์ : ์ •๋‹ต") + else: + print(f"โŒ ์ฑ„์ : ์˜ค๋‹ต") + else: + print(f"โ“ ์ฑ„์ : ๋‹ต์ง€ ์—†์Œ") + + # ResNet ์ •๋ณด + used_resnet = section.get('used_resnet', False) + resnet_conf = section.get('resnet_confidence', 0.0) + resnet_failed = section.get('resnet_failed', False) + + if used_resnet: + if resnet_failed: + print(f"๐Ÿค– ResNet: ์‹คํŒจ") + else: + print(f"๐Ÿค– ResNet: ์„ฑ๊ณต (์‹ ๋ขฐ๋„: {resnet_conf:.4f})") + else: + print(f"๐Ÿค– ResNet: ์‚ฌ์šฉ ์•ˆ ํ•จ") + + # YOLO IoU ๊ฒ€์ฆ ์ •๋ณด + yolo_iou = section.get('yolo_iou_verification') + if yolo_iou: + print(f"\n๐ŸŽฏ YOLO IoU ๊ฒ€์ฆ:") + print(f" - ResNet ์˜ˆ์ธก: {yolo_iou['resnet_pred']} (์‹ ๋ขฐ๋„: {yolo_iou['resnet_conf']:.4f})") + print(f" - YOLO ์ตœ๊ณ  IoU: {yolo_iou['yolo_best']} (IoU: {yolo_iou['yolo_iou']:.4f})") + + # ์ƒ์œ„ 3๊ฐœ IoU๋งŒ ์ถœ๋ ฅ + all_ious = sorted(yolo_iou['all_ious'], key=lambda x: x['iou'], reverse=True)[:3] + print(f" - IoU ์ƒ์œ„ 3๊ฐœ:") + for result in all_ious: + print(f" โ€ข {result['number']}: IoU={result['iou']:.4f}, Conf={result['confidence']:.3f}") + + # Crop ์ •๋ณด + crop_success = section.get('crop_success', False) + if crop_success: + section_path = section.get('section_crop_path') + print(f"\n๐Ÿ“ Section ์ด๋ฏธ์ง€: {section_path}") + else: + failure_reason = section.get('crop_failure_reason', 'unknown') + print(f"\nโŒ Crop ์‹คํŒจ: {failure_reason}") + + # ๊ฒฝ๊ณ„ ์ด์Šˆ + is_boundary = section.get('is_boundary_issue', False) + if is_boundary: + print(f"โš ๏ธ ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜ ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ๋จ") + + # ๋””๋ฒ„๊ทธ ์ •๋ณด + debug = section.get('debug_info', {}) + if debug: + print(f"\n๐Ÿ” ๋””๋ฒ„๊ทธ ์ •๋ณด:") + print(f" - ์›๋ณธ bbox: {debug.get('original_bbox')}") + print(f" - ํ™•์žฅ bbox: {debug.get('expanded_bbox')}") + print(f" - Crop ํฌ๊ธฐ: {debug.get('crop_size')}") + print(f" - answer_1 ๊ฒ€์ถœ: {debug.get('answer_1_count', 0)}๊ฐœ") + print(f" - answer_2 ๊ฒ€์ถœ: {debug.get('answer_2_count', 0)}๊ฐœ") + print(f" - ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ: {debug.get('problem_number_count', 0)}๊ฐœ") + + +def print_summary(result: dict): + """์ „์ฒด ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์š”์•ฝ ์ถœ๋ ฅ""" + print(f"\n{'='*60}") + print(f"์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์š”์•ฝ") + print(f"{'='*60}") + + print(f"๐Ÿ“„ ํŽ˜์ด์ง€: {result['page_name']}") + print(f"๐Ÿ”ข ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (OCR): {result.get('page_number_ocr', 'N/A')}") + print(f"โฑ๏ธ ์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {result['processing_time']:.2f}์ดˆ") + print(f"๐Ÿ“Š ์ด Section ์ˆ˜: {result['total_sections']}") + + crop_failures = result.get('crop_failure_count', 0) + if crop_failures > 0: + print(f"โŒ Crop ์‹คํŒจ: {crop_failures}๊ฐœ") + + # Section๋ณ„ ํ†ต๊ณ„ + sections = result['sections'] + total = len(sections) + + with_problem = sum(1 for s in sections if s.get('problem_number_ocr')) + with_answer = sum(1 for s in sections if s.get('answer_number')) + used_resnet = sum(1 for s in sections if s.get('used_resnet')) + resnet_success = sum(1 for s in sections if s.get('used_resnet') and not s.get('resnet_failed')) + + # ์ฑ„์  ํ†ต๊ณ„ + correct_count = sum(1 for s in sections if s.get('correction') == True) + incorrect_count = sum(1 for s in sections if s.get('correction') == False) + no_correction = sum(1 for s in sections if s.get('correction') is None) + + print(f"\n๐Ÿ“ˆ ํ†ต๊ณ„:") + print(f" - ๋ฌธ์ œ๋ฒˆํ˜ธ ์ธ์‹: {with_problem}/{total} ({with_problem/total*100:.1f}%)") + print(f" - ์ •๋‹ต ์ธ์‹: {with_answer}/{total} ({with_answer/total*100:.1f}%)") + print(f" - ResNet ์‚ฌ์šฉ: {used_resnet}/{total} ({used_resnet/total*100:.1f}%)") + if used_resnet > 0: + print(f" - ResNet ์„ฑ๊ณต: {resnet_success}/{used_resnet} ({resnet_success/used_resnet*100:.1f}% of used)") + + if correct_count + incorrect_count > 0: + print(f"\nโœ… ์ฑ„์  ๊ฒฐ๊ณผ:") + print(f" - ์ •๋‹ต: {correct_count}๊ฐœ") + print(f" - ์˜ค๋‹ต: {incorrect_count}๊ฐœ") + print(f" - ์ •๋‹ต๋ฅ : {correct_count/(correct_count+incorrect_count)*100:.1f}%") + if no_correction > 0: + print(f" - ์ฑ„์  ๋ถˆ๊ฐ€: {no_correction}๊ฐœ") + + # ๋‹ต์•ˆ ์ถœ์ฒ˜ ํ†ต๊ณ„ + answer_sources = {} + for s in sections: + source = s.get('answer_source') + if source: + answer_sources[source] = answer_sources.get(source, 0) + 1 + + if answer_sources: + print(f"\n๐Ÿ“ ๋‹ต์•ˆ ์ถœ์ฒ˜:") + for source, count in sorted(answer_sources.items()): + print(f" - {source}: {count}๊ฐœ") + + +def format_simplified_result(result: dict) -> dict: + """ + ๊ฒฐ๊ณผ๋ฅผ ๊ฐ„์†Œํ™”๋œ JSON ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ + + ํ˜•์‹: + { + "image_path": "...", + "page_number": "...", + "sections": [ + { + "problem_number": "...", + "answer": "...", + "correction": true/false/null + }, + ... + ] + } + """ + simplified = { + "image_path": result['image_path'], + "page_number": result.get('page_number_ocr'), + "sections": [] + } + + for section in result['sections']: + simplified_section = { + "problem_number": section.get('problem_number_ocr'), + "answer": section.get('answer_number'), + "correction": section.get('correction') + } + simplified['sections'].append(simplified_section) + + return simplified + + +def test_single_image(image_path: str, model_dir_1104: str, model_dir_1004: str, + output_dir: str, answer_key_path: str = None, + resnet_answer_1_path: str = None, + resnet_answer_2_path: str = None, + section_padding: int = 50): + """ + ๋‹จ์ผ ์ด๋ฏธ์ง€๋ฅผ HierarchicalCropPipeline์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆ + + Args: + image_path: ํ…Œ์ŠคํŠธํ•  ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + model_dir_1104: 1104 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ + model_dir_1004: 1004 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ + output_dir: ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ + answer_key_path: ๋‹ต์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ (์„ ํƒ) + resnet_answer_1_path: answer_1 ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ (์„ ํƒ) + resnet_answer_2_path: answer_2 ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ (์„ ํƒ) + section_padding: Section padding ๊ฐ’ (๊ธฐ๋ณธ 50px) + """ + + # ์ž…๋ ฅ ๊ฒ€์ฆ + if not os.path.exists(image_path): + logger.error(f"์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {image_path}") + return False + + if not os.path.exists(model_dir_1104): + logger.error(f"1104 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {model_dir_1104}") + return False + + if not os.path.exists(model_dir_1004): + logger.error(f"1004 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {model_dir_1004}") + return False + + # ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ + output_path = Path(output_dir) + output_path.mkdir(parents=True, exist_ok=True) + + # HierarchicalCropPipeline ์ดˆ๊ธฐํ™” + logger.info("HierarchicalCropPipeline ์ดˆ๊ธฐํ™” ์ค‘...") + + # ๊ฒฝ๋กœ ์ถ”๊ฐ€ (services ๋ชจ๋“ˆ์„ importํ•˜๊ธฐ ์œ„ํ•ด) + script_dir = Path(__file__).parent + if str(script_dir) not in sys.path: + sys.path.insert(0, str(script_dir)) + + try: + from services.hierarchical_crop import HierarchicalCropPipeline + except ImportError as e: + logger.error(f"HierarchicalCropPipeline import ์‹คํŒจ: {e}") + logger.error("services/hierarchical_crop.py ํŒŒ์ผ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.") + return False + + try: + pipeline = HierarchicalCropPipeline( + model_dir_1104=model_dir_1104, + model_dir_1004=model_dir_1004, + section_padding=section_padding, + answer_key_path=answer_key_path, + resnet_answer_1_path=resnet_answer_1_path, + resnet_answer_2_path=resnet_answer_2_path + ) + logger.info("โœ… ํŒŒ์ดํ”„๋ผ์ธ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ") + except Exception as e: + logger.error(f"ํŒŒ์ดํ”„๋ผ์ธ ์ดˆ๊ธฐํ™” ์‹คํŒจ: {e}") + import traceback + traceback.print_exc() + return False + + # ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ + logger.info(f"\n{'='*60}") + logger.info(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์‹œ์ž‘: {image_path}") + logger.info(f"{'='*60}\n") + + try: + result = pipeline.process_page(image_path, output_path) + + if result is None: + logger.warning("โš ๏ธ ํŽ˜์ด์ง€๊ฐ€ ๋‹ต์ง€์— ์—†์–ด ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.") + return True + + # ๊ฒฐ๊ณผ ์ถœ๋ ฅ + print_summary(result) + + # ๊ฐ Section ๊ฒฐ๊ณผ ์ถœ๋ ฅ + for idx, section in enumerate(result['sections']): + print_section_result(section, idx) + + # โœจ ๊ฐ„์†Œํ™”๋œ JSON ํ˜•์‹์œผ๋กœ ์ €์žฅ + simplified_result = format_simplified_result(result) + + json_path = output_path / f"{result['page_name']}_result.json" + with open(json_path, 'w', encoding='utf-8') as f: + json.dump(simplified_result, f, indent=2, ensure_ascii=False) + + logger.info(f"\nโœ… ๊ฐ„์†Œํ™”๋œ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค: {json_path}") + + # ์ƒ์„ธ ๊ฒฐ๊ณผ๋„ ๋ณ„๋„๋กœ ์ €์žฅ (๋””๋ฒ„๊น…์šฉ) + detailed_json_path = output_path / f"{result['page_name']}_detailed.json" + with open(detailed_json_path, 'w', encoding='utf-8') as f: + json.dump(result, f, indent=2, ensure_ascii=False) + + logger.info(f"โœ… ์ƒ์„ธ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค: {detailed_json_path}") + + # ๊ฐ„์†Œํ™”๋œ ๊ฒฐ๊ณผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ + print(f"\n{'='*60}") + print("๊ฐ„์†Œํ™”๋œ JSON ๊ฒฐ๊ณผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ") + print(f"{'='*60}") + print(json.dumps(simplified_result, indent=2, ensure_ascii=False)) + + return True + + except Exception as e: + logger.error(f"โŒ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}") + import traceback + traceback.print_exc() + return False + + +def main(): + """๋ฉ”์ธ ํ•จ์ˆ˜ - ์ปค๋งจ๋“œ๋ผ์ธ ์ธ์ž ํŒŒ์‹ฑ""" + import argparse + + # ============================================================ + # ๊ณ ์ • ์„ค์ •๊ฐ’ + # ============================================================ + MODEL_DIR_1104 = "./models/Detection/legacy/Model_routing_1104" + MODEL_DIR_1004 = "./models/Detection/legacy/Model_routing_1004" + ANSWER_KEY_PATH = "./test/Hierarchical_crop/answers/yolo_answer.txt" + RESNET_ANSWER_1_PATH = "./models/Recognition/models/answer_1_resnet.pth" + RESNET_ANSWER_2_PATH = "./models/Recognition/models/answer_2_resnet.pth" + SECTION_PADDING = 50 + # ============================================================ + + parser = argparse.ArgumentParser( + description='HierarchicalCropPipeline ๋‹จ์ผ ์ด๋ฏธ์ง€ ํ…Œ์ŠคํŠธ', + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +์˜ˆ์ œ: + # ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ๋งŒ ์ง€์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค + python test_hierarchical_crop.py --image test.jpg --output ./output + + # ๋˜๋Š” ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ + python test_hierarchical_crop.py --image test.jpg + +๊ณ ์ • ์„ค์ •๊ฐ’: + - 1104 ๋ชจ๋ธ: ./models/Detection/legacy/Model_routing_1104 + - 1004 ๋ชจ๋ธ: ./models/Detection/legacy/Model_routing_1004 + - ๋‹ต์ง€: ./DB/answer.txt + - ResNet answer_1: ./models/Recognition/models/resnet_answer_1.pth + - ResNet answer_2: ./models/Recognition/models/resnet_answer_2.pth + - Section padding: 50px + +์ถœ๋ ฅ JSON ํ˜•์‹: + { + "image_path": "...", + "page_number": "1", + "sections": [ + { + "problem_number": "1", + "answer": "3", + "correction": true + }, + ... + ] + } + """ + ) + + parser.add_argument('--image', required=True, help='ํ…Œ์ŠคํŠธํ•  ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ') + parser.add_argument('--output', default='./test_output', help='์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ (๊ธฐ๋ณธ: ./test_output)') + + args = parser.parse_args() + + # ๊ณ ์ •๊ฐ’ ์‚ฌ์šฉ ์•ˆ๋‚ด + logger.info("\n" + "="*60) + logger.info("๊ณ ์ • ์„ค์ •๊ฐ’ ์‚ฌ์šฉ") + logger.info("="*60) + logger.info(f"1104 ๋ชจ๋ธ: {MODEL_DIR_1104}") + logger.info(f"1004 ๋ชจ๋ธ: {MODEL_DIR_1004}") + logger.info(f"๋‹ต์ง€: {ANSWER_KEY_PATH}") + logger.info(f"ResNet answer_1: {RESNET_ANSWER_1_PATH}") + logger.info(f"ResNet answer_2: {RESNET_ANSWER_2_PATH}") + logger.info(f"Section padding: {SECTION_PADDING}px") + logger.info("="*60 + "\n") + + # ํ…Œ์ŠคํŠธ ์‹คํ–‰ + success = test_single_image( + image_path=args.image, + model_dir_1104=MODEL_DIR_1104, + model_dir_1004=MODEL_DIR_1004, + output_dir=args.output, + answer_key_path=ANSWER_KEY_PATH, + resnet_answer_1_path=RESNET_ANSWER_1_PATH, + resnet_answer_2_path=RESNET_ANSWER_2_PATH, + section_padding=SECTION_PADDING + ) + + if success: + logger.info("\nโœ… ํ…Œ์ŠคํŠธ ์™„๋ฃŒ!") + sys.exit(0) + else: + logger.error("\nโŒ ํ…Œ์ŠคํŠธ ์‹คํŒจ!") + sys.exit(1) + + +if __name__ == "__main__": + main() + +# python test_hierarchical_crop.py --image test.jpg --output ./my_output +# python -m test.Hierarchical_crop.services_hierarchical_crop_test --image "./test/Hierarchical_crop/images/exp_images/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1.jpg" --output "./test/Hierarchical_crop/images/service_test" \ No newline at end of file diff --git a/ai-service/test/OCR/__init__.py b/ai-service/test/OCR/__init__.py new file mode 100644 index 0000000..32d8681 --- /dev/null +++ b/ai-service/test/OCR/__init__.py @@ -0,0 +1 @@ +# ์ธ์‹ ๋ชจ๋ธ ํŒจํ‚ค์ง€ diff --git a/ai-service/test/OCR/__pycache__/__init__.cpython-312.pyc b/ai-service/test/OCR/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..5e1b5db Binary files /dev/null and b/ai-service/test/OCR/__pycache__/__init__.cpython-312.pyc differ diff --git a/ai-service/test/OCR/__pycache__/answer_ocr_test.cpython-312.pyc b/ai-service/test/OCR/__pycache__/answer_ocr_test.cpython-312.pyc new file mode 100644 index 0000000..e5faee5 Binary files /dev/null and b/ai-service/test/OCR/__pycache__/answer_ocr_test.cpython-312.pyc differ diff --git a/ai-service/test/OCR/answer_ocr_test.py b/ai-service/test/OCR/answer_ocr_test.py new file mode 100644 index 0000000..45ece45 --- /dev/null +++ b/ai-service/test/OCR/answer_ocr_test.py @@ -0,0 +1,162 @@ +import os +import sys +import csv +import time +from pathlib import Path + +# ocr_model ํด๋”์˜ ๋ชจ๋ธ๋“ค import +sys.path.append('ocr_model') +from easyocr_model import EasyOCRModel +from tesseract_model import TesseractOCRModel +from paddleocr_model import PaddleOCRModel +from cnocr_model import CNOCRModel + + +def get_images_with_labels(base_folder): + """ํ•˜์œ„ ํด๋” ๊ตฌ์กฐ์—์„œ ์ด๋ฏธ์ง€์™€ ์ •๋‹ต ๋ ˆ์ด๋ธ”์„ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.""" + images_with_labels = [] + + # 1, 2, 3, 4, 5 ํด๋”๋ฅผ ์ˆœํšŒ + for label in ['1', '2', '3', '4', '5']: + folder_path = os.path.join(base_folder, label) + if os.path.exists(folder_path): + image_files = sorted([f for f in os.listdir(folder_path) + if f.endswith(('.jpg', '.jpeg', '.png', '.JPG'))]) + + for image_file in image_files: + image_path = os.path.join(folder_path, image_file) + relative_path = f"{label}/{image_file}" + images_with_labels.append((relative_path, image_path, label)) + + return images_with_labels + + +def process_answer_images(model, model_name, base_folder, output_file): + """answer ํด๋”์˜ ์ด๋ฏธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.""" + images_with_labels = get_images_with_labels(base_folder) + results = [] + + print(f"\n{model_name} - Processing {len(images_with_labels)} images from {base_folder}...") + + for idx, (relative_path, image_path, true_label) in enumerate(images_with_labels, 1): + extracted_number = model.extract_number(image_path) + results.append((relative_path, extracted_number, true_label)) + + if idx % 10 == 0 or idx == len(images_with_labels): + print(f" Progress: {idx}/{len(images_with_labels)}") + + # ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ + with open(output_file, 'w', encoding='utf-8') as f: + for relative_path, extracted_number in [(r[0], r[1]) for r in results]: + f.write(f"{relative_path}, {extracted_number}\n") + + return results + + +def calculate_answer_accuracy(results): + """ํด๋” ๊ธฐ๋ฐ˜ ์ •๋‹ต๋ฅ ์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.""" + if not results: + return 0.0 + + correct = 0 + total = len(results) + + for relative_path, predicted, true_label in results: + if predicted == true_label: + correct += 1 + + accuracy = (correct / total * 100) if total > 0 else 0.0 + return accuracy + + +def main(): + # ๊ฒฐ๊ณผ ์ €์žฅ ํด๋” ์ƒ์„ฑ + result_folder = 'test_result' + os.makedirs(result_folder, exist_ok=True) + + # ๋ชจ๋ธ ์ดˆ๊ธฐํ™” + models = { + 'easyocr': EasyOCRModel(), + 'tesseract': TesseractOCRModel(), + 'paddleocr': PaddleOCRModel(), + 'cnocr': CNOCRModel() + } + + # ํด๋” ๊ฒฝ๋กœ ์„ค์ • + answer_1_folder = 'images/answer_1' + answer_2_folder = 'images/answer_2' + + # ๊ฒฐ๊ณผ ์ €์žฅ์šฉ ๋ฆฌ์ŠคํŠธ + accuracy_results = [] + + # ๊ฐ ๋ชจ๋ธ์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌ + for model_name, model in models.items(): + print(f"\n{'='*60}") + print(f"Processing with {model_name.upper()}") + print(f"{'='*60}") + + try: + # Answer 1 ์ฒ˜๋ฆฌ + answer_1_output_file = os.path.join(result_folder, f"{model_name}_answer_1_answer.txt") + answer_1_results = process_answer_images( + model, model_name, answer_1_folder, answer_1_output_file + ) + answer_1_accuracy = calculate_answer_accuracy(answer_1_results) + + # Answer 2 ์ฒ˜๋ฆฌ + answer_2_output_file = os.path.join(result_folder, f"{model_name}_answer_2_answer.txt") + answer_2_results = process_answer_images( + model, model_name, answer_2_folder, answer_2_output_file + ) + answer_2_accuracy = calculate_answer_accuracy(answer_2_results) + + # ๊ฒฐ๊ณผ ์ €์žฅ + accuracy_results.append({ + 'model': model_name, + 'answer_1_accuracy': answer_1_accuracy, + 'answer_2_accuracy': answer_2_accuracy, + 'average_accuracy': (answer_1_accuracy + answer_2_accuracy) / 2 + }) + + print(f"\n{model_name.upper()} Results:") + print(f" Answer 1 Accuracy: {answer_1_accuracy:.2f}%") + print(f" Answer 2 Accuracy: {answer_2_accuracy:.2f}%") + print(f" Average Accuracy: {(answer_1_accuracy + answer_2_accuracy) / 2:.2f}%") + + except Exception as e: + print(f"Error with {model_name}: {e}") + accuracy_results.append({ + 'model': model_name, + 'answer_1_accuracy': 0.0, + 'answer_2_accuracy': 0.0, + 'average_accuracy': 0.0 + }) + + # CSV ํŒŒ์ผ๋กœ ๊ฒฐ๊ณผ ์ €์žฅ + csv_filename = os.path.join(result_folder, 'ocr_accuracy_results_answer.csv') + with open(csv_filename, 'w', newline='', encoding='utf-8') as csvfile: + fieldnames = ['model', 'answer_1_accuracy', 'answer_2_accuracy', 'average_accuracy'] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + + writer.writeheader() + for result in accuracy_results: + writer.writerow(result) + + # ์ตœ์ข… ๊ฒฐ๊ณผ ์ถœ๋ ฅ + print(f"\n{'='*60}") + print("FINAL RESULTS") + print(f"{'='*60}") + print(f"\n{'Model':<15} {'Answer 1 %':<15} {'Answer 2 %':<15} {'Average %':<15}") + print("-" * 60) + + for result in accuracy_results: + print(f"{result['model']:<15} " + f"{result['answer_1_accuracy']:<15.2f} " + f"{result['answer_2_accuracy']:<15.2f} " + f"{result['average_accuracy']:<15.2f}") + + print(f"\nResults saved to {csv_filename}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ai-service/test/OCR/images/get_title_txt.ipynb b/ai-service/test/OCR/images/get_title_txt.ipynb new file mode 100644 index 0000000..5f8560f --- /dev/null +++ b/ai-service/test/OCR/images/get_title_txt.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 8, + "id": "bd9ca161", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… ์ž์—ฐ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ 'page_number.txt' ์ƒ์„ฑ ์™„๋ฃŒ!\n" + ] + } + ], + "source": [ + "import os\n", + "import re\n", + "\n", + "folder_path = \"page_number\"\n", + "output_file = \"page_number.txt\"\n", + "image_extensions = {\".jpg\", \".jpeg\", \".png\", \".bmp\", \".gif\"}\n", + "\n", + "def natural_key(text):\n", + " \"\"\"ํŒŒ์ผ๋ช… ์•ˆ์˜ ์ˆซ์ž๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ž์—ฐ ์ •๋ ฌ\"\"\"\n", + " return [int(t) if t.isdigit() else t.lower() for t in re.split(r'(\\d+)', text)]\n", + "\n", + "# ํด๋” ๋‚ด ์ด๋ฏธ์ง€ ํŒŒ์ผ๋งŒ ์ถ”์ถœ\n", + "files = [\n", + " f for f in os.listdir(folder_path)\n", + " if os.path.splitext(f)[1].lower() in image_extensions\n", + "]\n", + "\n", + "# ์ž์—ฐ ์ •๋ ฌ ์ ์šฉ\n", + "files.sort(key=natural_key)\n", + "\n", + "# txt๋กœ ์ €์žฅ\n", + "with open(output_file, \"w\", encoding=\"utf-8\") as f:\n", + " for filename in files:\n", + " f.write(filename + \", \\n\")\n", + "\n", + "print(f\"โœ… ์ž์—ฐ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ '{output_file}' ์ƒ์„ฑ ์™„๋ฃŒ!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "d7e65f98", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… ์ž์—ฐ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ 'problem_number.txt' ์ƒ์„ฑ ์™„๋ฃŒ!\n" + ] + } + ], + "source": [ + "import os\n", + "import re\n", + "\n", + "folder_path = \"problem_number\"\n", + "output_file = \"problem_number.txt\"\n", + "image_extensions = {\".jpg\", \".jpeg\", \".png\", \".bmp\", \".gif\"}\n", + "\n", + "def natural_key(text):\n", + " \"\"\"ํŒŒ์ผ๋ช… ์•ˆ์˜ ์ˆซ์ž๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ž์—ฐ ์ •๋ ฌ\"\"\"\n", + " return [int(t) if t.isdigit() else t.lower() for t in re.split(r'(\\d+)', text)]\n", + "\n", + "# ํด๋” ๋‚ด ์ด๋ฏธ์ง€ ํŒŒ์ผ๋งŒ ์ถ”์ถœ\n", + "files = [\n", + " f for f in os.listdir(folder_path)\n", + " if os.path.splitext(f)[1].lower() in image_extensions\n", + "]\n", + "\n", + "# ์ž์—ฐ ์ •๋ ฌ ์ ์šฉ\n", + "files.sort(key=natural_key)\n", + "\n", + "# txt๋กœ ์ €์žฅ\n", + "with open(output_file, \"w\", encoding=\"utf-8\") as f:\n", + " for filename in files:\n", + " f.write(filename + \", \\n\")\n", + "\n", + "print(f\"โœ… ์ž์—ฐ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ '{output_file}' ์ƒ์„ฑ ์™„๋ฃŒ!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "ddecee92", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“‚ ์ด 168๊ฐœ์˜ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n" + ] + } + ], + "source": [ + "import os\n", + "import re\n", + "\n", + "folder_path = \"page_number\"\n", + "output_file = \"page_number.txt\"\n", + "image_extensions = {\".jpg\", \".jpeg\", \".png\", \".bmp\", \".gif\"}\n", + "\n", + "# ํด๋” ๋‚ด ์ด๋ฏธ์ง€ ํŒŒ์ผ๋งŒ ์ถ”์ถœ\n", + "files = [\n", + " f for f in os.listdir(folder_path)\n", + " if os.path.splitext(f)[1].lower() in image_extensions\n", + "]\n", + "\n", + "print(f\"๐Ÿ“‚ ์ด {len(files)}๊ฐœ์˜ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "cce1bea4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“‚ ์ด 317๊ฐœ์˜ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n" + ] + } + ], + "source": [ + "import os\n", + "import re\n", + "\n", + "folder_path = \"problem_number\"\n", + "output_file = \"problem_number.txt\"\n", + "image_extensions = {\".jpg\", \".jpeg\", \".png\", \".bmp\", \".gif\"}\n", + "\n", + "# ํด๋” ๋‚ด ์ด๋ฏธ์ง€ ํŒŒ์ผ๋งŒ ์ถ”์ถœ\n", + "files = [\n", + " f for f in os.listdir(folder_path)\n", + " if os.path.splitext(f)[1].lower() in image_extensions\n", + "]\n", + "\n", + "print(f\"๐Ÿ“‚ ์ด {len(files)}๊ฐœ์˜ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "27839b33", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… ์ž์—ฐ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ 'page_number.txt' ์ƒ์„ฑ ์™„๋ฃŒ!\n", + "๐Ÿ“‚ ์ด 168๊ฐœ์˜ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n", + "๐Ÿ“ 'page_number.txt'์—๋Š” ์ด 168๊ฐœ์˜ ๋ฌธ์žฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.\n" + ] + } + ], + "source": [ + "import os\n", + "import re\n", + "\n", + "folder_path = \"page_number\"\n", + "output_file = \"page_number.txt\"\n", + "image_extensions = {\".jpg\", \".jpeg\", \".png\", \".bmp\", \".gif\"}\n", + "\n", + "# ํด๋” ๋‚ด ์ด๋ฏธ์ง€ ํŒŒ์ผ๋งŒ ์ถ”์ถœ\n", + "files = [\n", + " f for f in os.listdir(folder_path)\n", + " if os.path.splitext(f)[1].lower() in image_extensions\n", + "]\n", + "\n", + "# ํŒŒ์ผ ๊ฐœ์ˆ˜ ์ถœ๋ ฅ\n", + "print(f\"โœ… ์ž์—ฐ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ '{output_file}' ์ƒ์„ฑ ์™„๋ฃŒ!\")\n", + "print(f\"๐Ÿ“‚ ์ด {len(files)}๊ฐœ์˜ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\")\n", + "\n", + "# page_number.txt์˜ ๋ผ์ธ ์ˆ˜ ์ถœ๋ ฅ\n", + "with open(output_file, \"r\", encoding=\"utf-8\") as f:\n", + " line_count = sum(1 for _ in f)\n", + "\n", + "print(f\"๐Ÿ“ '{output_file}'์—๋Š” ์ด {line_count}๊ฐœ์˜ ๋ฌธ์žฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "dfee2e14", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… ์ž์—ฐ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ 'problem_number.txt' ์ƒ์„ฑ ์™„๋ฃŒ!\n", + "๐Ÿ“‚ ์ด 317๊ฐœ์˜ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n", + "๐Ÿ“ 'problem_number.txt'์—๋Š” ์ด 317๊ฐœ์˜ ๋ฌธ์žฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.\n" + ] + } + ], + "source": [ + "import os\n", + "import re\n", + "\n", + "folder_path = \"problem_number\"\n", + "output_file = \"problem_number.txt\"\n", + "image_extensions = {\".jpg\", \".jpeg\", \".png\", \".bmp\", \".gif\"}\n", + "\n", + "# ํด๋” ๋‚ด ์ด๋ฏธ์ง€ ํŒŒ์ผ๋งŒ ์ถ”์ถœ\n", + "files = [\n", + " f for f in os.listdir(folder_path)\n", + " if os.path.splitext(f)[1].lower() in image_extensions\n", + "]\n", + "\n", + "# ํŒŒ์ผ ๊ฐœ์ˆ˜ ์ถœ๋ ฅ\n", + "print(f\"โœ… ์ž์—ฐ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ '{output_file}' ์ƒ์„ฑ ์™„๋ฃŒ!\")\n", + "print(f\"๐Ÿ“‚ ์ด {len(files)}๊ฐœ์˜ ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\")\n", + "\n", + "# page_number.txt์˜ ๋ผ์ธ ์ˆ˜ ์ถœ๋ ฅ\n", + "with open(output_file, \"r\", encoding=\"utf-8\") as f:\n", + " line_count = sum(1 for _ in f)\n", + "\n", + "print(f\"๐Ÿ“ '{output_file}'์—๋Š” ์ด {line_count}๊ฐœ์˜ ๋ฌธ์žฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "cradi", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ai-service/test/OCR/images/page_number.txt b/ai-service/test/OCR/images/page_number.txt new file mode 100644 index 0000000..d5ea90f --- /dev/null +++ b/ai-service/test/OCR/images/page_number.txt @@ -0,0 +1,168 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_page_number_000_conf0.618.jpg, 88 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_page_number_011_conf0.577.jpg, 89 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_page_number_022_conf0.549.jpg, 90 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_page_number_033_conf0.583.jpg, 91 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_page_number_044_conf0.589.jpg, 92 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_page_number_055_conf0.574.jpg, 93 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_page_number_066_conf0.610.jpg, 94 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_page_number_077_conf0.548.jpg, 95 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_page_number_084_conf0.585.jpg, 96 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_page_number_001_conf0.587.jpg, 97 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_page_number_002_conf0.575.jpg, 98 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_page_number_003_conf0.549.jpg, 99 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_page_number_004_conf0.536.jpg, 100 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_page_number_005_conf0.613.jpg, 101 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_page_number_006_conf0.547.jpg, 102 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_page_number_007_conf0.616.jpg, 103 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_page_number_008_conf0.509.jpg, 104 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_page_number_009_conf0.625.jpg, 105 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_page_number_010_conf0.548.jpg, 106 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_page_number_012_conf0.626.jpg, 107 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_page_number_013_conf0.501.jpg, 108 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_page_number_014_conf0.602.jpg, 109 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_page_number_015_conf0.554.jpg, 110 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_page_number_016_conf0.687.jpg, 111 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_page_number_017_conf0.648.jpg, 112 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_page_number_018_conf0.672.jpg, 113 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_page_number_019_conf0.593.jpg, 114 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_page_number_020_conf0.627.jpg, 115 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_page_number_021_conf0.680.jpg, 116 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_page_number_023_conf0.573.jpg, 117 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_page_number_024_conf0.655.jpg, 118 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_page_number_025_conf0.633.jpg, 119 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_page_number_026_conf0.537.jpg, 120 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_page_number_027_conf0.646.jpg, 121 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_page_number_028_conf0.563.jpg, 122 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_page_number_029_conf0.593.jpg, 123 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_page_number_030_conf0.457.jpg, 124 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_page_number_031_conf0.642.jpg, 125 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_page_number_032_conf0.512.jpg, 126 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_page_number_034_conf0.653.jpg, 127 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_page_number_035_conf0.596.jpg, 128 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_page_number_036_conf0.629.jpg, 129 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_page_number_037_conf0.513.jpg, 130 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_page_number_038_conf0.699.jpg, 131 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_page_number_039_conf0.540.jpg, 132 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_page_number_040_conf0.618.jpg, 133 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_page_number_041_conf0.528.jpg, 134 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_page_number_042_conf0.577.jpg, 135 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_page_number_043_conf0.549.jpg, 136 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_page_number_045_conf0.615.jpg, 137 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_page_number_046_conf0.499.jpg, 138 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_page_number_047_conf0.617.jpg, 139 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_page_number_048_conf0.497.jpg, 140 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_page_number_049_conf0.617.jpg, 141 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_page_number_050_conf0.501.jpg, 142 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_page_number_051_conf0.592.jpg, 143 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_page_number_052_conf0.552.jpg, 144 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_page_number_053_conf0.588.jpg, 145 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_page_number_054_conf0.532.jpg, 146 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_page_number_056_conf0.600.jpg, 147 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_page_number_057_conf0.561.jpg, 148 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_page_number_058_conf0.633.jpg, 149 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_page_number_059_conf0.493.jpg, 150 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_page_number_060_conf0.621.jpg, 151 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_page_number_061_conf0.517.jpg, 152 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_page_number_062_conf0.601.jpg, 153 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_page_number_063_conf0.507.jpg, 154 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_page_number_064_conf0.586.jpg, 155 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_page_number_065_conf0.505.jpg, 156 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_page_number_067_conf0.607.jpg, 157 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_page_number_068_conf0.432.jpg, 158 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_page_number_069_conf0.570.jpg, 159 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_page_number_070_conf0.565.jpg, 160 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_page_number_071_conf0.605.jpg, 161 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_page_number_072_conf0.604.jpg, 162 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_page_number_073_conf0.616.jpg, 163 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_page_number_074_conf0.607.jpg, 164 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_page_number_075_conf0.695.jpg, 165 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_000_conf0.563.jpg, 166 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_076_conf0.563.jpg, 166 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_001_conf0.588.jpg, 167 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_078_conf0.588.jpg, 167 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_002_conf0.550.jpg, 168 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_079_conf0.550.jpg, 168 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_003_conf0.655.jpg, 169 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_080_conf0.655.jpg, 169 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_004_conf0.586.jpg, 170 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_081_conf0.586.jpg, 170 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_005_conf0.589.jpg, 171 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_082_conf0.589.jpg, 171 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_006_conf0.648.jpg, 172 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_083_conf0.648.jpg, 172 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_007_conf0.225.jpg, 9 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_085_conf0.225.jpg, 9 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_010_conf0.540.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_097_conf0.540.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_011_conf0.556.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_108_conf0.556.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_012_conf0.563.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_119_conf0.563.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_013_conf0.523.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_130_conf0.523.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_014_conf0.592.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_141_conf0.592.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_015_conf0.598.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_147_conf0.598.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_016_conf0.572.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_148_conf0.572.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_017_conf0.555.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_149_conf0.555.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_008_conf0.617.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_086_conf0.617.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_009_conf0.571.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_087_conf0.571.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_page_number_088_conf0.568.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_089_conf0.555.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_090_conf0.241.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_page_number_091_conf0.582.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_page_number_092_conf0.576.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_page_number_093_conf0.556.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_page_number_094_conf0.568.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_page_number_095_conf0.587.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_page_number_096_conf0.600.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_page_number_098_conf0.588.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_page_number_099_conf0.624.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_page_number_100_conf0.573.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_page_number_101_conf0.562.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_page_number_102_conf0.587.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_page_number_103_conf0.564.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_page_number_104_conf0.598.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_page_number_105_conf0.521.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_page_number_106_conf0.551.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_page_number_107_conf0.549.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_page_number_109_conf0.568.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_page_number_110_conf0.569.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_page_number_111_conf0.567.jpg, 46 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_page_number_112_conf0.599.jpg, 47 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_page_number_113_conf0.542.jpg, 48 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_page_number_114_conf0.584.jpg, 49 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_page_number_115_conf0.558.jpg, 51 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_page_number_116_conf0.595.jpg, 52 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_page_number_117_conf0.601.jpg, 53 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_page_number_118_conf0.587.jpg, 54 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_page_number_120_conf0.621.jpg, 55 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_page_number_121_conf0.602.jpg, 57 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_page_number_122_conf0.576.jpg, 58 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_page_number_123_conf0.555.jpg, 59 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_page_number_124_conf0.456.jpg, 60 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_page_number_125_conf0.571.jpg, 61 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_page_number_126_conf0.592.jpg, 63 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_page_number_127_conf0.565.jpg, 64 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_page_number_128_conf0.616.jpg, 65 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_page_number_129_conf0.579.jpg, 66 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_page_number_131_conf0.585.jpg, 67 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_page_number_132_conf0.577.jpg, 69 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_page_number_133_conf0.558.jpg, 70 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_page_number_134_conf0.584.jpg, 71 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_page_number_135_conf0.595.jpg, 72 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_page_number_136_conf0.573.jpg, 73 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_page_number_137_conf0.607.jpg, 75 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_page_number_138_conf0.576.jpg, 76 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_page_number_139_conf0.583.jpg, 77 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_page_number_140_conf0.601.jpg, 78 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_page_number_142_conf0.560.jpg, 79 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 61_page_number_143_conf0.577.jpg, 82 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_page_number_144_conf0.629.jpg, 83 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 63_page_number_145_conf0.554.jpg, 84 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_page_number_146_conf0.595.jpg, 85 diff --git a/ai-service/test/OCR/images/problem_number.txt b/ai-service/test/OCR/images/problem_number.txt new file mode 100644 index 0000000..ec95d21 --- /dev/null +++ b/ai-service/test/OCR/images/problem_number.txt @@ -0,0 +1,316 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_000_conf0.820.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_001_conf0.795.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_002_conf0.765.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_003_conf0.755.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_004_conf0.753.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_032_conf0.764.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_033_conf0.764.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_034_conf0.757.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_035_conf0.754.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_036_conf0.746.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_062_conf0.763.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_063_conf0.760.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_064_conf0.743.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_065_conf0.727.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_066_conf0.726.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_098_conf0.768.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_099_conf0.746.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_100_conf0.744.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_121_conf0.769.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_122_conf0.754.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_154_conf0.741.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_155_conf0.740.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_180_conf0.759.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_181_conf0.758.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_209_conf0.756.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_210_conf0.751.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_224_conf0.755.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_225_conf0.739.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_005_conf0.763.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_006_conf0.760.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_007_conf0.747.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_008_conf0.745.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_009_conf0.753.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_010_conf0.729.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_011_conf0.741.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_012_conf0.741.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_013_conf0.742.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_014_conf0.740.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_015_conf0.773.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_016_conf0.736.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_017_conf0.747.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_018_conf0.738.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_019_conf0.757.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_020_conf0.745.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_021_conf0.744.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_022_conf0.795.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_023_conf0.774.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_024_conf0.771.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_025_conf0.770.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_026_conf0.751.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_027_conf0.767.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_028_conf0.760.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_029_conf0.755.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_030_conf0.754.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_031_conf0.728.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_037_conf0.770.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_038_conf0.752.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_039_conf0.735.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_040_conf0.730.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_041_conf0.722.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_042_conf0.786.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_043_conf0.780.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_044_conf0.748.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_045_conf0.765.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_046_conf0.740.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_047_conf0.758.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_048_conf0.739.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_049_conf0.759.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_050_conf0.751.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_051_conf0.758.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_052_conf0.754.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_053_conf0.764.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_054_conf0.744.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_056_conf0.762.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_057_conf0.742.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_058_conf0.742.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_059_conf0.738.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_060_conf0.737.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_061_conf0.733.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_067_conf0.749.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_068_conf0.747.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_069_conf0.758.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_070_conf0.732.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_071_conf0.750.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_072_conf0.738.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_073_conf0.763.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_074_conf0.761.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_075_conf0.752.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_076_conf0.751.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_077_conf0.746.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_078_conf0.815.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_079_conf0.783.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_080_conf0.772.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_081_conf0.758.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_082_conf0.751.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_083_conf0.771.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_084_conf0.751.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_085_conf0.751.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_086_conf0.738.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_087_conf0.735.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_088_conf0.771.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_089_conf0.762.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_090_conf0.756.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_091_conf0.743.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_092_conf0.734.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_093_conf0.776.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_094_conf0.748.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_095_conf0.723.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_096_conf0.747.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_097_conf0.739.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_101_conf0.757.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_102_conf0.733.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_103_conf0.759.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_104_conf0.749.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_105_conf0.749.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_106_conf0.731.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_107_conf0.763.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_108_conf0.734.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_109_conf0.761.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_110_conf0.758.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_111_conf0.739.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_112_conf0.733.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_113_conf0.747.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_114_conf0.737.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_115_conf0.743.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_116_conf0.721.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_117_conf0.738.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_118_conf0.727.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_119_conf0.751.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_120_conf0.745.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_123_conf0.753.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_124_conf0.730.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_125_conf0.752.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_126_conf0.752.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_127_conf0.745.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_128_conf0.814.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_129_conf0.769.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_130_conf0.764.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_131_conf0.758.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_132_conf0.755.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_133_conf0.770.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_134_conf0.768.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_135_conf0.765.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_136_conf0.745.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_137_conf0.736.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_138_conf0.759.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_139_conf0.756.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_140_conf0.754.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_141_conf0.744.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_142_conf0.732.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_143_conf0.777.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_144_conf0.772.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_145_conf0.738.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_146_conf0.746.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_147_conf0.740.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_148_conf0.751.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_149_conf0.733.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_150_conf0.743.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_151_conf0.734.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_152_conf0.755.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_153_conf0.747.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_156_conf0.757.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_157_conf0.742.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_158_conf0.757.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_159_conf0.749.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_160_conf0.739.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_161_conf0.706.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_162_conf0.765.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_163_conf0.741.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_164_conf0.738.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_165_conf0.723.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_166_conf0.738.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_167_conf0.727.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_168_conf0.736.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_169_conf0.727.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_170_conf0.755.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_171_conf0.734.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_172_conf0.749.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_173_conf0.742.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_174_conf0.741.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_175_conf0.803.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_176_conf0.767.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_177_conf0.764.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_178_conf0.751.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_179_conf0.748.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_182_conf0.753.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_183_conf0.750.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_184_conf0.748.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_185_conf0.745.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_186_conf0.743.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_187_conf0.771.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_188_conf0.763.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_189_conf0.753.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_190_conf0.742.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_191_conf0.735.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_192_conf0.761.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_193_conf0.744.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_194_conf0.736.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_195_conf0.758.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_196_conf0.756.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_197_conf0.739.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_198_conf0.736.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_199_conf0.756.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_200_conf0.753.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_201_conf0.741.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_202_conf0.740.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_203_conf0.766.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_204_conf0.746.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_205_conf0.762.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_206_conf0.745.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_000_conf0.754.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_001_conf0.707.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_207_conf0.754.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_208_conf0.707.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_002_conf0.742.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_003_conf0.728.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_211_conf0.742.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_212_conf0.728.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_004_conf0.753.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_005_conf0.730.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_213_conf0.753.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_214_conf0.730.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_006_conf0.742.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_007_conf0.731.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_215_conf0.742.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_216_conf0.731.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_008_conf0.766.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_009_conf0.749.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_217_conf0.766.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_218_conf0.749.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_010_conf0.739.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_011_conf0.727.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_219_conf0.739.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_220_conf0.727.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_012_conf0.752.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_013_conf0.745.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_014_conf0.742.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_221_conf0.752.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_222_conf0.745.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_223_conf0.742.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_015_conf0.752.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_226_conf0.752.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_018_conf0.730.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_237_conf0.730.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_019_conf0.728.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_248_conf0.728.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_020_conf0.722.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_259_conf0.722.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_021_conf0.724.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_270_conf0.724.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_022_conf0.796.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_281_conf0.796.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_023_conf0.724.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_288_conf0.724.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_024_conf0.734.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_289_conf0.734.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_025_conf0.733.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_290_conf0.733.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_016_conf0.766.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_227_conf0.766.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_017_conf0.750.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_228_conf0.750.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_problem_number_229_conf0.722.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_problem_number_230_conf0.742.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_problem_number_231_conf0.735.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_problem_number_232_conf0.720.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_problem_number_233_conf0.789.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_problem_number_234_conf0.715.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_problem_number_235_conf0.737.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_problem_number_236_conf0.744.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_problem_number_238_conf0.709.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_problem_number_239_conf0.754.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_problem_number_240_conf0.723.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_problem_number_241_conf0.734.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_problem_number_242_conf0.721.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_problem_number_243_conf0.719.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_problem_number_244_conf0.752.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_problem_number_245_conf0.733.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_problem_number_246_conf0.736.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_problem_number_247_conf0.736.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_problem_number_249_conf0.717.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_problem_number_250_conf0.767.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_problem_number_251_conf0.717.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_problem_number_252_conf0.716.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_problem_number_253_conf0.728.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_problem_number_254_conf0.744.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_problem_number_255_conf0.723.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_problem_number_256_conf0.727.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_problem_number_257_conf0.724.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_problem_number_258_conf0.739.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_problem_number_260_conf0.723.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_problem_number_261_conf0.712.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_problem_number_262_conf0.721.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_problem_number_263_conf0.728.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_problem_number_264_conf0.730.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_problem_number_265_conf0.718.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_problem_number_266_conf0.769.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_problem_number_267_conf0.725.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_problem_number_268_conf0.742.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_problem_number_269_conf0.728.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_problem_number_271_conf0.716.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_problem_number_272_conf0.750.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_problem_number_273_conf0.728.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_problem_number_274_conf0.723.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_problem_number_275_conf0.729.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_problem_number_276_conf0.708.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_problem_number_277_conf0.762.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_problem_number_278_conf0.730.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_problem_number_279_conf0.730.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_problem_number_280_conf0.727.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_problem_number_282_conf0.736.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_283_conf0.722.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_284_conf0.714.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_285_conf0.737.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_286_conf0.721.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_287_conf0.720.jpg, 05 \ No newline at end of file diff --git a/ai-service/test/OCR/ocr_model/__init__.py b/ai-service/test/OCR/ocr_model/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-service/test/OCR/ocr_model/__pycache__/cnocr_model.cpython-311.pyc b/ai-service/test/OCR/ocr_model/__pycache__/cnocr_model.cpython-311.pyc new file mode 100644 index 0000000..622b03f Binary files /dev/null and b/ai-service/test/OCR/ocr_model/__pycache__/cnocr_model.cpython-311.pyc differ diff --git a/ai-service/test/OCR/ocr_model/__pycache__/easyocr_model.cpython-311.pyc b/ai-service/test/OCR/ocr_model/__pycache__/easyocr_model.cpython-311.pyc new file mode 100644 index 0000000..de78318 Binary files /dev/null and b/ai-service/test/OCR/ocr_model/__pycache__/easyocr_model.cpython-311.pyc differ diff --git a/ai-service/test/OCR/ocr_model/__pycache__/easyocr_model.cpython-312.pyc b/ai-service/test/OCR/ocr_model/__pycache__/easyocr_model.cpython-312.pyc new file mode 100644 index 0000000..ce18bac Binary files /dev/null and b/ai-service/test/OCR/ocr_model/__pycache__/easyocr_model.cpython-312.pyc differ diff --git a/ai-service/test/OCR/ocr_model/__pycache__/paddleocr_model.cpython-311.pyc b/ai-service/test/OCR/ocr_model/__pycache__/paddleocr_model.cpython-311.pyc new file mode 100644 index 0000000..89eed9e Binary files /dev/null and b/ai-service/test/OCR/ocr_model/__pycache__/paddleocr_model.cpython-311.pyc differ diff --git a/ai-service/test/OCR/ocr_model/__pycache__/tesseract_model.cpython-311.pyc b/ai-service/test/OCR/ocr_model/__pycache__/tesseract_model.cpython-311.pyc new file mode 100644 index 0000000..d6f28d8 Binary files /dev/null and b/ai-service/test/OCR/ocr_model/__pycache__/tesseract_model.cpython-311.pyc differ diff --git a/ai-service/test/OCR/ocr_model/__pycache__/tesseract_model.cpython-312.pyc b/ai-service/test/OCR/ocr_model/__pycache__/tesseract_model.cpython-312.pyc new file mode 100644 index 0000000..f55496a Binary files /dev/null and b/ai-service/test/OCR/ocr_model/__pycache__/tesseract_model.cpython-312.pyc differ diff --git a/ai-service/test/OCR/ocr_model/cnocr_model.py b/ai-service/test/OCR/ocr_model/cnocr_model.py new file mode 100644 index 0000000..d55597f --- /dev/null +++ b/ai-service/test/OCR/ocr_model/cnocr_model.py @@ -0,0 +1,30 @@ +import re +from cnocr import CnOcr +from pathlib import Path + +class CNOCRModel: + def __init__(self): + # CnOcr ๋ชจ๋ธ ์ดˆ๊ธฐํ™” + self.ocr = CnOcr() + + def extract_number(self, image_path): + """์ด๋ฏธ์ง€์—์„œ ์ˆซ์ž ์ถ”์ถœ""" + try: + image_path = str(Path(image_path).resolve()) + results = self.ocr.ocr(image_path) + + if isinstance(results, list): + text = ''.join([ + item['text'] for item in results + if isinstance(item, dict) and 'text' in item + ]) + elif isinstance(results, dict) and 'text' in results: + text = results['text'] + else: + text = "" + + numbers = re.findall(r'\d+', text) + return numbers[0] if numbers else "" + except Exception as e: + print(f"CNOCR Error processing {image_path}: {e}") + return "" diff --git a/ai-service/test/OCR/ocr_model/easyocr_model.py b/ai-service/test/OCR/ocr_model/easyocr_model.py new file mode 100644 index 0000000..f42a35d --- /dev/null +++ b/ai-service/test/OCR/ocr_model/easyocr_model.py @@ -0,0 +1,21 @@ +import easyocr +import re + +class EasyOCRModel: + def __init__(self): + self.reader = easyocr.Reader(['en'], gpu=False) + + def extract_number(self, image_path): + """์ด๋ฏธ์ง€์—์„œ ์ˆซ์ž๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.""" + try: + results = self.reader.readtext(image_path) + # ๋ชจ๋“  ํ…์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ํ•ฉ์นจ + text = ' '.join([result[1] for result in results]) + # ์ˆซ์ž๋งŒ ์ถ”์ถœ + numbers = re.findall(r'\d+', text) + if numbers: + return numbers[0] # ์ฒซ ๋ฒˆ์งธ ์ˆซ์ž ๋ฐ˜ํ™˜ + return "" + except Exception as e: + print(f"EasyOCR Error processing {image_path}: {e}") + return "" \ No newline at end of file diff --git a/ai-service/test/OCR/ocr_model/paddleocr_model.py b/ai-service/test/OCR/ocr_model/paddleocr_model.py new file mode 100644 index 0000000..ea5ec28 --- /dev/null +++ b/ai-service/test/OCR/ocr_model/paddleocr_model.py @@ -0,0 +1,38 @@ +import re +import logging +from paddleocr import PaddleOCR + +# PaddleOCR ๋กœ๊ทธ ์ตœ์†Œํ™” +logging.getLogger('paddleocr').setLevel(logging.WARNING) + +class PaddleOCRModel: + def __init__(self): + # PaddleOCR ์ดˆ๊ธฐํ™” + self.ocr = PaddleOCR(use_angle_cls=True, lang='en') + + def extract_number(self, image_path): + """์ด๋ฏธ์ง€์—์„œ ์ˆซ์ž๋งŒ ์ถ”์ถœ""" + try: + result = self.ocr.ocr(image_path) + + texts = [] + # PaddleOCR ๋ฒ„์ „๋ณ„ ๊ฒฐ๊ณผ ๊ตฌ์กฐ ๋Œ€์‘ + if isinstance(result, list): + for item in result: + if not item: + continue + if isinstance(item, list): + for line in item: + if isinstance(line, (list, tuple)) and len(line) > 1: + text_part = line[1][0] if isinstance(line[1], (list, tuple)) else line[1] + texts.append(str(text_part)) + elif isinstance(item, (list, tuple)) and len(item) > 1: + text_part = item[1][0] if isinstance(item[1], (list, tuple)) else item[1] + texts.append(str(text_part)) + + text = " ".join(texts) + numbers = re.findall(r'\d+', text) + return numbers[0] if numbers else "" + except Exception as e: + print(f"PaddleOCR Error processing {image_path}: {e}") + return "" diff --git a/ai-service/test/OCR/ocr_model/tesseract_model.py b/ai-service/test/OCR/ocr_model/tesseract_model.py new file mode 100644 index 0000000..ae67bfd --- /dev/null +++ b/ai-service/test/OCR/ocr_model/tesseract_model.py @@ -0,0 +1,24 @@ +import pytesseract +from PIL import Image +import re + +class TesseractOCRModel: + def __init__(self): + # Tesseract ์„ค์ • (ํ•„์š”์‹œ ๊ฒฝ๋กœ ์ง€์ •) + # pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' + pass + + def extract_number(self, image_path): + """์ด๋ฏธ์ง€์—์„œ ์ˆซ์ž๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.""" + try: + img = Image.open(image_path) + # ์ˆซ์ž๋งŒ ์ธ์‹ํ•˜๋„๋ก ์„ค์ • + text = pytesseract.image_to_string(img, config='--psm 6 digits') + # ์ˆซ์ž๋งŒ ์ถ”์ถœ + numbers = re.findall(r'\d+', text) + if numbers: + return numbers[0] # ์ฒซ ๋ฒˆ์งธ ์ˆซ์ž ๋ฐ˜ํ™˜ + return "" + except Exception as e: + print(f"Tesseract Error processing {image_path}: {e}") + return "" \ No newline at end of file diff --git a/ai-service/test/OCR/ocr_test.md b/ai-service/test/OCR/ocr_test.md new file mode 100644 index 0000000..da0e55e --- /dev/null +++ b/ai-service/test/OCR/ocr_test.md @@ -0,0 +1,96 @@ +# ๐Ÿ“ OCR ํ…Œ์ŠคํŠธ ๊ตฌ์กฐ +``` +project/ # OCR ๋ชจ๋ธ๋ณ„ ํŽ˜์ด์ง€/๋ฌธ์ œ ๋ฒˆํ˜ธ ์ธ์‹ ์„ฑ๋Šฅ ๋น„๊ต ํ”„๋กœ์ ํŠธ +โ”œโ”€โ”€ images/ # OCR ์ž…๋ ฅ ์ด๋ฏธ์ง€ ๋ฐ ์ •๋‹ต(label) ๋ฐ์ดํ„ฐ ํด๋” +โ”‚ โ”œโ”€โ”€ page_number/ # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹์šฉ ์ด๋ฏธ์ง€ +โ”‚ โ”œโ”€โ”€ problem_number/ # ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ธ์‹์šฉ ์ด๋ฏธ์ง€ +โ”‚ โ”œโ”€โ”€ page_number.txt # ๊ฐ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€์˜ ์ •๋‹ต(label) ์ •๋ณด +โ”‚ โ””โ”€โ”€ problem_number.txt # ๊ฐ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€์˜ ์ •๋‹ต(label) ์ •๋ณด +โ”‚ +โ”œโ”€โ”€ ocr_model/ # ๋‹ค์–‘ํ•œ OCR ์—”์ง„๋ณ„ ๋ชจ๋ธ ๊ตฌํ˜„ ํด๋” +โ”‚ โ”œโ”€โ”€ __init__.py # ํŒจํ‚ค์ง€ ์ดˆ๊ธฐํ™” ํŒŒ์ผ (๋ชจ๋ธ ํด๋ž˜์Šค import์šฉ) +โ”‚ โ”œโ”€โ”€ easyocr_model.py # EasyOCR ๊ธฐ๋ฐ˜ ์ธ์‹ ๋ชจ๋ธ ๊ตฌํ˜„ (PyTorch ๊ธฐ๋ฐ˜ ๋‹ค๊ตญ์–ด ์ง€์›) +โ”‚ โ”œโ”€โ”€ tesseract_model.py # Tesseract OCR ๊ธฐ๋ฐ˜ ์ธ์‹ ๋ชจ๋ธ ๊ตฌํ˜„ (pytesseract ์‚ฌ์šฉ) +โ”‚ โ”œโ”€โ”€ paddleocr_model.py # PaddleOCR ๊ธฐ๋ฐ˜ ์ธ์‹ ๋ชจ๋ธ ๊ตฌํ˜„ (๋”ฅ๋Ÿฌ๋‹ ๊ธฐ๋ฐ˜ OCR) +โ”‚ โ””โ”€โ”€ cnocr_model.py # CnOCR ๊ธฐ๋ฐ˜ ์ธ์‹ ๋ชจ๋ธ ๊ตฌํ˜„ (์ค‘๊ตญ์–ด/ํ•œ๊ธ€ OCR์— ๊ฐ•์ ) +โ”‚ +โ”œโ”€โ”€ test_result/ # OCR ์‹คํ–‰ ๊ฒฐ๊ณผ ๋ฐ ์„ฑ๋Šฅ ํ‰๊ฐ€ ๊ฒฐ๊ณผ ์ €์žฅ ํด๋” +โ”‚ โ”œโ”€โ”€ easyocr_page_number.txt # EasyOCR๋กœ ์ถ”์ถœํ•œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ ๊ฒฐ๊ณผ +โ”‚ โ”œโ”€โ”€ easyocr_problem_number.txt # EasyOCR๋กœ ์ถ”์ถœํ•œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ธ์‹ ๊ฒฐ๊ณผ +โ”‚ โ”œโ”€โ”€ tesseract_page_number.txt # Tesseract๋กœ ์ถ”์ถœํ•œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ ๊ฒฐ๊ณผ +โ”‚ โ”œโ”€โ”€ tesseract_problem_number.txt # Tesseract๋กœ ์ถ”์ถœํ•œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ธ์‹ ๊ฒฐ๊ณผ +โ”‚ โ”œโ”€โ”€ paddleocr_page_number.txt # PaddleOCR๋กœ ์ถ”์ถœํ•œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ ๊ฒฐ๊ณผ +โ”‚ โ”œโ”€โ”€ paddleocr_problem_number.txt # PaddleOCR๋กœ ์ถ”์ถœํ•œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ธ์‹ ๊ฒฐ๊ณผ +โ”‚ โ”œโ”€โ”€ cnocr_page_number.txt # CnOCR๋กœ ์ถ”์ถœํ•œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ ๊ฒฐ๊ณผ +โ”‚ โ”œโ”€โ”€ cnocr_problem_number.txt # CnOCR๋กœ ์ถ”์ถœํ•œ ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ธ์‹ ๊ฒฐ๊ณผ +โ”‚ โ””โ”€โ”€ ocr_accuracy_results.csv # ๊ฐ ๋ชจ๋ธ๋ณ„ ์ธ์‹ ์ •ํ™•๋„ ๋น„๊ต ํ‘œ +โ”‚ +โ””โ”€โ”€ ocr_test.py # ๋ฉ”์ธ ์‹คํ–‰ ์Šคํฌ๋ฆฝํŠธ: + # - ๋ชจ๋“  OCR ๋ชจ๋ธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ + # - ๊ฐ ์ด๋ฏธ์ง€์…‹(page/problem)๋ณ„ ์ธ์‹ ์ˆ˜ํ–‰ + # - ์ •๋‹ต๊ณผ ๋น„๊ตํ•˜์—ฌ ์ •ํ™•๋„ ๊ณ„์‚ฐ ํ›„ ๊ฒฐ๊ณผ ์ €์žฅ + +``` + +
+ +### ๐Ÿ”ง ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ +Tesseract ์ถ”๊ฐ€ ์„ค์น˜: Tesseract OCR์€ ๋ณ„๋„ ์„ค์น˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. +- Windows: https://github.com/UB-Mannheim/tesseract/wiki +- Mac: brew install tesseract +- Linux: sudo apt-get install tesseract-ocr + +```python +conda create -n ocr python=3.11 -y +conda activate ocr + +pip install "numpy<2" +pip install pytesseract easyocr paddleocr paddlepaddle cnocr onnxruntime +``` +- numpy ๋ฒ„์ „ ์ถฉ๋Œ ๋•Œ๋ฌธ์— ๋ณ„๋„์˜ ๊ฐ€์ƒ ํ™˜๊ฒฝ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค. + +
+ +### ๐Ÿ“ ์ฃผ์š” ๊ธฐ๋Šฅ + +- ๊ฐ ๋ชจ๋ธ๋ณ„ OCR ํด๋ž˜์Šค: ์ด๋ฏธ์ง€์—์„œ ์ˆซ์ž๋ฅผ ์ถ”์ถœํ•˜๋Š” extract_number() ๋ฉ”์„œ๋“œ ๊ตฌํ˜„ +- ์ž๋™ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ: ๊ฐ ํด๋”์˜ ๋ชจ๋“  ์ด๋ฏธ์ง€๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌ +- ๊ฒฐ๊ณผ ์ €์žฅ: {๋ชจ๋ธ๋ช…}_page_number.txt ๋ฐ {๋ชจ๋ธ๋ช…}_problem_number.txt ํ˜•์‹์œผ๋กœ ์ €์žฅ +- CSV ์ถœ๋ ฅ: ๋ชจ๋“  ๋ชจ๋ธ์˜ ์ •ํ™•๋„๋ฅผ CSV ํŒŒ์ผ๋กœ ์ €์žฅ + +**์ธก์ • ๋‚ด์šฉ** +- page_total_time: Page number ์ „์ฒด ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ (์ดˆ) +- page_avg_time: Page number ์ด๋ฏธ์ง€๋‹น ํ‰๊ท  ์‹œ๊ฐ„ (์ดˆ) +- problem_total_time: Problem number ์ „์ฒด ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ (์ดˆ) +- problem_avg_time: Problem number ์ด๋ฏธ์ง€๋‹น ํ‰๊ท  ์‹œ๊ฐ„ (์ดˆ) +- overall_total_time: ์ „์ฒด ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ด ์‹œ๊ฐ„ (์ดˆ) +- overall_avg_time: ์ „์ฒด ์ด๋ฏธ์ง€ ํ‰๊ท  ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ (์ดˆ) + +
+ +### ๐Ÿš€ ์‹คํ–‰ ๋ฐฉ๋ฒ• +``` +python ocr_test.py +``` +์‹คํ–‰ ๊ฒฐ๊ณผ๋กœ ๋‹ค์Œ ํŒŒ์ผ๋“ค์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค: +- `easyocr_page_number.txt`, `easyocr_problem_number.txt` +- `tesseract_page_number.txt`, `tesseract_problem_number.txt` +- `paddleocr_page_number.txt`, `paddleocr_problem_number.txt` +- `cnocr_page_number.txt`, `cnocr_problem_number.txt` +- `ocr_accuracy_results.csv` (์ตœ์ข… ์ •ํ™•๋„ ๊ฒฐ๊ณผ) + +
+ +### ๐Ÿ“Š ์ถœ๋ ฅ ๊ฒฐ๊ณผ +``` +============================================================ +FINAL RESULTS +============================================================ + +Model Page Num % Problem Num % Average % +------------------------------------------------------------ +easyocr 100.00 100.00 100.00 +tesseract 94.64 90.19 92.42 +paddleocr 0.00 0.00 0.00 +cnocr 3.57 0.00 1.79 +``` \ No newline at end of file diff --git a/ai-service/test/OCR/ocr_test.py b/ai-service/test/OCR/ocr_test.py new file mode 100644 index 0000000..b8e680b --- /dev/null +++ b/ai-service/test/OCR/ocr_test.py @@ -0,0 +1,172 @@ +import os +import sys +import csv +import time +from pathlib import Path + +# ocr_model ํด๋”์˜ ๋ชจ๋ธ๋“ค import +sys.path.append('ocr_model') +from easyocr_model import EasyOCRModel +from tesseract_model import TesseractOCRModel +from paddleocr_model import PaddleOCRModel +from cnocr_model import CNOCRModel + + +def load_ground_truth(file_path): + """์ •๋‹ต ํŒŒ์ผ์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.""" + ground_truth = {} + try: + with open(file_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if line: + parts = line.split(', ') + if len(parts) == 2: + filename = parts[0] + answer = parts[1] + ground_truth[filename] = answer + except FileNotFoundError: + print(f"Warning: {file_path} not found") + return ground_truth + + +def process_images(model, model_name, image_folder, output_file): + """์ด๋ฏธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.""" + results = [] + image_files = sorted([f for f in os.listdir(image_folder) + if f.endswith(('.jpg', '.jpeg', '.png', '.JPG'))]) + + print(f"\n{model_name} - Processing {len(image_files)} images from {image_folder}...") + + for idx, image_file in enumerate(image_files, 1): + image_path = os.path.join(image_folder, image_file) + extracted_number = model.extract_number(image_path) + results.append((image_file, extracted_number)) + + if idx % 10 == 0 or idx == len(image_files): + print(f" Progress: {idx}/{len(image_files)}") + + # ๊ฒฐ๊ณผ๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ + with open(output_file, 'w', encoding='utf-8') as f: + for filename, number in results: + f.write(f"{filename}, {number}\n") + + return results + + +def calculate_accuracy(predictions, ground_truth): + """์ •๋‹ต๋ฅ ์„ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.""" + if not ground_truth: + return 0.0 + + correct = 0 + total = 0 + + for filename, predicted in predictions: + if filename in ground_truth: + total += 1 + if predicted == ground_truth[filename]: + correct += 1 + + accuracy = (correct / total * 100) if total > 0 else 0.0 + return accuracy + + +def main(): + # ๊ฒฐ๊ณผ ์ €์žฅ ํด๋” ์ƒ์„ฑ + result_folder = 'test_result' + os.makedirs(result_folder, exist_ok=True) + + # ๋ชจ๋ธ ์ดˆ๊ธฐํ™” + models = { + 'easyocr': EasyOCRModel(), + 'tesseract': TesseractOCRModel(), + 'paddleocr': PaddleOCRModel(), + 'cnocr': CNOCRModel() + } + + # ํด๋” ๋ฐ ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • + page_number_folder = 'images/page_number' + problem_number_folder = 'images/problem_number' + page_number_gt_file = 'images/page_number.txt' + problem_number_gt_file = 'images/problem_number.txt' + + # ์ •๋‹ต ๋ฐ์ดํ„ฐ ๋กœ๋“œ + print("Loading ground truth data...") + page_number_gt = load_ground_truth(page_number_gt_file) + problem_number_gt = load_ground_truth(problem_number_gt_file) + + # ๊ฒฐ๊ณผ ์ €์žฅ์šฉ ๋ฆฌ์ŠคํŠธ + accuracy_results = [] + + # ๊ฐ ๋ชจ๋ธ์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌ + for model_name, model in models.items(): + print(f"\n{'='*60}") + print(f"Processing with {model_name.upper()}") + print(f"{'='*60}") + + try: + # Page number ์ฒ˜๋ฆฌ + page_output_file = os.path.join(result_folder, f"{model_name}_page_number.txt") + page_predictions = process_images( + model, model_name, page_number_folder, page_output_file + ) + page_accuracy = calculate_accuracy(page_predictions, page_number_gt) + + # Problem number ์ฒ˜๋ฆฌ + problem_output_file = os.path.join(result_folder, f"{model_name}_problem_number.txt") + problem_predictions = process_images( + model, model_name, problem_number_folder, problem_output_file + ) + problem_accuracy = calculate_accuracy(problem_predictions, problem_number_gt) + + # ๊ฒฐ๊ณผ ์ €์žฅ + accuracy_results.append({ + 'model': model_name, + 'page_number_accuracy': page_accuracy, + 'problem_number_accuracy': problem_accuracy, + 'average_accuracy': (page_accuracy + problem_accuracy) / 2 + }) + + print(f"\n{model_name.upper()} Results:") + print(f" Page Number Accuracy: {page_accuracy:.2f}%") + print(f" Problem Number Accuracy: {problem_accuracy:.2f}%") + print(f" Average Accuracy: {(page_accuracy + problem_accuracy) / 2:.2f}%") + + except Exception as e: + print(f"Error with {model_name}: {e}") + accuracy_results.append({ + 'model': model_name, + 'page_number_accuracy': 0.0, + 'problem_number_accuracy': 0.0, + 'average_accuracy': 0.0 + }) + + # CSV ํŒŒ์ผ๋กœ ๊ฒฐ๊ณผ ์ €์žฅ + csv_filename = os.path.join(result_folder, 'ocr_accuracy_results.csv') + with open(csv_filename, 'w', newline='', encoding='utf-8') as csvfile: + fieldnames = ['model', 'page_number_accuracy', 'problem_number_accuracy', 'average_accuracy'] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + + writer.writeheader() + for result in accuracy_results: + writer.writerow(result) + + # ์ตœ์ข… ๊ฒฐ๊ณผ ์ถœ๋ ฅ + print(f"\n{'='*60}") + print("FINAL RESULTS") + print(f"{'='*60}") + print(f"\n{'Model':<15} {'Page Num %':<15} {'Problem Num %':<15} {'Average %':<15}") + print("-" * 60) + + for result in accuracy_results: + print(f"{result['model']:<15} " + f"{result['page_number_accuracy']:<15.2f} " + f"{result['problem_number_accuracy']:<15.2f} " + f"{result['average_accuracy']:<15.2f}") + + print(f"\nResults saved to {csv_filename}") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ai-service/test/OCR/test_result.ipynb b/ai-service/test/OCR/test_result.ipynb new file mode 100644 index 0000000..482dcc0 --- /dev/null +++ b/ai-service/test/OCR/test_result.ipynb @@ -0,0 +1,132 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "724adf18", + "metadata": {}, + "outputs": [], + "source": [ + "def load_file_to_dict(file_path):\n", + " \"\"\"'{ํŒŒ์ผ๋ช…}, {ํŽ˜์ด์ง€๋ฒˆํ˜ธ}' ํ˜•์‹์˜ ํ…์ŠคํŠธ ํŒŒ์ผ์„ dict๋กœ ๋ณ€ํ™˜\"\"\"\n", + " data = {}\n", + " with open(file_path, \"r\", encoding=\"utf-8\") as f:\n", + " for line in f:\n", + " line = line.strip()\n", + " if not line:\n", + " continue\n", + " if ',' in line:\n", + " filename, value = line.split(',', 1)\n", + " data[filename.strip()] = value.strip()\n", + " return data\n", + "\n", + "\n", + "def compare_page_numbers(ground_truth_path, test_result_path):\n", + " gt_dict = load_file_to_dict(ground_truth_path)\n", + " test_dict = load_file_to_dict(test_result_path)\n", + "\n", + " differences = []\n", + "\n", + " for filename, gt_value in gt_dict.items():\n", + " test_value = test_dict.get(filename)\n", + " if test_value is None:\n", + " differences.append((filename, gt_value, \"ํŒŒ์ผ ์—†์Œ\"))\n", + " elif gt_value != test_value:\n", + " differences.append((filename, gt_value, test_value))\n", + "\n", + " # test_result์—๋งŒ ์กด์žฌํ•˜๋Š” ํŒŒ์ผ๋„ ์ฐพ๊ธฐ\n", + " for filename in test_dict:\n", + " if filename not in gt_dict:\n", + " differences.append((filename, \"์ •๋‹ต ์—†์Œ\", test_dict[filename]))\n", + "\n", + " return differences" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "85cd60b4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… ๋ชจ๋“  ๊ฐ’์ด ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.\n" + ] + } + ], + "source": [ + "ground_truth_file = \"images/page_number.txt\"\n", + "test_result_file = \"test_result/easyocr_page_number.txt\"\n", + "\n", + "diffs = compare_page_numbers(ground_truth_file, test_result_file)\n", + "\n", + "if not diffs:\n", + " print(\"โœ… ๋ชจ๋“  ๊ฐ’์ด ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.\")\n", + "else:\n", + " print(\"โŒ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ’์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:\\n\")\n", + " for filename, gt, pred in diffs:\n", + " print(f\"{filename}\\n โ†’ ์ •๋‹ต: {gt}\\n โ†’ ๊ฒฐ๊ณผ: {pred}\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9024c100", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โŒ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ’์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:\n", + "\n", + "ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_186_conf0.743.jpg\n", + " โ†’ ์ •๋‹ต: 10\n", + " โ†’ ๊ฒฐ๊ณผ: 08\n", + "\n", + "ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_218_conf0.749.jpg\n", + " โ†’ ์ •๋‹ต: 49\n", + " โ†’ ๊ฒฐ๊ณผ: 39\n", + "\n" + ] + } + ], + "source": [ + "ground_truth_file = \"images/problem_number.txt\"\n", + "test_result_file = \"test_result/easyocr_problem_number.txt\"\n", + "\n", + "diffs = compare_page_numbers(ground_truth_file, test_result_file)\n", + "\n", + "if not diffs:\n", + " print(\"โœ… ๋ชจ๋“  ๊ฐ’์ด ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.\")\n", + "else:\n", + " print(\"โŒ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ’์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค:\\n\")\n", + " for filename, gt, pred in diffs:\n", + " print(f\"{filename}\\n โ†’ ์ •๋‹ต: {gt}\\n โ†’ ๊ฒฐ๊ณผ: {pred}\\n\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "cradi", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ai-service/test/OCR/test_result/cnocr_answer_1_answer.txt b/ai-service/test/OCR/test_result/cnocr_answer_1_answer.txt new file mode 100644 index 0000000..9660c94 --- /dev/null +++ b/ai-service/test/OCR/test_result/cnocr_answer_1_answer.txt @@ -0,0 +1,260 @@ +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_021_conf0.525.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_038_conf0.662.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_039_conf0.625.jpg, 7 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_040_conf0.620.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_043_conf0.393.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_answer_1_048_conf0.547.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_answer_1_050_conf0.547.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_answer_1_062_conf0.682.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_answer_1_063_conf0.680.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_036_conf0.635.jpg, 1 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_093_conf0.690.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_095_conf0.592.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_107_conf0.632.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_1_116_conf0.620.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_120_conf0.575.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_121_conf0.554.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_122_conf0.244.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_007_conf0.593.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_139_conf0.593.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_012_conf0.341.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_144_conf0.341.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_1_022_conf0.560.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_1_156_conf0.560.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_answer_1_160_conf0.497.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_answer_1_161_conf0.528.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_1_019_conf0.610.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_1_153_conf0.610.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_answer_1_168_conf0.607.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_answer_1_171_conf0.544.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_answer_1_174_conf0.651.jpg, 5 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_1_179_conf0.531.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_1_180_conf0.274.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_answer_1_182_conf0.481.jpg, 6 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_answer_1_191_conf0.604.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_answer_1_196_conf0.631.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_answer_1_197_conf0.622.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_answer_1_199_conf0.537.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_1_205_conf0.543.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_1_206_conf0.527.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_1_027_conf0.424.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_1_207_conf0.424.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_1_031_conf0.543.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_1_227_conf0.543.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_answer_1_006_conf0.507.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_answer_1_015_conf0.544.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_answer_1_017_conf0.609.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_019_conf0.297.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_020_conf0.224.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_022_conf0.494.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_024_conf0.598.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_025_conf0.566.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_003_conf0.549.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_041_conf0.511.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_answer_1_053_conf0.520.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_answer_1_055_conf0.610.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_answer_1_060_conf0.575.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_answer_1_061_conf0.556.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_033_conf0.692.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_070_conf0.465.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_071_conf0.447.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_081_conf0.345.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_083_conf0.227.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_065_conf0.549.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_084_conf0.624.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_105_conf0.503.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_109_conf0.534.jpg, 34 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_117_conf0.516.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_001_conf0.428.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_131_conf0.428.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_answer_1_100_conf0.560.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_003_conf0.484.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_004_conf0.280.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_005_conf0.248.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_135_conf0.484.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_136_conf0.280.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_137_conf0.248.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_009_conf0.431.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_010_conf0.309.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_141_conf0.431.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_142_conf0.309.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_014_conf0.601.jpg, 20 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_015_conf0.388.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_146_conf0.601.jpg, 20 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_147_conf0.388.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_answer_1_133_conf0.540.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_answer_1_152_conf0.513.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_answer_1_021_conf0.450.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_answer_1_155_conf0.450.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_1_157_conf0.541.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_1_158_conf0.335.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_answer_1_166_conf0.572.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_1_172_conf0.371.jpg, 4 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_1_173_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_answer_1_176_conf0.514.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_answer_1_177_conf0.563.jpg, 9 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_1_023_conf0.658.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_1_167_conf0.658.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_1_183_conf0.518.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_1_184_conf0.338.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_1_186_conf0.593.jpg, 3 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_1_187_conf0.302.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_1_024_conf0.464.jpg, 42 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_1_181_conf0.464.jpg, 42 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_answer_1_202_conf0.601.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_answer_1_217_conf0.531.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_1_222_conf0.637.jpg, 34 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_answer_1_005_conf0.553.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_answer_1_007_conf0.658.jpg, 9 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_answer_1_009_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_011_conf0.558.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_answer_1_016_conf0.719.jpg, 9 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_026_conf0.439.jpg, 6 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_027_conf0.325.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_029_conf0.641.jpg, 0 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_000_conf0.691.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_002_conf0.600.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_004_conf0.488.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_042_conf0.509.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_answer_1_049_conf0.523.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_answer_1_059_conf0.723.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_037_conf0.566.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_069_conf0.653.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_answer_1_072_conf0.704.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_answer_1_074_conf0.537.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_064_conf0.666.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_066_conf0.504.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_068_conf0.383.jpg, 41 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_085_conf0.534.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_086_conf0.440.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_answer_1_088_conf0.636.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_094_conf0.631.jpg, 1 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_096_conf0.519.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_097_conf0.446.jpg, 1 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_098_conf0.310.jpg, 5 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_114_conf0.583.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_1_115_conf0.659.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_118_conf0.490.jpg, 9 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_119_conf0.246.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_1_123_conf0.566.jpg, 5 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_127_conf0.619.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_129_conf0.265.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_000_conf0.524.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_130_conf0.524.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_answer_1_099_conf0.640.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_1_162_conf0.410.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_answer_1_175_conf0.427.jpg, 5 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_answer_1_188_conf0.673.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_answer_1_192_conf0.488.jpg, 7 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_answer_1_211_conf0.761.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_answer_1_214_conf0.645.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_answer_1_216_conf0.757.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_answer_1_220_conf0.729.jpg, 4 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_225_conf0.542.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_1_032_conf0.683.jpg, 9 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_1_228_conf0.683.jpg, 9 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_answer_1_010_conf0.467.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_012_conf0.417.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_013_conf0.278.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_023_conf0.414.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_030_conf0.596.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_032_conf0.485.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_001_conf0.674.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_044_conf0.695.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_046_conf0.638.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_answer_1_054_conf0.665.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_answer_1_056_conf0.548.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_answer_1_057_conf0.514.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_answer_1_058_conf0.775.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_034_conf0.660.jpg, 0 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_035_conf0.641.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_answer_1_075_conf0.530.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_076_conf0.533.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_077_conf0.528.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_078_conf0.510.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_079_conf0.494.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_067_conf0.454.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_answer_1_087_conf0.649.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_089_conf0.564.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_091_conf0.253.jpg, 2 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_101_conf0.640.jpg, 1 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_102_conf0.605.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_103_conf0.547.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_104_conf0.506.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_106_conf0.483.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_110_conf0.511.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_112_conf0.626.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_1_124_conf0.437.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_1_125_conf0.590.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_128_conf0.609.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_002_conf0.551.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_134_conf0.551.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_008_conf0.621.jpg, 3 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_140_conf0.621.jpg, 3 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_013_conf0.606.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_145_conf0.606.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_018_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_150_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_answer_1_159_conf0.589.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_answer_1_163_conf0.652.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_1_164_conf0.478.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_1_165_conf0.226.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_answer_1_189_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_answer_1_193_conf0.673.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_answer_1_201_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_answer_1_203_conf0.671.jpg, 9 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_025_conf0.585.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_026_conf0.337.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_194_conf0.585.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_195_conf0.337.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_answer_1_210_conf0.565.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_1_221_conf0.647.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_223_conf0.782.jpg, 2 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_028_conf0.369.jpg, 2 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_029_conf0.241.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_218_conf0.369.jpg, 2 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_219_conf0.241.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_answer_1_008_conf0.569.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_answer_1_014_conf0.584.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_018_conf0.515.jpg, 2 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_028_conf0.670.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_031_conf0.578.jpg, 2 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_045_conf0.676.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_047_conf0.477.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_answer_1_051_conf0.516.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_answer_1_052_conf0.635.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_answer_1_073_conf0.659.jpg, 2 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_080_conf0.367.jpg, 9 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_082_conf0.318.jpg, 8 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_090_conf0.487.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_092_conf0.221.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_108_conf0.576.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_111_conf0.456.jpg, 4 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_113_conf0.609.jpg, 4 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_1_126_conf0.555.jpg, 5 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_006_conf0.606.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_138_conf0.606.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_011_conf0.524.jpg, 9 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_143_conf0.524.jpg, 9 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_016_conf0.571.jpg, 2 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_017_conf0.533.jpg, 9 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_148_conf0.571.jpg, 2 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_149_conf0.533.jpg, 9 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_answer_1_132_conf0.639.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_answer_1_151_conf0.659.jpg, 2 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_1_169_conf0.573.jpg, 0 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_1_170_conf0.307.jpg, 2 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_answer_1_178_conf0.458.jpg, 9 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_answer_1_185_conf0.677.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_answer_1_190_conf0.596.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_answer_1_198_conf0.661.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_answer_1_200_conf0.673.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_answer_1_204_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_answer_1_208_conf0.709.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_answer_1_209_conf0.743.jpg, 5 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_answer_1_212_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_answer_1_213_conf0.664.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_answer_1_215_conf0.656.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_224_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_1_030_conf0.557.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_1_226_conf0.557.jpg, diff --git a/ai-service/test/OCR/test_result/cnocr_answer_2_answer.txt b/ai-service/test/OCR/test_result/cnocr_answer_2_answer.txt new file mode 100644 index 0000000..2688570 --- /dev/null +++ b/ai-service/test/OCR/test_result/cnocr_answer_2_answer.txt @@ -0,0 +1,229 @@ +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_014_conf0.732.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_024_conf0.582.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_026_conf0.296.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_answer_2_047_conf0.703.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_answer_2_054_conf0.659.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_answer_2_058_conf0.706.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_061_conf0.667.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_065_conf0.707.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_066_conf0.695.jpg, 1 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_069_conf0.713.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_074_conf0.741.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_080_conf0.718.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_answer_2_085_conf0.710.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_answer_2_102_conf0.654.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_answer_2_104_conf0.677.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_109_conf0.725.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_111_conf0.690.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_119_conf0.750.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_2_127_conf0.742.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_2_131_conf0.716.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_2_132_conf0.711.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_007_conf0.656.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_146_conf0.656.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_answer_2_159_conf0.727.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_answer_2_160_conf0.714.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_answer_2_166_conf0.749.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_answer_2_168_conf0.756.jpg, 2 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_answer_2_170_conf0.748.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_2_175_conf0.751.jpg, 1 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_answer_2_177_conf0.751.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_answer_2_184_conf0.723.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_answer_2_193_conf0.785.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_answer_2_195_conf0.745.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_2_022_conf0.726.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_2_209_conf0.726.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_016_conf0.701.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_017_conf0.659.jpg, 8 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_021_conf0.609.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_030_conf0.672.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_032_conf0.724.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_033_conf0.709.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_answer_2_035_conf0.617.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_answer_2_037_conf0.675.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_answer_2_042_conf0.664.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_answer_2_044_conf0.655.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_answer_2_045_conf0.700.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_answer_2_051_conf0.681.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_answer_2_055_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_059_conf0.677.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_063_conf0.717.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_071_conf0.681.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_076_conf0.711.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_077_conf0.708.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_answer_2_083_conf0.651.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_answer_2_086_conf0.717.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_answer_2_094_conf0.641.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_answer_2_096_conf0.707.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_106_conf0.691.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_107_conf0.672.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_108_conf0.649.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_116_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_122_conf0.700.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_2_129_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_000_conf0.699.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_139_conf0.699.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_002_conf0.695.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_141_conf0.695.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_008_conf0.706.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_009_conf0.629.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_147_conf0.706.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_148_conf0.629.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_012_conf0.688.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_014_conf0.656.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_151_conf0.688.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_153_conf0.656.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_2_157_conf0.762.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_answer_2_164_conf0.779.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_2_169_conf0.766.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_answer_2_172_conf0.778.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_answer_2_173_conf0.783.jpg, 0 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_2_178_conf0.786.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_2_180_conf0.735.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_answer_2_188_conf0.769.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_answer_2_189_conf0.758.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_answer_2_191_conf0.776.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_answer_2_192_conf0.760.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_answer_2_199_conf0.760.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_answer_2_205_conf0.763.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_answer_2_206_conf0.737.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_018_conf0.618.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_020_conf0.627.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_031_conf0.640.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_answer_2_036_conf0.611.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_answer_2_038_conf0.673.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_answer_2_043_conf0.663.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_answer_2_048_conf0.687.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_answer_2_052_conf0.632.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_answer_2_056_conf0.610.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_answer_2_057_conf0.714.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_068_conf0.668.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_079_conf0.746.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_081_conf0.653.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_answer_2_091_conf0.670.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_answer_2_093_conf0.670.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_answer_2_100_conf0.645.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_answer_2_101_conf0.606.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_answer_2_103_conf0.617.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_110_conf0.720.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_112_conf0.669.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_113_conf0.627.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_124_conf0.672.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_2_128_conf0.648.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_2_130_conf0.661.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_2_133_conf0.739.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_003_conf0.669.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_142_conf0.669.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_006_conf0.688.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_145_conf0.688.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_013_conf0.674.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_152_conf0.674.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_2_017_conf0.781.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_2_156_conf0.781.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_2_161_conf0.751.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_answer_2_171_conf0.778.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_answer_2_181_conf0.790.jpg, 0 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_answer_2_185_conf0.795.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_answer_2_186_conf0.800.jpg, 0 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_2_019_conf0.766.jpg, 6 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_2_176_conf0.766.jpg, 6 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_answer_2_194_conf0.732.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_answer_2_196_conf0.771.jpg, 0 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_2_197_conf0.763.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_answer_2_201_conf0.761.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_answer_2_203_conf0.793.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_2_211_conf0.798.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_2_212_conf0.748.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_214_conf0.743.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_215_conf0.729.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_2_023_conf0.778.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_2_216_conf0.778.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_015_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_022_conf0.606.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_025_conf0.436.jpg, 1 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_028_conf0.703.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_029_conf0.673.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_answer_2_039_conf0.723.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_answer_2_050_conf0.638.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_answer_2_053_conf0.677.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_060_conf0.669.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_062_conf0.240.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_075_conf0.739.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_answer_2_082_conf0.734.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_answer_2_084_conf0.722.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_answer_2_087_conf0.693.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_answer_2_090_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_answer_2_092_conf0.695.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_answer_2_095_conf0.586.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_answer_2_097_conf0.701.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_answer_2_098_conf0.686.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_answer_2_099_conf0.682.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_114_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_115_conf0.676.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_117_conf0.664.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_118_conf0.647.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_121_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_125_conf0.668.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_2_134_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_2_135_conf0.736.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_2_137_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_004_conf0.683.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_143_conf0.683.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_answer_2_158_conf0.761.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_answer_2_162_conf0.774.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_2_163_conf0.795.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_2_016_conf0.753.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_2_155_conf0.753.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_2_018_conf0.766.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_2_165_conf0.766.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_answer_2_182_conf0.733.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_answer_2_190_conf0.785.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_answer_2_200_conf0.768.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_answer_2_202_conf0.689.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_answer_2_204_conf0.777.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_answer_2_207_conf0.777.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_answer_2_208_conf0.756.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_2_021_conf0.807.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_2_198_conf0.807.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_answer_2_210_conf0.734.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_213_conf0.759.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_019_conf0.684.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_023_conf0.590.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_027_conf0.715.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_034_conf0.675.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_answer_2_040_conf0.666.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_answer_2_041_conf0.678.jpg, 7 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_answer_2_046_conf0.667.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_answer_2_049_conf0.657.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_064_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_067_conf0.669.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_070_conf0.711.jpg, 2 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_072_conf0.654.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_073_conf0.653.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_078_conf0.685.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_answer_2_088_conf0.700.jpg, 7 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_answer_2_089_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_answer_2_105_conf0.674.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_120_conf0.722.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_123_conf0.689.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_126_conf0.663.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_2_136_conf0.723.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_2_138_conf0.673.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_001_conf0.626.jpg, 7 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_140_conf0.626.jpg, 7 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_005_conf0.671.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_144_conf0.671.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_010_conf0.681.jpg, 7 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_011_conf0.632.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_149_conf0.681.jpg, 7 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_150_conf0.632.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_2_167_conf0.737.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_answer_2_174_conf0.783.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_answer_2_179_conf0.780.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_answer_2_183_conf0.759.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_2_020_conf0.760.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_2_187_conf0.760.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_2_024_conf0.776.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_2_217_conf0.776.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_2_025_conf0.777.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_2_218_conf0.777.jpg, diff --git a/ai-service/test/OCR/test_result/cnocr_page_number.txt b/ai-service/test/OCR/test_result/cnocr_page_number.txt new file mode 100644 index 0000000..bafc6be --- /dev/null +++ b/ai-service/test/OCR/test_result/cnocr_page_number.txt @@ -0,0 +1,168 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_page_number_001_conf0.587.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_page_number_002_conf0.575.jpg, 6 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_page_number_003_conf0.549.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_page_number_004_conf0.536.jpg, 70 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_page_number_005_conf0.613.jpg, 101 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_page_number_006_conf0.547.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_page_number_007_conf0.616.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_page_number_008_conf0.509.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_page_number_009_conf0.625.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_page_number_010_conf0.548.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_page_number_000_conf0.618.jpg, 88 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_page_number_012_conf0.626.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_page_number_013_conf0.501.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_page_number_014_conf0.602.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_page_number_015_conf0.554.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_page_number_016_conf0.687.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_page_number_017_conf0.648.jpg, 179 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_page_number_018_conf0.672.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_page_number_019_conf0.593.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_page_number_020_conf0.627.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_page_number_021_conf0.680.jpg, 6 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_page_number_011_conf0.577.jpg, 7 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_page_number_023_conf0.573.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_page_number_024_conf0.655.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_page_number_025_conf0.633.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_page_number_026_conf0.537.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_page_number_027_conf0.646.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_page_number_028_conf0.563.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_page_number_029_conf0.593.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_page_number_030_conf0.457.jpg, 105 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_page_number_031_conf0.642.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_page_number_032_conf0.512.jpg, 6 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_page_number_022_conf0.549.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_page_number_034_conf0.653.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_page_number_035_conf0.596.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_page_number_036_conf0.629.jpg, 190 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_page_number_037_conf0.513.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_page_number_038_conf0.699.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_page_number_039_conf0.540.jpg, 1030 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_page_number_040_conf0.618.jpg, 6 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_page_number_041_conf0.528.jpg, 4 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_page_number_042_conf0.577.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_page_number_043_conf0.549.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_page_number_033_conf0.583.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_page_number_045_conf0.615.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_page_number_046_conf0.499.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_page_number_047_conf0.617.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_page_number_048_conf0.497.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_page_number_049_conf0.617.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_page_number_050_conf0.501.jpg, 92 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_page_number_051_conf0.592.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_page_number_052_conf0.552.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_page_number_053_conf0.588.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_page_number_054_conf0.532.jpg, 146 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_page_number_044_conf0.589.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_page_number_056_conf0.600.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_page_number_057_conf0.561.jpg, 148 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_page_number_058_conf0.633.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_page_number_059_conf0.493.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_page_number_060_conf0.621.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_page_number_061_conf0.517.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_page_number_062_conf0.601.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_page_number_063_conf0.507.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_page_number_064_conf0.586.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_page_number_065_conf0.505.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_page_number_055_conf0.574.jpg, 9 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_page_number_067_conf0.607.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_page_number_068_conf0.432.jpg, 108 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_page_number_069_conf0.570.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_page_number_070_conf0.565.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_page_number_071_conf0.605.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_page_number_072_conf0.604.jpg, 196 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_page_number_073_conf0.616.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_page_number_074_conf0.607.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_page_number_075_conf0.695.jpg, 5 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_000_conf0.563.jpg, 66 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_076_conf0.563.jpg, 66 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_page_number_066_conf0.610.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_001_conf0.588.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_078_conf0.588.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_002_conf0.550.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_079_conf0.550.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_003_conf0.655.jpg, 190 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_080_conf0.655.jpg, 190 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_004_conf0.586.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_081_conf0.586.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_005_conf0.589.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_082_conf0.589.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_006_conf0.648.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_083_conf0.648.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_page_number_077_conf0.548.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_page_number_084_conf0.585.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_008_conf0.617.jpg, 9 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_086_conf0.617.jpg, 9 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_009_conf0.571.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_087_conf0.571.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_page_number_088_conf0.568.jpg, 90 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_089_conf0.555.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_090_conf0.241.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_page_number_091_conf0.582.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_page_number_092_conf0.576.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_page_number_093_conf0.556.jpg, 2 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_page_number_094_conf0.568.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_page_number_095_conf0.587.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_page_number_096_conf0.600.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_007_conf0.225.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_085_conf0.225.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_page_number_098_conf0.588.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_page_number_099_conf0.624.jpg, 3 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_page_number_100_conf0.573.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_page_number_101_conf0.562.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_page_number_102_conf0.587.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_page_number_103_conf0.564.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_page_number_104_conf0.598.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_page_number_105_conf0.521.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_page_number_106_conf0.551.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_page_number_107_conf0.549.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_010_conf0.540.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_097_conf0.540.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_page_number_109_conf0.568.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_page_number_110_conf0.569.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_page_number_111_conf0.567.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_page_number_112_conf0.599.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_page_number_113_conf0.542.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_page_number_114_conf0.584.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_page_number_115_conf0.558.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_page_number_116_conf0.595.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_page_number_117_conf0.601.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_page_number_118_conf0.587.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_011_conf0.556.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_108_conf0.556.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_page_number_120_conf0.621.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_page_number_121_conf0.602.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_page_number_122_conf0.576.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_page_number_123_conf0.555.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_page_number_124_conf0.456.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_page_number_125_conf0.571.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_page_number_126_conf0.592.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_page_number_127_conf0.565.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_page_number_128_conf0.616.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_page_number_129_conf0.579.jpg, 00 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_012_conf0.563.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_119_conf0.563.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_page_number_131_conf0.585.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_page_number_132_conf0.577.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_page_number_133_conf0.558.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_page_number_134_conf0.584.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_page_number_135_conf0.595.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_page_number_136_conf0.573.jpg, 3 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_page_number_137_conf0.607.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_page_number_138_conf0.576.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_page_number_139_conf0.583.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_page_number_140_conf0.601.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_013_conf0.523.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_130_conf0.523.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_page_number_142_conf0.560.jpg, 4 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 61_page_number_143_conf0.577.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_page_number_144_conf0.629.jpg, 83 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 63_page_number_145_conf0.554.jpg, 7 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_page_number_146_conf0.595.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_014_conf0.592.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_141_conf0.592.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_015_conf0.598.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_147_conf0.598.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_016_conf0.572.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_148_conf0.572.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_017_conf0.555.jpg, 7 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_149_conf0.555.jpg, 7 diff --git a/ai-service/test/OCR/test_result/cnocr_problem_number.txt b/ai-service/test/OCR/test_result/cnocr_problem_number.txt new file mode 100644 index 0000000..e42c267 --- /dev/null +++ b/ai-service/test/OCR/test_result/cnocr_problem_number.txt @@ -0,0 +1,316 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_005_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_006_conf0.760.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_007_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_008_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_009_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_010_conf0.729.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_011_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_012_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_013_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_014_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_015_conf0.773.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_016_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_017_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_018_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_019_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_020_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_021_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_022_conf0.795.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_023_conf0.774.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_024_conf0.771.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_025_conf0.770.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_026_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_027_conf0.767.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_028_conf0.760.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_029_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_030_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_031_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_000_conf0.820.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_001_conf0.795.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_002_conf0.765.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_003_conf0.755.jpg, 2 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_004_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_037_conf0.770.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_038_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_039_conf0.735.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_040_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_041_conf0.722.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_042_conf0.786.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_043_conf0.780.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_044_conf0.748.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_045_conf0.765.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_046_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_047_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_048_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_049_conf0.759.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_050_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_051_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_052_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_053_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_054_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_056_conf0.762.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_057_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_058_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_059_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_060_conf0.737.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_061_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_032_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_033_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_034_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_035_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_036_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_067_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_068_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_069_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_070_conf0.732.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_071_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_072_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_073_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_074_conf0.761.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_075_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_076_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_077_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_078_conf0.815.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_079_conf0.783.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_080_conf0.772.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_081_conf0.758.jpg, 1 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_082_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_083_conf0.771.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_084_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_085_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_086_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_087_conf0.735.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_088_conf0.771.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_089_conf0.762.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_090_conf0.756.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_091_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_092_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_093_conf0.776.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_094_conf0.748.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_095_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_096_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_097_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_062_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_063_conf0.760.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_064_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_065_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_066_conf0.726.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_101_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_102_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_103_conf0.759.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_104_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_105_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_106_conf0.731.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_107_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_108_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_109_conf0.761.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_110_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_111_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_112_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_113_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_114_conf0.737.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_115_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_116_conf0.721.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_117_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_118_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_119_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_120_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_098_conf0.768.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_099_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_100_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_123_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_124_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_125_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_126_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_127_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_128_conf0.814.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_129_conf0.769.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_130_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_131_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_132_conf0.755.jpg, 4 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_133_conf0.770.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_134_conf0.768.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_135_conf0.765.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_136_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_137_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_138_conf0.759.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_139_conf0.756.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_140_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_141_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_142_conf0.732.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_143_conf0.777.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_144_conf0.772.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_145_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_146_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_147_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_148_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_149_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_150_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_151_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_152_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_153_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_121_conf0.769.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_122_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_156_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_157_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_158_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_159_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_160_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_161_conf0.706.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_162_conf0.765.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_163_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_164_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_165_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_166_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_167_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_168_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_169_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_170_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_171_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_172_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_173_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_174_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_175_conf0.803.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_176_conf0.767.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_177_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_178_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_179_conf0.748.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_154_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_155_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_182_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_183_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_184_conf0.748.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_185_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_186_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_187_conf0.771.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_188_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_189_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_190_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_191_conf0.735.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_192_conf0.761.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_193_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_194_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_195_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_196_conf0.756.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_197_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_198_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_199_conf0.756.jpg, 4 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_200_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_201_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_202_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_203_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_204_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_205_conf0.762.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_206_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_000_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_001_conf0.707.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_207_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_208_conf0.707.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_180_conf0.759.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_181_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_002_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_003_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_211_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_212_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_004_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_005_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_213_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_214_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_006_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_007_conf0.731.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_215_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_216_conf0.731.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_008_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_009_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_217_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_218_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_010_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_011_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_219_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_220_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_012_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_013_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_014_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_221_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_222_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_223_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_209_conf0.756.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_210_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_224_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_225_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_016_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_227_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_017_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_228_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_problem_number_229_conf0.722.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_problem_number_230_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_problem_number_231_conf0.735.jpg, 2 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_problem_number_232_conf0.720.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_problem_number_233_conf0.789.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_problem_number_234_conf0.715.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_problem_number_235_conf0.737.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_problem_number_236_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_015_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_226_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_problem_number_238_conf0.709.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_problem_number_239_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_problem_number_240_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_problem_number_241_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_problem_number_242_conf0.721.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_problem_number_243_conf0.719.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_problem_number_244_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_problem_number_245_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_problem_number_246_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_problem_number_247_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_018_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_237_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_problem_number_249_conf0.717.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_problem_number_250_conf0.767.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_problem_number_251_conf0.717.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_problem_number_252_conf0.716.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_problem_number_253_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_problem_number_254_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_problem_number_255_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_problem_number_256_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_problem_number_257_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_problem_number_258_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_019_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_248_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_problem_number_260_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_problem_number_261_conf0.712.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_problem_number_262_conf0.721.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_problem_number_263_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_problem_number_264_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_problem_number_265_conf0.718.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_problem_number_266_conf0.769.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_problem_number_267_conf0.725.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_problem_number_268_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_problem_number_269_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_020_conf0.722.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_259_conf0.722.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_problem_number_271_conf0.716.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_problem_number_272_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_problem_number_273_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_problem_number_274_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_problem_number_275_conf0.729.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_problem_number_276_conf0.708.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_problem_number_277_conf0.762.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_problem_number_278_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_problem_number_279_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_problem_number_280_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_021_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_270_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_problem_number_282_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_283_conf0.722.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_284_conf0.714.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_285_conf0.737.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_286_conf0.721.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_287_conf0.720.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_022_conf0.796.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_281_conf0.796.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_023_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_288_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_024_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_289_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_025_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_290_conf0.733.jpg, diff --git a/ai-service/test/OCR/test_result/easyocr_answer_1_answer.txt b/ai-service/test/OCR/test_result/easyocr_answer_1_answer.txt new file mode 100644 index 0000000..b6a3518 --- /dev/null +++ b/ai-service/test/OCR/test_result/easyocr_answer_1_answer.txt @@ -0,0 +1,260 @@ +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_021_conf0.525.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_038_conf0.662.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_039_conf0.625.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_040_conf0.620.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_043_conf0.393.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_answer_1_048_conf0.547.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_answer_1_050_conf0.547.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_answer_1_062_conf0.682.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_answer_1_063_conf0.680.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_036_conf0.635.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_093_conf0.690.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_095_conf0.592.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_107_conf0.632.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_1_116_conf0.620.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_120_conf0.575.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_121_conf0.554.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_122_conf0.244.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_007_conf0.593.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_139_conf0.593.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_012_conf0.341.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_144_conf0.341.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_1_022_conf0.560.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_1_156_conf0.560.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_answer_1_160_conf0.497.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_answer_1_161_conf0.528.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_1_019_conf0.610.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_1_153_conf0.610.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_answer_1_168_conf0.607.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_answer_1_171_conf0.544.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_answer_1_174_conf0.651.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_1_179_conf0.531.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_1_180_conf0.274.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_answer_1_182_conf0.481.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_answer_1_191_conf0.604.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_answer_1_196_conf0.631.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_answer_1_197_conf0.622.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_answer_1_199_conf0.537.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_1_205_conf0.543.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_1_206_conf0.527.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_1_027_conf0.424.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_1_207_conf0.424.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_1_031_conf0.543.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_1_227_conf0.543.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_answer_1_006_conf0.507.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_answer_1_015_conf0.544.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_answer_1_017_conf0.609.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_019_conf0.297.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_020_conf0.224.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_022_conf0.494.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_024_conf0.598.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_025_conf0.566.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_003_conf0.549.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_041_conf0.511.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_answer_1_053_conf0.520.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_answer_1_055_conf0.610.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_answer_1_060_conf0.575.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_answer_1_061_conf0.556.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_033_conf0.692.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_070_conf0.465.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_071_conf0.447.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_081_conf0.345.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_083_conf0.227.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_065_conf0.549.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_084_conf0.624.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_105_conf0.503.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_109_conf0.534.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_117_conf0.516.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_001_conf0.428.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_131_conf0.428.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_answer_1_100_conf0.560.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_003_conf0.484.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_004_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_005_conf0.248.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_135_conf0.484.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_136_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_137_conf0.248.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_009_conf0.431.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_010_conf0.309.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_141_conf0.431.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_142_conf0.309.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_014_conf0.601.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_015_conf0.388.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_146_conf0.601.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_147_conf0.388.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_answer_1_133_conf0.540.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_answer_1_152_conf0.513.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_answer_1_021_conf0.450.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_answer_1_155_conf0.450.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_1_157_conf0.541.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_1_158_conf0.335.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_answer_1_166_conf0.572.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_1_172_conf0.371.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_1_173_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_answer_1_176_conf0.514.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_answer_1_177_conf0.563.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_1_023_conf0.658.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_1_167_conf0.658.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_1_183_conf0.518.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_1_184_conf0.338.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_1_186_conf0.593.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_1_187_conf0.302.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_1_024_conf0.464.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_1_181_conf0.464.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_answer_1_202_conf0.601.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_answer_1_217_conf0.531.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_1_222_conf0.637.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_answer_1_005_conf0.553.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_answer_1_007_conf0.658.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_answer_1_009_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_011_conf0.558.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_answer_1_016_conf0.719.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_026_conf0.439.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_027_conf0.325.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_029_conf0.641.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_000_conf0.691.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_002_conf0.600.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_004_conf0.488.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_042_conf0.509.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_answer_1_049_conf0.523.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_answer_1_059_conf0.723.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_037_conf0.566.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_069_conf0.653.jpg, 1 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_answer_1_072_conf0.704.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_answer_1_074_conf0.537.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_064_conf0.666.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_066_conf0.504.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_068_conf0.383.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_085_conf0.534.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_086_conf0.440.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_answer_1_088_conf0.636.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_094_conf0.631.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_096_conf0.519.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_097_conf0.446.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_098_conf0.310.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_114_conf0.583.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_1_115_conf0.659.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_118_conf0.490.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_119_conf0.246.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_1_123_conf0.566.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_127_conf0.619.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_129_conf0.265.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_000_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_130_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_answer_1_099_conf0.640.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_1_162_conf0.410.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_answer_1_175_conf0.427.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_answer_1_188_conf0.673.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_answer_1_192_conf0.488.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_answer_1_211_conf0.761.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_answer_1_214_conf0.645.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_answer_1_216_conf0.757.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_answer_1_220_conf0.729.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_225_conf0.542.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_1_032_conf0.683.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_1_228_conf0.683.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_answer_1_010_conf0.467.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_012_conf0.417.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_013_conf0.278.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_023_conf0.414.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_030_conf0.596.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_032_conf0.485.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_001_conf0.674.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_044_conf0.695.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_046_conf0.638.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_answer_1_054_conf0.665.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_answer_1_056_conf0.548.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_answer_1_057_conf0.514.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_answer_1_058_conf0.775.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_034_conf0.660.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_035_conf0.641.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_answer_1_075_conf0.530.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_076_conf0.533.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_077_conf0.528.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_078_conf0.510.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_079_conf0.494.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_067_conf0.454.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_answer_1_087_conf0.649.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_089_conf0.564.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_091_conf0.253.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_101_conf0.640.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_102_conf0.605.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_103_conf0.547.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_104_conf0.506.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_106_conf0.483.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_110_conf0.511.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_112_conf0.626.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_1_124_conf0.437.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_1_125_conf0.590.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_128_conf0.609.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_002_conf0.551.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_134_conf0.551.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_008_conf0.621.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_140_conf0.621.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_013_conf0.606.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_145_conf0.606.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_018_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_150_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_answer_1_159_conf0.589.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_answer_1_163_conf0.652.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_1_164_conf0.478.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_1_165_conf0.226.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_answer_1_189_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_answer_1_193_conf0.673.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_answer_1_201_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_answer_1_203_conf0.671.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_025_conf0.585.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_026_conf0.337.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_194_conf0.585.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_195_conf0.337.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_answer_1_210_conf0.565.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_1_221_conf0.647.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_223_conf0.782.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_028_conf0.369.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_029_conf0.241.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_218_conf0.369.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_219_conf0.241.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_answer_1_008_conf0.569.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_answer_1_014_conf0.584.jpg, 10 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_018_conf0.515.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_028_conf0.670.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_031_conf0.578.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_045_conf0.676.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_047_conf0.477.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_answer_1_051_conf0.516.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_answer_1_052_conf0.635.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_answer_1_073_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_080_conf0.367.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_082_conf0.318.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_090_conf0.487.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_092_conf0.221.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_108_conf0.576.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_111_conf0.456.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_113_conf0.609.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_1_126_conf0.555.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_006_conf0.606.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_138_conf0.606.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_011_conf0.524.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_143_conf0.524.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_016_conf0.571.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_017_conf0.533.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_148_conf0.571.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_149_conf0.533.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_answer_1_132_conf0.639.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_answer_1_151_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_1_169_conf0.573.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_1_170_conf0.307.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_answer_1_178_conf0.458.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_answer_1_185_conf0.677.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_answer_1_190_conf0.596.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_answer_1_198_conf0.661.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_answer_1_200_conf0.673.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_answer_1_204_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_answer_1_208_conf0.709.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_answer_1_209_conf0.743.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_answer_1_212_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_answer_1_213_conf0.664.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_answer_1_215_conf0.656.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_224_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_1_030_conf0.557.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_1_226_conf0.557.jpg, diff --git a/ai-service/test/OCR/test_result/easyocr_answer_2_answer.txt b/ai-service/test/OCR/test_result/easyocr_answer_2_answer.txt new file mode 100644 index 0000000..e0754f6 --- /dev/null +++ b/ai-service/test/OCR/test_result/easyocr_answer_2_answer.txt @@ -0,0 +1,229 @@ +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_014_conf0.732.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_024_conf0.582.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_026_conf0.296.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_answer_2_047_conf0.703.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_answer_2_054_conf0.659.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_answer_2_058_conf0.706.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_061_conf0.667.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_065_conf0.707.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_066_conf0.695.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_069_conf0.713.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_074_conf0.741.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_080_conf0.718.jpg, 00 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_answer_2_085_conf0.710.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_answer_2_102_conf0.654.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_answer_2_104_conf0.677.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_109_conf0.725.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_111_conf0.690.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_119_conf0.750.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_2_127_conf0.742.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_2_131_conf0.716.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_2_132_conf0.711.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_007_conf0.656.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_146_conf0.656.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_answer_2_159_conf0.727.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_answer_2_160_conf0.714.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_answer_2_166_conf0.749.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_answer_2_168_conf0.756.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_answer_2_170_conf0.748.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_2_175_conf0.751.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_answer_2_177_conf0.751.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_answer_2_184_conf0.723.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_answer_2_193_conf0.785.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_answer_2_195_conf0.745.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_2_022_conf0.726.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_2_209_conf0.726.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_016_conf0.701.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_017_conf0.659.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_021_conf0.609.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_030_conf0.672.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_032_conf0.724.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_033_conf0.709.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_answer_2_035_conf0.617.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_answer_2_037_conf0.675.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_answer_2_042_conf0.664.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_answer_2_044_conf0.655.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_answer_2_045_conf0.700.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_answer_2_051_conf0.681.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_answer_2_055_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_059_conf0.677.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_063_conf0.717.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_071_conf0.681.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_076_conf0.711.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_077_conf0.708.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_answer_2_083_conf0.651.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_answer_2_086_conf0.717.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_answer_2_094_conf0.641.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_answer_2_096_conf0.707.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_106_conf0.691.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_107_conf0.672.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_108_conf0.649.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_116_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_122_conf0.700.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_2_129_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_000_conf0.699.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_139_conf0.699.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_002_conf0.695.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_141_conf0.695.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_008_conf0.706.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_009_conf0.629.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_147_conf0.706.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_148_conf0.629.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_012_conf0.688.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_014_conf0.656.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_151_conf0.688.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_153_conf0.656.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_2_157_conf0.762.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_answer_2_164_conf0.779.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_2_169_conf0.766.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_answer_2_172_conf0.778.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_answer_2_173_conf0.783.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_2_178_conf0.786.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_2_180_conf0.735.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_answer_2_188_conf0.769.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_answer_2_189_conf0.758.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_answer_2_191_conf0.776.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_answer_2_192_conf0.760.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_answer_2_199_conf0.760.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_answer_2_205_conf0.763.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_answer_2_206_conf0.737.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_018_conf0.618.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_020_conf0.627.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_031_conf0.640.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_answer_2_036_conf0.611.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_answer_2_038_conf0.673.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_answer_2_043_conf0.663.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_answer_2_048_conf0.687.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_answer_2_052_conf0.632.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_answer_2_056_conf0.610.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_answer_2_057_conf0.714.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_068_conf0.668.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_079_conf0.746.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_081_conf0.653.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_answer_2_091_conf0.670.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_answer_2_093_conf0.670.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_answer_2_100_conf0.645.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_answer_2_101_conf0.606.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_answer_2_103_conf0.617.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_110_conf0.720.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_112_conf0.669.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_113_conf0.627.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_124_conf0.672.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_2_128_conf0.648.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_2_130_conf0.661.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_2_133_conf0.739.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_003_conf0.669.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_142_conf0.669.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_006_conf0.688.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_145_conf0.688.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_013_conf0.674.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_152_conf0.674.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_2_017_conf0.781.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_2_156_conf0.781.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_2_161_conf0.751.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_answer_2_171_conf0.778.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_answer_2_181_conf0.790.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_answer_2_185_conf0.795.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_answer_2_186_conf0.800.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_2_019_conf0.766.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_2_176_conf0.766.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_answer_2_194_conf0.732.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_answer_2_196_conf0.771.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_2_197_conf0.763.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_answer_2_201_conf0.761.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_answer_2_203_conf0.793.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_2_211_conf0.798.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_2_212_conf0.748.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_214_conf0.743.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_215_conf0.729.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_2_023_conf0.778.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_2_216_conf0.778.jpg, 3 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_015_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_022_conf0.606.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_025_conf0.436.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_028_conf0.703.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_029_conf0.673.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_answer_2_039_conf0.723.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_answer_2_050_conf0.638.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_answer_2_053_conf0.677.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_060_conf0.669.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_062_conf0.240.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_075_conf0.739.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_answer_2_082_conf0.734.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_answer_2_084_conf0.722.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_answer_2_087_conf0.693.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_answer_2_090_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_answer_2_092_conf0.695.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_answer_2_095_conf0.586.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_answer_2_097_conf0.701.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_answer_2_098_conf0.686.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_answer_2_099_conf0.682.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_114_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_115_conf0.676.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_117_conf0.664.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_118_conf0.647.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_121_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_125_conf0.668.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_2_134_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_2_135_conf0.736.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_2_137_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_004_conf0.683.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_143_conf0.683.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_answer_2_158_conf0.761.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_answer_2_162_conf0.774.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_2_163_conf0.795.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_2_016_conf0.753.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_2_155_conf0.753.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_2_018_conf0.766.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_2_165_conf0.766.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_answer_2_182_conf0.733.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_answer_2_190_conf0.785.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_answer_2_200_conf0.768.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_answer_2_202_conf0.689.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_answer_2_204_conf0.777.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_answer_2_207_conf0.777.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_answer_2_208_conf0.756.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_2_021_conf0.807.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_2_198_conf0.807.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_answer_2_210_conf0.734.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_213_conf0.759.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_019_conf0.684.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_023_conf0.590.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_027_conf0.715.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_034_conf0.675.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_answer_2_040_conf0.666.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_answer_2_041_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_answer_2_046_conf0.667.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_answer_2_049_conf0.657.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_064_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_067_conf0.669.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_070_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_072_conf0.654.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_073_conf0.653.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_078_conf0.685.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_answer_2_088_conf0.700.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_answer_2_089_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_answer_2_105_conf0.674.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_120_conf0.722.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_123_conf0.689.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_126_conf0.663.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_2_136_conf0.723.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_2_138_conf0.673.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_001_conf0.626.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_140_conf0.626.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_005_conf0.671.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_144_conf0.671.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_010_conf0.681.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_011_conf0.632.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_149_conf0.681.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_150_conf0.632.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_2_167_conf0.737.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_answer_2_174_conf0.783.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_answer_2_179_conf0.780.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_answer_2_183_conf0.759.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_2_020_conf0.760.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_2_187_conf0.760.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_2_024_conf0.776.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_2_217_conf0.776.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_2_025_conf0.777.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_2_218_conf0.777.jpg, diff --git a/ai-service/test/OCR/test_result/easyocr_page_number.txt b/ai-service/test/OCR/test_result/easyocr_page_number.txt new file mode 100644 index 0000000..cea4e88 --- /dev/null +++ b/ai-service/test/OCR/test_result/easyocr_page_number.txt @@ -0,0 +1,168 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_page_number_001_conf0.587.jpg, 97 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_page_number_002_conf0.575.jpg, 98 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_page_number_003_conf0.549.jpg, 99 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_page_number_004_conf0.536.jpg, 100 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_page_number_005_conf0.613.jpg, 101 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_page_number_006_conf0.547.jpg, 102 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_page_number_007_conf0.616.jpg, 103 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_page_number_008_conf0.509.jpg, 104 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_page_number_009_conf0.625.jpg, 105 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_page_number_010_conf0.548.jpg, 106 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_page_number_000_conf0.618.jpg, 88 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_page_number_012_conf0.626.jpg, 107 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_page_number_013_conf0.501.jpg, 108 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_page_number_014_conf0.602.jpg, 109 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_page_number_015_conf0.554.jpg, 110 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_page_number_016_conf0.687.jpg, 111 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_page_number_017_conf0.648.jpg, 112 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_page_number_018_conf0.672.jpg, 113 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_page_number_019_conf0.593.jpg, 114 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_page_number_020_conf0.627.jpg, 115 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_page_number_021_conf0.680.jpg, 116 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_page_number_011_conf0.577.jpg, 89 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_page_number_023_conf0.573.jpg, 117 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_page_number_024_conf0.655.jpg, 118 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_page_number_025_conf0.633.jpg, 119 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_page_number_026_conf0.537.jpg, 120 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_page_number_027_conf0.646.jpg, 121 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_page_number_028_conf0.563.jpg, 122 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_page_number_029_conf0.593.jpg, 123 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_page_number_030_conf0.457.jpg, 124 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_page_number_031_conf0.642.jpg, 125 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_page_number_032_conf0.512.jpg, 126 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_page_number_022_conf0.549.jpg, 90 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_page_number_034_conf0.653.jpg, 127 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_page_number_035_conf0.596.jpg, 128 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_page_number_036_conf0.629.jpg, 129 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_page_number_037_conf0.513.jpg, 130 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_page_number_038_conf0.699.jpg, 131 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_page_number_039_conf0.540.jpg, 132 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_page_number_040_conf0.618.jpg, 133 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_page_number_041_conf0.528.jpg, 134 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_page_number_042_conf0.577.jpg, 135 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_page_number_043_conf0.549.jpg, 136 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_page_number_033_conf0.583.jpg, 91 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_page_number_045_conf0.615.jpg, 137 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_page_number_046_conf0.499.jpg, 138 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_page_number_047_conf0.617.jpg, 139 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_page_number_048_conf0.497.jpg, 140 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_page_number_049_conf0.617.jpg, 141 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_page_number_050_conf0.501.jpg, 142 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_page_number_051_conf0.592.jpg, 143 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_page_number_052_conf0.552.jpg, 144 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_page_number_053_conf0.588.jpg, 145 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_page_number_054_conf0.532.jpg, 146 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_page_number_044_conf0.589.jpg, 92 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_page_number_056_conf0.600.jpg, 147 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_page_number_057_conf0.561.jpg, 148 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_page_number_058_conf0.633.jpg, 149 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_page_number_059_conf0.493.jpg, 150 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_page_number_060_conf0.621.jpg, 151 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_page_number_061_conf0.517.jpg, 152 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_page_number_062_conf0.601.jpg, 153 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_page_number_063_conf0.507.jpg, 154 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_page_number_064_conf0.586.jpg, 155 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_page_number_065_conf0.505.jpg, 156 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_page_number_055_conf0.574.jpg, 93 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_page_number_067_conf0.607.jpg, 157 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_page_number_068_conf0.432.jpg, 158 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_page_number_069_conf0.570.jpg, 159 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_page_number_070_conf0.565.jpg, 160 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_page_number_071_conf0.605.jpg, 161 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_page_number_072_conf0.604.jpg, 162 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_page_number_073_conf0.616.jpg, 163 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_page_number_074_conf0.607.jpg, 164 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_page_number_075_conf0.695.jpg, 165 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_000_conf0.563.jpg, 166 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_076_conf0.563.jpg, 166 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_page_number_066_conf0.610.jpg, 94 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_001_conf0.588.jpg, 167 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_078_conf0.588.jpg, 167 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_002_conf0.550.jpg, 168 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_079_conf0.550.jpg, 168 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_003_conf0.655.jpg, 169 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_080_conf0.655.jpg, 169 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_004_conf0.586.jpg, 170 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_081_conf0.586.jpg, 170 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_005_conf0.589.jpg, 171 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_082_conf0.589.jpg, 171 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_006_conf0.648.jpg, 172 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_083_conf0.648.jpg, 172 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_page_number_077_conf0.548.jpg, 95 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_page_number_084_conf0.585.jpg, 96 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_008_conf0.617.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_086_conf0.617.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_009_conf0.571.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_087_conf0.571.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_page_number_088_conf0.568.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_089_conf0.555.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_090_conf0.241.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_page_number_091_conf0.582.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_page_number_092_conf0.576.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_page_number_093_conf0.556.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_page_number_094_conf0.568.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_page_number_095_conf0.587.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_page_number_096_conf0.600.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_007_conf0.225.jpg, 9 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_085_conf0.225.jpg, 9 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_page_number_098_conf0.588.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_page_number_099_conf0.624.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_page_number_100_conf0.573.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_page_number_101_conf0.562.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_page_number_102_conf0.587.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_page_number_103_conf0.564.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_page_number_104_conf0.598.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_page_number_105_conf0.521.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_page_number_106_conf0.551.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_page_number_107_conf0.549.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_010_conf0.540.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_097_conf0.540.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_page_number_109_conf0.568.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_page_number_110_conf0.569.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_page_number_111_conf0.567.jpg, 46 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_page_number_112_conf0.599.jpg, 47 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_page_number_113_conf0.542.jpg, 48 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_page_number_114_conf0.584.jpg, 49 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_page_number_115_conf0.558.jpg, 51 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_page_number_116_conf0.595.jpg, 52 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_page_number_117_conf0.601.jpg, 53 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_page_number_118_conf0.587.jpg, 54 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_011_conf0.556.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_108_conf0.556.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_page_number_120_conf0.621.jpg, 55 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_page_number_121_conf0.602.jpg, 57 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_page_number_122_conf0.576.jpg, 58 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_page_number_123_conf0.555.jpg, 59 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_page_number_124_conf0.456.jpg, 60 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_page_number_125_conf0.571.jpg, 61 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_page_number_126_conf0.592.jpg, 63 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_page_number_127_conf0.565.jpg, 64 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_page_number_128_conf0.616.jpg, 65 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_page_number_129_conf0.579.jpg, 66 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_012_conf0.563.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_119_conf0.563.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_page_number_131_conf0.585.jpg, 67 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_page_number_132_conf0.577.jpg, 69 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_page_number_133_conf0.558.jpg, 70 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_page_number_134_conf0.584.jpg, 71 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_page_number_135_conf0.595.jpg, 72 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_page_number_136_conf0.573.jpg, 73 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_page_number_137_conf0.607.jpg, 75 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_page_number_138_conf0.576.jpg, 76 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_page_number_139_conf0.583.jpg, 77 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_page_number_140_conf0.601.jpg, 78 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_013_conf0.523.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_130_conf0.523.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_page_number_142_conf0.560.jpg, 79 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 61_page_number_143_conf0.577.jpg, 82 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_page_number_144_conf0.629.jpg, 83 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 63_page_number_145_conf0.554.jpg, 84 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_page_number_146_conf0.595.jpg, 85 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_014_conf0.592.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_141_conf0.592.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_015_conf0.598.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_147_conf0.598.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_016_conf0.572.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_148_conf0.572.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_017_conf0.555.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_149_conf0.555.jpg, 18 diff --git a/ai-service/test/OCR/test_result/easyocr_problem_number.txt b/ai-service/test/OCR/test_result/easyocr_problem_number.txt new file mode 100644 index 0000000..fa1809d --- /dev/null +++ b/ai-service/test/OCR/test_result/easyocr_problem_number.txt @@ -0,0 +1,316 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_005_conf0.763.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_006_conf0.760.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_007_conf0.747.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_008_conf0.745.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_009_conf0.753.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_010_conf0.729.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_011_conf0.741.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_012_conf0.741.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_013_conf0.742.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_014_conf0.740.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_015_conf0.773.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_016_conf0.736.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_017_conf0.747.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_018_conf0.738.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_019_conf0.757.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_020_conf0.745.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_021_conf0.744.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_022_conf0.795.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_023_conf0.774.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_024_conf0.771.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_025_conf0.770.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_026_conf0.751.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_027_conf0.767.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_028_conf0.760.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_029_conf0.755.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_030_conf0.754.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_031_conf0.728.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_000_conf0.820.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_001_conf0.795.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_002_conf0.765.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_003_conf0.755.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_004_conf0.753.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_037_conf0.770.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_038_conf0.752.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_039_conf0.735.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_040_conf0.730.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_041_conf0.722.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_042_conf0.786.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_043_conf0.780.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_044_conf0.748.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_045_conf0.765.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_046_conf0.740.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_047_conf0.758.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_048_conf0.739.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_049_conf0.759.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_050_conf0.751.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_051_conf0.758.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_052_conf0.754.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_053_conf0.764.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_054_conf0.744.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_056_conf0.762.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_057_conf0.742.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_058_conf0.742.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_059_conf0.738.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_060_conf0.737.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_061_conf0.733.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_032_conf0.764.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_033_conf0.764.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_034_conf0.757.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_035_conf0.754.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_036_conf0.746.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_067_conf0.749.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_068_conf0.747.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_069_conf0.758.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_070_conf0.732.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_071_conf0.750.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_072_conf0.738.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_073_conf0.763.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_074_conf0.761.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_075_conf0.752.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_076_conf0.751.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_077_conf0.746.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_078_conf0.815.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_079_conf0.783.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_080_conf0.772.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_081_conf0.758.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_082_conf0.751.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_083_conf0.771.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_084_conf0.751.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_085_conf0.751.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_086_conf0.738.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_087_conf0.735.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_088_conf0.771.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_089_conf0.762.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_090_conf0.756.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_091_conf0.743.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_092_conf0.734.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_093_conf0.776.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_094_conf0.748.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_095_conf0.723.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_096_conf0.747.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_097_conf0.739.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_062_conf0.763.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_063_conf0.760.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_064_conf0.743.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_065_conf0.727.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_066_conf0.726.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_101_conf0.757.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_102_conf0.733.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_103_conf0.759.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_104_conf0.749.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_105_conf0.749.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_106_conf0.731.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_107_conf0.763.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_108_conf0.734.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_109_conf0.761.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_110_conf0.758.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_111_conf0.739.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_112_conf0.733.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_113_conf0.747.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_114_conf0.737.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_115_conf0.743.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_116_conf0.721.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_117_conf0.738.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_118_conf0.727.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_119_conf0.751.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_120_conf0.745.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_098_conf0.768.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_099_conf0.746.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_100_conf0.744.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_123_conf0.753.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_124_conf0.730.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_125_conf0.752.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_126_conf0.752.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_127_conf0.745.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_128_conf0.814.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_129_conf0.769.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_130_conf0.764.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_131_conf0.758.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_132_conf0.755.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_133_conf0.770.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_134_conf0.768.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_135_conf0.765.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_136_conf0.745.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_137_conf0.736.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_138_conf0.759.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_139_conf0.756.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_140_conf0.754.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_141_conf0.744.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_142_conf0.732.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_143_conf0.777.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_144_conf0.772.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_145_conf0.738.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_146_conf0.746.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_147_conf0.740.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_148_conf0.751.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_149_conf0.733.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_150_conf0.743.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_151_conf0.734.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_152_conf0.755.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_153_conf0.747.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_121_conf0.769.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_122_conf0.754.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_156_conf0.757.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_157_conf0.742.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_158_conf0.757.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_159_conf0.749.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_160_conf0.739.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_161_conf0.706.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_162_conf0.765.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_163_conf0.741.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_164_conf0.738.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_165_conf0.723.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_166_conf0.738.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_167_conf0.727.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_168_conf0.736.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_169_conf0.727.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_170_conf0.755.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_171_conf0.734.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_172_conf0.749.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_173_conf0.742.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_174_conf0.741.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_175_conf0.803.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_176_conf0.767.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_177_conf0.764.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_178_conf0.751.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_179_conf0.748.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_154_conf0.741.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_155_conf0.740.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_182_conf0.753.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_183_conf0.750.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_184_conf0.748.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_185_conf0.745.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_186_conf0.743.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_187_conf0.771.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_188_conf0.763.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_189_conf0.753.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_190_conf0.742.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_191_conf0.735.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_192_conf0.761.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_193_conf0.744.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_194_conf0.736.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_195_conf0.758.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_196_conf0.756.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_197_conf0.739.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_198_conf0.736.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_199_conf0.756.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_200_conf0.753.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_201_conf0.741.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_202_conf0.740.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_203_conf0.766.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_204_conf0.746.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_205_conf0.762.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_206_conf0.745.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_000_conf0.754.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_001_conf0.707.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_207_conf0.754.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_208_conf0.707.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_180_conf0.759.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_181_conf0.758.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_002_conf0.742.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_003_conf0.728.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_211_conf0.742.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_212_conf0.728.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_004_conf0.753.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_005_conf0.730.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_213_conf0.753.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_214_conf0.730.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_006_conf0.742.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_007_conf0.731.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_215_conf0.742.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_216_conf0.731.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_008_conf0.766.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_009_conf0.749.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_217_conf0.766.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_218_conf0.749.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_010_conf0.739.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_011_conf0.727.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_219_conf0.739.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_220_conf0.727.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_012_conf0.752.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_013_conf0.745.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_014_conf0.742.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_221_conf0.752.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_222_conf0.745.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_223_conf0.742.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_209_conf0.756.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_210_conf0.751.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_224_conf0.755.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_225_conf0.739.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_016_conf0.766.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_227_conf0.766.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_017_conf0.750.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_228_conf0.750.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_problem_number_229_conf0.722.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_problem_number_230_conf0.742.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_problem_number_231_conf0.735.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_problem_number_232_conf0.720.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_problem_number_233_conf0.789.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_problem_number_234_conf0.715.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_problem_number_235_conf0.737.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_problem_number_236_conf0.744.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_015_conf0.752.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_226_conf0.752.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_problem_number_238_conf0.709.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_problem_number_239_conf0.754.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_problem_number_240_conf0.723.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_problem_number_241_conf0.734.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_problem_number_242_conf0.721.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_problem_number_243_conf0.719.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_problem_number_244_conf0.752.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_problem_number_245_conf0.733.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_problem_number_246_conf0.736.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_problem_number_247_conf0.736.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_018_conf0.730.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_237_conf0.730.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_problem_number_249_conf0.717.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_problem_number_250_conf0.767.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_problem_number_251_conf0.717.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_problem_number_252_conf0.716.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_problem_number_253_conf0.728.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_problem_number_254_conf0.744.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_problem_number_255_conf0.723.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_problem_number_256_conf0.727.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_problem_number_257_conf0.724.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_problem_number_258_conf0.739.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_019_conf0.728.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_248_conf0.728.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_problem_number_260_conf0.723.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_problem_number_261_conf0.712.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_problem_number_262_conf0.721.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_problem_number_263_conf0.728.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_problem_number_264_conf0.730.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_problem_number_265_conf0.718.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_problem_number_266_conf0.769.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_problem_number_267_conf0.725.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_problem_number_268_conf0.742.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_problem_number_269_conf0.728.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_020_conf0.722.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_259_conf0.722.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_problem_number_271_conf0.716.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_problem_number_272_conf0.750.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_problem_number_273_conf0.728.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_problem_number_274_conf0.723.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_problem_number_275_conf0.729.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_problem_number_276_conf0.708.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_problem_number_277_conf0.762.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_problem_number_278_conf0.730.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_problem_number_279_conf0.730.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_problem_number_280_conf0.727.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_021_conf0.724.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_270_conf0.724.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_problem_number_282_conf0.736.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_283_conf0.722.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_284_conf0.714.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_285_conf0.737.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_286_conf0.721.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_287_conf0.720.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_022_conf0.796.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_281_conf0.796.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_023_conf0.724.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_288_conf0.724.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_024_conf0.734.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_289_conf0.734.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_025_conf0.733.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_290_conf0.733.jpg, 04 diff --git a/ai-service/test/OCR/test_result/ocr_accuracy_results.csv b/ai-service/test/OCR/test_result/ocr_accuracy_results.csv new file mode 100644 index 0000000..91eca9e --- /dev/null +++ b/ai-service/test/OCR/test_result/ocr_accuracy_results.csv @@ -0,0 +1,5 @@ +model,page_number_accuracy,problem_number_accuracy,average_accuracy +easyocr,100.0,100.0,100.0 +tesseract,94.64285714285714,90.18987341772153,92.41636528028934 +paddleocr,0.0,0.0,0.0 +cnocr,3.571428571428571,0.0,1.7857142857142856 diff --git a/ai-service/test/OCR/test_result/ocr_accuracy_results_answer.csv b/ai-service/test/OCR/test_result/ocr_accuracy_results_answer.csv new file mode 100644 index 0000000..de8f339 --- /dev/null +++ b/ai-service/test/OCR/test_result/ocr_accuracy_results_answer.csv @@ -0,0 +1,5 @@ +model,answer_1_accuracy,answer_2_accuracy,average_accuracy +easyocr,0.0,7.860262008733625,3.9301310043668125 +tesseract,0.7692307692307693,13.973799126637553,7.371514947934162 +paddleocr,0.0,0.0,0.0 +cnocr,13.076923076923078,2.1834061135371177,7.630164595230098 diff --git a/ai-service/test/OCR/test_result/paddleocr_answer_1_answer.txt b/ai-service/test/OCR/test_result/paddleocr_answer_1_answer.txt new file mode 100644 index 0000000..b0fdeeb --- /dev/null +++ b/ai-service/test/OCR/test_result/paddleocr_answer_1_answer.txt @@ -0,0 +1,260 @@ +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_021_conf0.525.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_038_conf0.662.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_039_conf0.625.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_040_conf0.620.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_043_conf0.393.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_answer_1_048_conf0.547.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_answer_1_050_conf0.547.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_answer_1_062_conf0.682.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_answer_1_063_conf0.680.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_036_conf0.635.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_093_conf0.690.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_095_conf0.592.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_107_conf0.632.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_1_116_conf0.620.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_120_conf0.575.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_121_conf0.554.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_122_conf0.244.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_007_conf0.593.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_139_conf0.593.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_012_conf0.341.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_144_conf0.341.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_1_022_conf0.560.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_1_156_conf0.560.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_answer_1_160_conf0.497.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_answer_1_161_conf0.528.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_1_019_conf0.610.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_1_153_conf0.610.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_answer_1_168_conf0.607.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_answer_1_171_conf0.544.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_answer_1_174_conf0.651.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_1_179_conf0.531.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_1_180_conf0.274.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_answer_1_182_conf0.481.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_answer_1_191_conf0.604.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_answer_1_196_conf0.631.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_answer_1_197_conf0.622.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_answer_1_199_conf0.537.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_1_205_conf0.543.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_1_206_conf0.527.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_1_027_conf0.424.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_1_207_conf0.424.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_1_031_conf0.543.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_1_227_conf0.543.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_answer_1_006_conf0.507.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_answer_1_015_conf0.544.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_answer_1_017_conf0.609.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_019_conf0.297.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_020_conf0.224.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_022_conf0.494.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_024_conf0.598.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_025_conf0.566.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_003_conf0.549.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_041_conf0.511.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_answer_1_053_conf0.520.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_answer_1_055_conf0.610.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_answer_1_060_conf0.575.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_answer_1_061_conf0.556.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_033_conf0.692.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_070_conf0.465.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_071_conf0.447.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_081_conf0.345.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_083_conf0.227.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_065_conf0.549.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_084_conf0.624.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_105_conf0.503.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_109_conf0.534.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_117_conf0.516.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_001_conf0.428.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_131_conf0.428.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_answer_1_100_conf0.560.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_003_conf0.484.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_004_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_005_conf0.248.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_135_conf0.484.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_136_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_137_conf0.248.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_009_conf0.431.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_010_conf0.309.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_141_conf0.431.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_142_conf0.309.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_014_conf0.601.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_015_conf0.388.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_146_conf0.601.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_147_conf0.388.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_answer_1_133_conf0.540.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_answer_1_152_conf0.513.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_answer_1_021_conf0.450.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_answer_1_155_conf0.450.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_1_157_conf0.541.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_1_158_conf0.335.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_answer_1_166_conf0.572.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_1_172_conf0.371.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_1_173_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_answer_1_176_conf0.514.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_answer_1_177_conf0.563.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_1_023_conf0.658.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_1_167_conf0.658.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_1_183_conf0.518.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_1_184_conf0.338.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_1_186_conf0.593.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_1_187_conf0.302.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_1_024_conf0.464.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_1_181_conf0.464.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_answer_1_202_conf0.601.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_answer_1_217_conf0.531.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_1_222_conf0.637.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_answer_1_005_conf0.553.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_answer_1_007_conf0.658.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_answer_1_009_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_011_conf0.558.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_answer_1_016_conf0.719.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_026_conf0.439.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_027_conf0.325.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_029_conf0.641.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_000_conf0.691.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_002_conf0.600.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_004_conf0.488.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_042_conf0.509.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_answer_1_049_conf0.523.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_answer_1_059_conf0.723.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_037_conf0.566.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_069_conf0.653.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_answer_1_072_conf0.704.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_answer_1_074_conf0.537.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_064_conf0.666.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_066_conf0.504.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_068_conf0.383.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_085_conf0.534.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_086_conf0.440.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_answer_1_088_conf0.636.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_094_conf0.631.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_096_conf0.519.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_097_conf0.446.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_098_conf0.310.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_114_conf0.583.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_1_115_conf0.659.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_118_conf0.490.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_119_conf0.246.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_1_123_conf0.566.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_127_conf0.619.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_129_conf0.265.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_000_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_130_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_answer_1_099_conf0.640.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_1_162_conf0.410.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_answer_1_175_conf0.427.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_answer_1_188_conf0.673.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_answer_1_192_conf0.488.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_answer_1_211_conf0.761.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_answer_1_214_conf0.645.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_answer_1_216_conf0.757.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_answer_1_220_conf0.729.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_225_conf0.542.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_1_032_conf0.683.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_1_228_conf0.683.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_answer_1_010_conf0.467.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_012_conf0.417.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_013_conf0.278.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_023_conf0.414.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_030_conf0.596.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_032_conf0.485.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_001_conf0.674.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_044_conf0.695.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_046_conf0.638.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_answer_1_054_conf0.665.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_answer_1_056_conf0.548.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_answer_1_057_conf0.514.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_answer_1_058_conf0.775.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_034_conf0.660.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_035_conf0.641.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_answer_1_075_conf0.530.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_076_conf0.533.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_077_conf0.528.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_078_conf0.510.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_079_conf0.494.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_067_conf0.454.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_answer_1_087_conf0.649.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_089_conf0.564.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_091_conf0.253.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_101_conf0.640.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_102_conf0.605.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_103_conf0.547.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_104_conf0.506.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_106_conf0.483.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_110_conf0.511.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_112_conf0.626.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_1_124_conf0.437.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_1_125_conf0.590.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_128_conf0.609.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_002_conf0.551.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_134_conf0.551.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_008_conf0.621.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_140_conf0.621.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_013_conf0.606.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_145_conf0.606.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_018_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_150_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_answer_1_159_conf0.589.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_answer_1_163_conf0.652.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_1_164_conf0.478.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_1_165_conf0.226.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_answer_1_189_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_answer_1_193_conf0.673.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_answer_1_201_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_answer_1_203_conf0.671.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_025_conf0.585.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_026_conf0.337.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_194_conf0.585.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_195_conf0.337.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_answer_1_210_conf0.565.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_1_221_conf0.647.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_223_conf0.782.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_028_conf0.369.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_029_conf0.241.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_218_conf0.369.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_219_conf0.241.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_answer_1_008_conf0.569.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_answer_1_014_conf0.584.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_018_conf0.515.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_028_conf0.670.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_031_conf0.578.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_045_conf0.676.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_047_conf0.477.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_answer_1_051_conf0.516.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_answer_1_052_conf0.635.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_answer_1_073_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_080_conf0.367.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_082_conf0.318.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_090_conf0.487.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_092_conf0.221.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_108_conf0.576.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_111_conf0.456.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_113_conf0.609.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_1_126_conf0.555.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_006_conf0.606.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_138_conf0.606.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_011_conf0.524.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_143_conf0.524.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_016_conf0.571.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_017_conf0.533.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_148_conf0.571.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_149_conf0.533.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_answer_1_132_conf0.639.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_answer_1_151_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_1_169_conf0.573.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_1_170_conf0.307.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_answer_1_178_conf0.458.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_answer_1_185_conf0.677.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_answer_1_190_conf0.596.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_answer_1_198_conf0.661.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_answer_1_200_conf0.673.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_answer_1_204_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_answer_1_208_conf0.709.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_answer_1_209_conf0.743.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_answer_1_212_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_answer_1_213_conf0.664.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_answer_1_215_conf0.656.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_224_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_1_030_conf0.557.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_1_226_conf0.557.jpg, diff --git a/ai-service/test/OCR/test_result/paddleocr_answer_2_answer.txt b/ai-service/test/OCR/test_result/paddleocr_answer_2_answer.txt new file mode 100644 index 0000000..f6cec03 --- /dev/null +++ b/ai-service/test/OCR/test_result/paddleocr_answer_2_answer.txt @@ -0,0 +1,229 @@ +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_014_conf0.732.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_024_conf0.582.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_026_conf0.296.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_answer_2_047_conf0.703.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_answer_2_054_conf0.659.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_answer_2_058_conf0.706.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_061_conf0.667.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_065_conf0.707.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_066_conf0.695.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_069_conf0.713.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_074_conf0.741.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_080_conf0.718.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_answer_2_085_conf0.710.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_answer_2_102_conf0.654.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_answer_2_104_conf0.677.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_109_conf0.725.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_111_conf0.690.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_119_conf0.750.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_2_127_conf0.742.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_2_131_conf0.716.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_2_132_conf0.711.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_007_conf0.656.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_146_conf0.656.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_answer_2_159_conf0.727.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_answer_2_160_conf0.714.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_answer_2_166_conf0.749.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_answer_2_168_conf0.756.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_answer_2_170_conf0.748.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_2_175_conf0.751.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_answer_2_177_conf0.751.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_answer_2_184_conf0.723.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_answer_2_193_conf0.785.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_answer_2_195_conf0.745.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_2_022_conf0.726.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_2_209_conf0.726.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_016_conf0.701.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_017_conf0.659.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_021_conf0.609.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_030_conf0.672.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_032_conf0.724.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_033_conf0.709.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_answer_2_035_conf0.617.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_answer_2_037_conf0.675.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_answer_2_042_conf0.664.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_answer_2_044_conf0.655.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_answer_2_045_conf0.700.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_answer_2_051_conf0.681.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_answer_2_055_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_059_conf0.677.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_063_conf0.717.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_071_conf0.681.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_076_conf0.711.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_077_conf0.708.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_answer_2_083_conf0.651.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_answer_2_086_conf0.717.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_answer_2_094_conf0.641.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_answer_2_096_conf0.707.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_106_conf0.691.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_107_conf0.672.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_108_conf0.649.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_116_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_122_conf0.700.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_2_129_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_000_conf0.699.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_139_conf0.699.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_002_conf0.695.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_141_conf0.695.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_008_conf0.706.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_009_conf0.629.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_147_conf0.706.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_148_conf0.629.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_012_conf0.688.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_014_conf0.656.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_151_conf0.688.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_153_conf0.656.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_2_157_conf0.762.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_answer_2_164_conf0.779.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_2_169_conf0.766.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_answer_2_172_conf0.778.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_answer_2_173_conf0.783.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_2_178_conf0.786.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_2_180_conf0.735.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_answer_2_188_conf0.769.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_answer_2_189_conf0.758.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_answer_2_191_conf0.776.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_answer_2_192_conf0.760.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_answer_2_199_conf0.760.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_answer_2_205_conf0.763.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_answer_2_206_conf0.737.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_018_conf0.618.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_020_conf0.627.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_031_conf0.640.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_answer_2_036_conf0.611.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_answer_2_038_conf0.673.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_answer_2_043_conf0.663.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_answer_2_048_conf0.687.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_answer_2_052_conf0.632.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_answer_2_056_conf0.610.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_answer_2_057_conf0.714.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_068_conf0.668.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_079_conf0.746.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_081_conf0.653.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_answer_2_091_conf0.670.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_answer_2_093_conf0.670.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_answer_2_100_conf0.645.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_answer_2_101_conf0.606.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_answer_2_103_conf0.617.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_110_conf0.720.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_112_conf0.669.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_113_conf0.627.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_124_conf0.672.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_2_128_conf0.648.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_2_130_conf0.661.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_2_133_conf0.739.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_003_conf0.669.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_142_conf0.669.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_006_conf0.688.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_145_conf0.688.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_013_conf0.674.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_152_conf0.674.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_2_017_conf0.781.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_2_156_conf0.781.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_2_161_conf0.751.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_answer_2_171_conf0.778.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_answer_2_181_conf0.790.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_answer_2_185_conf0.795.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_answer_2_186_conf0.800.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_2_019_conf0.766.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_2_176_conf0.766.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_answer_2_194_conf0.732.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_answer_2_196_conf0.771.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_2_197_conf0.763.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_answer_2_201_conf0.761.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_answer_2_203_conf0.793.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_2_211_conf0.798.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_2_212_conf0.748.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_214_conf0.743.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_215_conf0.729.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_2_023_conf0.778.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_2_216_conf0.778.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_015_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_022_conf0.606.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_025_conf0.436.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_028_conf0.703.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_029_conf0.673.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_answer_2_039_conf0.723.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_answer_2_050_conf0.638.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_answer_2_053_conf0.677.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_060_conf0.669.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_062_conf0.240.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_075_conf0.739.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_answer_2_082_conf0.734.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_answer_2_084_conf0.722.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_answer_2_087_conf0.693.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_answer_2_090_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_answer_2_092_conf0.695.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_answer_2_095_conf0.586.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_answer_2_097_conf0.701.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_answer_2_098_conf0.686.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_answer_2_099_conf0.682.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_114_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_115_conf0.676.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_117_conf0.664.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_118_conf0.647.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_121_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_125_conf0.668.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_2_134_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_2_135_conf0.736.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_2_137_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_004_conf0.683.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_143_conf0.683.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_answer_2_158_conf0.761.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_answer_2_162_conf0.774.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_2_163_conf0.795.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_2_016_conf0.753.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_2_155_conf0.753.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_2_018_conf0.766.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_2_165_conf0.766.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_answer_2_182_conf0.733.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_answer_2_190_conf0.785.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_answer_2_200_conf0.768.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_answer_2_202_conf0.689.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_answer_2_204_conf0.777.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_answer_2_207_conf0.777.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_answer_2_208_conf0.756.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_2_021_conf0.807.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_2_198_conf0.807.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_answer_2_210_conf0.734.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_213_conf0.759.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_019_conf0.684.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_023_conf0.590.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_027_conf0.715.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_034_conf0.675.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_answer_2_040_conf0.666.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_answer_2_041_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_answer_2_046_conf0.667.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_answer_2_049_conf0.657.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_064_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_067_conf0.669.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_070_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_072_conf0.654.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_073_conf0.653.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_078_conf0.685.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_answer_2_088_conf0.700.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_answer_2_089_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_answer_2_105_conf0.674.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_120_conf0.722.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_123_conf0.689.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_126_conf0.663.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_2_136_conf0.723.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_2_138_conf0.673.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_001_conf0.626.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_140_conf0.626.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_005_conf0.671.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_144_conf0.671.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_010_conf0.681.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_011_conf0.632.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_149_conf0.681.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_150_conf0.632.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_2_167_conf0.737.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_answer_2_174_conf0.783.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_answer_2_179_conf0.780.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_answer_2_183_conf0.759.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_2_020_conf0.760.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_2_187_conf0.760.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_2_024_conf0.776.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_2_217_conf0.776.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_2_025_conf0.777.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_2_218_conf0.777.jpg, diff --git a/ai-service/test/OCR/test_result/paddleocr_page_number.txt b/ai-service/test/OCR/test_result/paddleocr_page_number.txt new file mode 100644 index 0000000..f79589f --- /dev/null +++ b/ai-service/test/OCR/test_result/paddleocr_page_number.txt @@ -0,0 +1,168 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_page_number_001_conf0.587.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_page_number_002_conf0.575.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_page_number_003_conf0.549.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_page_number_004_conf0.536.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_page_number_005_conf0.613.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_page_number_006_conf0.547.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_page_number_007_conf0.616.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_page_number_008_conf0.509.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_page_number_009_conf0.625.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_page_number_010_conf0.548.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_page_number_000_conf0.618.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_page_number_012_conf0.626.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_page_number_013_conf0.501.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_page_number_014_conf0.602.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_page_number_015_conf0.554.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_page_number_016_conf0.687.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_page_number_017_conf0.648.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_page_number_018_conf0.672.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_page_number_019_conf0.593.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_page_number_020_conf0.627.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_page_number_021_conf0.680.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_page_number_011_conf0.577.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_page_number_023_conf0.573.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_page_number_024_conf0.655.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_page_number_025_conf0.633.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_page_number_026_conf0.537.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_page_number_027_conf0.646.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_page_number_028_conf0.563.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_page_number_029_conf0.593.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_page_number_030_conf0.457.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_page_number_031_conf0.642.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_page_number_032_conf0.512.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_page_number_022_conf0.549.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_page_number_034_conf0.653.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_page_number_035_conf0.596.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_page_number_036_conf0.629.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_page_number_037_conf0.513.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_page_number_038_conf0.699.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_page_number_039_conf0.540.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_page_number_040_conf0.618.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_page_number_041_conf0.528.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_page_number_042_conf0.577.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_page_number_043_conf0.549.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_page_number_033_conf0.583.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_page_number_045_conf0.615.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_page_number_046_conf0.499.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_page_number_047_conf0.617.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_page_number_048_conf0.497.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_page_number_049_conf0.617.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_page_number_050_conf0.501.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_page_number_051_conf0.592.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_page_number_052_conf0.552.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_page_number_053_conf0.588.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_page_number_054_conf0.532.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_page_number_044_conf0.589.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_page_number_056_conf0.600.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_page_number_057_conf0.561.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_page_number_058_conf0.633.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_page_number_059_conf0.493.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_page_number_060_conf0.621.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_page_number_061_conf0.517.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_page_number_062_conf0.601.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_page_number_063_conf0.507.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_page_number_064_conf0.586.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_page_number_065_conf0.505.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_page_number_055_conf0.574.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_page_number_067_conf0.607.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_page_number_068_conf0.432.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_page_number_069_conf0.570.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_page_number_070_conf0.565.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_page_number_071_conf0.605.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_page_number_072_conf0.604.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_page_number_073_conf0.616.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_page_number_074_conf0.607.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_page_number_075_conf0.695.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_000_conf0.563.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_076_conf0.563.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_page_number_066_conf0.610.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_001_conf0.588.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_078_conf0.588.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_002_conf0.550.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_079_conf0.550.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_003_conf0.655.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_080_conf0.655.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_004_conf0.586.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_081_conf0.586.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_005_conf0.589.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_082_conf0.589.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_006_conf0.648.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_083_conf0.648.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_page_number_077_conf0.548.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_page_number_084_conf0.585.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_008_conf0.617.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_086_conf0.617.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_009_conf0.571.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_087_conf0.571.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_page_number_088_conf0.568.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_089_conf0.555.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_090_conf0.241.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_page_number_091_conf0.582.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_page_number_092_conf0.576.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_page_number_093_conf0.556.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_page_number_094_conf0.568.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_page_number_095_conf0.587.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_page_number_096_conf0.600.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_007_conf0.225.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_085_conf0.225.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_page_number_098_conf0.588.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_page_number_099_conf0.624.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_page_number_100_conf0.573.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_page_number_101_conf0.562.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_page_number_102_conf0.587.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_page_number_103_conf0.564.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_page_number_104_conf0.598.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_page_number_105_conf0.521.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_page_number_106_conf0.551.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_page_number_107_conf0.549.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_010_conf0.540.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_097_conf0.540.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_page_number_109_conf0.568.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_page_number_110_conf0.569.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_page_number_111_conf0.567.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_page_number_112_conf0.599.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_page_number_113_conf0.542.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_page_number_114_conf0.584.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_page_number_115_conf0.558.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_page_number_116_conf0.595.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_page_number_117_conf0.601.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_page_number_118_conf0.587.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_011_conf0.556.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_108_conf0.556.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_page_number_120_conf0.621.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_page_number_121_conf0.602.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_page_number_122_conf0.576.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_page_number_123_conf0.555.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_page_number_124_conf0.456.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_page_number_125_conf0.571.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_page_number_126_conf0.592.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_page_number_127_conf0.565.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_page_number_128_conf0.616.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_page_number_129_conf0.579.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_012_conf0.563.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_119_conf0.563.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_page_number_131_conf0.585.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_page_number_132_conf0.577.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_page_number_133_conf0.558.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_page_number_134_conf0.584.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_page_number_135_conf0.595.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_page_number_136_conf0.573.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_page_number_137_conf0.607.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_page_number_138_conf0.576.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_page_number_139_conf0.583.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_page_number_140_conf0.601.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_013_conf0.523.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_130_conf0.523.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_page_number_142_conf0.560.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 61_page_number_143_conf0.577.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_page_number_144_conf0.629.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 63_page_number_145_conf0.554.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_page_number_146_conf0.595.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_014_conf0.592.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_141_conf0.592.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_015_conf0.598.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_147_conf0.598.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_016_conf0.572.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_148_conf0.572.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_017_conf0.555.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_149_conf0.555.jpg, diff --git a/ai-service/test/OCR/test_result/paddleocr_problem_number.txt b/ai-service/test/OCR/test_result/paddleocr_problem_number.txt new file mode 100644 index 0000000..3a57ffe --- /dev/null +++ b/ai-service/test/OCR/test_result/paddleocr_problem_number.txt @@ -0,0 +1,316 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_005_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_006_conf0.760.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_007_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_008_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_009_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_010_conf0.729.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_011_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_012_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_013_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_014_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_015_conf0.773.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_016_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_017_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_018_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_019_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_020_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_021_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_022_conf0.795.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_023_conf0.774.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_024_conf0.771.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_025_conf0.770.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_026_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_027_conf0.767.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_028_conf0.760.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_029_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_030_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_031_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_000_conf0.820.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_001_conf0.795.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_002_conf0.765.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_003_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_004_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_037_conf0.770.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_038_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_039_conf0.735.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_040_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_041_conf0.722.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_042_conf0.786.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_043_conf0.780.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_044_conf0.748.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_045_conf0.765.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_046_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_047_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_048_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_049_conf0.759.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_050_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_051_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_052_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_053_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_054_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_056_conf0.762.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_057_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_058_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_059_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_060_conf0.737.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_061_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_032_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_033_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_034_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_035_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_036_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_067_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_068_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_069_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_070_conf0.732.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_071_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_072_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_073_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_074_conf0.761.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_075_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_076_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_077_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_078_conf0.815.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_079_conf0.783.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_080_conf0.772.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_081_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_082_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_083_conf0.771.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_084_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_085_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_086_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_087_conf0.735.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_088_conf0.771.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_089_conf0.762.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_090_conf0.756.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_091_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_092_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_093_conf0.776.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_094_conf0.748.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_095_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_096_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_097_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_062_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_063_conf0.760.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_064_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_065_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_066_conf0.726.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_101_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_102_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_103_conf0.759.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_104_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_105_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_106_conf0.731.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_107_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_108_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_109_conf0.761.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_110_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_111_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_112_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_113_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_114_conf0.737.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_115_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_116_conf0.721.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_117_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_118_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_119_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_120_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_098_conf0.768.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_099_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_100_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_123_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_124_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_125_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_126_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_127_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_128_conf0.814.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_129_conf0.769.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_130_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_131_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_132_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_133_conf0.770.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_134_conf0.768.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_135_conf0.765.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_136_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_137_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_138_conf0.759.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_139_conf0.756.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_140_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_141_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_142_conf0.732.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_143_conf0.777.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_144_conf0.772.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_145_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_146_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_147_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_148_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_149_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_150_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_151_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_152_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_153_conf0.747.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_121_conf0.769.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_122_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_156_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_157_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_158_conf0.757.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_159_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_160_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_161_conf0.706.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_162_conf0.765.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_163_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_164_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_165_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_166_conf0.738.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_167_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_168_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_169_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_170_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_171_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_172_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_173_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_174_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_175_conf0.803.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_176_conf0.767.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_177_conf0.764.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_178_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_179_conf0.748.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_154_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_155_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_182_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_183_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_184_conf0.748.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_185_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_186_conf0.743.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_187_conf0.771.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_188_conf0.763.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_189_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_190_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_191_conf0.735.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_192_conf0.761.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_193_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_194_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_195_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_196_conf0.756.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_197_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_198_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_199_conf0.756.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_200_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_201_conf0.741.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_202_conf0.740.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_203_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_204_conf0.746.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_205_conf0.762.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_206_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_000_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_001_conf0.707.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_207_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_208_conf0.707.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_180_conf0.759.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_181_conf0.758.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_002_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_003_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_211_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_212_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_004_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_005_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_213_conf0.753.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_214_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_006_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_007_conf0.731.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_215_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_216_conf0.731.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_008_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_009_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_217_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_218_conf0.749.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_010_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_011_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_219_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_220_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_012_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_013_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_014_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_221_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_222_conf0.745.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_223_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_209_conf0.756.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_210_conf0.751.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_224_conf0.755.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_225_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_016_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_227_conf0.766.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_017_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_228_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_problem_number_229_conf0.722.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_problem_number_230_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_problem_number_231_conf0.735.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_problem_number_232_conf0.720.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_problem_number_233_conf0.789.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_problem_number_234_conf0.715.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_problem_number_235_conf0.737.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_problem_number_236_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_015_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_226_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_problem_number_238_conf0.709.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_problem_number_239_conf0.754.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_problem_number_240_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_problem_number_241_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_problem_number_242_conf0.721.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_problem_number_243_conf0.719.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_problem_number_244_conf0.752.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_problem_number_245_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_problem_number_246_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_problem_number_247_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_018_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_237_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_problem_number_249_conf0.717.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_problem_number_250_conf0.767.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_problem_number_251_conf0.717.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_problem_number_252_conf0.716.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_problem_number_253_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_problem_number_254_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_problem_number_255_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_problem_number_256_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_problem_number_257_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_problem_number_258_conf0.739.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_019_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_248_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_problem_number_260_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_problem_number_261_conf0.712.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_problem_number_262_conf0.721.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_problem_number_263_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_problem_number_264_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_problem_number_265_conf0.718.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_problem_number_266_conf0.769.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_problem_number_267_conf0.725.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_problem_number_268_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_problem_number_269_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_020_conf0.722.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_259_conf0.722.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_problem_number_271_conf0.716.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_problem_number_272_conf0.750.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_problem_number_273_conf0.728.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_problem_number_274_conf0.723.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_problem_number_275_conf0.729.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_problem_number_276_conf0.708.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_problem_number_277_conf0.762.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_problem_number_278_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_problem_number_279_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_problem_number_280_conf0.727.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_021_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_270_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_problem_number_282_conf0.736.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_283_conf0.722.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_284_conf0.714.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_285_conf0.737.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_286_conf0.721.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_287_conf0.720.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_022_conf0.796.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_281_conf0.796.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_023_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_288_conf0.724.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_024_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_289_conf0.734.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_025_conf0.733.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_290_conf0.733.jpg, diff --git a/ai-service/test/OCR/test_result/tesseract_answer_1_answer.txt b/ai-service/test/OCR/test_result/tesseract_answer_1_answer.txt new file mode 100644 index 0000000..370be9c --- /dev/null +++ b/ai-service/test/OCR/test_result/tesseract_answer_1_answer.txt @@ -0,0 +1,260 @@ +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_021_conf0.525.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_038_conf0.662.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_039_conf0.625.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_040_conf0.620.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_043_conf0.393.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_answer_1_048_conf0.547.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_answer_1_050_conf0.547.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_answer_1_062_conf0.682.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_answer_1_063_conf0.680.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_036_conf0.635.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_093_conf0.690.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_095_conf0.592.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_107_conf0.632.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_1_116_conf0.620.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_120_conf0.575.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_121_conf0.554.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_1_122_conf0.244.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_007_conf0.593.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_139_conf0.593.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_012_conf0.341.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_144_conf0.341.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_1_022_conf0.560.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_1_156_conf0.560.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_answer_1_160_conf0.497.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_answer_1_161_conf0.528.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_1_019_conf0.610.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_1_153_conf0.610.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_answer_1_168_conf0.607.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_answer_1_171_conf0.544.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_answer_1_174_conf0.651.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_1_179_conf0.531.jpg, 4 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_1_180_conf0.274.jpg, 6 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_answer_1_182_conf0.481.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_answer_1_191_conf0.604.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_answer_1_196_conf0.631.jpg, 7 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_answer_1_197_conf0.622.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_answer_1_199_conf0.537.jpg, 6 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_1_205_conf0.543.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_1_206_conf0.527.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_1_027_conf0.424.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_1_207_conf0.424.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_1_031_conf0.543.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_1_227_conf0.543.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_answer_1_006_conf0.507.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_answer_1_015_conf0.544.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_answer_1_017_conf0.609.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_019_conf0.297.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_020_conf0.224.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_022_conf0.494.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_024_conf0.598.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_025_conf0.566.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_003_conf0.549.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_041_conf0.511.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_answer_1_053_conf0.520.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_answer_1_055_conf0.610.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_answer_1_060_conf0.575.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_answer_1_061_conf0.556.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_033_conf0.692.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_070_conf0.465.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_071_conf0.447.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_081_conf0.345.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_083_conf0.227.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_065_conf0.549.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_084_conf0.624.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_105_conf0.503.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_109_conf0.534.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_117_conf0.516.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_001_conf0.428.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_131_conf0.428.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_answer_1_100_conf0.560.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_003_conf0.484.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_004_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_005_conf0.248.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_135_conf0.484.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_136_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_137_conf0.248.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_009_conf0.431.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_010_conf0.309.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_141_conf0.431.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_142_conf0.309.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_014_conf0.601.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_015_conf0.388.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_146_conf0.601.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_147_conf0.388.jpg, 6 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_answer_1_133_conf0.540.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_answer_1_152_conf0.513.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_answer_1_021_conf0.450.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_answer_1_155_conf0.450.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_1_157_conf0.541.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_1_158_conf0.335.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_answer_1_166_conf0.572.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_1_172_conf0.371.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_1_173_conf0.280.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_answer_1_176_conf0.514.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_answer_1_177_conf0.563.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_1_023_conf0.658.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_1_167_conf0.658.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_1_183_conf0.518.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_1_184_conf0.338.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_1_186_conf0.593.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_1_187_conf0.302.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_1_024_conf0.464.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_1_181_conf0.464.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_answer_1_202_conf0.601.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_answer_1_217_conf0.531.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_1_222_conf0.637.jpg, 6 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_answer_1_005_conf0.553.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_answer_1_007_conf0.658.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_answer_1_009_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_011_conf0.558.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_answer_1_016_conf0.719.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_026_conf0.439.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_answer_1_027_conf0.325.jpg, 7 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_029_conf0.641.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_000_conf0.691.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_002_conf0.600.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_004_conf0.488.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_answer_1_042_conf0.509.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_answer_1_049_conf0.523.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_answer_1_059_conf0.723.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_037_conf0.566.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_answer_1_069_conf0.653.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_answer_1_072_conf0.704.jpg, 8 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_answer_1_074_conf0.537.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_064_conf0.666.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_066_conf0.504.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_068_conf0.383.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_085_conf0.534.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_answer_1_086_conf0.440.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_answer_1_088_conf0.636.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_094_conf0.631.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_096_conf0.519.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_097_conf0.446.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_1_098_conf0.310.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_114_conf0.583.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_1_115_conf0.659.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_118_conf0.490.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_1_119_conf0.246.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_1_123_conf0.566.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_127_conf0.619.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_129_conf0.265.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_000_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_1_130_conf0.524.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_answer_1_099_conf0.640.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_1_162_conf0.410.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_answer_1_175_conf0.427.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_answer_1_188_conf0.673.jpg, 6 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_answer_1_192_conf0.488.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_answer_1_211_conf0.761.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_answer_1_214_conf0.645.jpg, 6 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_answer_1_216_conf0.757.jpg, 6 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_answer_1_220_conf0.729.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_225_conf0.542.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_1_032_conf0.683.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_1_228_conf0.683.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_answer_1_010_conf0.467.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_012_conf0.417.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_answer_1_013_conf0.278.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_answer_1_023_conf0.414.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_030_conf0.596.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_032_conf0.485.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_answer_1_001_conf0.674.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_044_conf0.695.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_046_conf0.638.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_answer_1_054_conf0.665.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_answer_1_056_conf0.548.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_answer_1_057_conf0.514.jpg, 6 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_answer_1_058_conf0.775.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_034_conf0.660.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_answer_1_035_conf0.641.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_answer_1_075_conf0.530.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_076_conf0.533.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_077_conf0.528.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_answer_1_078_conf0.510.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_079_conf0.494.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_answer_1_067_conf0.454.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_answer_1_087_conf0.649.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_089_conf0.564.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_091_conf0.253.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_101_conf0.640.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_102_conf0.605.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_103_conf0.547.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_104_conf0.506.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_1_106_conf0.483.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_110_conf0.511.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_112_conf0.626.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_1_124_conf0.437.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_1_125_conf0.590.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_1_128_conf0.609.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_002_conf0.551.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_1_134_conf0.551.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_008_conf0.621.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_1_140_conf0.621.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_013_conf0.606.jpg, 6 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_1_145_conf0.606.jpg, 6 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_018_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_150_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_answer_1_159_conf0.589.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_answer_1_163_conf0.652.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_1_164_conf0.478.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_1_165_conf0.226.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_answer_1_189_conf0.519.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_answer_1_193_conf0.673.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_answer_1_201_conf0.680.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_answer_1_203_conf0.671.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_025_conf0.585.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_026_conf0.337.jpg, 6 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_194_conf0.585.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_1_195_conf0.337.jpg, 6 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_answer_1_210_conf0.565.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_1_221_conf0.647.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_223_conf0.782.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_028_conf0.369.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_029_conf0.241.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_218_conf0.369.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_1_219_conf0.241.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_answer_1_008_conf0.569.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_answer_1_014_conf0.584.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_answer_1_018_conf0.515.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_028_conf0.670.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_answer_1_031_conf0.578.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_045_conf0.676.jpg, 5 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_answer_1_047_conf0.477.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_answer_1_051_conf0.516.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_answer_1_052_conf0.635.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_answer_1_073_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_080_conf0.367.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_answer_1_082_conf0.318.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_090_conf0.487.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_answer_1_092_conf0.221.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_108_conf0.576.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_1_111_conf0.456.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_1_113_conf0.609.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_1_126_conf0.555.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_006_conf0.606.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_1_138_conf0.606.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_011_conf0.524.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_1_143_conf0.524.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_016_conf0.571.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_017_conf0.533.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_148_conf0.571.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_1_149_conf0.533.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_answer_1_132_conf0.639.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_answer_1_151_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_1_169_conf0.573.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_1_170_conf0.307.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_answer_1_178_conf0.458.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_answer_1_185_conf0.677.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_answer_1_190_conf0.596.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_answer_1_198_conf0.661.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_answer_1_200_conf0.673.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_answer_1_204_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_answer_1_208_conf0.709.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_answer_1_209_conf0.743.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_answer_1_212_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_answer_1_213_conf0.664.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_answer_1_215_conf0.656.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_1_224_conf0.678.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_1_030_conf0.557.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_1_226_conf0.557.jpg, diff --git a/ai-service/test/OCR/test_result/tesseract_answer_2_answer.txt b/ai-service/test/OCR/test_result/tesseract_answer_2_answer.txt new file mode 100644 index 0000000..1613ffb --- /dev/null +++ b/ai-service/test/OCR/test_result/tesseract_answer_2_answer.txt @@ -0,0 +1,229 @@ +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_014_conf0.732.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_024_conf0.582.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_026_conf0.296.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_answer_2_047_conf0.703.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_answer_2_054_conf0.659.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_answer_2_058_conf0.706.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_061_conf0.667.jpg, 1 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_065_conf0.707.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_066_conf0.695.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_069_conf0.713.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_074_conf0.741.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_080_conf0.718.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_answer_2_085_conf0.710.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_answer_2_102_conf0.654.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_answer_2_104_conf0.677.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_109_conf0.725.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_111_conf0.690.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_119_conf0.750.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_2_127_conf0.742.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_2_131_conf0.716.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_answer_2_132_conf0.711.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_007_conf0.656.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_146_conf0.656.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_answer_2_159_conf0.727.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_answer_2_160_conf0.714.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_answer_2_166_conf0.749.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_answer_2_168_conf0.756.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_answer_2_170_conf0.748.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_answer_2_175_conf0.751.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_answer_2_177_conf0.751.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_answer_2_184_conf0.723.jpg, +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_answer_2_193_conf0.785.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_answer_2_195_conf0.745.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_2_022_conf0.726.jpg, 0 +1/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_answer_2_209_conf0.726.jpg, 0 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_016_conf0.701.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_017_conf0.659.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_021_conf0.609.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_030_conf0.672.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_032_conf0.724.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_033_conf0.709.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_answer_2_035_conf0.617.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_answer_2_037_conf0.675.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_answer_2_042_conf0.664.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_answer_2_044_conf0.655.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_answer_2_045_conf0.700.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_answer_2_051_conf0.681.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_answer_2_055_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_059_conf0.677.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_063_conf0.717.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_071_conf0.681.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_076_conf0.711.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_077_conf0.708.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_answer_2_083_conf0.651.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_answer_2_086_conf0.717.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_answer_2_094_conf0.641.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_answer_2_096_conf0.707.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_106_conf0.691.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_107_conf0.672.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_answer_2_108_conf0.649.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_116_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_122_conf0.700.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_2_129_conf0.668.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_000_conf0.699.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_139_conf0.699.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_002_conf0.695.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_141_conf0.695.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_008_conf0.706.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_009_conf0.629.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_147_conf0.706.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_answer_2_148_conf0.629.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_012_conf0.688.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_014_conf0.656.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_151_conf0.688.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_153_conf0.656.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_answer_2_157_conf0.762.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_answer_2_164_conf0.779.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_answer_2_169_conf0.766.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_answer_2_172_conf0.778.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_answer_2_173_conf0.783.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_answer_2_178_conf0.786.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_answer_2_180_conf0.735.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_answer_2_188_conf0.769.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_answer_2_189_conf0.758.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_answer_2_191_conf0.776.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_answer_2_192_conf0.760.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_answer_2_199_conf0.760.jpg, 2 +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_answer_2_205_conf0.763.jpg, +2/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_answer_2_206_conf0.737.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_018_conf0.618.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_020_conf0.627.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_031_conf0.640.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_answer_2_036_conf0.611.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_answer_2_038_conf0.673.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_answer_2_043_conf0.663.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_answer_2_048_conf0.687.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_answer_2_052_conf0.632.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_answer_2_056_conf0.610.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_answer_2_057_conf0.714.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_068_conf0.668.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_079_conf0.746.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_answer_2_081_conf0.653.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_answer_2_091_conf0.670.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_answer_2_093_conf0.670.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_answer_2_100_conf0.645.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_answer_2_101_conf0.606.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_answer_2_103_conf0.617.jpg, 6 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_110_conf0.720.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_112_conf0.669.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_answer_2_113_conf0.627.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_124_conf0.672.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_answer_2_128_conf0.648.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_answer_2_130_conf0.661.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_2_133_conf0.739.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_003_conf0.669.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_answer_2_142_conf0.669.jpg, 3 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_006_conf0.688.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_answer_2_145_conf0.688.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_013_conf0.674.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_answer_2_152_conf0.674.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_2_017_conf0.781.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_answer_2_156_conf0.781.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_answer_2_161_conf0.751.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_answer_2_171_conf0.778.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_answer_2_181_conf0.790.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_answer_2_185_conf0.795.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_answer_2_186_conf0.800.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_2_019_conf0.766.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_answer_2_176_conf0.766.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_answer_2_194_conf0.732.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_answer_2_196_conf0.771.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_answer_2_197_conf0.763.jpg, 2 +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_answer_2_201_conf0.761.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_answer_2_203_conf0.793.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_2_211_conf0.798.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_answer_2_212_conf0.748.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_214_conf0.743.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_215_conf0.729.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_2_023_conf0.778.jpg, +3/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_answer_2_216_conf0.778.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_answer_2_015_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_022_conf0.606.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_025_conf0.436.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_028_conf0.703.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_029_conf0.673.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_answer_2_039_conf0.723.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_answer_2_050_conf0.638.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_answer_2_053_conf0.677.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_060_conf0.669.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_answer_2_062_conf0.240.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_075_conf0.739.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_answer_2_082_conf0.734.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_answer_2_084_conf0.722.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_answer_2_087_conf0.693.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_answer_2_090_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_answer_2_092_conf0.695.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_answer_2_095_conf0.586.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_answer_2_097_conf0.701.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_answer_2_098_conf0.686.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_answer_2_099_conf0.682.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_114_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_115_conf0.676.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_117_conf0.664.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_answer_2_118_conf0.647.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_121_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_125_conf0.668.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_answer_2_134_conf0.680.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_2_135_conf0.736.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_2_137_conf0.715.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_004_conf0.683.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_143_conf0.683.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_answer_2_158_conf0.761.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_answer_2_162_conf0.774.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_answer_2_163_conf0.795.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_2_016_conf0.753.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_answer_2_155_conf0.753.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_2_018_conf0.766.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_answer_2_165_conf0.766.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_answer_2_182_conf0.733.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_answer_2_190_conf0.785.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_answer_2_200_conf0.768.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_answer_2_202_conf0.689.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_answer_2_204_conf0.777.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_answer_2_207_conf0.777.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_answer_2_208_conf0.756.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_2_021_conf0.807.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_answer_2_198_conf0.807.jpg, 4 +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_answer_2_210_conf0.734.jpg, +4/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_answer_2_213_conf0.759.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_019_conf0.684.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_answer_2_023_conf0.590.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_answer_2_027_conf0.715.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_answer_2_034_conf0.675.jpg, 5 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_answer_2_040_conf0.666.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_answer_2_041_conf0.678.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_answer_2_046_conf0.667.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_answer_2_049_conf0.657.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_064_conf0.711.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_answer_2_067_conf0.669.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_070_conf0.711.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_072_conf0.654.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_answer_2_073_conf0.653.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_answer_2_078_conf0.685.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_answer_2_088_conf0.700.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_answer_2_089_conf0.659.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_answer_2_105_conf0.674.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_120_conf0.722.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_answer_2_123_conf0.689.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_answer_2_126_conf0.663.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_answer_2_136_conf0.723.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_answer_2_138_conf0.673.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_001_conf0.626.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_answer_2_140_conf0.626.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_005_conf0.671.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_answer_2_144_conf0.671.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_010_conf0.681.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_011_conf0.632.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_149_conf0.681.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_answer_2_150_conf0.632.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_answer_2_167_conf0.737.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_answer_2_174_conf0.783.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_answer_2_179_conf0.780.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_answer_2_183_conf0.759.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_2_020_conf0.760.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_answer_2_187_conf0.760.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_2_024_conf0.776.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_answer_2_217_conf0.776.jpg, 6 +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_2_025_conf0.777.jpg, +5/ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_answer_2_218_conf0.777.jpg, diff --git a/ai-service/test/OCR/test_result/tesseract_page_number.txt b/ai-service/test/OCR/test_result/tesseract_page_number.txt new file mode 100644 index 0000000..da0fcf4 --- /dev/null +++ b/ai-service/test/OCR/test_result/tesseract_page_number.txt @@ -0,0 +1,168 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_page_number_001_conf0.587.jpg, 97 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_page_number_002_conf0.575.jpg, 98 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_page_number_003_conf0.549.jpg, 99 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_page_number_004_conf0.536.jpg, 100 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_page_number_005_conf0.613.jpg, 101 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_page_number_006_conf0.547.jpg, 102 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_page_number_007_conf0.616.jpg, 103 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_page_number_008_conf0.509.jpg, 104 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_page_number_009_conf0.625.jpg, 105 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_page_number_010_conf0.548.jpg, 106 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_page_number_000_conf0.618.jpg, 88 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_page_number_012_conf0.626.jpg, 107 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_page_number_013_conf0.501.jpg, 108 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_page_number_014_conf0.602.jpg, 109 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_page_number_015_conf0.554.jpg, 110 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_page_number_016_conf0.687.jpg, 111 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_page_number_017_conf0.648.jpg, 112 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_page_number_018_conf0.672.jpg, 113 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_page_number_019_conf0.593.jpg, 114 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_page_number_020_conf0.627.jpg, 415 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_page_number_021_conf0.680.jpg, 116 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_page_number_011_conf0.577.jpg, 89 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_page_number_023_conf0.573.jpg, 117 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_page_number_024_conf0.655.jpg, 118 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_page_number_025_conf0.633.jpg, 119 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_page_number_026_conf0.537.jpg, 120 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_page_number_027_conf0.646.jpg, 121 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_page_number_028_conf0.563.jpg, 122 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_page_number_029_conf0.593.jpg, 123 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_page_number_030_conf0.457.jpg, 124 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_page_number_031_conf0.642.jpg, 125 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_page_number_032_conf0.512.jpg, 126 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_page_number_022_conf0.549.jpg, 90 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_page_number_034_conf0.653.jpg, 127 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_page_number_035_conf0.596.jpg, 128 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_page_number_036_conf0.629.jpg, 129 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_page_number_037_conf0.513.jpg, 130 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_page_number_038_conf0.699.jpg, 131 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_page_number_039_conf0.540.jpg, 132 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_page_number_040_conf0.618.jpg, 133 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_page_number_041_conf0.528.jpg, 134 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_page_number_042_conf0.577.jpg, 135 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_page_number_043_conf0.549.jpg, 136 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_page_number_033_conf0.583.jpg, 91 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_page_number_045_conf0.615.jpg, 137 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_page_number_046_conf0.499.jpg, 138 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_page_number_047_conf0.617.jpg, 139 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_page_number_048_conf0.497.jpg, 140 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_page_number_049_conf0.617.jpg, 141 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_page_number_050_conf0.501.jpg, 142 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_page_number_051_conf0.592.jpg, 143 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_page_number_052_conf0.552.jpg, 144 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_page_number_053_conf0.588.jpg, 145 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_page_number_054_conf0.532.jpg, 146 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_page_number_044_conf0.589.jpg, 92 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_page_number_056_conf0.600.jpg, 147 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_page_number_057_conf0.561.jpg, 148 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_page_number_058_conf0.633.jpg, 149 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_page_number_059_conf0.493.jpg, 150 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_page_number_060_conf0.621.jpg, 151 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_page_number_061_conf0.517.jpg, 152 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_page_number_062_conf0.601.jpg, 153 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_page_number_063_conf0.507.jpg, 154 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_page_number_064_conf0.586.jpg, 155 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_page_number_065_conf0.505.jpg, 156 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_page_number_055_conf0.574.jpg, 93 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_page_number_067_conf0.607.jpg, 157 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_page_number_068_conf0.432.jpg, 158 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_page_number_069_conf0.570.jpg, 159 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_page_number_070_conf0.565.jpg, 160 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_page_number_071_conf0.605.jpg, 161 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_page_number_072_conf0.604.jpg, 162 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_page_number_073_conf0.616.jpg, 163 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_page_number_074_conf0.607.jpg, 164 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_page_number_075_conf0.695.jpg, 165 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_000_conf0.563.jpg, 166 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_page_number_076_conf0.563.jpg, 166 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_page_number_066_conf0.610.jpg, 94 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_001_conf0.588.jpg, 167 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_page_number_078_conf0.588.jpg, 167 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_002_conf0.550.jpg, 168 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_page_number_079_conf0.550.jpg, 168 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_003_conf0.655.jpg, 169 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_page_number_080_conf0.655.jpg, 169 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_004_conf0.586.jpg, 170 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_page_number_081_conf0.586.jpg, 170 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_005_conf0.589.jpg, 171 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_page_number_082_conf0.589.jpg, 171 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_006_conf0.648.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_page_number_083_conf0.648.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_page_number_077_conf0.548.jpg, 95 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_page_number_084_conf0.585.jpg, 96 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_008_conf0.617.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_page_number_086_conf0.617.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_009_conf0.571.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_page_number_087_conf0.571.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_page_number_088_conf0.568.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_089_conf0.555.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_page_number_090_conf0.241.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_page_number_091_conf0.582.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_page_number_092_conf0.576.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_page_number_093_conf0.556.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_page_number_094_conf0.568.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_page_number_095_conf0.587.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_page_number_096_conf0.600.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_007_conf0.225.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_page_number_085_conf0.225.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_page_number_098_conf0.588.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_page_number_099_conf0.624.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_page_number_100_conf0.573.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_page_number_101_conf0.562.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_page_number_102_conf0.587.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_page_number_103_conf0.564.jpg, 7 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_page_number_104_conf0.598.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_page_number_105_conf0.521.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_page_number_106_conf0.551.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_page_number_107_conf0.549.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_010_conf0.540.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_page_number_097_conf0.540.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_page_number_109_conf0.568.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_page_number_110_conf0.569.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_page_number_111_conf0.567.jpg, 46 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_page_number_112_conf0.599.jpg, 47 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_page_number_113_conf0.542.jpg, 48 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_page_number_114_conf0.584.jpg, 49 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_page_number_115_conf0.558.jpg, 51 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_page_number_116_conf0.595.jpg, 52 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_page_number_117_conf0.601.jpg, 53 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_page_number_118_conf0.587.jpg, 54 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_011_conf0.556.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_page_number_108_conf0.556.jpg, 11 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_page_number_120_conf0.621.jpg, 55 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_page_number_121_conf0.602.jpg, 57 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_page_number_122_conf0.576.jpg, 58 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_page_number_123_conf0.555.jpg, 59 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_page_number_124_conf0.456.jpg, 60 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_page_number_125_conf0.571.jpg, 61 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_page_number_126_conf0.592.jpg, 63 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_page_number_127_conf0.565.jpg, 64 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_page_number_128_conf0.616.jpg, 65 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_page_number_129_conf0.579.jpg, 66 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_012_conf0.563.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_page_number_119_conf0.563.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_page_number_131_conf0.585.jpg, 67 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_page_number_132_conf0.577.jpg, 69 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_page_number_133_conf0.558.jpg, 70 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_page_number_134_conf0.584.jpg, 7 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_page_number_135_conf0.595.jpg, 72 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_page_number_136_conf0.573.jpg, 73 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_page_number_137_conf0.607.jpg, 75 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_page_number_138_conf0.576.jpg, 76 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_page_number_139_conf0.583.jpg, 77 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_page_number_140_conf0.601.jpg, 78 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_013_conf0.523.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_page_number_130_conf0.523.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_page_number_142_conf0.560.jpg, 79 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 61_page_number_143_conf0.577.jpg, 82 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_page_number_144_conf0.629.jpg, 83 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 63_page_number_145_conf0.554.jpg, 84 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_page_number_146_conf0.595.jpg, 85 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_014_conf0.592.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_page_number_141_conf0.592.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_015_conf0.598.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_page_number_147_conf0.598.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_016_conf0.572.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_page_number_148_conf0.572.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_017_conf0.555.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_page_number_149_conf0.555.jpg, 18 diff --git a/ai-service/test/OCR/test_result/tesseract_problem_number.txt b/ai-service/test/OCR/test_result/tesseract_problem_number.txt new file mode 100644 index 0000000..6c9bc8b --- /dev/null +++ b/ai-service/test/OCR/test_result/tesseract_problem_number.txt @@ -0,0 +1,316 @@ +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_005_conf0.763.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 10_problem_number_006_conf0.760.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_007_conf0.747.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 11_problem_number_008_conf0.745.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_009_conf0.753.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 12_problem_number_010_conf0.729.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_011_conf0.741.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 13_problem_number_012_conf0.741.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_013_conf0.742.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 14_problem_number_014_conf0.740.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_015_conf0.773.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 15_problem_number_016_conf0.736.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_017_conf0.747.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 16_problem_number_018_conf0.738.jpg, 4 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_019_conf0.757.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_020_conf0.745.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 17_problem_number_021_conf0.744.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_022_conf0.795.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_023_conf0.774.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_024_conf0.771.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_025_conf0.770.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 18_problem_number_026_conf0.751.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_027_conf0.767.jpg, 9 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_028_conf0.760.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_029_conf0.755.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_030_conf0.754.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 19_problem_number_031_conf0.728.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_000_conf0.820.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_001_conf0.795.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_002_conf0.765.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_003_conf0.755.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 1_problem_number_004_conf0.753.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_037_conf0.770.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_038_conf0.752.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_039_conf0.735.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_040_conf0.730.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 20_problem_number_041_conf0.722.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_042_conf0.786.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_043_conf0.780.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 21_problem_number_044_conf0.748.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_045_conf0.765.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 22_problem_number_046_conf0.740.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_047_conf0.758.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 23_problem_number_048_conf0.739.jpg, 2 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_049_conf0.759.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 24_problem_number_050_conf0.751.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_051_conf0.758.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 25_problem_number_052_conf0.754.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_053_conf0.764.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 26_problem_number_054_conf0.744.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_056_conf0.762.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 27_problem_number_057_conf0.742.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_058_conf0.742.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 28_problem_number_059_conf0.738.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_060_conf0.737.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 29_problem_number_061_conf0.733.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_032_conf0.764.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_033_conf0.764.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_034_conf0.757.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_035_conf0.754.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 2_problem_number_036_conf0.746.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_067_conf0.749.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 30_problem_number_068_conf0.747.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_069_conf0.758.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 31_problem_number_070_conf0.732.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_071_conf0.750.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 32_problem_number_072_conf0.738.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_073_conf0.763.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 33_problem_number_074_conf0.761.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_075_conf0.752.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_076_conf0.751.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 34_problem_number_077_conf0.746.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_078_conf0.815.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_079_conf0.783.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_080_conf0.772.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_081_conf0.758.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 35_problem_number_082_conf0.751.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_083_conf0.771.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_084_conf0.751.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_085_conf0.751.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_086_conf0.738.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 36_problem_number_087_conf0.735.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_088_conf0.771.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_089_conf0.762.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_090_conf0.756.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_091_conf0.743.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 37_problem_number_092_conf0.734.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_093_conf0.776.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_094_conf0.748.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 38_problem_number_095_conf0.723.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_096_conf0.747.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 39_problem_number_097_conf0.739.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_062_conf0.763.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_063_conf0.760.jpg, 2 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_064_conf0.743.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_065_conf0.727.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 3_problem_number_066_conf0.726.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_101_conf0.757.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 40_problem_number_102_conf0.733.jpg, 2 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_103_conf0.759.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 41_problem_number_104_conf0.749.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_105_conf0.749.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 42_problem_number_106_conf0.731.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_107_conf0.763.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 43_problem_number_108_conf0.734.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_109_conf0.761.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 44_problem_number_110_conf0.758.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_111_conf0.739.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 45_problem_number_112_conf0.733.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_113_conf0.747.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 46_problem_number_114_conf0.737.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_115_conf0.743.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 47_problem_number_116_conf0.721.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_117_conf0.738.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 48_problem_number_118_conf0.727.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_119_conf0.751.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 49_problem_number_120_conf0.745.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_098_conf0.768.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_099_conf0.746.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 4_problem_number_100_conf0.744.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_123_conf0.753.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 50_problem_number_124_conf0.730.jpg, 41 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_125_conf0.752.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_126_conf0.752.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 51_problem_number_127_conf0.745.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_128_conf0.814.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_129_conf0.769.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_130_conf0.764.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_131_conf0.758.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 52_problem_number_132_conf0.755.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_133_conf0.770.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_134_conf0.768.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_135_conf0.765.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_136_conf0.745.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 53_problem_number_137_conf0.736.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_138_conf0.759.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_139_conf0.756.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_140_conf0.754.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_141_conf0.744.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 54_problem_number_142_conf0.732.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_143_conf0.777.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_144_conf0.772.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 55_problem_number_145_conf0.738.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_146_conf0.746.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 56_problem_number_147_conf0.740.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_148_conf0.751.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 57_problem_number_149_conf0.733.jpg, 21 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_150_conf0.743.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 58_problem_number_151_conf0.734.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_152_conf0.755.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 59_problem_number_153_conf0.747.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_121_conf0.769.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 5_problem_number_122_conf0.754.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_156_conf0.757.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 60_problem_number_157_conf0.742.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_158_conf0.757.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 61_problem_number_159_conf0.749.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_160_conf0.739.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 62_problem_number_161_conf0.706.jpg, 3 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_162_conf0.765.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 63_problem_number_163_conf0.741.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_164_conf0.738.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 64_problem_number_165_conf0.723.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_166_conf0.738.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 65_problem_number_167_conf0.727.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_168_conf0.736.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 66_problem_number_169_conf0.727.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_170_conf0.755.jpg, 4 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 67_problem_number_171_conf0.734.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_172_conf0.749.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_173_conf0.742.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 68_problem_number_174_conf0.741.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_175_conf0.803.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_176_conf0.767.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_177_conf0.764.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_178_conf0.751.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 69_problem_number_179_conf0.748.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_154_conf0.741.jpg, 2 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 6_problem_number_155_conf0.740.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_182_conf0.753.jpg, 06 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_183_conf0.750.jpg, 07 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_184_conf0.748.jpg, 09 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_185_conf0.745.jpg, 10 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 70_problem_number_186_conf0.743.jpg, 08 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_187_conf0.771.jpg, 13 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_188_conf0.763.jpg, 15 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_189_conf0.753.jpg, 14 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_190_conf0.742.jpg, +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 71_problem_number_191_conf0.735.jpg, 12 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_192_conf0.761.jpg, 18 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_193_conf0.744.jpg, 17 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 72_problem_number_194_conf0.736.jpg, 16 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_195_conf0.758.jpg, 20 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 73_problem_number_196_conf0.756.jpg, 19 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_197_conf0.739.jpg, 2 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 74_problem_number_198_conf0.736.jpg, 22 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_199_conf0.756.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 75_problem_number_200_conf0.753.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_201_conf0.741.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 76_problem_number_202_conf0.740.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_203_conf0.766.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 77_problem_number_204_conf0.746.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_205_conf0.762.jpg, 29 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 78_problem_number_206_conf0.745.jpg, 30 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_000_conf0.754.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_001_conf0.707.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_207_conf0.754.jpg, 32 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 79_problem_number_208_conf0.707.jpg, 31 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_180_conf0.759.jpg, 24 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 7_problem_number_181_conf0.758.jpg, 23 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_002_conf0.742.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_003_conf0.728.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_211_conf0.742.jpg, 33 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 80_problem_number_212_conf0.728.jpg, 34 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_004_conf0.753.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_005_conf0.730.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_213_conf0.753.jpg, 35 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 81_problem_number_214_conf0.730.jpg, 36 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_006_conf0.742.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_007_conf0.731.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_215_conf0.742.jpg, 38 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 82_problem_number_216_conf0.731.jpg, 37 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_008_conf0.766.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_009_conf0.749.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_217_conf0.766.jpg, 40 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 83_problem_number_218_conf0.749.jpg, 39 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_010_conf0.739.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_011_conf0.727.jpg, 4 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_219_conf0.739.jpg, 42 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 84_problem_number_220_conf0.727.jpg, 4 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_012_conf0.752.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_013_conf0.745.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_014_conf0.742.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_221_conf0.752.jpg, 45 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_222_conf0.745.jpg, 44 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 85_problem_number_223_conf0.742.jpg, 43 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_209_conf0.756.jpg, 26 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 8_problem_number_210_conf0.751.jpg, 25 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_224_conf0.755.jpg, 28 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์‹ค์ „ ๋ชจ์˜๊ณ ์‚ฌ) - 9_problem_number_225_conf0.739.jpg, 27 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_016_conf0.766.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 10_problem_number_227_conf0.766.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_017_conf0.750.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 11_problem_number_228_conf0.750.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 12_problem_number_229_conf0.722.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 13_problem_number_230_conf0.742.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 14_problem_number_231_conf0.735.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 15_problem_number_232_conf0.720.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 16_problem_number_233_conf0.789.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 17_problem_number_234_conf0.715.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 18_problem_number_235_conf0.737.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 19_problem_number_236_conf0.744.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_015_conf0.752.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 1_problem_number_226_conf0.752.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 20_problem_number_238_conf0.709.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 21_problem_number_239_conf0.754.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 22_problem_number_240_conf0.723.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 23_problem_number_241_conf0.734.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 24_problem_number_242_conf0.721.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 25_problem_number_243_conf0.719.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 26_problem_number_244_conf0.752.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 27_problem_number_245_conf0.733.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 28_problem_number_246_conf0.736.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 29_problem_number_247_conf0.736.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_018_conf0.730.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 2_problem_number_237_conf0.730.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 30_problem_number_249_conf0.717.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 31_problem_number_250_conf0.767.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 32_problem_number_251_conf0.717.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 33_problem_number_252_conf0.716.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 34_problem_number_253_conf0.728.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 35_problem_number_254_conf0.744.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 36_problem_number_255_conf0.723.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 37_problem_number_256_conf0.727.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 38_problem_number_257_conf0.724.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 39_problem_number_258_conf0.739.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_019_conf0.728.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 3_problem_number_248_conf0.728.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 40_problem_number_260_conf0.723.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 41_problem_number_261_conf0.712.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 42_problem_number_262_conf0.721.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 43_problem_number_263_conf0.728.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 44_problem_number_264_conf0.730.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 45_problem_number_265_conf0.718.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 46_problem_number_266_conf0.769.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 47_problem_number_267_conf0.725.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 48_problem_number_268_conf0.742.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 49_problem_number_269_conf0.728.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_020_conf0.722.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 4_problem_number_259_conf0.722.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 50_problem_number_271_conf0.716.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 51_problem_number_272_conf0.750.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 52_problem_number_273_conf0.728.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 53_problem_number_274_conf0.723.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 54_problem_number_275_conf0.729.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 55_problem_number_276_conf0.708.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 56_problem_number_277_conf0.762.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 57_problem_number_278_conf0.730.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 58_problem_number_279_conf0.730.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 59_problem_number_280_conf0.727.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_021_conf0.724.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 5_problem_number_270_conf0.724.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 60_problem_number_282_conf0.736.jpg, 0 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_283_conf0.722.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 62_problem_number_284_conf0.714.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_285_conf0.737.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_286_conf0.721.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 64_problem_number_287_conf0.720.jpg, 05 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_022_conf0.796.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 6_problem_number_281_conf0.796.jpg, 01 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_023_conf0.724.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 7_problem_number_288_conf0.724.jpg, 02 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_024_conf0.734.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 8_problem_number_289_conf0.734.jpg, 03 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_025_conf0.733.jpg, 04 +ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ(์œ ํ˜•ํŽธ) - 9_problem_number_290_conf0.733.jpg, 04 diff --git a/ai-service/test/YOLO/__init__.py b/ai-service/test/YOLO/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-service/test/YOLO/__pycache__/__init__.cpython-311.pyc b/ai-service/test/YOLO/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..b61144a Binary files /dev/null and b/ai-service/test/YOLO/__pycache__/__init__.cpython-311.pyc differ diff --git a/ai-service/test/YOLO/__pycache__/__init__.cpython-312.pyc b/ai-service/test/YOLO/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..f178721 Binary files /dev/null and b/ai-service/test/YOLO/__pycache__/__init__.cpython-312.pyc differ diff --git a/ai-service/test/YOLO/__pycache__/section_crop.cpython-311.pyc b/ai-service/test/YOLO/__pycache__/section_crop.cpython-311.pyc new file mode 100644 index 0000000..c451b58 Binary files /dev/null and b/ai-service/test/YOLO/__pycache__/section_crop.cpython-311.pyc differ diff --git a/ai-service/test/YOLO/__pycache__/section_crop.cpython-312.pyc b/ai-service/test/YOLO/__pycache__/section_crop.cpython-312.pyc new file mode 100644 index 0000000..ccd5b4b Binary files /dev/null and b/ai-service/test/YOLO/__pycache__/section_crop.cpython-312.pyc differ diff --git a/ai-service/test/YOLO/__pycache__/yolo_test.cpython-311.pyc b/ai-service/test/YOLO/__pycache__/yolo_test.cpython-311.pyc new file mode 100644 index 0000000..0a2f982 Binary files /dev/null and b/ai-service/test/YOLO/__pycache__/yolo_test.cpython-311.pyc differ diff --git a/ai-service/test/YOLO/__pycache__/yolo_test_crop.cpython-311.pyc b/ai-service/test/YOLO/__pycache__/yolo_test_crop.cpython-311.pyc new file mode 100644 index 0000000..4a79fed Binary files /dev/null and b/ai-service/test/YOLO/__pycache__/yolo_test_crop.cpython-311.pyc differ diff --git a/ai-service/test/YOLO/answers/accuracy_analysis.ipynb b/ai-service/test/YOLO/answers/accuracy_analysis.ipynb new file mode 100644 index 0000000..c40399a --- /dev/null +++ b/ai-service/test/YOLO/answers/accuracy_analysis.ipynb @@ -0,0 +1,1503 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ๐Ÿ“Š YOLO ๋‹ต์•ˆ ์ธ์‹ ์ •ํ™•๋„ ๋ถ„์„\n", + "\n", + "## ๊ฐœ์š”\n", + "- **results_summary.txt**: ์ด๋ฏธ์ง€ ํŒŒ์ผ, ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ์ •๋‹ต\n", + "- **yolo_answer.txt**: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ์ •๋‹ต (์ •๋‹ต์ง€)\n", + "\n", + "์ •๋‹ต์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ธ์‹ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ตํ•˜์—ฌ ์ •ํ™•๋„๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค." + ] + }, + { + "cell_type": "code", + "execution_count": 167, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋“œ ์™„๋ฃŒ\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "from pathlib import Path\n", + "from typing import Dict, List, Tuple\n", + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "print(\"โœ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋“œ ์™„๋ฃŒ\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ •" + ] + }, + { + "cell_type": "code", + "execution_count": 168, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… Results ํŒŒ์ผ: results_summary.txt\n", + "โœ… Answer Key ํŒŒ์ผ: yolo_answer.txt\n" + ] + } + ], + "source": [ + "# ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • (ํ•„์š”์‹œ ์ˆ˜์ •)\n", + "results_path = Path(\"results_summary.txt\")\n", + "answer_key_path = Path(\"yolo_answer.txt\")\n", + "output_dir = Path(\"./\")\n", + "\n", + "# ํŒŒ์ผ ์กด์žฌ ํ™•์ธ\n", + "if not results_path.exists():\n", + " print(f\"โŒ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {results_path}\")\n", + "else:\n", + " print(f\"โœ… Results ํŒŒ์ผ: {results_path}\")\n", + "\n", + "if not answer_key_path.exists():\n", + " print(f\"โŒ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {answer_key_path}\")\n", + "else:\n", + " print(f\"โœ… Answer Key ํŒŒ์ผ: {answer_key_path}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. ๋ฐ์ดํ„ฐ ๋กœ๋“œ ๋ฐ ์ „์ฒ˜๋ฆฌ" + ] + }, + { + "cell_type": "code", + "execution_count": 169, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“„ Results Summary ๋กœ๋“œ ์™„๋ฃŒ: 155๊ฐœ ํ•ญ๋ชฉ\n", + " - None ๋‹ต์•ˆ: 1๊ฐœ\n", + "\n", + "๐Ÿ“˜ Answer Key ๋กœ๋“œ ์™„๋ฃŒ: 155๊ฐœ ํ•ญ๋ชฉ\n", + "\n", + "============================================================\n" + ] + } + ], + "source": [ + "def load_results(file_path: Path) -> pd.DataFrame:\n", + " \"\"\"results_summary.txt ๋กœ๋“œ\n", + " ํ˜•์‹: ์ด๋ฏธ์ง€ํŒŒ์ผ, ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต\n", + " \"\"\"\n", + " data = []\n", + " with open(file_path, 'r', encoding='utf-8') as f:\n", + " for line_num, line in enumerate(f, 1):\n", + " line = line.strip()\n", + " if not line:\n", + " continue\n", + " \n", + " parts = [p.strip() for p in line.split(',')]\n", + " if len(parts) >= 4:\n", + " data.append({\n", + " 'image_file': parts[0],\n", + " 'page_number': parts[1],\n", + " 'problem_number': parts[2],\n", + " 'predicted_answer': parts[3] if parts[3].lower() != 'none' else None\n", + " })\n", + " else:\n", + " print(f\"โš ๏ธ Warning: ๋ผ์ธ {line_num} ํ˜•์‹ ์˜ค๋ฅ˜: {line}\")\n", + " \n", + " df = pd.DataFrame(data)\n", + " print(f\"\\n๐Ÿ“„ Results Summary ๋กœ๋“œ ์™„๋ฃŒ: {len(df)}๊ฐœ ํ•ญ๋ชฉ\")\n", + " print(f\" - None ๋‹ต์•ˆ: {df['predicted_answer'].isna().sum()}๊ฐœ\")\n", + " return df\n", + "\n", + "def load_answer_key(file_path: Path) -> pd.DataFrame:\n", + " \"\"\"yolo_answer.txt ๋กœ๋“œ (์ •๋‹ต์ง€)\n", + " ํ˜•์‹: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต\n", + " \"\"\"\n", + " data = []\n", + " with open(file_path, 'r', encoding='utf-8') as f:\n", + " for line_num, line in enumerate(f, 1):\n", + " line = line.strip()\n", + " if not line:\n", + " continue\n", + " \n", + " parts = [p.strip() for p in line.split(',')]\n", + " if len(parts) >= 3:\n", + " data.append({\n", + " 'page_number': parts[0],\n", + " 'problem_number': parts[1],\n", + " 'correct_answer': parts[2]\n", + " })\n", + " else:\n", + " print(f\"โš ๏ธ Warning: ๋ผ์ธ {line_num} ํ˜•์‹ ์˜ค๋ฅ˜: {line}\")\n", + " \n", + " df = pd.DataFrame(data)\n", + " print(f\"\\n๐Ÿ“˜ Answer Key ๋กœ๋“œ ์™„๋ฃŒ: {len(df)}๊ฐœ ํ•ญ๋ชฉ\")\n", + " return df\n", + "\n", + "# ๋ฐ์ดํ„ฐ ๋กœ๋“œ\n", + "results_df = load_results(results_path)\n", + "answer_key_df = load_answer_key(answer_key_path)\n", + "\n", + "print(\"\\n\" + \"=\"*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ ํ™•์ธ" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. ์ •๋‹ต ๋น„๊ต ๋ฐ ์ •ํ™•๋„ ๊ณ„์‚ฐ" + ] + }, + { + "cell_type": "code", + "execution_count": 170, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "โœ… ์ •๋‹ต ๋น„๊ต ์™„๋ฃŒ\n", + "\n", + "๐Ÿ“Š ์ „์ฒด ๊ฒฐ๊ณผ:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberproblem_numbercorrect_answerimage_filepredicted_answer_mergeresult
09011แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11bothcorrect
110022แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 22bothcorrect
211032แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 32bothcorrect
312044แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 44bothcorrect
413051แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 51bothcorrect
515014แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64bothcorrect
616025แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 75bothcorrect
717031แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 81bothcorrect
818043แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 93bothcorrect
919052แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 102bothcorrect
1021011แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 111bothcorrect
1122022แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 122bothcorrect
1223034แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 134bothcorrect
1324041แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 141bothcorrect
1425051แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 151bothcorrect
1527013แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 163bothcorrect
1628024แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 174bothcorrect
1729034แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 184bothcorrect
1830042แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 192bothcorrect
1931051แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 201bothcorrect
\n", + "
" + ], + "text/plain": [ + " page_number problem_number correct_answer \\\n", + "0 9 01 1 \n", + "1 10 02 2 \n", + "2 11 03 2 \n", + "3 12 04 4 \n", + "4 13 05 1 \n", + "5 15 01 4 \n", + "6 16 02 5 \n", + "7 17 03 1 \n", + "8 18 04 3 \n", + "9 19 05 2 \n", + "10 21 01 1 \n", + "11 22 02 2 \n", + "12 23 03 4 \n", + "13 24 04 1 \n", + "14 25 05 1 \n", + "15 27 01 3 \n", + "16 28 02 4 \n", + "17 29 03 4 \n", + "18 30 04 2 \n", + "19 31 05 1 \n", + "\n", + " image_file predicted_answer _merge result \n", + "0 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1 1 both correct \n", + "1 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2 2 both correct \n", + "2 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3 2 both correct \n", + "3 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4 4 both correct \n", + "4 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5 1 both correct \n", + "5 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6 4 both correct \n", + "6 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7 5 both correct \n", + "7 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8 1 both correct \n", + "8 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9 3 both correct \n", + "9 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10 2 both correct \n", + "10 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11 1 both correct \n", + "11 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 12 2 both correct \n", + "12 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 13 4 both correct \n", + "13 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14 1 both correct \n", + "14 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 15 1 both correct \n", + "15 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 16 3 both correct \n", + "16 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 17 4 both correct \n", + "17 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 18 4 both correct \n", + "18 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 19 2 both correct \n", + "19 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 20 1 both correct " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ์ •๋‹ต์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ results์™€ merge\n", + "merged_df = answer_key_df.merge(\n", + " results_df,\n", + " on=['page_number', 'problem_number'],\n", + " how='left',\n", + " indicator=True\n", + ")\n", + "\n", + "# ๋น„๊ต ๊ฒฐ๊ณผ ์ปฌ๋Ÿผ ์ถ”๊ฐ€\n", + "def compare_answers(row):\n", + " \"\"\"์ •๋‹ต ๋น„๊ต\"\"\"\n", + " if row['_merge'] == 'left_only':\n", + " return 'missing' # results์— ์—†์Œ\n", + " elif pd.isna(row['predicted_answer']):\n", + " return 'none' # None์œผ๋กœ ์˜ˆ์ธก๋จ\n", + " elif str(row['predicted_answer']).strip() == str(row['correct_answer']).strip():\n", + " return 'correct' # ์ •๋‹ต\n", + " else:\n", + " return 'wrong' # ์˜ค๋‹ต\n", + "\n", + "merged_df['result'] = merged_df.apply(compare_answers, axis=1)\n", + "\n", + "print(\"\\nโœ… ์ •๋‹ต ๋น„๊ต ์™„๋ฃŒ\")\n", + "print(\"\\n๐Ÿ“Š ์ „์ฒด ๊ฒฐ๊ณผ:\")\n", + "display(merged_df.head(20))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. ์ •ํ™•๋„ ํ†ต๊ณ„" + ] + }, + { + "cell_type": "code", + "execution_count": 171, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "๐Ÿ“Š ์ •ํ™•๋„ ํ†ต๊ณ„\n", + "============================================================\n", + "\n", + "๐Ÿ“˜ ์ •๋‹ต์ง€ ๊ธฐ์ค€:\n", + " ์ด ๋ฌธ์ œ ์ˆ˜: 155๊ฐœ\n", + "\n", + "โœ… ์ •๋‹ต: 153๊ฐœ (98.71%)\n", + "โŒ ์˜ค๋‹ต: 1๊ฐœ (0.65%)\n", + "โš ๏ธ None: 1๊ฐœ (0.65%)\n", + "๐Ÿ” ๋ˆ„๋ฝ: 0๊ฐœ (0.00%)\n", + "\n", + "============================================================\n", + "๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: 98.71%\n", + "๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): 100.00%\n", + "โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„ (None ํฌํ•จ): 98.71%\n", + "============================================================\n" + ] + } + ], + "source": [ + "# ๊ฒฐ๊ณผ๋ณ„ ๊ฐœ์ˆ˜ ๊ณ„์‚ฐ\n", + "total_count = len(merged_df)\n", + "correct_count = (merged_df['result'] == 'correct').sum()\n", + "wrong_count = (merged_df['result'] == 'wrong').sum()\n", + "none_count = (merged_df['result'] == 'none').sum()\n", + "missing_count = (merged_df['result'] == 'missing').sum()\n", + "\n", + "# ์ •ํ™•๋„ ๊ณ„์‚ฐ\n", + "accuracy = correct_count / total_count * 100 if total_count > 0 else 0\n", + "\n", + "# ์ธ์‹ ์„ฑ๊ณต๋ฅ  (None ์ œ์™ธ)\n", + "recognized_count = total_count - missing_count\n", + "recognition_rate = recognized_count / total_count * 100 if total_count > 0 else 0\n", + "\n", + "# ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„\n", + "accuracy_of_recognized = correct_count / recognized_count * 100 if recognized_count > 0 else 0\n", + "\n", + "print(\"=\"*60)\n", + "print(\"๐Ÿ“Š ์ •ํ™•๋„ ํ†ต๊ณ„\")\n", + "print(\"=\"*60)\n", + "print(f\"\\n๐Ÿ“˜ ์ •๋‹ต์ง€ ๊ธฐ์ค€:\")\n", + "print(f\" ์ด ๋ฌธ์ œ ์ˆ˜: {total_count}๊ฐœ\")\n", + "print(f\"\\nโœ… ์ •๋‹ต: {correct_count}๊ฐœ ({correct_count/total_count*100:.2f}%)\")\n", + "print(f\"โŒ ์˜ค๋‹ต: {wrong_count}๊ฐœ ({wrong_count/total_count*100:.2f}%)\")\n", + "print(f\"โš ๏ธ None: {none_count}๊ฐœ ({none_count/total_count*100:.2f}%)\")\n", + "print(f\"๐Ÿ” ๋ˆ„๋ฝ: {missing_count}๊ฐœ ({missing_count/total_count*100:.2f}%)\")\n", + "print(f\"\\n{'='*60}\")\n", + "print(f\"๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: {accuracy:.2f}%\")\n", + "print(f\"๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): {recognition_rate:.2f}%\")\n", + "print(f\"โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„ (None ํฌํ•จ): {accuracy_of_recognized:.2f}%\")\n", + "print(\"=\"*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. ์‹œ๊ฐํ™”" + ] + }, + { + "cell_type": "code", + "execution_count": 172, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“Š Visualization saved: accuracy_visualization.png\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABXIAAAJNCAYAAACcOY1uAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAxq1JREFUeJzs3Xd4VGX6xvH7zExm0huEQOhFFJCmIGJZUFEsa++i4Lqray9YWXtfcHXt+tN1QdeCrgp2FOkgvffeSYH0NsmU8/sjy8iQSQiQ5CSZ7+e6uMi8p8wzkxDO3PPO8xqmaZoCAAAAAAAAADRYNqsLAAAAAAAAAABUjyAXAAAAAAAAABo4glwAAAAAAAAAaOAIcgEAAAAAAACggSPIBQAAAAAAAIAGjiAXAAAAAAAAABo4glwAAAAAAAAAaOAIcgEAAAAAAACggSPIBQAAAAAAAIAGjiAXYa1Dhw4yDEOGYeipp54KjE+fPj0wbhiGtm3bZlmNVtu2bVvQczF9+nSrSwpoiN+n6p6vp556KjDeoUMHy2o80Lhx44LqBQAAQMNz4403Bq7XBg8ebHU5AACLEORCy5cv1+23366ePXsqMTFRTqdTqampOvPMM/WPf/xD+fn5VpfYaAwePDgoFNv/JzIyUu3atdPFF1+sCRMmWF1mrTnakPfgINYwDDmdTiUkJKhTp04aMmSInn76ae3cubNuHsABDvze3XjjjXV+f/WBkBYAAISbUNeXhmHIbrcrMTFRJ5xwgh5++GFlZGRYXWqtqa2Q1zRN/fjjj7rhhhvUtWtXxcfHKyIiQqmpqTrrrLM0evRopaen117h9aSqyTsA0Bg5rC4A1vF6vbr//vv1+uuvV9qWlZWlrKwsTZs2TaNHj9Ynn3yic845x4Iqm4aysjLt3LlTO3fu1Lfffqu//e1vev75560uq0HyeDzyeDwqKCjQ1q1bNWXKFD377LN6/PHH9fjjj8tm+/39p86dO+ull14K3E5OTrai5CDJyclBNXXu3NnCag6tf//+QfUCAAA0RX6/X/n5+Vq6dKmWLl2qjz76SAsWLFDbtm2tLq1B2Llzp6677jrNnj270rasrCxNnTpVU6dO1dq1azVu3Lj6LxAAIIkgN6zdddddevfddwO309LSdNVVV6l58+ZauXKlvvzyS/l8Pu3bt08XXnihpk6dqlNPPdXCiivz+XwqKytTdHS01aVUkpSUpL/97W/yer3asGGDPvnkE5WXl0uSRo8erfvvv79BBI8NydVXX61+/fopPz9fS5Ys0c8//yyfzyefz6ennnpKGRkZeueddwL7t23bVg888ICFFf+uvLxcpmkqPj6+wdRUEz169FCPHj2sLgMAAKBO7L++LCgo0MSJE7Vy5UpJUkZGhv75z3/qlVdesbhC62VmZmrQoEHaunVrYKxjx4666KKLlJqaqtzcXM2bNy9kyAsAqGcmwtKcOXNMSYE/J5xwgpmfnx+0z5QpU0ybzRbYp0ePHqbP5zN9Pp/Zrl27wPiTTz5Z6fwPPfRQYPsxxxwTtC0jI8McNWqU2bt3bzM2NtZ0uVxm586dzdtvv93cvn17pXONGDEicK5BgwaZ27dvN6+//nqzRYsWpmEY5oQJE0zTNM0PPvjAvPLKK83jjjvObNasmelwOMy4uDizd+/e5kMPPWTu3bu30rnbt28f8nFMmzYt6PnZunVrjZ7XQYMGBY5p37590LaHH3446Jxz586tdHx+fr75wgsvmCeddJIZHx9vRkREmG3btjVHjBhhrlq1qtL+Ho/H/Oc//2mefPLJZkJCgmm3283k5GSze/fu5g033GB+9tlngX23bt0adP/Tpk2rsvYRI0Yc8rgDn7tQfwYNGnTI5+vg53ns2LFB29esWWN27NgxaJ+ffvqpyuMP/D4VFRWZTz/9tNm3b18zNjbWdDgcZkpKitm7d2/zL3/5S+A8Tz75ZLWP48DzHvwcrVy50rz44ovN5ORkU5K5dOnSap/nA++rffv2ZkFBgTly5EizTZs2psvlMrt162a+8cYbpt/vr9H3xjRNc+zYsUH3F+p7FurP/p/3UMcfqKSkxHzllVfMU045xUxMTDQjIiLMFi1amOedd575+eefH/J7unnzZvOtt94ye/bsabpcLjMlJcX885//bObk5FT3owEAAHBEqru+zMvLM51OZ2Db0KFDQ55j5syZ5tVXX222bdvWdDqdZlxcnHnyySebb775plleXl5p/xUrVpjDhg0z27dvbzqdTjMyMtJs27atecYZZ5iPPPKIuWvXrsC+B7+2qa72A69tQx138HVcqD8HX/OHcs011wQdc9ttt5kej6fSfhs2bDA//vjjSuNffvmlef7555upqalmRESEmZiYaA4cOND8xz/+YRYXFwftW5uvST777DPzpJNOMqOioszExETziiuuMHfs2BHyOavqz37btm0zb7nlFrNLly5mZGSk6XK5zLS0NPOUU04x77vvPnPNmjWHfB4BoD4wIzdMvffee0G3x4wZo/j4+KCxM888U1dffbU+++wzSdLq1as1a9YsDRo0SCNGjNCzzz4rSfrss8+Ceg2Zpqnx48cHbv/pT38KfD137lxddNFF2rdvX9B9bd68WW+//bY++eQTfffddzr99NND1r1nzx4NGDAgZE+rt99+W4sXLw4aKyws1PLly7V8+XJ98sknWrBggdLS0qp6WupU69atg243b9486PbGjRt1zjnnVFqwa+fOnfrwww81fvx4/ec//9GVV14Z2PaXv/xFH374YdD+OTk5ysnJ0Zo1a7RhwwZdc801tftA6lG3bt30+eef66STTgqM/fOf/9S55557yGP/+Mc/VurZu3fvXu3du1fLly9XYWFhjc5TlRUrVujkk09WcXHxER3vdrt15plnatGiRYGxtWvX6q677tKGDRtCtjypbxkZGRoyZIhWr14dNJ6VlaWffvpJP/30k7744guNHz9eDkfo/05GjBgRNHtj7969+uCDD7Rx40bNmDGjTusHAAA4UEJCgmJjY5WTkyOp8vW4JD366KN64YUXgsbKy8s1b948zZs3T59//rl++uknxcTESJLWrFmjk08+WSUlJUHH7G+rNm3aNA0aNKjSa4GGIj09XZ9//nngdp8+ffTmm28GtTPb75hjjtExxxwTuO3z+XTdddfpiy++CNovLy9Pc+fO1dy5c/XBBx9oypQpatWqVa3W/fjjjwddY5aWlurLL7/U8uXLtWLFCkVGRtb4XFlZWerfv7/27t0bNL5nzx7t2bNHv/32m7p27apu3brVWv0AcKQIcsPUrFmzAl8nJSXprLPOCrnfgUHu/uMGDRqkG2+8Uc8995xM09SGDRu0ePFinXjiiZKkOXPmaMeOHZIku92u4cOHS5IKCgp0ySWXBELc9u3b6+qrr1ZUVJS+/PJLrV69Wvn5+br88su1ceNGJSQkVKpn48aNkqTLLrtMvXv31vbt2wP7tWjRQhdeeKE6d+6s5ORk2e127d69W59//rmys7O1e/duPffcc3r77beP9uk7LD6fTxs2bNC///3vwNgJJ5ygLl26BO1z6aWXBkLclJQUXXfddUpOTtbPP/+s3377TWVlZRo+fLhOPPFEderUSUVFRfr4448D57j88st1wgknKD8/X9u3b6/zkOzRRx/Vtm3bgi50b7311kBP2NrqN9a/f3/17t1by5cvlyTNnDlTPp9Pdru9ymPWrl0bCHFtNpuGDx+url27at++fdq6dWtQwHvOOecoNjZW77zzjrZs2SJJ6tevn66++urAPqFaYCxdulQOh0M33HCDjjnmGK1bt+6wLhgzMzOVl5enW2+9VYmJifr444+1a9cuSdIbb7yhyy+/XIMGDarx+Q60v0/vokWLgi7MD+yFe8oppxzyPMOGDQsKca+44gp1795dkydP1ty5cyVJX331lV544QU98cQTIc8xe/ZsnXXWWTrllFOCPs44c+ZMzZs3TyeffPIRPUYAAIDDUVBQoHHjxgVCXEm66qqrgvYZP3580LXt0KFDdeqppyozM1MffvihioqKNGvWLN13332BiTEffvhhIMRt06aNrr/+esXExGjXrl1atWqV5s2bV2ePaf9aB59//nlgckCnTp102223BfY51HoN06ZNk2magdsjRowIGeKG8sILLwSFuCeffLLOOeccrV27Vv/9738lVVyXDxs2TFOnTq3x46qJ2bNnq3///ho6dKimTZumOXPmSKp4vThx4kRdc801uuaaa3T88cfrhRdeUG5uriTp7LPPrrT2y1dffRUIcZOSkvSnP/1JzZo10549e7Ru3bqg184AYDmLZwTDIlFRUYGPk/Tp06fK/ZYuXRr00ZPbb789sG3w4MGB8fvvvz8wfvvttwfGzzvvvMD4a6+9FhhPSkoys7OzA9uKiorMlJSUwPbXXnstsO3gj8S8+uqrVdZbXFxs/vrrr+Z7771nvvLKK+ZLL71kXnzxxYFjO3XqFLR/XbZWqOpP//79zW3btgUd98033wS22+12c8OGDYFtXq/X7NmzZ2D7fffdZ5qmaebk5ATG4uPjzbKysqBz+v1+c8uWLYHbtd1aoSbnPJRDtVbY76qrrgraLysrK+Tx+79PS5YsCYx169atUqsCr9db6XtQXfuCUPtIMidOnFhpn5q2VpBkfvLJJ0HHRUREBLYNGzasRrVV1xrhUG0Tqtvn4H/7Dz30UNDzN3DgwMC25ORk0+fzmaZZ+Xty6aWXBp7/7Oxs0263B7a9/vrrIWsCAAA4Ugdfi4T6Ex0dbb700kuV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1N13333I4//5z39q3rx5gRmnb775pn766SddeOGFSk1NVU5OjubPn69Zs2Zp+PDhGjZsmGw2m+677z49/vjjkip64J522mk655xztG7duqBPdp5xxhnq3bu3pLp5TXIorVu31qZNmyRJ48aNU1RUlOLi4tS5c2ddeumlmjlzpoYNG6bTTjtN3bp1U1pamnw+n77++uvAOZxOZ40nRABAnbJokTU0AB6Px7zzzjsPuaprs2bNzJ9//rnK84wePbrSMVWtRj9nzhyzefPmh7zPA1cvrckqrBs3bjTj4uIqncfhcJjDhg0LGjtQVSuYVrdibHUOXGW1ffv2lbY/8MADQef9/PPPA9vWr19vdujQ4ZDPzdixYwPHuFyuavft2LGjmZeXF9j/X//6V8j9OnXqZB533HE1WiH24JVlL7300pDnDLUS8MFqsqrw/u/js88+a/p8vmqP3/99Sk9PP+Q5TzrpJNPj8QTO9c0334Tcr0ePHiG/vwc+Rweq7vl68sknA+PNmzc3e/ToEfI+b7/99qBzZmZmms2aNau0n81mM4cOHVrlz7fb7TZbtWoV8j4WLlxomqZpjh07tsrj09PTze7du1f7PF5++eVBz+Oh/u0catVgAACAo3HwtciB186maZpZWVlmdHR00LWe3+8PbB81atQhryMPvM5/8cUXD7n/ga+NSktLzWOOOSbkfueff36V11HVvSZaunSpabPZKp0vJiamxs/btm3bzIEDBx7ysRx4Dez1es0rr7yy2v27detm7t69O+i+6uI1SXXX6a+99lrI+7vgggtM0zTNzz777JCPe+TIkTV+LgGgLjGFKow5HA698cYbWrp0qW677TZ1795dcXFxcjgcSklJ0eDBgzVmzBht3ry52lmQN9xwQ9DHbpxOZ+Bd7YOdcsopWr16tR5//HGdeOKJio+Pl91uV2Jiok488UTdeeedmjx5sv7whz8c1mPp0qWLZs6cqXPOOUfR0dGKjY3VoEGDNGXKFA0ZMuSwzlWX7r///qDWCC+88EKgH1XXrl21YsUKjRkzRqeccoqSkpJkt9sVFxenXr166S9/+YsmTJgQ9Ny+8847+tOf/qRevXopJSVFDodDsbGx6tWrlx566CHNnz8/qKfun//8Z73//vvq1q2bnE6nWrZsqdtuu00LFiw44pVY33//fY0YMUKpqam1Mitz/2Pu2LGjzjrrLD399NPatm2bHnvssRqfPykpSW+++aauvfZade/eXcnJybLb7YqPj1e/fv307LPPasqUKUEL51100UV68803A89NXYuJidHs2bN11113qXXr1nI6nTr22GP12muv6c033wzat0WLFpoxY4bOO+88xcbGKiYmRmeeeaamT59eqfXEgVwul3788Uedc845io+PP+waW7ZsqYULF+rll1/WwIEDlZCQEPj9cO6552r8+PH68ssvQy5ACAAA0BClpKQEffJp9erVgU8+SRXX53PmzNH111+vjh07yuVyKSIiQq1bt9Y555yjF154IfCJJanik3RPPPGEhgwZog4dOig6OloOh0OtWrXSBRdcoG+//VZ33XVXYP/IyEhNmTJFV111lRITExUZGakBAwZowoQJevDBB4/oMfXp00efffaZTjjhBEVGRh7ROdq3b685c+bou+++07Bhw9SlSxfFxMTI4XCoRYsWGjJkiN566y2NGTMmcIzdbtcXX3yh//73vzr//PPVokULORwOJSQkaMCAAXrppZe0cOFCpaWlBd1XXbwmqc4dd9yhp556Sp06dQp53Xraaafp+eef1wUXXKDOnTsHvSY+66yzNG7cOL388su1XhcAHAnDNA9jaU4AAAAAAAAAQL1jRi4AAAAAAAAANHAEuQAAAAAAAADQwBHkAgAAAAAAAEADR5ALAAAAAAAAAA0cQS4AAAAAAAAANHAOqwsAAABA3Zk5c6ZeeuklLV68WOnp6ZowYYIuueSSoH3Wrl2rhx9+WDNmzJDX61X37t311VdfqV27dpIkt9ut+++/X+PHj1dZWZmGDh2qt99+W6mpqTWuw+/3a8+ePYqLi5NhGLX5EAEAAIBGyzRNFRYWKi0tTTZb9XNuCXIBAACasOLiYvXu3Vs33XSTLrvsskrbN2/erNNOO01//vOf9fTTTys+Pl6rV69WZGRkYJ/77rtPP/zwg/773/8qISFBd955py677DLNmTOnxnXs2bNHbdu2rZXHBAAAADQ1O3fuVJs2bardxzBN06ynegAAAGAhwzAqzci95pprFBERof/85z8hj8nPz1dKSoo+/fRTXXHFFZKkdevWqVu3bpo7d65OPvnkkMeVlZWprKws6Dzt2rXT9u3bFR8fX3sPCpKkLVu26LXXXtOCBQu0fv167b/ET09PDwrle/XqpZ07d4Y8x8yZM9WzZ09J0qJFi/TSSy9p9erVys7Olt/vV+vWrTVkyBA99NBDat68ed0/KAAAgDBQUFCg9u3bKy8vTwkJCdXuy4xcAACAMOX3+/XDDz/ooYce0tChQ7V06VJ17NhRo0aNCoS9ixcvlsfj0ZAhQwLHHXfccWrXrl21Qe6LL76op59+utJ4WVmZ3G53nTyecLZ8+XJ99NFHlcYPfq6rm8Nx4Pdm+fLl+uWXX4K2b926Ve+//75mzpypqVOnHvKjfwAAADi0/ZMfatJ+jCAXAAAgTGVlZamoqEh///vf9dxzz2n06NGaNGmSLrvsMk2bNk2DBg1SRkaGnE6nEhMTg45NTU1VRkZGleceNWqURo4cGbhdUFCgtm3bKiUlhRm5daB79+4aNWqUTj75ZD3//PNasGCBJKlFixZBM3Ltdrsk6YMPPtCNN95Y5fn69eunjz76SIMGDVJKSooWLFigyy+/XNnZ2Vq/fr3S09PVt2/fOn1MAAAA4eDAa7VDIcgFAAAIU36/X5J08cUX67777pMk9enTR7/99pveffddDRo06IjP7XK55HK5Ko3bbDZmctaBAQMGaMCAAZKkV155JTBe1fN9qO/Dwd/7QYMGadCgQfr6668lVXx/+T4CAAAcvcO5puLqCwAAIEw1b95cDodD3bt3Dxrv1q2bduzYIUlq2bKlysvLlZeXF7RPZmamWrZsWV+lopY98MADcjqdSkpK0vnnn6+5c+dWuW9ZWZlmzpyp6dOnS5JOP/109ejRo54qBQAAwH4EuQAAAGHK6XSqf//+Wr9+fdD4hg0b1L59e0nSiSeeqIiICE2ZMiWwff369dqxY4cGDhxYr/Wi9mRnZ8vj8SgvL08//fSTBg0apJkzZ1baLzIyUpGRkRo0aJBycnI0ePBgfffddzXq4QYAAIDaRZALAADQhBUVFWnZsmVatmyZpIoFq5YtWxaYcfvggw/q888/1/vvv69NmzbpzTff1Hfffafbb79dkpSQkKA///nPGjlypKZNm6bFixfrT3/6kwYOHFjlQmdouG699VbNmTNH+fn5ysjI0F//+ldJksfj0RNPPHHI46dPn66LL75YXq+3rksFAADAQQyzuqVrAQAA0KhNnz5dZ5xxRqXxESNGaNy4cZKkf//733rxxRe1a9cuHXvssXr66ad18cUXB/Z1u926//779dlnn6msrExDhw7V22+/fVitFQoKCpSQkKD8/HwWO6tjgwcP1owZMyRJpaWl1S6g4fV6lZCQoJKSEkVHR6u4uLjSPm63W6tWrdJNN92klStXSpK+/PJLXX755XXzAAAAAMLI4VwnE+QCAACgzhHk1p+qgly/319pMQ2fz6eEhAQVFxcrJiZGRUVFVZ73tdde07333itJevHFF/XII4/UzQMAAAAII4dznUxrBQAAAKCR83g82rdvn/bt2yePxxMYz87O1r59+1RSUqLvvvtOV111laZPn66SkhJlZmbqjjvuCMzCPfXUUwPH3X///frhhx+Unp6usrIyLVu2LDCDW5I6depUb48NAAAAFZiRCwAAgDrHjNy6VVULjf2efPJJ9enTR5deemnI7TExMZo1a5b69u0rSerQoYO2b98ect9+/fppzpw5cjqdR184AABAmGNGLgAAAIAgAwcO1JNPPqkBAwYoJSVFDodDrVq10nXXXafFixcHQlxJuuWWWzRw4MDAfrGxsTrhhBP07LPPatq0aYS4AAAAFmBGLgAAAOocM3IBAACAypiRCwAAAAAAAABNCEEuAAAAAAAAADRwBLkAAAAAAAAA0MAR5AIAAAAAAABAA0eQCwAAAAAAAAANHEEuAAAAAAAAADRwBLkAAAAAAAAA0MAR5AIAAAAAAABAA0eQCwAAAAAAAAANHEEuAAAAAAAAADRwBLkAAAAAAAAA0MA5rC4AAAAAqC8XTrzU6hLQgH13yQSrSwAAAKgSM3KBBmzw4MG69957j/o8N954oy655JKjPg8AAAAAAACsQZAL1LMbb7xRhmHo1ltvrbTtjjvukGEYuvHGGyVJX3/9tZ599tmjvs/XXntN48aNO+rz1NT+x/j3v/89aHzixIkyDCOwT1MNl2srgAcAAAAAANiPIBewQNu2bTV+/HiVlpYGxtxutz799FO1a9cuMJacnKy4uLijvr+EhAQlJiYe9XkOR2RkpEaPHq3c3Nx6vd+aKi8vrzTm8/nk9/stqAYAAAAAAKB6BLmABU444QS1bdtWX3/9dWDs66+/Vrt27dS3b9/A2MEzO99++20dc8wxioyMVGpqqq644orAti+//FI9e/ZUVFSUmjVrpiFDhqi4uFhS5dmvgwcP1t13362HHnpIycnJatmypZ566qmgGtetW6fTTjtNkZGR6t69u3799VcZhqGJEyfW6DEOGTJELVu21IsvvljlPnv27FGPHj1ks9kUHx+vM844I6ieDh066IUXXtBNN92kuLg4xcbGKj4+XpGRkTr++OP1/fffa+fOnbrqqqsUExMju90um82mNm3a6OWXXw66rw4dOujZZ5/V8OHDFR8fr1tuuUXjxo1TYmKivv32W3Xv3l0ul0s7duxQWVmZHnjgAbVu3VoxMTEaMGCApk+fHnS+OXPmaPDgwYqOjlZSUpKGDh2q3Nxc3XjjjZoxY4Zee+01GYYhwzC0bdu2Gj1nAAAAAAAAVSHIBSxy0003aezYsYHb//73v/WnP/2pyv0XLVqku+++W88884zWr1+vSZMm6Q9/+IMkKT09Xddee61uuukmrV27VtOnT9dll10m0zSrPN+HH36omJgYzZ8/X2PGjNEzzzyjyZMnS6qYmXrJJZcoOjpa8+fP13vvvadHH330sB6f3W7XCy+8oDfeeEO7du2qtD07O1sLFy7UNddco379+snj8Wj27Nl6+OGHA/W43W69/PLLOvHEE9WlSxfFxMSouLhY33//vf7+97/LNE0NHTpUZWVlKi0t1R133KELLrhAPp9Pjz32WKV2Ev/4xz/Uu3dvLV26VI8//rgkqaSkRKNHj9a//vUvrV69Wi1atNCdd96puXPnavz48VqxYoWuvPJKnXvuudq4caMkadmyZTrrrLPUvXt3zZ07V7Nnz9aFF14on8+n1157TQMHDtTNN9+s9PR0paenq23btof13AEAAAAAABzMYXUBQLi6/vrrNWrUKG3fvl1SxQzP8ePHV5r5ud+OHTsUExOjP/7xj4qLi1P79u0Ds3fT09Pl9Xp12WWXqX379pKknj17Vnv/vXr10pNPPilJOuaYY/Tmm29qypQpOvvsszV58mRt3rxZ06dPV8uWLSVJzz//vM4+++zDeoyXXnqp+vTpoyeffFIffPBB0LbVq1crJSVFjz/+uKZMmaJ+/fpp4MCB+uijj7R69Wq9+eabWr9+vS666CIdc8wxWrFihdasWaM//OEP2rRpk2699VZ9/PHH8vv9iomJ0ZAhQ/T666+rvLxciYmJ+uMf/6iXXnop0G9Yks4880zdf//9gduzZs2Sx+PR22+/rd69ewee57Fjx2rHjh1KS0uTJD3wwAOaNGmSxo4dqxdeeEFjxoxRv3799PbbbwfO1aNHj8DXTqdT0dHRgecOAAAAAADgaBHkAhZJSUnRBRdcoHHjxsk0TV1wwQVq3rx5lfufffbZat++vTp16qRzzz1X5557ri699FJFR0erd+/eOuuss9SzZ08NHTpU55xzjq644golJSVVeb5evXoF3W7VqpWysrIkSevXr1fbtm2DgsiTTjrpiB7n6NGjdeaZZ+qBBx4IGs/Pz1dKSkpQPaeeeqpeffVV+Xw+tWrVSmvXrlWvXr20bNkytWnTRscee6xatmwZqHP58uXatGmTNm7cKLvdrtjYWEkV/YabNWumjRs3yufzyW63S5L69etXqT6n0xn0XKxcuVI+n09du3YN2q+srEzNmjWTVDEj98orrzyi5wMAAAAAAOBI0FoBsNBNN92kcePG6cMPP9RNN91U7b5xcXFasmSJPvvsM7Vq1UpPPPGEevfurby8PNntdk2ePFk//fSTunfvrjfeeEPHHnustm7dWuX5IiIigm4bhlEnC3394Q9/0NChQzVq1Khq9wtVj2maioiIUFRUVMg6i4qKdOKJJ+q4447TrbfeqmXLlmnZsmXasGFDoO3EgWJiYiqNRUVFyTCMwO2ioiLZ7XYtXrw4cL5ly5Zp7dq1eu211wLHAAAAAAAA1CeCXMBC5557rsrLy+XxeDR06NBD7u9wODRkyBCNGTNGK1as0LZt2zR16lRJFQHnqaeeqqefflpLly6V0+nUhAkTjqiuY489Vjt37lRmZmZgbOHChUd0Lkn6+9//ru+++05z584NjCUkJCgnJydovzlz5qhr166BGbT79erVS7t27dKGDRuCxk844QRt3LhRPXr00Lp169SlS5fAn2XLloU816H07dtXPp9PWVlZQefr0qVLYIZyr169NGXKlCrP4XQ65fP5Dut+AQAAAAAAqkNrBcBCdrtda9euDXxdne+//15btmzRH/7wByUlJenHH3+U3+/Xscceq/nz52vKlCk655xz1KJFC82fP1979+5Vt27djqius88+W507d9aIESM0ZswYFRYW6rHHHpOkoNmrNdWzZ08NGzZMr7/+emCsR48e+v777/Xss8+qpKREa9as0ezZs4P6zu43aNAg/eEPf9Dll1+ukpIS5ebm6qefflJKSoqaN2+uLVu2aMmSJRo5cqT69u2rjz76SLNnz9Y777xz2LV27dpVw4YN0/Dhw/Xyyy+rb9++2rt3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YqIcDofy8/P1r//6r3rkkUciHQ/dxIxcoIdUV1frxRdf1Pe+9z1FRUWddL/f71coFAqXuBs2bFBHR4dWrlypq6++WuvXrw+P3b17t55++mmtXbtWVqs1vH316tV68MEH9eMf/1g2m02vv/66li9frocffljnnXee9uzZoy996UuSpHvuuUehUEgXX3yxGhoa9Nvf/lY5OTn66KOPZLVaNXPmTP34xz/W3XffHV4jx+v19u43CQAAAAAARERaWpp+85vfRDoGzgFFLtBDdu/eLdM0lZeX1+mYdevWadu2bdq3b58yMjIkSU888YTGjBmjd955R1OmTJF0fDmFJ5544qSrRl577bW68cYbw7dXrFihb37zm7r++uslHV/A/L777tPXv/513XPPPXrllVe0adMmbd++Xbm5ueExn4iJiZFhGEpJSemZbwIAAAAAAAB6BUUu0ENM0+xyzPbt25WRkREucSWpoKBAfr9f27dvDxe5WVlZJ5W4kjR58uQTbr/33nvauHFjeJkFSQoGg2ptbVVzc7O2bt2q9PT0cIkLAAAAAACAgYkiF+gho0aNkmEYZ3VBs0871dIMp9re2NioNWvWaMmSJSeNdblccrvd55wFAAAAAAAAkcfFzoAeEhcXp4ULF+qRRx5RU1PTSffX1tYqPz9fZWVlKisrC2//6KOPVFtbq4KCgjN+zKKiIpWUlGjkyJEnfVgsFhUWFurgwYPauXPnKfd3OBwKBoNn/LgAAAAAAADoWxS5QA965JFHFAwGNXXqVD399NPatWuXtm/frocfflgzZsxQcXGxxo0bp2XLlmnLli3atGmTli9frrlz5560bEJ33H333XriiSe0Zs0affjhh9q+fbueeuopfec735EkzZ07V3PmzNHSpUv18ssva9++ffrzn/+sF198UZI0fPhwNTY2at26dTp69Kiam5t79PsBAAAAAACAnkGRC/Sg7OxsbdmyRRdccIHuvPNOjR07VgsWLNC6dev06KOPyjAMPffcc4qNjdWcOXNUXFys7Oxs/eEPfzirx1u4cKFeeOEFvfTSS5oyZYqmT5+uH/3oR8rKygqPefrppzVlyhRdc801Kigo0Ne//vXwLNyZM2fqlltu0dVXX63ExEQ99NBDPfJ9AAAAAAAAQM8yzO5coQkAAAA4B/X19YqJiVFdXZ18Pl/Eclz27BURe2z0f88vfibSEQAAwBBzJr8nMyMXAAAAAAAAAPo5W6QDAAAAYOB45JFH9IMf/EDl5eUaP368fvrTn2rq1KmRjgUMKk3F0yIdAf1c1CtvRzrCcb80Ip0A/d3NvAkc6EnMyAUAAEC3/OEPf9CqVat0zz33aMuWLRo/frwWLlyoysrKSEcDAAAABj1m5AIAAKBb/vVf/1U33XSTbrzxRknSL37xC/3pT3/Sf/zHf+ib3/zmCWPb2trU1tYWvl1XVydJqq2tVSgU6rvQn9LR3BGxx0b/V1tbG+kIkqSmjy9MC3Qm0E/OVbUwIxdd6C/nKtCP1dfXS5K6cxkzilwAAAB0qb29XZs3b9Zdd90V3maxWFRcXKw333zzpPEPPPCA1qxZc9L2rKysXs0JnItYxUY6AtA9sZyrGCC+yrkKdFdDQ4NiYmJOO4YiFwAAAF06evSogsGgkpOTT9ienJysHTt2nDT+rrvu0qpVq8K3Q6GQqqurFR8fL8NgBld/UF9fr4yMDJWVlXV5hWQgkjhXMVBwrmKg4FztX0zTVENDg1JTU7scS5ELAACAHud0OuV0Ok/Y5vf7IxMGp+Xz+fgjDgMC5yoGCs5VDBScq/1HVzNxP8HFzgAAANClhIQEWa1WVVRUnLC9oqJCKSkpEUoFAAAADB0UuQAAAOiSw+HQpEmTtG7duvC2UCikdevWacaMGRFMBgAAAAwNLK0AAACAblm1apWuv/56TZ48WVOnTtWPf/xjNTU16cYbb4x0NJwFp9Ope+6556QlMID+hnMVAwXnKgYKztWByzBN04x0CAAAAAwMP/vZz/SDH/xA5eXlmjBhgh5++GFNmzYt0rEAAACAQY8iFwAAAAAAAAD6OdbIBQAAAAAAAIB+jiIXAAAAAAAAAPo5ilwAAAAAAAAA6OcocgEAAAAAAIAB6Pzzz9cdd9xxzse54YYbtHjx4nM+DnoXRS4AAADQj5WXl+u2225Tdna2nE6nMjIydNlll2ndunWRjnaSxx9/XH6/P9Ix0IsG8x/6PVWGYOC64YYbZBiGHnzwwRO2P/vsszIMI0KpMBR9ci7ecsstJ923cuVKGYahG264QZK0du1a3Xfffef8mD/5yU/0+OOPn/Nx0LsocgEAAIB+av/+/Zo0aZJeffVV/eAHP9C2bdv04osv6oILLtDKlSvP6pjt7e2n3B4IBM4lKtAnTnX+BoNBhUKhCKTBYORyufT9739fNTU1kY6CIS4jI0NPPfWUWlpawttaW1v15JNPKjMzM7wtLi5O0dHR5/x4MTExvBg7AFDkAgAAAP3Ul7/8ZRmGoU2bNmnp0qXKzc3VmDFjtGrVKr311luSpNLSUi1atEher1c+n09XXXWVKioqwsdYvXq1JkyYoF//+tcaMWKEXC6XJMkwDD366KO6/PLLFRUVpe9973uSpOeee05FRUVyuVzKzs7WmjVr1NHRET5ebW2tbr75ZiUnJ8vlcmns2LF64YUXtH79et14442qq6uTYRgyDEOrV6/uu28W+tz555+vr3zlK/r617+uuLg4paSknPTvvLPz5RNPP/20xowZI6fTqeHDh+uHP/zhCfsPHz5c9913n5YvXy6fz6cvfelL4Znf//M//6OCggI5nU6Vlpaqra1NX/va15SWlqaoqChNmzZN69evP+F4Gzdu1Pnnny+Px6PY2FgtXLhQNTU1uuGGG7Rhwwb95Cc/CZ+/+/fv76XvHPqz4uJipaSk6IEHHuh0THfO2/vvv18rVqxQdHS0MjMz9atf/eqEMWVlZbrqqqvk9/sVFxenRYsWcc7hBEVFRcrIyNDatWvD29auXavMzExNnDgxvO3T7yb4+c9/rlGjRsnlcik5OVmf/exnw/f993//t8aNGye32634+HgVFxerqalJ0snvuOjOz/gdO3Zo9uzZcrlcKigo0CuvvCLDMPTss8/26PcCf0eRCwAAAPRD1dXVevHFF7Vy5UpFRUWddL/f71coFNKiRYtUXV2tDRs26OWXX9bevXt19dVXnzB29+7devrpp7V27Vpt3bo1vH316tW64oortG3bNq1YsUKvv/66li9frttvv10fffSRfvnLX+rxxx8Pl7yhUEgXX3yxNm7cqN/+9rf66KOP9OCDD8pqtWrmzJn68Y9/LJ/PpyNHjujIkSP62te+1qvfI0Teb37zG0VFRentt9/WQw89pHvvvVcvv/yypNOfL5K0efNmXXXVVfrc5z6nbdu2afXq1frud7970lt7/+Vf/kXjx4/Xu+++q+9+97uSpObmZn3/+9/Xr3/9a3344YdKSkrSrbfeqjfffFNPPfWU3n//fV155ZW66KKLtGvXLknS1q1bNX/+fBUUFOjNN9/UX//6V1122WUKBoP6yU9+ohkzZuimm24Kn78ZGRl9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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "# ๊ฒฐ๊ณผ ๋ถ„ํฌ ํŒŒ์ด ์ฐจํŠธ\n", + "fig, axes = plt.subplots(1, 2, figsize=(15, 6))\n", + "\n", + "# Pie Chart 1: Overall Results\n", + "labels = ['Correct', 'Incorrect', 'None', 'Missing']\n", + "sizes = [correct_count, wrong_count, none_count, missing_count]\n", + "colors = ['#4CAF50', '#F44336', '#FF9800', '#9E9E9E']\n", + "explode = (0.1, 0, 0, 0)\n", + "\n", + "axes[0].pie(\n", + " sizes, explode=explode, labels=labels, colors=colors,\n", + " autopct='%1.1f%%', shadow=True, startangle=90\n", + ")\n", + "axes[0].set_title('Overall Result Distribution', fontsize=14, fontweight='bold')\n", + "\n", + "# Bar Chart: Counts\n", + "categories = ['Correct', 'Incorrect', 'None', 'Missing']\n", + "counts = [correct_count, wrong_count, none_count, missing_count]\n", + "axes[1].bar(categories, counts, color=colors)\n", + "axes[1].set_ylabel('Count', fontsize=12)\n", + "axes[1].set_title('Result Counts', fontsize=14, fontweight='bold')\n", + "axes[1].grid(axis='y', alpha=0.3)\n", + "\n", + "# Add value labels\n", + "for i, v in enumerate(counts):\n", + " axes[1].text(i, v + max(counts) * 0.02, str(v),\n", + " ha='center', va='bottom', fontsize=11, fontweight='bold')\n", + "\n", + "plt.tight_layout()\n", + "plt.savefig(output_dir / 'accuracy_visualization.png', dpi=300, bbox_inches='tight')\n", + "print(f\"\\n๐Ÿ“Š Visualization saved: {output_dir / 'accuracy_visualization.png'}\")\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ถ„์„" + ] + }, + { + "cell_type": "code", + "execution_count": 173, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "๐Ÿ” ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ถ„์„ (์ด 0๊ฐœ)\n", + "============================================================\n", + "\n", + "โœ… ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!\n" + ] + } + ], + "source": [ + "# ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ (์ •๋‹ต์ง€์—๋Š” ์žˆ์ง€๋งŒ results์— ์—†๋Š” ๊ฒฝ์šฐ)\n", + "missing_df = merged_df[merged_df['result'] == 'missing'].copy()\n", + "\n", + "print(\"=\"*60)\n", + "print(f\"๐Ÿ” ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ถ„์„ (์ด {len(missing_df)}๊ฐœ)\")\n", + "print(\"=\"*60)\n", + "\n", + "if len(missing_df) > 0:\n", + " print(\"\\n๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ชฉ๋ก:\")\n", + " display(missing_df[['page_number', 'problem_number', 'correct_answer']].sort_values(['page_number', 'problem_number']))\n", + " \n", + " # ํŽ˜์ด์ง€๋ณ„ ๋ˆ„๋ฝ ํ†ต๊ณ„\n", + " print(\"\\n๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ ๋ˆ„๋ฝ ํ†ต๊ณ„:\")\n", + " page_missing = missing_df.groupby('page_number').size().reset_index(name='missing_count')\n", + " page_missing = page_missing.sort_values('missing_count', ascending=False)\n", + " display(page_missing)\n", + "else:\n", + " print(\"\\nโœ… ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. None ๋‹ต์•ˆ ๋ถ„์„" + ] + }, + { + "cell_type": "code", + "execution_count": 174, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "โš ๏ธ None ๋‹ต์•ˆ ๋ถ„์„ (์ด 1๊ฐœ)\n", + "============================================================\n", + "\n", + "None์œผ๋กœ ์ธ์‹๋œ ๋ฌธ์ œ ๋ชฉ๋ก:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberproblem_numbercorrect_answerimage_file
113105044แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18
\n", + "
" + ], + "text/plain": [ + " page_number problem_number correct_answer \\\n", + "113 105 04 4 \n", + "\n", + " image_file \n", + "113 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ None ํ†ต๊ณ„:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numbernone_count
01051
\n", + "
" + ], + "text/plain": [ + " page_number none_count\n", + "0 105 1" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# None์œผ๋กœ ์ธ์‹๋œ ๋ฌธ์ œ\n", + "none_df = merged_df[merged_df['result'] == 'none'].copy()\n", + "\n", + "print(\"=\"*60)\n", + "print(f\"โš ๏ธ None ๋‹ต์•ˆ ๋ถ„์„ (์ด {len(none_df)}๊ฐœ)\")\n", + "print(\"=\"*60)\n", + "\n", + "if len(none_df) > 0:\n", + " print(\"\\nNone์œผ๋กœ ์ธ์‹๋œ ๋ฌธ์ œ ๋ชฉ๋ก:\")\n", + " display(none_df[['page_number', 'problem_number', 'correct_answer', 'image_file']].sort_values(['page_number', 'problem_number']))\n", + " \n", + " # ํŽ˜์ด์ง€๋ณ„ None ํ†ต๊ณ„\n", + " print(\"\\n๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ None ํ†ต๊ณ„:\")\n", + " page_none = none_df.groupby('page_number').size().reset_index(name='none_count')\n", + " page_none = page_none.sort_values('none_count', ascending=False)\n", + " display(page_none)\n", + "else:\n", + " print(\"\\nโœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 9. ์˜ค๋‹ต ๋ถ„์„" + ] + }, + { + "cell_type": "code", + "execution_count": 175, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "โŒ ์˜ค๋‹ต ๋ถ„์„ (์ด 1๊ฐœ)\n", + "============================================================\n", + "\n", + "์˜ค๋‹ต ๋ชฉ๋ก:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberproblem_numbercorrect_answerpredicted_answerimage_file
49670553แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 50
\n", + "
" + ], + "text/plain": [ + " page_number problem_number correct_answer predicted_answer \\\n", + "49 67 05 5 3 \n", + "\n", + " image_file \n", + "49 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 50 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ ์˜ค๋‹ต ํ†ต๊ณ„:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberwrong_count
0671
\n", + "
" + ], + "text/plain": [ + " page_number wrong_count\n", + "0 67 1" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ์˜ค๋‹ต\n", + "wrong_df = merged_df[merged_df['result'] == 'wrong'].copy()\n", + "\n", + "print(\"=\"*60)\n", + "print(f\"โŒ ์˜ค๋‹ต ๋ถ„์„ (์ด {len(wrong_df)}๊ฐœ)\")\n", + "print(\"=\"*60)\n", + "\n", + "if len(wrong_df) > 0:\n", + " print(\"\\n์˜ค๋‹ต ๋ชฉ๋ก:\")\n", + " display(wrong_df[['page_number', 'problem_number', 'correct_answer', 'predicted_answer', 'image_file']].sort_values(['page_number', 'problem_number']))\n", + " \n", + " # ํŽ˜์ด์ง€๋ณ„ ์˜ค๋‹ต ํ†ต๊ณ„\n", + " print(\"\\n๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ ์˜ค๋‹ต ํ†ต๊ณ„:\")\n", + " page_wrong = wrong_df.groupby('page_number').size().reset_index(name='wrong_count')\n", + " page_wrong = page_wrong.sort_values('wrong_count', ascending=False)\n", + " display(page_wrong.head(10))\n", + "else:\n", + " print(\"\\nโœ… ์˜ค๋‹ต์ด ์—†์Šต๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 10. ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„" + ] + }, + { + "cell_type": "code", + "execution_count": 176, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "๐Ÿ“Š ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„\n", + "============================================================\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
totalcorrectwrongnonemissingaccuracy
page_number
1011000100.0
10022000100.0
10122000100.0
10222000100.0
10322000100.0
.....................
9522000100.0
9922000100.0
9722000100.0
1055401080.0
67101000.0
\n", + "

96 rows ร— 6 columns

\n", + "
" + ], + "text/plain": [ + " total correct wrong none missing accuracy\n", + "page_number \n", + "10 1 1 0 0 0 100.0\n", + "100 2 2 0 0 0 100.0\n", + "101 2 2 0 0 0 100.0\n", + "102 2 2 0 0 0 100.0\n", + "103 2 2 0 0 0 100.0\n", + "... ... ... ... ... ... ...\n", + "95 2 2 0 0 0 100.0\n", + "99 2 2 0 0 0 100.0\n", + "97 2 2 0 0 0 100.0\n", + "105 5 4 0 1 0 80.0\n", + "67 1 0 1 0 0 0.0\n", + "\n", + "[96 rows x 6 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "โš ๏ธ ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ํŽ˜์ด์ง€ (80% ๋ฏธ๋งŒ):\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
totalcorrectwrongnonemissingaccuracy
page_number
67101000.0
\n", + "
" + ], + "text/plain": [ + " total correct wrong none missing accuracy\n", + "page_number \n", + "67 1 0 1 0 0 0.0" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„ ๊ณ„์‚ฐ\n", + "page_stats = merged_df.groupby('page_number').agg({\n", + " 'result': 'count',\n", + "}).rename(columns={'result': 'total'})\n", + "\n", + "page_stats['correct'] = merged_df[merged_df['result'] == 'correct'].groupby('page_number').size()\n", + "page_stats['wrong'] = merged_df[merged_df['result'] == 'wrong'].groupby('page_number').size()\n", + "page_stats['none'] = merged_df[merged_df['result'] == 'none'].groupby('page_number').size()\n", + "page_stats['missing'] = merged_df[merged_df['result'] == 'missing'].groupby('page_number').size()\n", + "\n", + "page_stats = page_stats.fillna(0).astype(int)\n", + "page_stats['accuracy'] = (page_stats['correct'] / page_stats['total'] * 100).round(2)\n", + "page_stats = page_stats.sort_values('accuracy', ascending=False)\n", + "\n", + "print(\"=\"*60)\n", + "print(\"๐Ÿ“Š ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„\")\n", + "print(\"=\"*60)\n", + "display(page_stats)\n", + "\n", + "# ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ํŽ˜์ด์ง€\n", + "print(\"\\nโš ๏ธ ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ํŽ˜์ด์ง€ (80% ๋ฏธ๋งŒ):\")\n", + "low_accuracy_pages = page_stats[page_stats['accuracy'] < 80]\n", + "if len(low_accuracy_pages) > 0:\n", + " display(low_accuracy_pages)\n", + "else:\n", + " print(\"โœ… ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ 80% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋ณด์ž…๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 11. ๊ฒฐ๊ณผ ์ €์žฅ" + ] + }, + { + "cell_type": "code", + "execution_count": 177, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ’พ ์ƒ์„ธ ๋น„๊ต ๊ฒฐ๊ณผ ์ €์žฅ: detailed_comparison.csv\n", + "๐Ÿ’พ ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„ ์ €์žฅ: page_statistics.csv\n", + "๐Ÿ’พ ์š”์•ฝ ๋ฆฌํฌํŠธ ์ €์žฅ: accuracy_summary.txt\n", + "\n", + "============================================================\n", + "โœ… ๋ชจ๋“  ๋ถ„์„์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\n", + "============================================================\n" + ] + } + ], + "source": [ + "# ์ƒ์„ธ ๊ฒฐ๊ณผ ์ €์žฅ\n", + "detailed_results_path = output_dir / \"detailed_comparison.csv\"\n", + "merged_df.to_csv(detailed_results_path, index=False, encoding='utf-8-sig')\n", + "print(f\"\\n๐Ÿ’พ ์ƒ์„ธ ๋น„๊ต ๊ฒฐ๊ณผ ์ €์žฅ: {detailed_results_path}\")\n", + "\n", + "# ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„ ์ €์žฅ\n", + "page_stats_path = output_dir / \"page_statistics.csv\"\n", + "page_stats.to_csv(page_stats_path, encoding='utf-8-sig')\n", + "print(f\"๐Ÿ’พ ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„ ์ €์žฅ: {page_stats_path}\")\n", + "\n", + "# ์š”์•ฝ ๋ฆฌํฌํŠธ ์ €์žฅ\n", + "summary_path = output_dir / \"accuracy_summary.txt\"\n", + "with open(summary_path, 'w', encoding='utf-8') as f:\n", + " f.write(\"=\"*60 + \"\\n\")\n", + " f.write(\"YOLO ๋‹ต์•ˆ ์ธ์‹ ์ •ํ™•๋„ ๋ถ„์„ ๋ณด๊ณ ์„œ\\n\")\n", + " f.write(\"=\"*60 + \"\\n\\n\")\n", + " \n", + " f.write(\"๐Ÿ“Š ์ „์ฒด ํ†ต๊ณ„\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " f.write(f\"์ด ๋ฌธ์ œ ์ˆ˜: {total_count}๊ฐœ\\n\")\n", + " f.write(f\"์ •๋‹ต: {correct_count}๊ฐœ ({correct_count/total_count*100:.2f}%)\\n\")\n", + " f.write(f\"์˜ค๋‹ต: {wrong_count}๊ฐœ ({wrong_count/total_count*100:.2f}%)\\n\")\n", + " f.write(f\"None: {none_count}๊ฐœ ({none_count/total_count*100:.2f}%)\\n\")\n", + " f.write(f\"๋ˆ„๋ฝ: {missing_count}๊ฐœ ({missing_count/total_count*100:.2f}%)\\n\\n\")\n", + " \n", + " f.write(\"=\"*60 + \"\\n\")\n", + " f.write(f\"๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: {accuracy:.2f}%\\n\")\n", + " f.write(f\"๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): {recognition_rate:.2f}%\\n\")\n", + " f.write(f\"โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„: {accuracy_of_recognized:.2f}%\\n\")\n", + " f.write(\"=\"*60 + \"\\n\\n\")\n", + " \n", + " if len(missing_df) > 0:\n", + " f.write(f\"\\n๐Ÿ” ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ: {len(missing_df)}๊ฐœ\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for _, row in missing_df.iterrows():\n", + " f.write(f\"ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}, ์ •๋‹ต {row['correct_answer']}\\n\")\n", + " \n", + " if len(none_df) > 0:\n", + " f.write(f\"\\nโš ๏ธ None ๋‹ต์•ˆ: {len(none_df)}๊ฐœ\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for _, row in none_df.head(20).iterrows():\n", + " f.write(f\"ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}, ์ •๋‹ต {row['correct_answer']}\\n\")\n", + " if len(none_df) > 20:\n", + " f.write(f\"... ์™ธ {len(none_df)-20}๊ฐœ\\n\")\n", + " \n", + " if len(wrong_df) > 0:\n", + " f.write(f\"\\nโŒ ์˜ค๋‹ต: {len(wrong_df)}๊ฐœ\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for _, row in wrong_df.head(20).iterrows():\n", + " f.write(f\"ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}, ์ •๋‹ต {row['correct_answer']}, ์˜ˆ์ธก {row['predicted_answer']}\\n\")\n", + " if len(wrong_df) > 20:\n", + " f.write(f\"... ์™ธ {len(wrong_df)-20}๊ฐœ\\n\")\n", + "\n", + "print(f\"๐Ÿ’พ ์š”์•ฝ ๋ฆฌํฌํŠธ ์ €์žฅ: {summary_path}\")\n", + "\n", + "print(\"\\n\" + \"=\"*60)\n", + "print(\"โœ… ๋ชจ๋“  ๋ถ„์„์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\")\n", + "print(\"=\"*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 12. ์ตœ์ข… ์š”์•ฝ" + ] + }, + { + "cell_type": "code", + "execution_count": 178, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "\n", + "# ๐Ÿ“Š ์ตœ์ข… ๋ถ„์„ ์š”์•ฝ\n", + "\n", + "## ๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: **98.71%**\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ˆ ์ฃผ์š” ์ง€ํ‘œ\n", + "- **์ธ์‹ ์„ฑ๊ณต๋ฅ **: 100.00% (๋ˆ„๋ฝ ์ œ์™ธ)\n", + "- **์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„**: 98.71%\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“Š ์ƒ์„ธ ํ†ต๊ณ„\n", + "| ๊ตฌ๋ถ„ | ๊ฐœ์ˆ˜ | ๋น„์œจ |\n", + "|------|------|------|\n", + "| โœ… ์ •๋‹ต | 153๊ฐœ | 98.71% |\n", + "| โŒ ์˜ค๋‹ต | 1๊ฐœ | 0.65% |\n", + "| โš ๏ธ None | 1๊ฐœ | 0.65% |\n", + "| ๐Ÿ” ๋ˆ„๋ฝ | 0๊ฐœ | 0.00% |\n", + "| **๐Ÿ“˜ ์ „์ฒด** | **155๊ฐœ** | **100.00%** |\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ’ก ๊ฐœ์„  ํฌ์ธํŠธ\n", + "\n", + "- โš ๏ธ **None ๋‹ต์•ˆ ๊ฐœ์„ **: 1๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ธ์‹๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. `none_debug_analysis.txt` ํŒŒ์ผ์„ ํ™•์ธํ•˜์„ธ์š”.\n", + "- โŒ **์˜ค๋‹ต ๋ถ„์„**: 1๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ž˜๋ชป ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค. IoU threshold๋‚˜ ๋ชจ๋ธ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•˜์„ธ์š”.\n", + "\n", + "### ๐ŸŽ‰ ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ!\n", + "95% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค!\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ ์ƒ์„ฑ๋œ ํŒŒ์ผ\n", + "- `detailed_comparison.csv`: ์ „์ฒด ๋น„๊ต ๊ฒฐ๊ณผ\n", + "- `page_statistics.csv`: ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„\n", + "- `accuracy_summary.txt`: ์š”์•ฝ ๋ฆฌํฌํŠธ\n", + "- `accuracy_visualization.png`: ์‹œ๊ฐํ™” ์ฐจํŠธ\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Markdown, display\n", + "\n", + "summary_md = f\"\"\"\n", + "# ๐Ÿ“Š ์ตœ์ข… ๋ถ„์„ ์š”์•ฝ\n", + "\n", + "## ๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: **{accuracy:.2f}%**\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ˆ ์ฃผ์š” ์ง€ํ‘œ\n", + "- **์ธ์‹ ์„ฑ๊ณต๋ฅ **: {recognition_rate:.2f}% (๋ˆ„๋ฝ ์ œ์™ธ)\n", + "- **์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„**: {accuracy_of_recognized:.2f}%\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“Š ์ƒ์„ธ ํ†ต๊ณ„\n", + "| ๊ตฌ๋ถ„ | ๊ฐœ์ˆ˜ | ๋น„์œจ |\n", + "|------|------|------|\n", + "| โœ… ์ •๋‹ต | {correct_count}๊ฐœ | {correct_count/total_count*100:.2f}% |\n", + "| โŒ ์˜ค๋‹ต | {wrong_count}๊ฐœ | {wrong_count/total_count*100:.2f}% |\n", + "| โš ๏ธ None | {none_count}๊ฐœ | {none_count/total_count*100:.2f}% |\n", + "| ๐Ÿ” ๋ˆ„๋ฝ | {missing_count}๊ฐœ | {missing_count/total_count*100:.2f}% |\n", + "| **๐Ÿ“˜ ์ „์ฒด** | **{total_count}๊ฐœ** | **100.00%** |\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ’ก ๊ฐœ์„  ํฌ์ธํŠธ\n", + "\"\"\" \n", + "\n", + "if missing_count > 0:\n", + " summary_md += f\"\\n- ๐Ÿ” **๋ˆ„๋ฝ ๋ฌธ์ œ ํ•ด๊ฒฐ**: {missing_count}๊ฐœ ๋ฌธ์ œ๊ฐ€ results์— ์—†์Šต๋‹ˆ๋‹ค. Section ๊ฒ€์ถœ ๋ฌธ์ œ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\"\n", + "\n", + "if none_count > 0:\n", + " summary_md += f\"\\n- โš ๏ธ **None ๋‹ต์•ˆ ๊ฐœ์„ **: {none_count}๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ธ์‹๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. `none_debug_analysis.txt` ํŒŒ์ผ์„ ํ™•์ธํ•˜์„ธ์š”.\"\n", + "\n", + "if wrong_count > 0:\n", + " summary_md += f\"\\n- โŒ **์˜ค๋‹ต ๋ถ„์„**: {wrong_count}๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ž˜๋ชป ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค. IoU threshold๋‚˜ ๋ชจ๋ธ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•˜์„ธ์š”.\"\n", + "\n", + "if accuracy >= 95:\n", + " summary_md += \"\\n\\n### ๐ŸŽ‰ ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ!\"\n", + " summary_md += \"\\n95% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค!\"\n", + "elif accuracy >= 90:\n", + " summary_md += \"\\n\\n### ๐Ÿ‘ ์–‘ํ˜ธํ•œ ์„ฑ๋Šฅ\"\n", + " summary_md += \"\\n90% ์ด์ƒ์˜ ์ •ํ™•๋„์ž…๋‹ˆ๋‹ค. ์กฐ๊ธˆ ๋” ๊ฐœ์„ ํ•˜๋ฉด ๋” ์ข‹์Šต๋‹ˆ๋‹ค!\"\n", + "else:\n", + " summary_md += \"\\n\\n### ๐Ÿ”ง ๊ฐœ์„  ํ•„์š”\"\n", + " summary_md += \"\\n์ •ํ™•๋„๊ฐ€ 90% ๋ฏธ๋งŒ์ž…๋‹ˆ๋‹ค. ์œ„์˜ ๊ฐœ์„  ํฌ์ธํŠธ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋ชจ๋ธ์„ ๊ฐœ์„ ํ•˜์„ธ์š”.\"\n", + "\n", + "summary_md += f\"\"\"\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ ์ƒ์„ฑ๋œ ํŒŒ์ผ\n", + "- `detailed_comparison.csv`: ์ „์ฒด ๋น„๊ต ๊ฒฐ๊ณผ\n", + "- `page_statistics.csv`: ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„\n", + "- `accuracy_summary.txt`: ์š”์•ฝ ๋ฆฌํฌํŠธ\n", + "- `accuracy_visualization.png`: ์‹œ๊ฐํ™” ์ฐจํŠธ\n", + "\"\"\"\n", + "\n", + "display(Markdown(summary_md))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ocr", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.13" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/ai-service/test/YOLO/answers/accuracy_summary.txt b/ai-service/test/YOLO/answers/accuracy_summary.txt new file mode 100644 index 0000000..6a155d2 --- /dev/null +++ b/ai-service/test/YOLO/answers/accuracy_summary.txt @@ -0,0 +1,26 @@ +============================================================ +YOLO ๋‹ต์•ˆ ์ธ์‹ ์ •ํ™•๋„ ๋ถ„์„ ๋ณด๊ณ ์„œ +============================================================ + +๐Ÿ“Š ์ „์ฒด ํ†ต๊ณ„ +------------------------------------------------------------ +์ด ๋ฌธ์ œ ์ˆ˜: 155๊ฐœ +์ •๋‹ต: 153๊ฐœ (98.71%) +์˜ค๋‹ต: 1๊ฐœ (0.65%) +None: 1๊ฐœ (0.65%) +๋ˆ„๋ฝ: 0๊ฐœ (0.00%) + +============================================================ +๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: 98.71% +๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): 100.00% +โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„: 98.71% +============================================================ + + +โš ๏ธ None ๋‹ต์•ˆ: 1๊ฐœ +------------------------------------------------------------ +ํŽ˜์ด์ง€ 105, ๋ฌธ์ œ 04, ์ •๋‹ต 4 + +โŒ ์˜ค๋‹ต: 1๊ฐœ +------------------------------------------------------------ +ํŽ˜์ด์ง€ 67, ๋ฌธ์ œ 05, ์ •๋‹ต 5, ์˜ˆ์ธก 3 diff --git a/ai-service/test/YOLO/answers/answer.txt b/ai-service/test/YOLO/answers/answer.txt new file mode 100644 index 0000000..db6a69c --- /dev/null +++ b/ai-service/test/YOLO/answers/answer.txt @@ -0,0 +1,290 @@ +9, 01, 4 +10, 02, 4 +11, 03, 3 +12, 04, 5 +13, 05, 4 +15, 01, 1 +16, 02, 3 +17, 03, 5 +18, 04, 5 +19, 05, 5 +21, 01, 3 +22, 02, 1 +23, 03, 1 +24, 04, 5 +25, 05, 5 +27, 01, 1 +28, 02, 5 +29, 03, 5 +30, 04, 1 +31, 05, 3 +33, 01, 3 +34, 02, 4 +35, 03, 3 +36, 04, 5 +37, 05, 2 +39, 01, 4 +40, 02, 4 +41, 03, 4 +42, 04, 3 +43, 05, 3 +45, 01, 3 +46, 02, 1 +47, 03, 4 +48, 04, 2 +49, 05, 2 +51, 01, 1 +52, 02, 3 +53, 03, 1 +54, 04, 2 +55, 05, 4 +57, 01, 4 +58, 02, 3 +59, 03, 4 +60, 04, 4 +61, 05, 3 +63, 01, 4 +64, 02, 3 +65, 03, 2 +66, 04, 4 +67, 05, 4 +69, 01, 3 +70, 02, 5 +71, 03, 5 +72, 04, 4 +73, 05, 3 +75, 01, 4 +76, 02, 4 +77, 03, 2 +78, 04, 3 +79, 05, 2 +83, 01, 5 +83, 02, 1 +85, 03, 4 +85, 04, 5 +85, 05, 2 +88, 01, 1 +88, 02, 3 +88, 03, 2 +88, 04, 5 +88, 05, 2 +89, 06, 3 +89, 07, 2 +89, 08, 3 +89, 09, 2 +89, 10, 4 +90, 11, 5 +90, 12, 1 +90, 13, 1 +90, 14, 3 +90, 15, 4 +91, 16, 5 +91, 17, 3 +91, 18, 5 +92, 19, 1 +92, 20, 2 +93, 21, 1 +93, 22, 1 +94, 23, 2 +94, 24, 1 +95, 25, 5 +95, 26, 4 +96, 27, 4 +96, 28, 5 +97, 29, 4 +97, 30, 3 +98, 31, 1 +98, 32, 3 +99, 33, 2 +99, 34, 1 +100, 35, 3 +100, 36, 4 +101, 37, 5 +101, 38, 4 +102, 39, 4 +102, 40, 1 +103, 41, 4 +103, 42, 5 +104, 43, 5 +104, 44, 3 +104, 45, 2 +105, 01, 2 +105, 02, 3 +105, 03, 3 +105, 04, 4 +105, 05, 2 +106, 06, 4 +106, 07, 5 +106, 08, 3 +106, 09, 5 +106, 10, 4 +107, 11, 2 +107, 12, 1 +107, 13, 1 +107, 14, 1 +107, 15, 3 +108, 16, 4 +108, 17, 4 +108, 18, 5 +109, 19, 1 +109, 20, 3 +110, 21, 5 +110, 22, 1 +111, 23, 5 +111, 24, 2 +112, 25, 4 +112, 26, 2 +113, 27, 4 +113, 28, 4 +114, 29, 3 +114, 30, 4 +115, 31, 2 +115, 32, 2 +116, 33, 1 +116, 34, 1 +117, 35, 3 +117, 36, 2 +118, 37, 5 +118, 38, 3 +119, 39, 3 +119, 40, 4 +120, 41, 4 +120, 42, 4 +121, 43, 4 +121, 44, 2 +121, 45, 5 +122, 01, 5 +122, 02, 3 +122, 03, 2 +122, 04, 5 +122, 05, 3 +123, 06, 3 +123, 07, 1 +123, 08, 4 +123, 09, 4 +123, 10, 3 +124, 11, 5 +124, 12, 4 +124, 13, 5 +124, 14, 3 +124, 15, 5 +125, 16, 3 +125, 17, 4 +125, 18, 1 +126, 19, 2 +126, 20, 1 +127, 21, 2 +127, 22, 1 +128, 23, 1 +128, 24, 1 +129, 25, 5 +129, 26, 4 +130, 27, 4 +130, 28, 5 +131, 29, 3 +131, 30, 4 +132, 31, 2 +132, 32, 2 +133, 33, 3 +133, 34, 1 +134, 35, 4 +134, 36, 4 +135, 37, 2 +135, 38, 5 +136, 39, 4 +136, 40, 1 +137, 41, 2 +137, 42, 5 +138, 43, 5 +138, 44, 3 +138, 45, 4 +139, 01, 1 +139, 02, 2 +139, 03, 5 +139, 04, 3 +139, 05, 1 +140, 06, 5 +140, 07, 2 +140, 08, 5 +140, 09, 5 +140, 10, 1 +141, 11, 1 +141, 12, 2 +141, 13, 4 +141, 14, 5 +141, 15, 2 +142, 16, 1 +142, 17, 3 +142, 18, 3 +143, 19, 2 +143, 20, 4 +144, 21, 4 +144, 22, 1 +145, 23, 4 +145, 24, 2 +146, 25, 5 +146, 26, 5 +147, 27, 4 +147, 28, 3 +148, 29, 4 +148, 30, 3 +149, 31, 4 +149, 32, 2 +150, 33, 4 +150, 34, 2 +151, 35, 4 +151, 36, 4 +152, 37, 3 +152, 38, 3 +153, 39, 3 +153, 40, 1 +154, 41, 1 +154, 42, 5 +155, 43, 2 +155, 44, 2 +155, 45, 2 +156, 01, 1 +156, 02, 1 +156, 03, 3 +156, 04, 3 +156, 05, 3 +157, 06, 2 +157, 07, 4 +157, 08, 4 +157, 09, 4 +157, 10, 4 +158, 11, 1 +158, 12, 2 +158, 13, 4 +158, 14, 5 +158, 15, 5 +159, 16, 4 +159, 17, 3 +159, 18, 5 +160, 19, 3 +160, 20, 1 +161, 21, 3 +161, 22, 2 +162, 23, 1 +162, 24, 1 +163, 25, 3 +163, 26, 4 +164, 27, 4 +164, 28, 5 +165, 29, 4 +165, 30, 5 +166, 31, 2 +166, 32, 5 +167, 33, 3 +167, 34, 2 +168, 35, 4 +168, 36, 5 +169, 37, 1 +169, 38, 3 +170, 39, 2 +170, 40, 2 +171, 41, 5 +171, 42, 5 +172, 43, 2 +172, 44, 2 +172, 45, 3 \ No newline at end of file diff --git a/ai-service/test/YOLO/answers/crop_failure_analysis.txt b/ai-service/test/YOLO/answers/crop_failure_analysis.txt new file mode 100644 index 0000000..e8355dc --- /dev/null +++ b/ai-service/test/YOLO/answers/crop_failure_analysis.txt @@ -0,0 +1,6 @@ +================================================================================ +Section Crop ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„ +================================================================================ + +โœ… ๋ชจ๋“  Section์ด ์ •์ƒ์ ์œผ๋กœ crop๋˜์—ˆ์Šต๋‹ˆ๋‹ค! + diff --git a/ai-service/test/YOLO/answers/detailed_comparison.csv b/ai-service/test/YOLO/answers/detailed_comparison.csv new file mode 100644 index 0000000..67c2348 --- /dev/null +++ b/ai-service/test/YOLO/answers/detailed_comparison.csv @@ -0,0 +1,156 @@ +๏ปฟpage_number,problem_number,correct_answer,image_file,predicted_answer,_merge,result +9,01,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1,1,both,correct +10,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2,2,both,correct +11,03,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3,2,both,correct +12,04,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4,4,both,correct +13,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5,1,both,correct +15,01,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6,4,both,correct +16,02,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7,5,both,correct +17,03,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8,1,both,correct +18,04,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9,3,both,correct +19,05,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10,2,both,correct +21,01,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11,1,both,correct +22,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 12,2,both,correct +23,03,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 13,4,both,correct +24,04,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14,1,both,correct +25,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 15,1,both,correct +27,01,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 16,3,both,correct +28,02,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 17,4,both,correct +29,03,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 18,4,both,correct +30,04,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 19,2,both,correct +31,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 20,1,both,correct +33,01,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 21,5,both,correct +34,02,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 22,1,both,correct +35,03,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 23,2,both,correct +36,04,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 24,1,both,correct +37,05,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 25,3,both,correct +39,01,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 26,2,both,correct +40,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 27,2,both,correct +41,03,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 28,5,both,correct +42,04,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 29,1,both,correct +43,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 30,1,both,correct +45,01,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 31,2,both,correct +46,02,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 32,5,both,correct +47,03,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 33,2,both,correct +48,04,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 34,3,both,correct +49,05,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 35,4,both,correct +51,01,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 36,5,both,correct +52,02,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 37,1,both,correct +53,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 38,3,both,correct +54,04,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 39,4,both,correct +55,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 40,1,both,correct +57,01,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 41,1,both,correct +58,02,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 42,5,both,correct +59,03,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 43,1,both,correct +60,04,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 44,5,both,correct +61,05,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 45,4,both,correct +63,01,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 46,2,both,correct +64,02,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 47,4,both,correct +65,03,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 48,5,both,correct +66,04,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 49,1,both,correct +67,05,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 50,3,both,wrong +69,01,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 51,5,both,correct +70,02,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 52,4,both,correct +71,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 53,3,both,correct +72,04,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 54,5,both,correct +73,05,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 55,5,both,correct +75,01,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 56,3,both,correct +76,02,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 57,5,both,correct +77,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 58,3,both,correct +78,04,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 59,2,both,correct +79,05,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 60,3,both,correct +83,01,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62,4,both,correct +83,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62,2,both,correct +85,03,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64,5,both,correct +85,04,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64,3,both,correct +85,05,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64,4,both,correct +88,01,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,4,both,correct +88,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,2,both,correct +88,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,3,both,correct +88,04,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,3,both,correct +88,05,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,3,both,correct +89,06,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,4,both,correct +89,07,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,3,both,correct +89,08,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,1,both,correct +89,09,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,4,both,correct +89,10,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,2,both,correct +90,11,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,4,both,correct +90,12,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,3,both,correct +90,13,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,3,both,correct +90,14,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,2,both,correct +90,15,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,3,both,correct +91,16,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4,3,both,correct +91,17,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4,2,both,correct +91,18,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4,3,both,correct +92,19,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5,4,both,correct +92,20,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5,3,both,correct +93,21,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6,5,both,correct +93,22,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6,4,both,correct +94,23,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7,3,both,correct +94,24,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7,2,both,correct +95,25,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8,2,both,correct +95,26,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8,5,both,correct +96,27,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9,5,both,correct +96,28,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9,2,both,correct +97,29,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10,3,both,correct +97,30,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10,2,both,correct +98,31,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11,3,both,correct +98,32,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11,5,both,correct +99,33,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12,3,both,correct +99,34,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12,4,both,correct +100,35,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13,4,both,correct +100,36,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13,3,both,correct +101,37,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14,2,both,correct +101,38,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14,5,both,correct +102,39,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15,3,both,correct +102,40,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15,2,both,correct +103,41,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16,5,both,correct +103,42,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16,2,both,correct +104,43,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17,4,both,correct +104,44,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17,2,both,correct +104,45,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17,1,both,correct +105,01,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,2,both,correct +105,02,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,3,both,correct +105,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,3,both,correct +105,04,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,,both,none +105,05,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,2,both,correct +106,06,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,4,both,correct +106,07,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,5,both,correct +106,08,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,3,both,correct +106,09,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,5,both,correct +106,10,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,4,both,correct +107,11,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,2,both,correct +107,12,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,1,both,correct +107,13,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,1,both,correct +107,14,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,1,both,correct +107,15,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,3,both,correct +108,16,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21,4,both,correct +108,17,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21,4,both,correct +108,18,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21,5,both,correct +109,19,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22,1,both,correct +109,20,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22,3,both,correct +110,21,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23,5,both,correct +110,22,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23,1,both,correct +111,23,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24,5,both,correct +111,24,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24,2,both,correct +112,25,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25,4,both,correct +112,26,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25,2,both,correct +113,27,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26,4,both,correct +113,28,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26,4,both,correct +114,29,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27,3,both,correct +114,30,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27,4,both,correct +115,31,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28,2,both,correct +115,32,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28,2,both,correct +116,33,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29,1,both,correct +116,34,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29,1,both,correct +117,35,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30,3,both,correct +117,36,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30,2,both,correct +118,37,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31,5,both,correct +118,38,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31,3,both,correct +119,39,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32,3,both,correct +119,40,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32,4,both,correct +120,41,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33,4,both,correct +120,42,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33,4,both,correct +121,43,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34,4,both,correct +121,44,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34,2,both,correct +121,45,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34,5,both,correct diff --git a/ai-service/test/YOLO/answers/missing_sections_analysis.txt b/ai-service/test/YOLO/answers/missing_sections_analysis.txt new file mode 100644 index 0000000..ad429e8 --- /dev/null +++ b/ai-service/test/YOLO/answers/missing_sections_analysis.txt @@ -0,0 +1,5 @@ +================================================================================ +๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ Section ๋ถ„์„ +================================================================================ + +โœ… ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ๋ฌธ์ œ ์ˆ˜๊ฐ€ ๋‹ต์ง€์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค! diff --git a/ai-service/test/YOLO/answers/none_debug_analysis.txt b/ai-service/test/YOLO/answers/none_debug_analysis.txt new file mode 100644 index 0000000..1f4ce6b --- /dev/null +++ b/ai-service/test/YOLO/answers/none_debug_analysis.txt @@ -0,0 +1,35 @@ +================================================================================ +None ๋‹ต์•ˆ ๋””๋ฒ„๊น… ๋ถ„์„ +================================================================================ + +์ด 1๊ฐœ์˜ None ๋‹ต์•ˆ ๋ฐœ๊ฒฌ + +๐Ÿ“Š ์›์ธ๋ณ„ ํ†ต๊ณ„: + - answer_1 ๋ฏธ๊ฒ€์ถœ: 0๊ฐœ (0.0%) + - ์ˆซ์ž(1-5) ๋ฏธ๊ฒ€์ถœ: 0๊ฐœ (0.0%) + - IoU 0 (์œ„์น˜ ๋ถˆ์ผ์น˜): 1๊ฐœ (100.0%) + + +================================================================================ +[1] ํŽ˜์ด์ง€: แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18 (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: 105) + Section: 0, ๋ฌธ์ œ๋ฒˆํ˜ธ: 04 +-------------------------------------------------------------------------------- + ๐Ÿ“‹ ๊ฒ€์ถœ ์ •๋ณด: + answer_1 ๊ฒ€์ถœ ๊ฐœ์ˆ˜: 2 + ์ˆซ์ž(1-5) ๊ฒ€์ถœ ๊ฐœ์ˆ˜: 3 + ์ตœ๊ณ  IoU: 0.0000 + + ๐Ÿ” ์›์ธ ๋ถ„์„: + โŒ IoU๊ฐ€ 0 (answer_1๊ณผ ์ˆซ์ž์˜ ์œ„์น˜๊ฐ€ ๊ฒน์น˜์ง€ ์•Š์Œ) + โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: + 1. section padding์„ 50 โ†’ 70 ๋˜๋Š” 100์œผ๋กœ ์ฆ๊ฐ€ + 2. ๊ฒ€์ถœ ์œ„์น˜๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ โ†’ ๋ชจ๋ธ ์žฌํ•™์Šต + + ๐Ÿ“ IoU ์ƒ์„ธ ์ •๋ณด: + - ์ˆซ์ž 2: IoU = 0.0000, bbox = [1243.9910888671875, 743.727783203125, 1286.1524658203125, 787.7964477539062] + - ์ˆซ์ž 1: IoU = 0.0000, bbox = [1506.6593017578125, 654.8740844726562, 1544.8289794921875, 693.9087524414062] + - ์ˆซ์ž 3: IoU = 0.0000, bbox = [1307.9222412109375, 935.8869018554688, 1344.872314453125, 973.0953369140625] + + ๐Ÿ“ ๊ด€๋ จ ํŒŒ์ผ: + Section ์ด๋ฏธ์ง€: /home/yerim/workspace/Gradi_25Fall/ai-service/test/YOLO/images/test_results/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18/sections/section_00.jpg + ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€: /home/yerim/workspace/Gradi_25Fall/ai-service/test/YOLO/images/test_results/แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18/problem_numbers/section_00_problem_number.jpg diff --git a/ai-service/test/YOLO/answers/page_statistics.csv b/ai-service/test/YOLO/answers/page_statistics.csv new file mode 100644 index 0000000..b19c673 --- /dev/null +++ b/ai-service/test/YOLO/answers/page_statistics.csv @@ -0,0 +1,97 @@ +๏ปฟpage_number,total,correct,wrong,none,missing,accuracy +10,1,1,0,0,0,100.0 +100,2,2,0,0,0,100.0 +101,2,2,0,0,0,100.0 +102,2,2,0,0,0,100.0 +103,2,2,0,0,0,100.0 +104,3,3,0,0,0,100.0 +106,5,5,0,0,0,100.0 +107,5,5,0,0,0,100.0 +110,2,2,0,0,0,100.0 +108,3,3,0,0,0,100.0 +109,2,2,0,0,0,100.0 +11,1,1,0,0,0,100.0 +112,2,2,0,0,0,100.0 +111,2,2,0,0,0,100.0 +113,2,2,0,0,0,100.0 +114,2,2,0,0,0,100.0 +121,3,3,0,0,0,100.0 +115,2,2,0,0,0,100.0 +116,2,2,0,0,0,100.0 +117,2,2,0,0,0,100.0 +118,2,2,0,0,0,100.0 +119,2,2,0,0,0,100.0 +12,1,1,0,0,0,100.0 +120,2,2,0,0,0,100.0 +17,1,1,0,0,0,100.0 +13,1,1,0,0,0,100.0 +15,1,1,0,0,0,100.0 +16,1,1,0,0,0,100.0 +19,1,1,0,0,0,100.0 +18,1,1,0,0,0,100.0 +21,1,1,0,0,0,100.0 +22,1,1,0,0,0,100.0 +60,1,1,0,0,0,100.0 +23,1,1,0,0,0,100.0 +24,1,1,0,0,0,100.0 +25,1,1,0,0,0,100.0 +27,1,1,0,0,0,100.0 +28,1,1,0,0,0,100.0 +29,1,1,0,0,0,100.0 +30,1,1,0,0,0,100.0 +31,1,1,0,0,0,100.0 +33,1,1,0,0,0,100.0 +34,1,1,0,0,0,100.0 +35,1,1,0,0,0,100.0 +36,1,1,0,0,0,100.0 +37,1,1,0,0,0,100.0 +39,1,1,0,0,0,100.0 +40,1,1,0,0,0,100.0 +41,1,1,0,0,0,100.0 +42,1,1,0,0,0,100.0 +43,1,1,0,0,0,100.0 +45,1,1,0,0,0,100.0 +46,1,1,0,0,0,100.0 +47,1,1,0,0,0,100.0 +48,1,1,0,0,0,100.0 +49,1,1,0,0,0,100.0 +51,1,1,0,0,0,100.0 +52,1,1,0,0,0,100.0 +53,1,1,0,0,0,100.0 +54,1,1,0,0,0,100.0 +55,1,1,0,0,0,100.0 +57,1,1,0,0,0,100.0 +58,1,1,0,0,0,100.0 +59,1,1,0,0,0,100.0 +92,2,2,0,0,0,100.0 +61,1,1,0,0,0,100.0 +63,1,1,0,0,0,100.0 +64,1,1,0,0,0,100.0 +65,1,1,0,0,0,100.0 +66,1,1,0,0,0,100.0 +69,1,1,0,0,0,100.0 +70,1,1,0,0,0,100.0 +75,1,1,0,0,0,100.0 +71,1,1,0,0,0,100.0 +72,1,1,0,0,0,100.0 +73,1,1,0,0,0,100.0 +77,1,1,0,0,0,100.0 +76,1,1,0,0,0,100.0 +78,1,1,0,0,0,100.0 +79,1,1,0,0,0,100.0 +96,2,2,0,0,0,100.0 +83,2,2,0,0,0,100.0 +85,3,3,0,0,0,100.0 +88,5,5,0,0,0,100.0 +89,5,5,0,0,0,100.0 +9,1,1,0,0,0,100.0 +90,5,5,0,0,0,100.0 +91,3,3,0,0,0,100.0 +98,2,2,0,0,0,100.0 +93,2,2,0,0,0,100.0 +94,2,2,0,0,0,100.0 +95,2,2,0,0,0,100.0 +99,2,2,0,0,0,100.0 +97,2,2,0,0,0,100.0 +105,5,4,0,1,0,80.0 +67,1,0,1,0,0,0.0 diff --git a/ai-service/test/YOLO/answers/results_summary.txt b/ai-service/test/YOLO/answers/results_summary.txt new file mode 100644 index 0000000..0f95a44 --- /dev/null +++ b/ai-service/test/YOLO/answers/results_summary.txt @@ -0,0 +1,155 @@ +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10, 97, 29, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10, 97, 30, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11, 98, 32, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11, 98, 31, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12, 99, 34, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12, 99, 33, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13, 100, 35, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13, 100, 36, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14, 101, 37, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14, 101, 38, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15, 102, 40, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15, 102, 39, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16, 103, 41, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16, 103, 42, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17, 104, 43, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17, 104, 44, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17, 104, 45, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 04, None +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 02, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 05, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 09, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 06, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 07, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 10, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 08, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 09, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 06, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 07, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 10, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 08, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 14, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 11, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 12, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 13, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 15, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21, 108, 18, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21, 108, 16, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21, 108, 17, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22, 109, 20, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22, 109, 19, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23, 110, 21, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23, 110, 22, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24, 111, 24, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24, 111, 23, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25, 112, 25, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25, 112, 26, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26, 113, 27, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26, 113, 28, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27, 114, 30, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27, 114, 29, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28, 115, 32, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28, 115, 31, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29, 116, 34, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29, 116, 33, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 14, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 11, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 12, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 15, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 13, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30, 117, 35, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30, 117, 36, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31, 118, 37, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31, 118, 38, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32, 119, 39, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32, 119, 40, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33, 120, 41, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33, 120, 42, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34, 121, 43, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34, 121, 44, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34, 121, 45, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4, 91, 18, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4, 91, 16, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4, 91, 17, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5, 92, 20, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5, 92, 19, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6, 93, 22, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6, 93, 21, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7, 94, 24, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7, 94, 23, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8, 95, 26, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8, 95, 25, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9, 96, 28, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9, 96, 27, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1, 9, 01, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10, 19, 05, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11, 21, 01, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 12, 22, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 13, 23, 03, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14, 24, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 15, 25, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 16, 27, 01, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 17, 28, 02, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 18, 29, 03, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 19, 30, 04, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2, 10, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 20, 31, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 21, 33, 01, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 22, 34, 02, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 23, 35, 03, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 24, 36, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 25, 37, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 26, 39, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 27, 40, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 28, 41, 03, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 29, 42, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3, 11, 03, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 30, 43, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 31, 45, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 32, 46, 02, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 33, 47, 03, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 34, 48, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 35, 49, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 36, 51, 01, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 37, 52, 02, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 38, 53, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 39, 54, 04, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4, 12, 04, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 40, 55, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 41, 57, 01, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 42, 58, 02, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 43, 59, 03, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 44, 60, 04, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 45, 61, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 46, 63, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 47, 64, 02, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 48, 65, 03, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 49, 66, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5, 13, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 50, 67, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 51, 69, 01, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 52, 70, 02, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 53, 71, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 54, 72, 04, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 55, 73, 05, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 56, 75, 01, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 57, 76, 02, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 58, 77, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 59, 78, 04, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6, 15, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 60, 79, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62, 83, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62, 83, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64, 85, 03, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64, 85, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64, 85, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7, 16, 02, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8, 17, 03, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9, 18, 04, 3 diff --git a/ai-service/test/YOLO/answers/yolo_answer.txt b/ai-service/test/YOLO/answers/yolo_answer.txt new file mode 100644 index 0000000..4d5bf1a --- /dev/null +++ b/ai-service/test/YOLO/answers/yolo_answer.txt @@ -0,0 +1,155 @@ +9, 01, 1 +10, 02, 2 +11, 03, 2 +12, 04, 4 +13, 05, 1 +15, 01, 4 +16, 02, 5 +17, 03, 1 +18, 04, 3 +19, 05, 2 +21, 01, 1 +22, 02, 2 +23, 03, 4 +24, 04, 1 +25, 05, 1 +27, 01, 3 +28, 02, 4 +29, 03, 4 +30, 04, 2 +31, 05, 1 +33, 01, 5 +34, 02, 1 +35, 03, 2 +36, 04, 1 +37, 05, 3 +39, 01, 2 +40, 02, 2 +41, 03, 5 +42, 04, 1 +43, 05, 1 +45, 01, 2 +46, 02, 5 +47, 03, 2 +48, 04, 3 +49, 05, 4 +51, 01, 5 +52, 02, 1 +53, 03, 3 +54, 04, 4 +55, 05, 1 +57, 01, 1 +58, 02, 5 +59, 03, 1 +60, 04, 5 +61, 05, 4 +63, 01, 2 +64, 02, 4 +65, 03, 5 +66, 04, 1 +67, 05, 5 +69, 01, 5 +70, 02, 4 +71, 03, 3 +72, 04, 5 +73, 05, 5 +75, 01, 3 +76, 02, 5 +77, 03, 3 +78, 04, 2 +79, 05, 3 +83, 01, 4 +83, 02, 2 +85, 03, 5 +85, 04, 3 +85, 05, 4 +88, 01, 4 +88, 02, 2 +88, 03, 3 +88, 04, 3 +88, 05, 3 +89, 06, 4 +89, 07, 3 +89, 08, 1 +89, 09, 4 +89, 10, 2 +90, 11, 4 +90, 12, 3 +90, 13, 3 +90, 14, 2 +90, 15, 3 +91, 16, 3 +91, 17, 2 +91, 18, 3 +92, 19, 4 +92, 20, 3 +93, 21, 5 +93, 22, 4 +94, 23, 3 +94, 24, 2 +95, 25, 2 +95, 26, 5 +96, 27, 5 +96, 28, 2 +97, 29, 3 +97, 30, 2 +98, 31, 3 +98, 32, 5 +99, 33, 3 +99, 34, 4 +100, 35, 4 +100, 36, 3 +101, 37, 2 +101, 38, 5 +102, 39, 3 +102, 40, 2 +103, 41, 5 +103, 42, 2 +104, 43, 4 +104, 44, 2 +104, 45, 1 +105, 01, 2 +105, 02, 3 +105, 03, 3 +105, 04, 4 +105, 05, 2 +106, 06, 4 +106, 07, 5 +106, 08, 3 +106, 09, 5 +106, 10, 4 +107, 11, 2 +107, 12, 1 +107, 13, 1 +107, 14, 1 +107, 15, 3 +108, 16, 4 +108, 17, 4 +108, 18, 5 +109, 19, 1 +109, 20, 3 +110, 21, 5 +110, 22, 1 +111, 23, 5 +111, 24, 2 +112, 25, 4 +112, 26, 2 +113, 27, 4 +113, 28, 4 +114, 29, 3 +114, 30, 4 +115, 31, 2 +115, 32, 2 +116, 33, 1 +116, 34, 1 +117, 35, 3 +117, 36, 2 +118, 37, 5 +118, 38, 3 +119, 39, 3 +119, 40, 4 +120, 41, 4 +120, 42, 4 +121, 43, 4 +121, 44, 2 +121, 45, 5 \ No newline at end of file diff --git a/ai-service/test/YOLO/yolo_test.py b/ai-service/test/YOLO/yolo_test.py new file mode 100644 index 0000000..b1ad0fe --- /dev/null +++ b/ai-service/test/YOLO/yolo_test.py @@ -0,0 +1,722 @@ +# yolo_test.py +import logging +import time +from pathlib import Path +from test.YOLO.yolo_test_crop import HierarchicalCropPipeline + +# === ๋กœ๊น… ์„ค์ • === +current_dir = Path(__file__).parent +log_file = current_dir / "ocr_results.log" + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + +# ํŒŒ์ผ ์ถœ๋ ฅ ์ถ”๊ฐ€ (utf-8 ์ธ์ฝ”๋”ฉ) +file_handler = logging.FileHandler(log_file, encoding="utf-8") +file_handler.setLevel(logging.INFO) +file_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") +file_handler.setFormatter(file_formatter) +logger.addHandler(file_handler) + +logger.info(f"โœ… ๋กœ๊ทธ ํŒŒ์ผ์ด '{log_file}'๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.") + + +def main(): + """๋ฉ”์ธ ์‹คํ—˜ ํ•จ์ˆ˜""" + total_start_time = time.time() + + # ๊ฒฝ๋กœ ์„ค์ • + input_images_dir = current_dir / "images" / "exp_images" + output_dir = current_dir / "images" / "test_results" + model_dir_1104 = current_dir.parent.parent / "models" / "Detection" / "legacy" / "Model_routing_1104" + model_dir_1004 = current_dir.parent.parent / "models" / "Detection" / "legacy" / "Model_routing_1004" + + # ๋‹ต์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ + answer_key_path = current_dir / "answers" / "answer.txt" + + # ๋‹ต์ง€ ํŒŒ์ผ์ด ์—†์œผ๋ฉด None์œผ๋กœ ์„ค์ • (๋ชจ๋“  ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ) + if not answer_key_path.exists(): + logger.warning(f"๋‹ต์ง€ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {answer_key_path}") + logger.warning("๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.") + answer_key_path = None + + logger.info("=" * 60) + logger.info("๊ณ„์ธต์  ํฌ๋กญ ํŒŒ์ดํ”„๋ผ์ธ (๊ฐœ์„  ๋ฒ„์ „) ์‹คํ—˜ ์‹œ์ž‘") + logger.info("=" * 60) + logger.info(f"์ž…๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ: {input_images_dir}") + logger.info(f"์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ: {output_dir}") + logger.info(f"1104 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ: {model_dir_1104}") + logger.info(f"1004 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ: {model_dir_1004}") + logger.info(f"๋‹ต์ง€ ํŒŒ์ผ: {answer_key_path}") + + # ํŒŒ์ดํ”„๋ผ์ธ ์ดˆ๊ธฐํ™” + pipeline = HierarchicalCropPipeline( + str(model_dir_1104), + str(model_dir_1004), + section_padding=50, + answer_key_path=str(answer_key_path) if answer_key_path else None + ) + + # ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ˆ˜์ง‘ + image_extensions = [".jpg", ".jpeg", ".png", ".bmp"] + image_files = [] + for ext in image_extensions: + image_files.extend(input_images_dir.glob(f"*{ext}")) + image_files.extend(input_images_dir.glob(f"*{ext.upper()}")) + + image_files = sorted(image_files) + logger.info(f"\n์ฒ˜๋ฆฌํ•  ์ด๋ฏธ์ง€: {len(image_files)}๊ฐœ") + + if not image_files: + logger.warning(f"์ž…๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ์— ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค: {input_images_dir}") + return + + # ๊ฐ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ + all_results = [] + skipped_pages = [] + + for idx, image_path in enumerate(image_files): + logger.info(f"\n\n{'#' * 60}") + logger.info(f"[{idx + 1}/{len(image_files)}] ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘: {Path(image_path).name}") + logger.info(f"{'#' * 60}") + + try: + result = pipeline.process_page(str(image_path), output_dir) + + if result is None: + # ๋‹ต์ง€์— ์—†๋Š” ํŽ˜์ด์ง€ + skipped_pages.append(Path(image_path).name) + logger.info(f"โญ๏ธ ํŽ˜์ด์ง€ ๊ฑด๋„ˆ๋œ€ (๋‹ต์ง€์— ์—†์Œ)") + else: + all_results.append(result) + logger.info(f"โœ… ํŽ˜์ด์ง€ '{result['page_name']}' ์ฒ˜๋ฆฌ ์™„๋ฃŒ: {result['processing_time']:.2f}์ดˆ") + except Exception as e: + logger.error(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์‹คํŒจ: {image_path}") + logger.error(f"์—๋Ÿฌ: {e}", exc_info=True) + continue + + total_end_time = time.time() + total_processing_time = total_end_time - total_start_time + + # ์š”์•ฝ ๋ฐ ๊ฒฐ๊ณผ ์ €์žฅ + print_summary(all_results, skipped_pages, output_dir, total_processing_time) + save_results_txt(all_results, output_dir) + save_none_analysis(all_results, output_dir) + save_crop_failure_analysis(all_results, output_dir) + check_missing_sections_against_answer_key(all_results, output_dir, pipeline.answer_key) # โœจ ๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ ๊ฒ€์ถœ ์ถ”๊ฐ€ + + +def save_results_txt(all_results: list, output_dir: Path): + """ + TXT ํŒŒ์ผ์— ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ์ธ์‹๋œ ๋‹ต์„ ํ•œ ์ค„์”ฉ ์ €์žฅ + """ + txt_path = output_dir.parent.parent / "answers" / "results_summary.txt" + output_dir.mkdir(parents=True, exist_ok=True) + + if not all_results: + logger.warning("โš ๏ธ ์ €์žฅํ•  ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.") + return + + with open(txt_path, "w", encoding="utf-8") as f: + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + for section in sections: + problem_number = section.get("problem_number_ocr", "") + answer_number = section.get("answer_number", "") + + # ์ด๋ฏธ์ง€ ํŒŒ์ผ๋ช…, ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ๋‹ต ๋ฒˆํ˜ธ๋ฅผ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ํ•œ ์ค„์— ์ž‘์„ฑ + line = f"{page_name}, {page_num_ocr}, {problem_number}, {answer_number}\n" + f.write(line) + + logger.info(f"\n๐Ÿ“„ TXT ๊ฒฐ๊ณผ ์ €์žฅ ์™„๋ฃŒ: {txt_path}") + + # ์ด ๋ผ์ธ ์ˆ˜ ๊ณ„์‚ฐ + total_lines = sum(len(r.get("sections", [])) for r in all_results) + logger.info(f"์ด {total_lines}๊ฐœ ๋ฌธ์ œ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") + + # None ๋‹ต์•ˆ ํ†ต๊ณ„ + none_count = 0 + for result in all_results: + for section in result.get("sections", []): + if section.get("answer_number") is None: + none_count += 1 + + logger.info(f"None ๋‹ต์•ˆ: {none_count}๊ฐœ ({none_count/total_lines*100:.1f}%)") + + +def save_none_analysis(all_results: list, output_dir: Path): + """ + None์œผ๋กœ ์ €์žฅ๋œ ๋‹ต์•ˆ์˜ ์ƒ์„ธ ๋””๋ฒ„๊น… ์ •๋ณด๋ฅผ ๋ณ„๋„ ํŒŒ์ผ๋กœ ์ €์žฅ + """ + analysis_path = output_dir.parent.parent / "answers" / "none_debug_analysis.txt" + + none_cases = [] + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + for section in sections: + if section.get("answer_number") is None: + debug_info = section.get("debug_info", {}) + none_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'section_idx': section.get('section_idx'), + 'problem_number': section.get('problem_number_ocr'), + 'debug_info': debug_info, + 'section_crop_path': section.get('section_crop_path'), + 'problem_crop_path': section.get('problem_crop_path') + }) + + if not none_cases: + logger.info("โœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค!") + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("None ๋‹ต์•ˆ ๋””๋ฒ„๊น… ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write("โœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค! ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n") + return + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("None ๋‹ต์•ˆ ๋””๋ฒ„๊น… ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write(f"์ด {len(none_cases)}๊ฐœ์˜ None ๋‹ต์•ˆ ๋ฐœ๊ฒฌ\n\n") + + # ์›์ธ๋ณ„ ํ†ต๊ณ„ + answer_1_missing = sum(1 for case in none_cases if case['debug_info'].get('answer_1_count', 0) == 0) + class_missing = sum(1 for case in none_cases if case['debug_info'].get('class_count', 0) == 0) + iou_zero = sum(1 for case in none_cases + if case['debug_info'].get('answer_1_count', 0) > 0 + and case['debug_info'].get('class_count', 0) > 0 + and case['debug_info'].get('best_iou', 0) == 0) + + f.write("๐Ÿ“Š ์›์ธ๋ณ„ ํ†ต๊ณ„:\n") + f.write(f" - answer_1 ๋ฏธ๊ฒ€์ถœ: {answer_1_missing}๊ฐœ ({answer_1_missing/len(none_cases)*100:.1f}%)\n") + f.write(f" - ์ˆซ์ž(1-5) ๋ฏธ๊ฒ€์ถœ: {class_missing}๊ฐœ ({class_missing/len(none_cases)*100:.1f}%)\n") + f.write(f" - IoU 0 (์œ„์น˜ ๋ถˆ์ผ์น˜): {iou_zero}๊ฐœ ({iou_zero/len(none_cases)*100:.1f}%)\n") + f.write("\n") + + for i, case in enumerate(none_cases, 1): + f.write(f"\n{'='*80}\n") + f.write(f"[{i}] ํŽ˜์ด์ง€: {case['page_name']} (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: {case['page_num']})\n") + f.write(f" Section: {case['section_idx']}, ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['problem_number']}\n") + f.write(f"{'-'*80}\n") + + debug = case['debug_info'] + answer_1_count = debug.get('answer_1_count', 0) + class_count = debug.get('class_count', 0) + best_iou = debug.get('best_iou', 0.0) + + f.write(f" ๐Ÿ“‹ ๊ฒ€์ถœ ์ •๋ณด:\n") + f.write(f" answer_1 ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {answer_1_count}\n") + f.write(f" ์ˆซ์ž(1-5) ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {class_count}\n") + f.write(f" ์ตœ๊ณ  IoU: {best_iou:.4f}\n\n") + + # ์›์ธ ๋ถ„์„ + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + if answer_1_count == 0: + f.write(f" โŒ answer_1์ด ๊ฒ€์ถœ๋˜์ง€ ์•Š์Œ (1104 ๋ชจ๋ธ ๋ฌธ์ œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: 1104 ๋ชจ๋ธ ์žฌํ•™์Šต ๋˜๋Š” confidence threshold ์กฐ์ •\n") + elif class_count == 0: + f.write(f" โŒ ์ˆซ์ž(1-5)๊ฐ€ ๊ฒ€์ถœ๋˜์ง€ ์•Š์Œ (1104 ๋ชจ๋ธ ๋ฌธ์ œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: 1104 ๋ชจ๋ธ ์žฌํ•™์Šต ๋˜๋Š” confidence threshold ์กฐ์ •\n") + elif best_iou == 0.0: + f.write(f" โŒ IoU๊ฐ€ 0 (answer_1๊ณผ ์ˆซ์ž์˜ ์œ„์น˜๊ฐ€ ๊ฒน์น˜์ง€ ์•Š์Œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: \n") + f.write(f" 1. section padding์„ 50 โ†’ 70 ๋˜๋Š” 100์œผ๋กœ ์ฆ๊ฐ€\n") + f.write(f" 2. ๊ฒ€์ถœ ์œ„์น˜๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ โ†’ ๋ชจ๋ธ ์žฌํ•™์Šต\n") + else: + f.write(f" โš ๏ธ ์›์ธ ๋ถˆ๋ช… (๋””๋ฒ„๊น… ํ•„์š”)\n") + + # IoU ์ƒ์„ธ ์ •๋ณด + iou_details = debug.get('iou_details', []) + if iou_details: + f.write(f"\n ๐Ÿ“ IoU ์ƒ์„ธ ์ •๋ณด:\n") + for detail in iou_details: + f.write(f" - ์ˆซ์ž {detail['class']}: IoU = {detail['iou']:.4f}, bbox = {detail['bbox']}\n") + + # ํŒŒ์ผ ๊ฒฝ๋กœ + f.write(f"\n ๐Ÿ“ ๊ด€๋ จ ํŒŒ์ผ:\n") + f.write(f" Section ์ด๋ฏธ์ง€: {case['section_crop_path']}\n") + if case['problem_crop_path']: + f.write(f" ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€: {case['problem_crop_path']}\n") + else: + f.write(f" ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€: (๋ฏธ์ƒ์„ฑ - ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ)\n") + + logger.info(f"๐Ÿ“Š None ๋””๋ฒ„๊น… ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + logger.info(f" ์ด {len(none_cases)}๊ฐœ None ์ผ€์ด์Šค ๋ถ„์„") + logger.info(f" ์›์ธ๋ณ„: answer_1 ๋ฏธ๊ฒ€์ถœ={answer_1_missing}, ์ˆซ์ž ๋ฏธ๊ฒ€์ถœ={class_missing}, IoU=0={iou_zero}") + + +def save_crop_failure_analysis(all_results: list, output_dir: Path): + """ + Section crop ์‹คํŒจ ์ผ€์ด์Šค๋ฅผ ๋ถ„์„ํ•˜์—ฌ ๋ณ„๋„ ํŒŒ์ผ๋กœ ์ €์žฅ + + ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ ๋ชฉ๋ก์„ ๊ฒ€์ฆ + """ + analysis_path = output_dir.parent.parent / "answers" / "crop_failure_analysis.txt" + + crop_failure_cases = [] + total_expected_sections = 0 + total_actual_files = 0 + duplicate_removed_count = 0 # ์ค‘๋ณต ์ œ๊ฑฐ ๊ฐœ์ˆ˜ + + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + # ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ ํ™•์ธ + sections_dir = output_dir / page_name / "sections" + actual_files = [] + if sections_dir.exists(): + actual_files = sorted(sections_dir.glob("section_*.jpg")) + total_actual_files += len(actual_files) + + total_expected_sections += len(sections) + + for section in sections: + if not section.get("crop_success", True): + crop_failure_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'section_idx': section.get('section_idx'), + 'failure_reason': section.get('crop_failure_reason', 'unknown'), + 'debug_info': section.get('debug_info', {}), + 'expected_path': section.get('section_crop_path') + }) + + # ์˜ˆ์ƒ ๊ฐœ์ˆ˜์™€ ์‹ค์ œ ํŒŒ์ผ ๊ฐœ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ๊ฒฝ์šฐ ๊ฒฝ๊ณ  + if len(sections) != len(actual_files): + logger.warning(f"โš ๏ธ ํŽ˜์ด์ง€ '{page_name}': ์˜ˆ์ƒ section ๊ฐœ์ˆ˜({len(sections)}) โ‰  ์‹ค์ œ ํŒŒ์ผ ๊ฐœ์ˆ˜({len(actual_files)})") + logger.warning(f" ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ: {[f.name for f in actual_files]}") + + # ๋ˆ„๋ฝ๋œ section ์ฐพ๊ธฐ + expected_indices = set(s.get('section_idx') for s in sections) + actual_indices = set(int(f.stem.split('_')[1]) for f in actual_files if f.stem.startswith('section_')) + missing_indices = expected_indices - actual_indices + + if missing_indices: + logger.error(f" โŒ ๋ˆ„๋ฝ๋œ section ์ธ๋ฑ์Šค: {sorted(missing_indices)}") + + # ๋ˆ„๋ฝ๋œ section์„ failure case์— ์ถ”๊ฐ€ + for idx in missing_indices: + matching_sections = [s for s in sections if s.get('section_idx') == idx] + if matching_sections: + section = matching_sections[0] + if section.get('crop_success', True): # crop_success=True์ธ๋ฐ ํŒŒ์ผ์ด ์—†๋Š” ๊ฒฝ์šฐ + crop_failure_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'section_idx': idx, + 'failure_reason': 'file_not_found_despite_success', + 'debug_info': section.get('debug_info', {}), + 'expected_path': section.get('section_crop_path') + }) + + logger.info(f"\n๐Ÿ“Š Section ํŒŒ์ผ ๊ฒ€์ฆ:") + logger.info(f" ์˜ˆ์ƒ section ์ด ๊ฐœ์ˆ˜: {total_expected_sections}") + logger.info(f" ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ ๊ฐœ์ˆ˜: {total_actual_files}") + logger.info(f" ์ค‘๋ณต ์ œ๊ฑฐ๋œ section: {duplicate_removed_count}๊ฐœ") + + if total_expected_sections != total_actual_files: + logger.error(f" โŒ ๋ถˆ์ผ์น˜ ๋ฐœ๊ฒฌ: {total_expected_sections - total_actual_files}๊ฐœ ํŒŒ์ผ ๋ˆ„๋ฝ") + else: + logger.info(f" โœ… ๋ชจ๋“  section ํŒŒ์ผ์ด ์ •์ƒ์ ์œผ๋กœ ์ €์žฅ๋จ") + + if not crop_failure_cases: + logger.info("โœ… Section crop ์‹คํŒจ ์ผ€์ด์Šค๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!") + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("Section Crop ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + if total_expected_sections == total_actual_files: + f.write("โœ… ๋ชจ๋“  Section์ด ์ •์ƒ์ ์œผ๋กœ crop๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\n\n") + if duplicate_removed_count > 0: + f.write(f"๐Ÿ“Š ์ค‘๋ณต ์ œ๊ฑฐ ํ†ต๊ณ„:\n") + f.write(f" - ์ค‘๋ณต์œผ๋กœ ์ œ๊ฑฐ๋œ section: {duplicate_removed_count}๊ฐœ\n") + f.write(f" - ๊ฐ™์€ ๋ฌธ์ œ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ง„ section ์ค‘ ๋” ํฐ ๊ฒƒ๋งŒ ์„ ํƒ๋จ\n") + else: + f.write(f"โš ๏ธ ์ผ๋ถ€ ํŒŒ์ผ์ด ๋ˆ„๋ฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n") + f.write(f" ์˜ˆ์ƒ: {total_expected_sections}๊ฐœ\n") + f.write(f" ์‹ค์ œ: {total_actual_files}๊ฐœ\n") + f.write(f" ๋ˆ„๋ฝ: {total_expected_sections - total_actual_files}๊ฐœ\n") + if duplicate_removed_count > 0: + f.write(f"\n๐Ÿ“Š ์ค‘๋ณต ์ œ๊ฑฐ ํ†ต๊ณ„:\n") + f.write(f" - ์ค‘๋ณต์œผ๋กœ ์ œ๊ฑฐ๋œ section: {duplicate_removed_count}๊ฐœ\n") + return + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("Section Crop ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write(f"์ด {len(crop_failure_cases)}๊ฐœ์˜ Section crop ์‹คํŒจ ๋ฐœ๊ฒฌ\n") + + if duplicate_removed_count > 0: + f.write(f"\n๐Ÿ“Š ์ค‘๋ณต ์ œ๊ฑฐ ํ†ต๊ณ„:\n") + f.write(f" - ์ค‘๋ณต์œผ๋กœ ์ œ๊ฑฐ๋œ section: {duplicate_removed_count}๊ฐœ\n") + f.write(f" - ๊ฐ™์€ ๋ฌธ์ œ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ง„ section ์ค‘ ๋” ํฐ ๊ฒƒ๋งŒ ์„ ํƒ๋จ\n") + + f.write("\n") + + # ์›์ธ๋ณ„ ํ†ต๊ณ„ + failure_reasons = {} + for case in crop_failure_cases: + reason = case['failure_reason'] + failure_reasons[reason] = failure_reasons.get(reason, 0) + 1 + + f.write("๐Ÿ“Š ์‹คํŒจ ์›์ธ๋ณ„ ํ†ต๊ณ„:\n") + for reason, count in failure_reasons.items(): + f.write(f" - {reason}: {count}๊ฐœ ({count/len(crop_failure_cases)*100:.1f}%)\n") + f.write("\n") + + for i, case in enumerate(crop_failure_cases, 1): + f.write(f"\n{'='*80}\n") + f.write(f"[{i}] ํŽ˜์ด์ง€: {case['page_name']} (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: {case['page_num']})\n") + f.write(f" Section: {case['section_idx']}\n") + f.write(f"{'-'*80}\n") + + f.write(f" โŒ ์‹คํŒจ ์›์ธ: {case['failure_reason']}\n\n") + + debug = case['debug_info'] + + # ์›์ธ๋ณ„ ์ƒ์„ธ ์ •๋ณด + if case['failure_reason'] == 'invalid_bbox': + f.write(f" ๐Ÿ“‹ Bbox ์ •๋ณด:\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" Bbox ๋„ˆ๋น„: {debug.get('bbox_width', 'N/A'):.1f}\n") + f.write(f" Bbox ๋†’์ด: {debug.get('bbox_height', 'N/A'):.1f}\n") + f.write(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {debug.get('image_size', 'N/A')}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ Section bbox๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์Šต๋‹ˆ๋‹ค (x2 <= x1 or y2 <= y1)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. 1004 ๋ชจ๋ธ์˜ Section ๊ฒ€์ถœ์ด ์ž˜๋ชป๋จ โ†’ ๋ชจ๋ธ ์žฌํ•™์Šต ํ•„์š”\n") + f.write(f" 2. Post-processing ์˜ค๋ฅ˜ โ†’ bbox ์กฐ์ • ๋กœ์ง ํ™•์ธ\n") + + elif case['failure_reason'] == 'invalid_expanded_bbox': + f.write(f" ๐Ÿ“‹ Bbox ์ •๋ณด:\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" ํ™•์žฅ bbox: {debug.get('expanded_bbox', 'N/A')}\n") + f.write(f" Padding: {debug.get('padding', 'N/A')}px\n") + f.write(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {debug.get('image_size', 'N/A')}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ Padding ์ถ”๊ฐ€ ํ›„ bbox๊ฐ€ ์ž˜๋ชป๋จ\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. Padding ๊ฐ’ ์กฐ์ • (ํ˜„์žฌ: {debug.get('padding', 50)}px)\n") + f.write(f" 2. ์›๋ณธ bbox๊ฐ€ ์ด๋ฏธ์ง€ ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์žˆ๋Š” ๊ฒฝ์šฐ โ†’ ๋ชจ๋ธ ์žฌํ•™์Šต\n") + + elif case['failure_reason'] == 'zero_size_crop': + f.write(f" ๐Ÿ“‹ Bbox ์ •๋ณด:\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" ํ™•์žฅ bbox: {debug.get('expanded_bbox', 'N/A')}\n") + f.write(f" Crop ํฌ๊ธฐ: {debug.get('crop_size', 'N/A')}\n") + f.write(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {debug.get('image_size', 'N/A')}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ Crop๋œ ์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ๊ฐ€ 0\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. Bbox๊ฐ€ ์ด๋ฏธ์ง€ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚จ โ†’ clip ๋กœ์ง ํ™•์ธ\n") + f.write(f" 2. ์›๋ณธ bbox๊ฐ€ ์ž˜๋ชป๋จ โ†’ ๋ชจ๋ธ ์žฌํ•™์Šต\n") + + elif case['failure_reason'] == 'file_write_failed': + f.write(f" ๐Ÿ“‹ ํŒŒ์ผ ์ €์žฅ ์ •๋ณด:\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" ํ™•์žฅ bbox: {debug.get('expanded_bbox', 'N/A')}\n") + f.write(f" Crop ํฌ๊ธฐ: {debug.get('crop_size', 'N/A')}\n") + f.write(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {debug.get('image_size', 'N/A')}\n") + f.write(f" cv2.imwrite ๋ฐ˜ํ™˜๊ฐ’: {debug.get('write_success', 'N/A')}\n") + f.write(f" ํŒŒ์ผ ์กด์žฌ ์—ฌ๋ถ€: {debug.get('file_exists', 'N/A')}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ ํŒŒ์ผ ์ €์žฅ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. ๋””์Šคํฌ ๊ณต๊ฐ„ ํ™•์ธ\n") + f.write(f" 2. ํŒŒ์ผ ๊ฒฝ๋กœ ๊ถŒํ•œ ํ™•์ธ\n") + f.write(f" 3. ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ ์œ ํšจ์„ฑ ํ™•์ธ\n") + + elif case['failure_reason'] == 'zero_size_file': + f.write(f" ๐Ÿ“‹ ํŒŒ์ผ ์ •๋ณด:\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" ํ™•์žฅ bbox: {debug.get('expanded_bbox', 'N/A')}\n") + f.write(f" Crop ํฌ๊ธฐ: {debug.get('crop_size', 'N/A')}\n") + f.write(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {debug.get('image_size', 'N/A')}\n") + f.write(f" ์ €์žฅ๋œ ํŒŒ์ผ ํฌ๊ธฐ: {debug.get('file_size', 'N/A')} bytes\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ ํŒŒ์ผ์€ ์ €์žฅ๋˜์—ˆ์ง€๋งŒ ํฌ๊ธฐ๊ฐ€ 0 bytes\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. Crop๋œ ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ๊ฐ€ ๋น„์–ด์žˆ์Œ\n") + f.write(f" 2. OpenCV imwrite ์ธ์ฝ”๋”ฉ ์‹คํŒจ\n") + f.write(f" 3. ์ด๋ฏธ์ง€ ํฌ๋งท ๋ฌธ์ œ ํ™•์ธ\n") + + elif case['failure_reason'] == 'file_not_found_despite_success': + f.write(f" ๐Ÿ“‹ ํŒŒ์ผ ์ •๋ณด:\n") + f.write(f" ์˜ˆ์ƒ ํŒŒ์ผ ๊ฒฝ๋กœ: {case.get('expected_path', 'N/A')}\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" ํ™•์žฅ bbox: {debug.get('expanded_bbox', 'N/A')}\n") + f.write(f" Crop ํฌ๊ธฐ: {debug.get('crop_size', 'N/A')}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ crop_success=True๋กœ ๊ธฐ๋ก๋˜์—ˆ์ง€๋งŒ ์‹ค์ œ ํŒŒ์ผ์ด ์—†์Œ\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. ํŒŒ์ผ ์ €์žฅ ํ›„ ์‚ญ์ œ๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ ํ™•์ธ\n") + f.write(f" 2. ํŒŒ์ผ ๊ฒฝ๋กœ ์˜ค๋ฅ˜ ํ™•์ธ\n") + f.write(f" 3. ํŒŒ์ผ ์ €์žฅ ๊ฒ€์ฆ ๋กœ์ง ๊ฐ•ํ™” ํ•„์š”\n") + + elif case['failure_reason'] == 'file_read_failed': + f.write(f" ๐Ÿ“‹ ํŒŒ์ผ ์ •๋ณด:\n") + f.write(f" ํŒŒ์ผ ๊ฒฝ๋กœ: {debug.get('file_path', 'N/A')}\n") + f.write(f" ํŒŒ์ผ ํฌ๊ธฐ: {debug.get('file_size', 'N/A')} bytes\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" ํ™•์žฅ bbox: {debug.get('expanded_bbox', 'N/A')}\n") + f.write(f" Crop ํฌ๊ธฐ: {debug.get('crop_size', 'N/A')}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ ํŒŒ์ผ์€ ์ €์žฅ๋˜์—ˆ์ง€๋งŒ cv2.imread()๋กœ ์ฝ์„ ์ˆ˜ ์—†์Œ\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. ํŒŒ์ผ์ด ์†์ƒ๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ\n") + f.write(f" 2. ์ด๋ฏธ์ง€ ํฌ๋งท์ด ์ž˜๋ชป๋จ (OpenCV๊ฐ€ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ํ˜•์‹)\n") + f.write(f" 3. ์ €์žฅ ์ค‘ I/O ์—๋Ÿฌ ๋ฐœ์ƒ\n") + f.write(f" 4. ํŒŒ์ผ ๊ฒฝ๋กœ์— ํŠน์ˆ˜๋ฌธ์ž ํฌํ•จ ์—ฌ๋ถ€ ํ™•์ธ\n") + + elif case['failure_reason'] == 'size_mismatch_after_read': + f.write(f" ๐Ÿ“‹ ํŒŒ์ผ ์ •๋ณด:\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" ํ™•์žฅ bbox: {debug.get('expanded_bbox', 'N/A')}\n") + f.write(f" ์ €์žฅ ์‹œ Crop ํฌ๊ธฐ: {debug.get('crop_size', 'N/A')}\n") + f.write(f" ์ฝ๊ธฐ ํ›„ ํฌ๊ธฐ: {debug.get('verify_size', 'N/A')}\n") + f.write(f" ํŒŒ์ผ ํฌ๊ธฐ: {debug.get('file_size', 'N/A')} bytes\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ ์ €์žฅ ์‹œ์™€ ์ฝ๊ธฐ ํ›„์˜ ์ด๋ฏธ์ง€ ํฌ๊ธฐ๊ฐ€ ๋‹ค๋ฆ„\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. JPEG ์••์ถ• ๊ณผ์ •์—์„œ ๋ฌธ์ œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ\n") + f.write(f" 2. ๋ฉ”๋ชจ๋ฆฌ ์˜ค์—ผ ๊ฐ€๋Šฅ์„ฑ\n") + f.write(f" 3. ๋‹ค๋ฅธ ํฌ๋งท(PNG ๋“ฑ)์œผ๋กœ ์ €์žฅ ์‹œ๋„\n") + + elif case['failure_reason'].startswith('verification_exception:'): + error_msg = case['failure_reason'][23:] + f.write(f" ๐Ÿ“‹ ํŒŒ์ผ ๊ฒ€์ฆ ์ •๋ณด:\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" ํ™•์žฅ bbox: {debug.get('expanded_bbox', 'N/A')}\n") + f.write(f" Crop ํฌ๊ธฐ: {debug.get('crop_size', 'N/A')}\n") + f.write(f" ํŒŒ์ผ ํฌ๊ธฐ: {debug.get('file_size', 'N/A')} bytes\n") + f.write(f" ์—๋Ÿฌ ๋ฉ”์‹œ์ง€: {error_msg}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ ํŒŒ์ผ ๊ฒ€์ฆ ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ™•์ธ ๋ฐ ๋””๋ฒ„๊น…\n") + f.write(f" 2. ํŒŒ์ผ ์‹œ์Šคํ…œ ๋ฌธ์ œ ํ™•์ธ\n") + f.write(f" 3. ๊ถŒํ•œ ๋ฌธ์ œ ํ™•์ธ\n") + + elif case['failure_reason'].startswith('exception:'): + error_msg = case['failure_reason'][10:] + f.write(f" ๐Ÿ“‹ Exception ์ •๋ณด:\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" ํ™•์žฅ bbox: {debug.get('expanded_bbox', 'N/A')}\n") + f.write(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {debug.get('image_size', 'N/A')}\n") + f.write(f" ์—๋Ÿฌ ๋ฉ”์‹œ์ง€: {error_msg}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ Crop ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ํ™•์ธ ๋ฐ ๋””๋ฒ„๊น…\n") + f.write(f" 2. Bbox ๋ฒ”์œ„ ํ™•์ธ\n") + + logger.info(f"๐Ÿ“Š Crop ์‹คํŒจ ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + logger.info(f" ์ด {len(crop_failure_cases)}๊ฐœ ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„") + + # ์›์ธ๋ณ„ ํ†ต๊ณ„ ๋กœ๊ทธ + for reason, count in failure_reasons.items(): + logger.info(f" {reason}: {count}๊ฐœ") + + +def check_missing_sections_against_answer_key(all_results: list, output_dir: Path, answer_key: dict): + """ + ๋‹ต์ง€์™€ ์‹ค์ œ ์ฒ˜๋ฆฌ๋œ section์„ ๋น„๊ตํ•˜์—ฌ ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋ƒ„ + """ + if not answer_key: + logger.info("๋‹ต์ง€๊ฐ€ ์—†์–ด ๋ˆ„๋ฝ ๊ฒ€์ถœ์„ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + return + + analysis_path = output_dir.parent.parent / "answers" / "missing_sections_analysis.txt" + + missing_cases = [] + + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + # ๋‹ต์ง€์—์„œ ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ๋ฌธ์ œ ๊ฐœ์ˆ˜ ํ™•์ธ + if page_num_ocr not in answer_key: + logger.warning(f"ํŽ˜์ด์ง€ {page_num_ocr}๊ฐ€ ๋‹ต์ง€์— ์—†์Šต๋‹ˆ๋‹ค.") + continue + + expected_problems = answer_key[page_num_ocr] + expected_count = len(expected_problems) + actual_count = len(sections) + + logger.info(f"ํŽ˜์ด์ง€ {page_num_ocr}: ๋‹ต์ง€ ๋ฌธ์ œ ์ˆ˜={expected_count}, ์‹ค์ œ section ์ˆ˜={actual_count}") + + if expected_count != actual_count: + logger.error(f"โŒ ํŽ˜์ด์ง€ {page_num_ocr}: ๋ฌธ์ œ ์ˆ˜ ๋ถˆ์ผ์น˜!") + logger.error(f" ์˜ˆ์ƒ: {expected_count}๊ฐœ, ์‹ค์ œ: {actual_count}๊ฐœ") + logger.error(f" ์ฐจ์ด: {expected_count - actual_count}๊ฐœ") + + # ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ + expected_problem_numbers = set(p['problem'] for p in expected_problems) + actual_problem_numbers = set(s.get('problem_number_ocr') for s in sections if s.get('problem_number_ocr')) + + # OCR ์‹คํŒจ๋กœ ์ธํ•œ ๋ˆ„๋ฝ๋„ ๊ณ ๋ ค + missing_problems = [] + for exp_prob in expected_problem_numbers: + found = False + for act_prob in actual_problem_numbers: + if act_prob and str(exp_prob) == str(act_prob): + found = True + break + if not found: + missing_problems.append(exp_prob) + + if missing_problems: + logger.error(f" ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๋ฒˆํ˜ธ: {sorted(missing_problems)}") + + missing_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'expected_count': expected_count, + 'actual_count': actual_count, + 'difference': expected_count - actual_count, + 'expected_problems': sorted(expected_problem_numbers), + 'actual_problems': sorted(actual_problem_numbers), + 'missing_problems': sorted(missing_problems), + 'sections': sections + }) + + if not missing_cases: + logger.info("โœ… ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ๋ฌธ์ œ ์ˆ˜๊ฐ€ ๋‹ต์ง€์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค!") + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ Section ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write("โœ… ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ๋ฌธ์ œ ์ˆ˜๊ฐ€ ๋‹ต์ง€์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค!\n") + return + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ Section ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write(f"์ด {len(missing_cases)}๊ฐœ ํŽ˜์ด์ง€์—์„œ ๋ถˆ์ผ์น˜ ๋ฐœ๊ฒฌ\n\n") + + total_missing = sum(case['difference'] for case in missing_cases if case['difference'] > 0) + total_extra = sum(-case['difference'] for case in missing_cases if case['difference'] < 0) + + f.write(f"๐Ÿ“Š ์ „์ฒด ํ†ต๊ณ„:\n") + f.write(f" - ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ (๋‹ต์ง€๋ณด๋‹ค ์ ์Œ): {total_missing}๊ฐœ\n") + f.write(f" - ์ดˆ๊ณผ ๊ฒ€์ถœ (๋‹ต์ง€๋ณด๋‹ค ๋งŽ์Œ): {total_extra}๊ฐœ\n\n") + + for i, case in enumerate(missing_cases, 1): + f.write(f"\n{'='*80}\n") + f.write(f"[{i}] ํŽ˜์ด์ง€: {case['page_name']} (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: {case['page_num']})\n") + f.write(f"{'-'*80}\n") + + f.write(f" ๐Ÿ“Š ๋ฌธ์ œ ์ˆ˜:\n") + f.write(f" ๋‹ต์ง€ ์˜ˆ์ƒ: {case['expected_count']}๊ฐœ\n") + f.write(f" ์‹ค์ œ ๊ฒ€์ถœ: {case['actual_count']}๊ฐœ\n") + f.write(f" ์ฐจ์ด: {case['difference']:+d}๊ฐœ\n\n") + + if case['difference'] > 0: + f.write(f" โŒ ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ:\n") + f.write(f" ๋‹ต์ง€ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['expected_problems']}\n") + f.write(f" ์‹ค์ œ ์ธ์‹๋œ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['actual_problems']}\n") + f.write(f" ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['missing_problems']}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + + # Section crop ์‹คํŒจ ํ™•์ธ + failed_crops = [s for s in case['sections'] if not s.get('crop_success', True)] + if failed_crops: + f.write(f" โŒ {len(failed_crops)}๊ฐœ Section crop ์‹คํŒจ\n") + for s in failed_crops: + f.write(f" - Section {s.get('section_idx')}: {s.get('crop_failure_reason')}\n") + + # Section ์ž์ฒด๊ฐ€ ๊ฒ€์ถœ ์•ˆ ๋จ + if case['actual_count'] < case['expected_count']: + not_detected = case['expected_count'] - case['actual_count'] + f.write(f" โŒ {not_detected}๊ฐœ Section์ด ๊ฒ€์ถœ๋˜์ง€ ์•Š์Œ (1004 ๋ชจ๋ธ ๋ฌธ์ œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. 1004 ๋ชจ๋ธ์˜ Section ๊ฒ€์ถœ ์žฌํ•™์Šต\n") + f.write(f" 2. Confidence threshold ์กฐ์ • (ํ˜„์žฌ ๊ฐ’ ํ™•์ธ ํ•„์š”)\n") + f.write(f" 3. ์ด๋ฏธ์ง€ ํ’ˆ์งˆ ํ™•์ธ (ํ•ด์ƒ๋„, ์„ ๋ช…๋„)\n") + + # ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ์‹คํŒจ + ocr_failures = [s for s in case['sections'] if not s.get('problem_number_ocr')] + if ocr_failures: + f.write(f" โš ๏ธ {len(ocr_failures)}๊ฐœ ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ์‹คํŒจ\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: OCR ๋ชจ๋ธ ๊ฐœ์„  ๋˜๋Š” ์ „์ฒ˜๋ฆฌ ์ถ”๊ฐ€\n") + + elif case['difference'] < 0: + f.write(f" โš ๏ธ ์ดˆ๊ณผ ๊ฒ€์ถœ (๋‹ต์ง€๋ณด๋‹ค ๋งŽ์Œ):\n") + f.write(f" ๋‹ต์ง€ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['expected_problems']}\n") + f.write(f" ์‹ค์ œ ์ธ์‹๋œ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['actual_problems']}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โš ๏ธ Section์ด ๊ณผ๋‹ค ๊ฒ€์ถœ๋จ (1004 ๋ชจ๋ธ ๋ฌธ์ œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. NMS (Non-Maximum Suppression) threshold ์กฐ์ •\n") + f.write(f" 2. Confidence threshold ์ƒํ–ฅ ์กฐ์ •\n") + f.write(f" 3. ์ค‘๋ณต ๊ฒ€์ถœ ํ•„ํ„ฐ๋ง ๋กœ์ง ์ถ”๊ฐ€\n") + + logger.info(f"๐Ÿ“Š ๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + logger.info(f" ๋ถˆ์ผ์น˜ ํŽ˜์ด์ง€: {len(missing_cases)}๊ฐœ") + logger.info(f" ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ: {total_missing}๊ฐœ") + logger.info(f" ์ดˆ๊ณผ ๊ฒ€์ถœ: {total_extra}๊ฐœ") + + +def print_summary(all_results: list, skipped_pages: list, output_dir: Path, total_processing_time: float): + """์‹คํ—˜ ๊ฒฐ๊ณผ ์š”์•ฝ ์ถœ๋ ฅ""" + logger.info("\n\n" + "=" * 60) + logger.info("์ „์ฒด ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์š”์•ฝ") + logger.info("=" * 60) + + total_pages = len(all_results) + total_sections = sum(len(r.get("sections", [])) for r in all_results) + total_crop_failures = sum(r.get("crop_failure_count", 0) for r in all_results) + + logger.info(f" ์ฒ˜๋ฆฌ๋œ ํŽ˜์ด์ง€ ์ˆ˜: {total_pages}") + logger.info(f" ๊ฑด๋„ˆ๋›ด ํŽ˜์ด์ง€ ์ˆ˜: {len(skipped_pages)}") + if skipped_pages: + logger.info(f" ๊ฑด๋„ˆ๋›ด ํŽ˜์ด์ง€: {', '.join(skipped_pages)}") + logger.info(f" ์ด Section ์ˆ˜: {total_sections}") + logger.info(f" Section crop ์‹คํŒจ: {total_crop_failures}๊ฐœ") + logger.info(f" ์ „์ฒด ์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {total_processing_time:.2f}์ดˆ ({total_processing_time / 60:.2f}๋ถ„)") + + if all_results: + avg_time = sum(r.get("processing_time", 0.0) for r in all_results) / len(all_results) + logger.info(f" ํŽ˜์ด์ง€๋‹น ํ‰๊ท  ์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {avg_time:.2f}์ดˆ") + + logger.info(f"\n๐Ÿ“ ๊ฒฐ๊ณผ TXT: {output_dir.parent.parent / 'answers' / 'results_summary.txt'}") + logger.info(f"๐Ÿ“Š None ๋””๋ฒ„๊น…: {output_dir.parent.parent / 'answers' / 'none_debug_analysis.txt'}") + logger.info(f"๐Ÿ“Š Crop ์‹คํŒจ ๋ถ„์„: {output_dir.parent.parent / 'answers' / 'crop_failure_analysis.txt'}") + logger.info(f"๐Ÿ“Š ๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ ๋ถ„์„: {output_dir.parent.parent / 'answers' / 'missing_sections_analysis.txt'}") + logger.info(f"๐Ÿ“ ๋กœ๊ทธ ํŒŒ์ผ: {log_file}") + logger.info("=" * 60) + logger.info("๋ชจ๋“  ์‹คํ—˜์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") + logger.info("=" * 60) + + +if __name__ == "__main__": + main() + +# ํŒŒ์ผ ์‹คํ–‰: python -m test.YOLO.yolo_test \ No newline at end of file diff --git a/ai-service/test/YOLO/yolo_test_crop.py b/ai-service/test/YOLO/yolo_test_crop.py new file mode 100644 index 0000000..83ca500 --- /dev/null +++ b/ai-service/test/YOLO/yolo_test_crop.py @@ -0,0 +1,872 @@ +# yolo_test_crop.py +import logging +import time +import os +from pathlib import Path +from typing import Dict, List, Tuple, Optional +import cv2 +import numpy as np +from models.Detection.legacy.Model_routing_1104.run_routed_inference import RoutedInference as RoutedInference_1104 +from models.Detection.legacy.Model_routing_1004.run_routed_inference import RoutedInference as RoutedInference_1004 +from models.Recognition.ocr import OCRModel + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + + +class HierarchicalCropPipeline: + """๊ณ„์ธต์  ํฌ๋กญ ํŒŒ์ดํ”„๋ผ์ธ: ํŽ˜์ด์ง€ โ†’ Section โ†’ ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ ์ •๋‹ต (OCR ํฌํ•จ)""" + + def __init__(self, model_dir_1104: str, model_dir_1004: str, + section_padding: int = 50, + answer_key_path: Optional[str] = None): + """ + Args: + model_dir_1104: 1104 ๋ชจ๋ธ ๊ฒฝ๋กœ + model_dir_1004: 1004 ๋ชจ๋ธ ๊ฒฝ๋กœ + section_padding: Section crop ์‹œ ์ถ”๊ฐ€ํ•  ์—ฌ๋ฐฑ (ํ”ฝ์…€). ๊ธฐ๋ณธ๊ฐ’ 50 + answer_key_path: ๋‹ต์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ (txt ํŒŒ์ผ) + """ + self.router_1104 = RoutedInference_1104(model_dir_1104) # ๋‹ต์•ˆ ์ถ”๋ก ์šฉ + self.router_1004 = RoutedInference_1004(model_dir_1004) # ํฌ๋กญ์šฉ (ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section) + self.ocr = OCRModel() + self.section_padding = section_padding + + # ๋‹ต์ง€ ๋กœ๋“œ + self.answer_key = self._load_answer_key(answer_key_path) if answer_key_path else None + + logger.info("HierarchicalCropPipeline ์ดˆ๊ธฐํ™” (๋‘ ๊ฐœ์˜ ๋ชจ๋ธ + OCR ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ)") + logger.info(" - 1104 ๋ชจ๋ธ: ๋‹ต์•ˆ ์ถ”๋ก ์šฉ") + logger.info(" - 1004 ๋ชจ๋ธ: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ํฌ๋กญ์šฉ") + logger.info(f" - Section padding: {section_padding}px") + if self.answer_key: + logger.info(f" - ๋‹ต์ง€ ๋กœ๋“œ ์™„๋ฃŒ: {len(self.answer_key)}๊ฐœ ํŽ˜์ด์ง€") + + def _load_answer_key(self, answer_key_path: str) -> Dict[str, List[Dict]]: + """๋‹ต์ง€ ํŒŒ์ผ ๋กœ๋“œ + + ํŒŒ์ผ ํ˜•์‹: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต + ์˜ˆ: 1, 1, 3 + + Returns: + Dict[str, List[Dict]]: {ํŽ˜์ด์ง€๋ฒˆํ˜ธ: [{'problem': ๋ฌธ์ œ๋ฒˆํ˜ธ, 'answer': ์ •๋‹ต}, ...]} + """ + answer_key = {} + try: + with open(answer_key_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line: + continue + + parts = [p.strip() for p in line.split(',')] + if len(parts) >= 3: + page_num = parts[0] + problem_num = parts[1] + answer = parts[2] + + if page_num not in answer_key: + answer_key[page_num] = [] + + answer_key[page_num].append({ + 'problem': problem_num, + 'answer': answer + }) + + logger.info(f"๋‹ต์ง€ ๋กœ๋“œ ์™„๋ฃŒ: {answer_key_path}") + for page, problems in answer_key.items(): + logger.info(f" ํŽ˜์ด์ง€ {page}: {len(problems)}๊ฐœ ๋ฌธ์ œ") + + except Exception as e: + logger.error(f"๋‹ต์ง€ ๋กœ๋“œ ์‹คํŒจ: {e}") + return {} + + return answer_key + + def is_valid_page(self, page_number: Optional[str]) -> bool: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๊ฐ€ ๋‹ต์ง€์— ์žˆ๋Š”์ง€ ํ™•์ธ + + Args: + page_number: OCR๋กœ ์ธ์‹๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ + + Returns: + bool: ๋‹ต์ง€์— ์žˆ์œผ๋ฉด True, ๋‹ต์ง€๊ฐ€ ์—†๊ฑฐ๋‚˜ ํŽ˜์ด์ง€๊ฐ€ ์—†์œผ๋ฉด True (๊ธฐ๋ณธ ์ฒ˜๋ฆฌ) + """ + if self.answer_key is None: + # ๋‹ต์ง€๊ฐ€ ์—†์œผ๋ฉด ๋ชจ๋“  ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ + return True + + if page_number is None: + logger.warning("ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + return False + + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ •๊ทœํ™” (๊ณต๋ฐฑ ์ œ๊ฑฐ, ๋ฌธ์ž์—ด ๋ณ€ํ™˜) + page_number_normalized = str(page_number).strip() + + is_valid = page_number_normalized in self.answer_key + + if not is_valid: + logger.warning(f"ํŽ˜์ด์ง€ {page_number}๋Š” ๋‹ต์ง€์— ์—†์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + else: + logger.info(f"ํŽ˜์ด์ง€ {page_number}๋Š” ๋‹ต์ง€์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜๋ฆฌ๋ฅผ ๊ณ„์†ํ•ฉ๋‹ˆ๋‹ค.") + + return is_valid + + def calculate_iou(self, bbox1: List[float], bbox2: List[float]) -> float: + """๋‘ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค์˜ IoU(Intersection over Union) ๊ณ„์‚ฐ + + Args: + bbox1: [x1, y1, x2, y2] + bbox2: [x1, y1, x2, y2] + + Returns: + float: IoU ๊ฐ’ (0.0 ~ 1.0) + """ + x1_1, y1_1, x2_1, y2_1 = bbox1 + x1_2, y1_2, x2_2, y2_2 = bbox2 + + # ๊ฒน์น˜๋Š” ์˜์—ญ ๊ณ„์‚ฐ + x1_i = max(x1_1, x1_2) + y1_i = max(y1_1, y1_2) + x2_i = min(x2_1, x2_2) + y2_i = min(y2_1, y2_2) + + if x2_i <= x1_i or y2_i <= y1_i: + return 0.0 + + # Intersection ๋ฉด์  + intersection = (x2_i - x1_i) * (y2_i - y1_i) + + # ๊ฐ ๋ฐ•์Šค์˜ ๋ฉด์  + area1 = (x2_1 - x1_1) * (y2_1 - y1_1) + area2 = (x2_2 - x1_2) * (y2_2 - y1_2) + + # Union ๋ฉด์  + union = area1 + area2 - intersection + + if union == 0: + return 0.0 + + return intersection / union + + def expand_bbox_with_padding(self, bbox: List[float], padding: int, img_width: int, img_height: int) -> List[int]: + """๋ฐ”์šด๋”ฉ ๋ฐ•์Šค์— padding์„ ์ถ”๊ฐ€ํ•˜๋˜, ์ด๋ฏธ์ง€ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์ง€ ์•Š๋„๋ก ์ฒ˜๋ฆฌ + + Args: + bbox: [x1, y1, x2, y2] + padding: ์ถ”๊ฐ€ํ•  ์—ฌ๋ฐฑ (ํ”ฝ์…€) + img_width: ์ด๋ฏธ์ง€ ๋„ˆ๋น„ + img_height: ์ด๋ฏธ์ง€ ๋†’์ด + + Returns: + List[int]: ํ™•์žฅ๋œ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + """ + x1, y1, x2, y2 = bbox + + # Padding ์ถ”๊ฐ€ + x1_expanded = max(0, int(x1 - padding)) + y1_expanded = max(0, int(y1 - padding)) + x2_expanded = min(img_width, int(x2 + padding)) + y2_expanded = min(img_height, int(y2 + padding)) + + return [x1_expanded, y1_expanded, x2_expanded, y2_expanded] + + def is_bbox_near_section_boundary(self, bbox: List[float], section_bbox: List[float], threshold: int = 30) -> bool: + """๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ•์Šค๊ฐ€ section ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์žˆ๋Š”์ง€ ํ™•์ธ + + Args: + bbox: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + section_bbox: Section ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + threshold: ๊ฒฝ๊ณ„๋กœ ๊ฐ„์ฃผํ•  ๊ฑฐ๋ฆฌ (ํ”ฝ์…€) + + Returns: + bool: ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์žˆ์œผ๋ฉด True + """ + bx1, by1, bx2, by2 = bbox + sx1, sy1, sx2, sy2 = section_bbox + + # ์ƒํ•˜์ขŒ์šฐ ๊ฒฝ๊ณ„์™€์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ + dist_top = abs(by1 - sy1) + dist_bottom = abs(by2 - sy2) + dist_left = abs(bx1 - sx1) + dist_right = abs(bx2 - sx2) + + # ํ•˜๋‚˜๋ผ๋„ threshold ์ด๋‚ด์ด๋ฉด ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜๋กœ ํŒ๋‹จ + return min(dist_top, dist_bottom, dist_left, dist_right) < threshold + + def visualize_section_detection(self, image_path: str, section_bbox: List[float], + section_idx: int, output_dir: Path, page_name: str): + """Section ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐํ™”ํ•˜์—ฌ ์ €์žฅ (๋””๋ฒ„๊น…์šฉ) + + Args: + image_path: ์›๋ณธ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + section_bbox: Section ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + section_idx: Section ์ธ๋ฑ์Šค + output_dir: ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ + page_name: ํŽ˜์ด์ง€ ์ด๋ฆ„ + """ + image = cv2.imread(image_path) + if image is None: + return + + # Section bbox ๊ทธ๋ฆฌ๊ธฐ + x1, y1, x2, y2 = map(int, section_bbox) + cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 3) + + # ๋ผ๋ฒจ ์ถ”๊ฐ€ + label = f"Section {section_idx}" + cv2.putText(image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) + + # ์ €์žฅ + debug_dir = output_dir / page_name / "debug" + debug_dir.mkdir(parents=True, exist_ok=True) + + save_path = debug_dir / f"section_{section_idx:02d}_detection_visual.jpg" + cv2.imwrite(str(save_path), image) + logger.info(f"Section ๊ฒ€์ถœ ์‹œ๊ฐํ™” ์ €์žฅ: {save_path}") + + def crop_page_number(self, image_path: str, detections_1004: List[Dict], output_dir: Path) -> Tuple[Optional[str], Optional[str]]: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ํฌ๋กญํ•˜๊ณ  OCR๋กœ ์ธ์‹ (1004 ๋ชจ๋ธ ์‚ฌ์šฉ) + + Returns: + Tuple[Optional[str], Optional[str]]: (ํฌ๋กญ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ, ์ธ์‹๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ) + """ + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return None, None + + page_num_detections = [d for d in detections_1004 if d['class_name'] == 'page_number'] + + if not page_num_detections: + logger.warning(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ: {image_path}") + return None, None + + # ์‹ ๋ขฐ๋„ ๊ฐ€์žฅ ๋†’์€ ๊ฒƒ ์„ ํƒ + best_det = max(page_num_detections, key=lambda x: x['confidence']) + x1, y1, x2, y2 = map(int, best_det['bbox']) + + h, w = image.shape[:2] + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 <= x1 or y2 <= y1: + logger.warning(f"์ž˜๋ชป๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐ•์Šค: {best_det['bbox']}") + return None, None + + # ํฌ๋กญ ๋ฐ ์ €์žฅ + cropped = image[y1:y2, x1:x2] + page_num_dir = output_dir / "page_numbers" + page_num_dir.mkdir(parents=True, exist_ok=True) + + image_name = Path(image_path).stem + save_path = page_num_dir / f"{image_name}_page_number.jpg" + cv2.imwrite(str(save_path), cropped) + + # OCR๋กœ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ + recognized_number = self.ocr.extract_number(str(save_path)) + + logger.info(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ crop ์™„๋ฃŒ (1004 ๋ชจ๋ธ): {save_path}") + logger.info(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ OCR ๊ฒฐ๊ณผ: '{recognized_number}'") + + return str(save_path), recognized_number + + def process_single_section(self, original_image_path: str, section_idx: int, + page_name: str, output_dir: Path, + section_bbox: List[float], detections_1004: List[Dict], + detections_1104: List[Dict]) -> Dict: + """์„น์…˜ ๋‚ด์˜ ๋ฌธ์ œ๋ฒˆํ˜ธ์™€ ์ •๋‹ต์„ ์ถ”๋ก  + - ๋ฌธ์ œ๋ฒˆํ˜ธ ํฌ๋กญ: 1004 ๋ชจ๋ธ ์‚ฌ์šฉ + - ๋‹ต์•ˆ ์ถ”๋ก : 1104 ๋ชจ๋ธ ์‚ฌ์šฉ (IoU ๊ธฐ๋ฐ˜ ์ •๋‹ต ๋ฒˆํ˜ธ ๊ฒฐ์ •) + + Returns: + Dict: {'section_idx', 'problem_number_ocr', 'answer_number', 'section_crop_path', 'problem_crop_path', 'crop_success', 'crop_failure_reason'} + """ + sx1, sy1, sx2, sy2 = section_bbox + image = cv2.imread(original_image_path) + h, w = image.shape[:2] + + # Section bbox ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if sx2 <= sx1 or sy2 <= sy1: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ์ž˜๋ชป๋œ bbox [{sx1:.1f}, {sy1:.1f}, {sx2:.1f}, {sy2:.1f}]") + logger.error(f" bbox ๋„ˆ๋น„: {sx2 - sx1:.1f}, ๋†’์ด: {sy2 - sy1:.1f}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'invalid_bbox', + 'debug_info': { + 'original_bbox': section_bbox, + 'bbox_width': sx2 - sx1, + 'bbox_height': sy2 - sy1, + 'image_size': (w, h) + } + } + + # Section ์ด๋ฏธ์ง€ ํฌ๋กญ ์‹œ padding ์ถ”๊ฐ€ + expanded_section_bbox = self.expand_bbox_with_padding( + [sx1, sy1, sx2, sy2], + self.section_padding, + w, h + ) + sx1_exp, sy1_exp, sx2_exp, sy2_exp = expanded_section_bbox + + # ํ™•์žฅ๋œ bbox ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if sx2_exp <= sx1_exp or sy2_exp <= sy1_exp: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ์ž˜๋ชป๋œ ํ™•์žฅ bbox [{sx1_exp}, {sy1_exp}, {sx2_exp}, {sy2_exp}]") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'invalid_expanded_bbox', + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'padding': self.section_padding, + 'image_size': (w, h) + } + } + + # Crop ์‹คํ–‰ + try: + section_cropped = image[sy1_exp:sy2_exp, sx1_exp:sx2_exp] + + # Crop๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ํ™•์ธ + crop_h, crop_w = section_cropped.shape[:2] + if crop_h == 0 or crop_w == 0: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ํฌ๋กญ๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ๊ฐ€ 0") + logger.error(f" ์›๋ณธ bbox: [{sx1:.1f}, {sy1:.1f}, {sx2:.1f}, {sy2:.1f}]") + logger.error(f" ํ™•์žฅ bbox: [{sx1_exp}, {sy1_exp}, {sx2_exp}, {sy2_exp}]") + logger.error(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {w}x{h}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'zero_size_crop', + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h) + } + } + + section_dir = output_dir / page_name / "sections" + section_dir.mkdir(parents=True, exist_ok=True) + + section_crop_path = section_dir / f"section_{section_idx:02d}.jpg" + + # ํŒŒ์ผ ์ €์žฅ ์‹œ๋„ + write_success = cv2.imwrite(str(section_crop_path), section_cropped) + + # ํŒŒ์ผ์ด ์‹ค์ œ๋กœ ์ €์žฅ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ + if not write_success or not section_crop_path.exists(): + logger.error(f"โŒ Section {section_idx} ํŒŒ์ผ ์ €์žฅ ์‹คํŒจ: {section_crop_path}") + logger.error(f" cv2.imwrite ๋ฐ˜ํ™˜๊ฐ’: {write_success}") + logger.error(f" ํŒŒ์ผ ์กด์žฌ ์—ฌ๋ถ€: {section_crop_path.exists()}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'file_write_failed', + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h), + 'write_success': write_success, + 'file_exists': section_crop_path.exists() + } + } + + # ์ €์žฅ๋œ ํŒŒ์ผ ํฌ๊ธฐ ํ™•์ธ + file_size = section_crop_path.stat().st_size + if file_size == 0: + logger.error(f"โŒ Section {section_idx} ์ €์žฅ๋œ ํŒŒ์ผ ํฌ๊ธฐ๊ฐ€ 0: {section_crop_path}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'zero_size_file', + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h), + 'file_size': file_size + } + } + + # ์ €์žฅ๋œ ํŒŒ์ผ์„ ์‹ค์ œ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ๋Š”์ง€ ๊ฒ€์ฆ + try: + verify_image = cv2.imread(str(section_crop_path)) + if verify_image is None: + logger.error(f"โŒ Section {section_idx} ์ €์žฅ๋œ ํŒŒ์ผ์„ ์ฝ์„ ์ˆ˜ ์—†์Œ: {section_crop_path}") + logger.error(f" ํŒŒ์ผ์€ ์กด์žฌํ•˜์ง€๋งŒ OpenCV๋กœ ์ฝ๊ธฐ ์‹คํŒจ") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'file_read_failed', + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h), + 'file_size': file_size, + 'file_path': str(section_crop_path) + } + } + + verify_h, verify_w = verify_image.shape[:2] + if verify_h != crop_h or verify_w != crop_w: + logger.error(f"โŒ Section {section_idx} ์ €์žฅ/์ฝ๊ธฐ ํ›„ ํฌ๊ธฐ ๋ถˆ์ผ์น˜") + logger.error(f" ์ €์žฅ ์‹œ ํฌ๊ธฐ: {crop_w}x{crop_h}") + logger.error(f" ์ฝ๊ธฐ ํ›„ ํฌ๊ธฐ: {verify_w}x{verify_h}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'size_mismatch_after_read', + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'verify_size': (verify_w, verify_h), + 'image_size': (w, h), + 'file_size': file_size + } + } + except Exception as e: + logger.error(f"โŒ Section {section_idx} ํŒŒ์ผ ๊ฒ€์ฆ ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ: {e}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': f'verification_exception: {str(e)}', + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h), + 'file_size': file_size, + 'error': str(e) + } + } + + logger.info(f"โœ… Section {section_idx} ์ด๋ฏธ์ง€ ์ €์žฅ ์„ฑ๊ณต (padding {self.section_padding}px ์ถ”๊ฐ€): {section_crop_path}") + logger.info(f" ์›๋ณธ bbox: [{sx1:.1f}, {sy1:.1f}, {sx2:.1f}, {sy2:.1f}] (ํฌ๊ธฐ: {sx2-sx1:.1f}x{sy2-sy1:.1f})") + logger.info(f" ํ™•์žฅ bbox: [{sx1_exp}, {sy1_exp}, {sx2_exp}, {sy2_exp}] (ํฌ๊ธฐ: {sx2_exp-sx1_exp}x{sy2_exp-sy1_exp})") + logger.info(f" Crop ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {crop_w}x{crop_h}") + logger.info(f" ์ €์žฅ๋œ ํŒŒ์ผ ํฌ๊ธฐ: {file_size} bytes") + logger.info(f" ํŒŒ์ผ ๊ฒ€์ฆ: โœ… ์ •์ƒ") + + except Exception as e: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: {e}") + logger.error(f" ์›๋ณธ bbox: [{sx1:.1f}, {sy1:.1f}, {sx2:.1f}, {sy2:.1f}]") + logger.error(f" ํ™•์žฅ bbox: [{sx1_exp}, {sy1_exp}, {sx2_exp}, {sy2_exp}]") + logger.error(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {w}x{h}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': f'exception: {str(e)}', + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'image_size': (w, h), + 'error': str(e) + } + } + + # Section ๊ฒ€์ถœ ์‹œ๊ฐํ™” ์ €์žฅ + self.visualize_section_detection(original_image_path, section_bbox, section_idx, output_dir, page_name) + + # 1004 ๋ชจ๋ธ์—์„œ ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ (ํ™•์žฅ๋œ ์˜์—ญ ๊ธฐ์ค€) + section_dets_1004 = [] + for det in detections_1004: + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + # ํ™•์žฅ๋œ ์˜์—ญ ๋‚ด์—์„œ ๊ฒ€์ถœ (padding ๊ณ ๋ ค) + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + if det['class_name'] == 'problem_number': + section_dets_1004.append(det) + # ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜ ์—ฌ๋ถ€ ์ฒดํฌ + if self.is_bbox_near_section_boundary(det['bbox'], [sx1, sy1, sx2, sy2]): + logger.warning(f"Section {section_idx}: ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์œ„์น˜ (padding์œผ๋กœ ๋ณด์ •)") + + # ๋””๋ฒ„๊น…: ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ ๊ฒฐ๊ณผ + logger.info(f"Section {section_idx}: 1004 ๋ชจ๋ธ ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ ๊ฐœ์ˆ˜ = {len(section_dets_1004)}") + if section_dets_1004: + for i, det in enumerate(section_dets_1004): + logger.info(f" ๋ฌธ์ œ๋ฒˆํ˜ธ {i+1}: confidence={det['confidence']:.3f}, bbox={det['bbox']}") + + # 1104 ๋ชจ๋ธ์—์„œ ๋‹ต์•ˆ ๊ด€๋ จ ๊ฒ€์ถœ (ํ™•์žฅ๋œ ์˜์—ญ ๊ธฐ์ค€) + section_dets_1104 = [] + for det in detections_1104: + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + if det['class_name'] in ['answer_1', '1', '2', '3', '4', '5']: + section_dets_1104.append(det) + + # ๋””๋ฒ„๊น…: ๋‹ต์•ˆ ๊ฒ€์ถœ ๊ฒฐ๊ณผ + answer_1_dets = [d for d in section_dets_1104 if d['class_name'] == 'answer_1'] + class_dets = [d for d in section_dets_1104 if d['class_name'] in ['1', '2', '3', '4', '5']] + + logger.info(f"Section {section_idx}: 1104 ๋ชจ๋ธ answer_1 ๊ฒ€์ถœ ๊ฐœ์ˆ˜ = {len(answer_1_dets)}") + if answer_1_dets: + for i, det in enumerate(answer_1_dets): + logger.info(f" answer_1 {i+1}: confidence={det['confidence']:.3f}, bbox={det['bbox']}") + + logger.info(f"Section {section_idx}: 1104 ๋ชจ๋ธ ์ˆซ์ž(1-5) ๊ฒ€์ถœ ๊ฐœ์ˆ˜ = {len(class_dets)}") + if class_dets: + for i, det in enumerate(class_dets): + logger.info(f" ์ˆซ์ž {det['class_name']}: confidence={det['confidence']:.3f}, bbox={det['bbox']}") + + # ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ๋ฐ ์ด๋ฏธ์ง€ ์ €์žฅ (1004 ๋ชจ๋ธ ๊ฒฐ๊ณผ ์‚ฌ์šฉ) + problem_ocr = None + problem_crop_path = None + if section_dets_1004: + best_det = max(section_dets_1004, key=lambda x: x['confidence']) + x1, y1, x2, y2 = map(int, best_det['bbox']) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped = image[y1:y2, x1:x2] + + # Problem number ์ด๋ฏธ์ง€ ์ €์žฅ + problem_dir = output_dir / page_name / "problem_numbers" + problem_dir.mkdir(parents=True, exist_ok=True) + problem_crop_path = problem_dir / f"section_{section_idx:02d}_problem_number.jpg" + cv2.imwrite(str(problem_crop_path), cropped) + logger.info(f"Section {section_idx} ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€ ์ €์žฅ: {problem_crop_path}") + + # OCR ์ˆ˜ํ–‰ + problem_ocr = self.ocr.extract_number(str(problem_crop_path)) + logger.info(f"Section {section_idx} ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ๊ฒฐ๊ณผ: '{problem_ocr}'") + else: + logger.warning(f"Section {section_idx}: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ") + + # answer_1๊ณผ class 1~5์˜ IoU ๊ณ„์‚ฐ (1104 ๋ชจ๋ธ ๊ฒฐ๊ณผ ์‚ฌ์šฉ) + best_answer = None + best_iou = 0.0 + debug_iou_info = [] + + if answer_1_dets and class_dets: + a_bbox = answer_1_dets[0]['bbox'] + logger.info(f"Section {section_idx}: answer_1 bbox = {a_bbox}") + + for det in class_dets: + iou = self.calculate_iou(a_bbox, det['bbox']) + debug_iou_info.append({ + 'class': det['class_name'], + 'bbox': det['bbox'], + 'iou': iou + }) + logger.info(f" IoU with {det['class_name']}: {iou:.4f}") + + if iou > best_iou: + best_iou = iou + best_answer = det['class_name'] + + if best_answer: + logger.info(f"Section {section_idx}: ์ตœ์ข… ์„ ํƒ๋œ ๋‹ต์•ˆ = {best_answer} (IoU: {best_iou:.4f})") + else: + logger.warning(f"Section {section_idx}: IoU๊ฐ€ 0์ธ ๊ฒฝ์šฐ - ๋‹ต์•ˆ์„ ์„ ํƒํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.") + else: + if not answer_1_dets: + logger.warning(f"Section {section_idx}: answer_1์ด ๊ฒ€์ถœ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.") + if not class_dets: + logger.warning(f"Section {section_idx}: ์ˆซ์ž(1-5)๊ฐ€ ๊ฒ€์ถœ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.") + + return { + 'section_idx': section_idx, + 'problem_number_ocr': problem_ocr, + 'answer_number': best_answer, + 'section_crop_path': str(section_crop_path), + 'problem_crop_path': str(problem_crop_path) if problem_crop_path else None, + 'crop_success': True, + 'is_boundary_issue': len(section_dets_1004) > 0 and any( + self.is_bbox_near_section_boundary(d['bbox'], [sx1, sy1, sx2, sy2]) + for d in section_dets_1004 + ), + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h), + 'answer_1_count': len(answer_1_dets), + 'class_count': len(class_dets), + 'iou_details': debug_iou_info, + 'best_iou': best_iou + } + } + + def filter_duplicate_sections(self, image_path: str, section_detections: List[Dict], + detections_1004: List[Dict]) -> List[Dict]: + """ + ์ค‘๋ณต๋œ section์„ ํ•„ํ„ฐ๋ง (๊ฐ™์€ problem_number๋ฅผ ๊ฐ€์ง„ section ์ค‘ ๋” ํฐ ๊ฒƒ ์„ ํƒ) + + Args: + image_path: ์›๋ณธ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + section_detections: section ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ + detections_1004: 1004 ๋ชจ๋ธ์˜ ์ „์ฒด ๊ฒ€์ถœ ๊ฒฐ๊ณผ + + Returns: + ํ•„ํ„ฐ๋ง๋œ section ๋ฆฌ์ŠคํŠธ + """ + if len(section_detections) <= 1: + return section_detections + + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return section_detections + + h, w = image.shape[:2] + + # ๊ฐ section์— ๋Œ€ํ•ด problem_number ์ฐพ๊ธฐ + section_with_problem = [] + + for idx, section in enumerate(section_detections): + sx1, sy1, sx2, sy2 = section['bbox'] + section_area = (sx2 - sx1) * (sy2 - sy1) + + # ํ•ด๋‹น section ๋‚ด์˜ problem_number ์ฐพ๊ธฐ + problem_numbers = [] + for det in detections_1004: + if det['class_name'] != 'problem_number': + continue + + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + + # Section ์˜์—ญ ๋‚ด์— ์žˆ๋Š”์ง€ ํ™•์ธ + if sx1 <= cx <= sx2 and sy1 <= cy <= sy2: + problem_numbers.append(det) + + # ๊ฐ€์žฅ ์‹ ๋ขฐ๋„ ๋†’์€ problem_number ์‚ฌ์šฉ + if problem_numbers: + best_problem = max(problem_numbers, key=lambda x: x['confidence']) + + # OCR๋กœ ๋ฌธ์ œ๋ฒˆํ˜ธ ์ธ์‹ (์ž„์‹œ) + x1, y1, x2, y2 = map(int, best_problem['bbox']) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped = image[y1:y2, x1:x2] + # OCR ๋ชจ๋ธ์ด numpy array๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธ + try: + problem_ocr = self.ocr.extract_number(cropped) + except: + # ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ ํ›„ OCR + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmp: + cv2.imwrite(tmp.name, cropped) + problem_ocr = self.ocr.extract_number(tmp.name) + os.unlink(tmp.name) + else: + problem_ocr = None + else: + problem_ocr = None + + section_with_problem.append({ + 'section': section, + 'original_index': idx, + 'problem_number_ocr': problem_ocr, + 'section_area': section_area, + 'bbox': section['bbox'] + }) + + # problem_number๋ณ„๋กœ ๊ทธ๋ฃนํ™” + problem_groups = {} + no_problem_sections = [] + + for item in section_with_problem: + problem_num = item['problem_number_ocr'] + + if problem_num is None or problem_num == '': + # ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ ์—†๋Š” section์€ ๋ณ„๋„ ์ฒ˜๋ฆฌ + no_problem_sections.append(item) + else: + if problem_num not in problem_groups: + problem_groups[problem_num] = [] + problem_groups[problem_num].append(item) + + # ์ค‘๋ณต ์ œ๊ฑฐ: ๊ฐ ๊ทธ๋ฃน์—์„œ ๊ฐ€์žฅ ํฐ section ์„ ํƒ + filtered_sections = [] + removed_count = 0 + + for problem_num, items in problem_groups.items(): + if len(items) > 1: + # ๋ฉด์ ์ด ๊ฐ€์žฅ ํฐ section ์„ ํƒ + largest = max(items, key=lambda x: x['section_area']) + filtered_sections.append(largest['section']) + + removed_count += len(items) - 1 + + logger.warning(f"โš ๏ธ ๋ฌธ์ œ๋ฒˆํ˜ธ '{problem_num}': {len(items)}๊ฐœ section ๊ฒ€์ถœ๋จ") + logger.warning(f" ๊ฐ€์žฅ ํฐ section ์„ ํƒ (๋ฉด์ : {largest['section_area']:.1f})") + + # ์ œ๊ฑฐ๋œ section๋“ค ๋กœ๊ทธ + for item in items: + if item != largest: + logger.warning(f" - ์ œ๊ฑฐ: Section index {item['original_index']}, " + f"๋ฉด์ ={item['section_area']:.1f}, bbox={item['bbox']}") + else: + filtered_sections.append(items[0]['section']) + + # ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ ์—†๋Š” section๋“ค ์ถ”๊ฐ€ + for item in no_problem_sections: + filtered_sections.append(item['section']) + logger.warning(f"โš ๏ธ Section index {item['original_index']}: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ (ํฌํ•จ)") + + if removed_count > 0: + logger.info(f"โœ‚๏ธ ์ค‘๋ณต ํ•„ํ„ฐ๋ง: {removed_count}๊ฐœ section ์ œ๊ฑฐ๋จ") + logger.info(f" ํ•„ํ„ฐ๋ง ์ „: {len(section_detections)}๊ฐœ โ†’ ํ•„ํ„ฐ๋ง ํ›„: {len(filtered_sections)}๊ฐœ") + + # y ์ขŒํ‘œ ๊ธฐ์ค€์œผ๋กœ ์žฌ์ •๋ ฌ + filtered_sections = sorted(filtered_sections, key=lambda x: x['bbox'][1]) + + return filtered_sections + + def process_page(self, image_path: str, output_dir: Path) -> Optional[Dict]: + """ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ: 1004 ๋ชจ๋ธ๋กœ ํฌ๋กญ, 1104 ๋ชจ๋ธ๋กœ ๋‹ต์•ˆ ์ถ”๋ก  + + Returns: + Optional[Dict]: ํŽ˜์ด์ง€๊ฐ€ ๋‹ต์ง€์— ์žˆ์œผ๋ฉด ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜, ์—†์œผ๋ฉด None + """ + start_time = time.time() + + # 1004 ๋ชจ๋ธ: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ๊ฒ€์ถœ + logger.info("1004 ๋ชจ๋ธ ์‹คํ–‰ ์ค‘ (ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ๊ฒ€์ถœ)...") + result_1004 = self.router_1004.route_infer_single_image(image_path) + detections_1004 = result_1004['detections'] + + # Section ๊ฒ€์ถœ ํ†ต๊ณ„ + section_detections = [d for d in detections_1004 if d['class_name'] == 'section'] + logger.info(f"1004 ๋ชจ๋ธ Section ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {len(section_detections)}") + + if not section_detections: + logger.error(f"โŒ Section์ด ํ•˜๋‚˜๋„ ๊ฒ€์ถœ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค!") + logger.error(f" 1004 ๋ชจ๋ธ ์ „์ฒด ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {len(detections_1004)}") + logger.error(f" ๊ฒ€์ถœ๋œ ํด๋ž˜์Šค: {set(d['class_name'] for d in detections_1004)}") + + # ๊ฒ€์ถœ๋œ ํด๋ž˜์Šค๋ณ„ ๊ฐœ์ˆ˜ ์ถœ๋ ฅ + class_counts = {} + for det in detections_1004: + class_name = det['class_name'] + class_counts[class_name] = class_counts.get(class_name, 0) + 1 + + logger.error(f" ํด๋ž˜์Šค๋ณ„ ๊ฒ€์ถœ ๊ฐœ์ˆ˜:") + for class_name, count in sorted(class_counts.items()): + logger.error(f" - {class_name}: {count}๊ฐœ") + else: + for i, det in enumerate(section_detections): + bbox = det['bbox'] + conf = det['confidence'] + logger.info(f" Section {i}: confidence={conf:.3f}, bbox=[{bbox[0]:.1f}, {bbox[1]:.1f}, {bbox[2]:.1f}, {bbox[3]:.1f}]") + + # Bbox ์œ ํšจ์„ฑ ์‚ฌ์ „ ๊ฒ€์‚ฌ + if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]: + logger.error(f" โš ๏ธ ๊ฒฝ๊ณ : Section {i}์˜ bbox๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Œ!") + logger.error(f" ๋„ˆ๋น„: {bbox[2] - bbox[0]:.1f}, ๋†’์ด: {bbox[3] - bbox[1]:.1f}") + + # ์ด๋ฏธ์ง€ ๋ฒ”์œ„ ๋ฒ—์–ด๋‚จ ์ฒดํฌ + image = cv2.imread(image_path) + h, w = image.shape[:2] + if bbox[0] < 0 or bbox[1] < 0 or bbox[2] > w or bbox[3] > h: + logger.warning(f" โš ๏ธ ๊ฒฝ๊ณ : Section {i}์˜ bbox๊ฐ€ ์ด๋ฏธ์ง€ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚จ!") + logger.warning(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {w}x{h}") + logger.warning(f" Bbox: [{bbox[0]:.1f}, {bbox[1]:.1f}, {bbox[2]:.1f}, {bbox[3]:.1f}]") + + page_name = Path(image_path).stem + page_output_dir = output_dir / page_name + page_output_dir.mkdir(parents=True, exist_ok=True) + + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ OCR (1004 ๋ชจ๋ธ ์‚ฌ์šฉ) + page_num_path, page_num_ocr = self.crop_page_number(image_path, detections_1004, page_output_dir) + + # ๋‹ต์ง€ ํ•„ํ„ฐ๋ง: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๊ฐ€ ๋‹ต์ง€์— ์—†์œผ๋ฉด ๊ฑด๋„ˆ๋›ฐ๊ธฐ + if not self.is_valid_page(page_num_ocr): + logger.info(f"ํŽ˜์ด์ง€ '{page_name}' (ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ: {page_num_ocr})๋Š” ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") + return None + + # 1104 ๋ชจ๋ธ: ๋‹ต์•ˆ ์ถ”๋ก ์šฉ + logger.info("1104 ๋ชจ๋ธ ์‹คํ–‰ ์ค‘ (๋‹ต์•ˆ ์ถ”๋ก )...") + result_1104 = self.router_1104.route_infer_single_image(image_path) + detections_1104 = result_1104['detections'] + + # Section ์˜์—ญ ๊ฒ€์ถœ (1004 ๋ชจ๋ธ ์‚ฌ์šฉ) + logger.info(f"ํŽ˜์ด์ง€ '{page_name}': {len(section_detections)}๊ฐœ Section ๊ฒ€์ถœ (ํ•„ํ„ฐ๋ง ์ „)") + + # ์ค‘๋ณต section ํ•„ํ„ฐ๋ง + section_detections = self.filter_duplicate_sections(image_path, section_detections, detections_1004) + + # ์ •๋ ฌ (y ์ขŒํ‘œ ๊ธฐ์ค€) + section_detections = sorted(section_detections, key=lambda x: x['bbox'][1]) + + logger.info(f"ํŽ˜์ด์ง€ '{page_name}': {len(section_detections)}๊ฐœ Section ์ฒ˜๋ฆฌ (ํ•„ํ„ฐ๋ง ํ›„)") + + page_result = [] + crop_failure_count = 0 + + for idx, det in enumerate(section_detections): + section_bbox = det['bbox'] + section_result = self.process_single_section( + image_path, idx, page_name, output_dir, section_bbox, + detections_1004, detections_1104 + ) + page_result.append(section_result) + + if not section_result.get('crop_success', True): + crop_failure_count += 1 + + end_time = time.time() + + # Crop ์‹คํŒจ ํ†ต๊ณ„ + if crop_failure_count > 0: + logger.warning(f"โš ๏ธ ํŽ˜์ด์ง€ '{page_name}': {crop_failure_count}๊ฐœ Section crop ์‹คํŒจ") + + return { + "image_path": image_path, + "page_name": page_name, + "page_number_ocr": page_num_ocr, + "sections": page_result, + "processing_time": end_time - start_time, + "total_sections": len(section_detections), + "crop_failure_count": crop_failure_count + } \ No newline at end of file diff --git a/ai-service/test/__init__.py b/ai-service/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-service/test/__pycache__/__init__.cpython-311.pyc b/ai-service/test/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..9797321 Binary files /dev/null and b/ai-service/test/__pycache__/__init__.cpython-311.pyc differ diff --git a/ai-service/test/__pycache__/__init__.cpython-312.pyc b/ai-service/test/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..1e5e4fe Binary files /dev/null and b/ai-service/test/__pycache__/__init__.cpython-312.pyc differ diff --git a/ai-service/test/api/monitoring.py b/ai-service/test/api/monitoring.py new file mode 100644 index 0000000..6c3f69f --- /dev/null +++ b/ai-service/test/api/monitoring.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +""" +Kafka ํ† ํ”ฝ ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํฌ๋ฆฝํŠธ +grading-status์™€ student-answer ํ† ํ”ฝ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. +""" + +import asyncio +import json +from aiokafka import AIOKafkaConsumer + +KAFKA_BOOTSTRAP_SERVERS = "3.34.214.133:9092" +TOPICS = ["grading-status", "student-answer"] + + +async def monitor_topics(): + """ํ† ํ”ฝ ๋ฉ”์‹œ์ง€ ๋ชจ๋‹ˆํ„ฐ๋ง""" + consumer = AIOKafkaConsumer( + *TOPICS, + bootstrap_servers=KAFKA_BOOTSTRAP_SERVERS, + group_id="monitor-consumer", + value_deserializer=lambda v: v.decode("utf-8"), + auto_offset_reset="latest", + enable_auto_commit=True + ) + + await consumer.start() + print(f"โœ… ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์ž‘: {TOPICS}") + print("=" * 60) + + try: + async for msg in consumer: + print(f"\n๐Ÿ“จ ํ† ํ”ฝ: {msg.topic}") + print(f" ํŒŒํ‹ฐ์…˜: {msg.partition}, ์˜คํ”„์…‹: {msg.offset}") + + try: + data = json.loads(msg.value) + print(f" ๋ฉ”์‹œ์ง€:") + print(json.dumps(data, indent=4, ensure_ascii=False)) + except json.JSONDecodeError: + print(f" ์›๋ณธ: {msg.value}") + + print("-" * 60) + + except asyncio.CancelledError: + print("\n๋ชจ๋‹ˆํ„ฐ๋ง ์ข…๋ฃŒ") + finally: + await consumer.stop() + + +if __name__ == "__main__": + try: + asyncio.run(monitor_topics()) + except KeyboardInterrupt: + print("\n์ข…๋ฃŒ๋จ") \ No newline at end of file diff --git a/ai-service/test/api/test_producer.py b/ai-service/test/api/test_producer.py new file mode 100644 index 0000000..e0eecad --- /dev/null +++ b/ai-service/test/api/test_producer.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +""" +ํ…Œ์ŠคํŠธ์šฉ Kafka ๋ฉ”์‹œ์ง€ ๋ฐœ์†ก ์Šคํฌ๋ฆฝํŠธ +s3-download-url ํ† ํ”ฝ์œผ๋กœ ํ…Œ์ŠคํŠธ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. +""" + +import asyncio +import json +from aiokafka import AIOKafkaProducer + +KAFKA_BOOTSTRAP_SERVERS = "3.34.214.133:9092" +TOPIC = "s3-download-url" + + +async def send_test_message(): + """ํ…Œ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ์ „์†ก""" + producer = AIOKafkaProducer( + bootstrap_servers=KAFKA_BOOTSTRAP_SERVERS + ) + + await producer.start() + + try: + # ํ…Œ์ŠคํŠธ ๋ฉ”์‹œ์ง€ + message = { + "downloadUrl": "https://example.com/test-image.jpg", + "uploadUrl": "https://example-bucket.s3.amazonaws.com/uploads", + "academy_user_id": 1, + "user_id": 100, + "class_id": 10, + "academy_id": 1, + "student_response_id": 12345, + "index": 1, + "total": 1 + } + + await producer.send_and_wait( + TOPIC, + value=json.dumps(message).encode('utf-8') + ) + + print(f"โœ… ํ…Œ์ŠคํŠธ ๋ฉ”์‹œ์ง€ ์ „์†ก ์™„๋ฃŒ") + print(f" ํ† ํ”ฝ: {TOPIC}") + print(f" ๋ฉ”์‹œ์ง€: {json.dumps(message, indent=2)}") + + finally: + await producer.stop() + + +if __name__ == "__main__": + asyncio.run(send_test_message()) \ No newline at end of file diff --git a/ai-service/test/yolo_resnet_answer/__init__.py b/ai-service/test/yolo_resnet_answer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-service/test/yolo_resnet_answer/__pycache__/__init__.cpython-311.pyc b/ai-service/test/yolo_resnet_answer/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000..e7ba1a1 Binary files /dev/null and b/ai-service/test/yolo_resnet_answer/__pycache__/__init__.cpython-311.pyc differ diff --git a/ai-service/test/yolo_resnet_answer/__pycache__/__init__.cpython-312.pyc b/ai-service/test/yolo_resnet_answer/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..815c4d3 Binary files /dev/null and b/ai-service/test/yolo_resnet_answer/__pycache__/__init__.cpython-312.pyc differ diff --git a/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test.cpython-311.pyc b/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test.cpython-311.pyc new file mode 100644 index 0000000..e584d11 Binary files /dev/null and b/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test.cpython-311.pyc differ diff --git a/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test.cpython-312.pyc b/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test.cpython-312.pyc new file mode 100644 index 0000000..f833075 Binary files /dev/null and b/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test.cpython-312.pyc differ diff --git a/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test_crop.cpython-311.pyc b/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test_crop.cpython-311.pyc new file mode 100644 index 0000000..c472b56 Binary files /dev/null and b/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test_crop.cpython-311.pyc differ diff --git a/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test_crop.cpython-312.pyc b/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test_crop.cpython-312.pyc new file mode 100644 index 0000000..82a0d2d Binary files /dev/null and b/ai-service/test/yolo_resnet_answer/__pycache__/yolo_test_crop.cpython-312.pyc differ diff --git a/ai-service/test/yolo_resnet_answer/answers/accuracy_analysis.ipynb b/ai-service/test/yolo_resnet_answer/answers/accuracy_analysis.ipynb new file mode 100644 index 0000000..6da4672 --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/accuracy_analysis.ipynb @@ -0,0 +1,1348 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ๐Ÿ“Š YOLO ๋‹ต์•ˆ ์ธ์‹ ์ •ํ™•๋„ ๋ถ„์„\n", + "\n", + "## ๊ฐœ์š”\n", + "- **results_summary.txt**: ์ด๋ฏธ์ง€ ํŒŒ์ผ, ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ์ •๋‹ต\n", + "- **yolo_answer.txt**: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ์ •๋‹ต (์ •๋‹ต์ง€)\n", + "\n", + "์ •๋‹ต์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ธ์‹ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ตํ•˜์—ฌ ์ •ํ™•๋„๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋“œ ์™„๋ฃŒ\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "from pathlib import Path\n", + "from typing import Dict, List, Tuple\n", + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "print(\"โœ… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋กœ๋“œ ์™„๋ฃŒ\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ •" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… Results ํŒŒ์ผ: results_summary.txt\n", + "โœ… Answer Key ํŒŒ์ผ: yolo_answer.txt\n" + ] + } + ], + "source": [ + "# ํŒŒ์ผ ๊ฒฝ๋กœ ์„ค์ • (ํ•„์š”์‹œ ์ˆ˜์ •)\n", + "results_path = Path(\"results_summary.txt\")\n", + "answer_key_path = Path(\"yolo_answer.txt\")\n", + "output_dir = Path(\"./\")\n", + "\n", + "# ํŒŒ์ผ ์กด์žฌ ํ™•์ธ\n", + "if not results_path.exists():\n", + " print(f\"โŒ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {results_path}\")\n", + "else:\n", + " print(f\"โœ… Results ํŒŒ์ผ: {results_path}\")\n", + "\n", + "if not answer_key_path.exists():\n", + " print(f\"โŒ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {answer_key_path}\")\n", + "else:\n", + " print(f\"โœ… Answer Key ํŒŒ์ผ: {answer_key_path}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. ๋ฐ์ดํ„ฐ ๋กœ๋“œ ๋ฐ ์ „์ฒ˜๋ฆฌ" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“„ Results Summary ๋กœ๋“œ ์™„๋ฃŒ: 155๊ฐœ ํ•ญ๋ชฉ\n", + " - None ๋‹ต์•ˆ: 0๊ฐœ\n", + "\n", + "๐Ÿ“˜ Answer Key ๋กœ๋“œ ์™„๋ฃŒ: 155๊ฐœ ํ•ญ๋ชฉ\n", + "\n", + "============================================================\n" + ] + } + ], + "source": [ + "def load_results(file_path: Path) -> pd.DataFrame:\n", + " \"\"\"results_summary.txt ๋กœ๋“œ\n", + " ํ˜•์‹: ์ด๋ฏธ์ง€ํŒŒ์ผ, ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต\n", + " \"\"\"\n", + " data = []\n", + " with open(file_path, 'r', encoding='utf-8') as f:\n", + " for line_num, line in enumerate(f, 1):\n", + " line = line.strip()\n", + " if not line:\n", + " continue\n", + " \n", + " parts = [p.strip() for p in line.split(',')]\n", + " if len(parts) >= 4:\n", + " data.append({\n", + " 'image_file': parts[0],\n", + " 'page_number': parts[1],\n", + " 'problem_number': parts[2],\n", + " 'predicted_answer': parts[3] if parts[3].lower() != 'none' else None\n", + " })\n", + " else:\n", + " print(f\"โš ๏ธ Warning: ๋ผ์ธ {line_num} ํ˜•์‹ ์˜ค๋ฅ˜: {line}\")\n", + " \n", + " df = pd.DataFrame(data)\n", + " print(f\"\\n๐Ÿ“„ Results Summary ๋กœ๋“œ ์™„๋ฃŒ: {len(df)}๊ฐœ ํ•ญ๋ชฉ\")\n", + " print(f\" - None ๋‹ต์•ˆ: {df['predicted_answer'].isna().sum()}๊ฐœ\")\n", + " return df\n", + "\n", + "def load_answer_key(file_path: Path) -> pd.DataFrame:\n", + " \"\"\"yolo_answer.txt ๋กœ๋“œ (์ •๋‹ต์ง€)\n", + " ํ˜•์‹: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต\n", + " \"\"\"\n", + " data = []\n", + " with open(file_path, 'r', encoding='utf-8') as f:\n", + " for line_num, line in enumerate(f, 1):\n", + " line = line.strip()\n", + " if not line:\n", + " continue\n", + " \n", + " parts = [p.strip() for p in line.split(',')]\n", + " if len(parts) >= 3:\n", + " data.append({\n", + " 'page_number': parts[0],\n", + " 'problem_number': parts[1],\n", + " 'correct_answer': parts[2]\n", + " })\n", + " else:\n", + " print(f\"โš ๏ธ Warning: ๋ผ์ธ {line_num} ํ˜•์‹ ์˜ค๋ฅ˜: {line}\")\n", + " \n", + " df = pd.DataFrame(data)\n", + " print(f\"\\n๐Ÿ“˜ Answer Key ๋กœ๋“œ ์™„๋ฃŒ: {len(df)}๊ฐœ ํ•ญ๋ชฉ\")\n", + " return df\n", + "\n", + "# ๋ฐ์ดํ„ฐ ๋กœ๋“œ\n", + "results_df = load_results(results_path)\n", + "answer_key_df = load_answer_key(answer_key_path)\n", + "\n", + "print(\"\\n\" + \"=\"*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ ํ™•์ธ" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. ์ •๋‹ต ๋น„๊ต ๋ฐ ์ •ํ™•๋„ ๊ณ„์‚ฐ" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "โœ… ์ •๋‹ต ๋น„๊ต ์™„๋ฃŒ\n", + "\n", + "๐Ÿ“Š ์ „์ฒด ๊ฒฐ๊ณผ:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberproblem_numbercorrect_answerimage_filepredicted_answer_mergeresult
09011แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11bothcorrect
110022แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 22bothcorrect
211032แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 32bothcorrect
312044แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 44bothcorrect
413051แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 51bothcorrect
515014แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64bothcorrect
616025แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 75bothcorrect
717031แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 81bothcorrect
818043แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 93bothcorrect
919052แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 102bothcorrect
1021011แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 111bothcorrect
1122022แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 122bothcorrect
1223034แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 134bothcorrect
1324041แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 141bothcorrect
1425051แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 151bothcorrect
1527013แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 163bothcorrect
1628024แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 174bothcorrect
1729034แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 184bothcorrect
1830042แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 192bothcorrect
1931051แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 201bothcorrect
\n", + "
" + ], + "text/plain": [ + " page_number problem_number correct_answer \\\n", + "0 9 01 1 \n", + "1 10 02 2 \n", + "2 11 03 2 \n", + "3 12 04 4 \n", + "4 13 05 1 \n", + "5 15 01 4 \n", + "6 16 02 5 \n", + "7 17 03 1 \n", + "8 18 04 3 \n", + "9 19 05 2 \n", + "10 21 01 1 \n", + "11 22 02 2 \n", + "12 23 03 4 \n", + "13 24 04 1 \n", + "14 25 05 1 \n", + "15 27 01 3 \n", + "16 28 02 4 \n", + "17 29 03 4 \n", + "18 30 04 2 \n", + "19 31 05 1 \n", + "\n", + " image_file predicted_answer _merge result \n", + "0 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1 1 both correct \n", + "1 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2 2 both correct \n", + "2 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3 2 both correct \n", + "3 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4 4 both correct \n", + "4 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5 1 both correct \n", + "5 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6 4 both correct \n", + "6 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7 5 both correct \n", + "7 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8 1 both correct \n", + "8 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9 3 both correct \n", + "9 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10 2 both correct \n", + "10 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11 1 both correct \n", + "11 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 12 2 both correct \n", + "12 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 13 4 both correct \n", + "13 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14 1 both correct \n", + "14 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 15 1 both correct \n", + "15 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 16 3 both correct \n", + "16 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 17 4 both correct \n", + "17 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 18 4 both correct \n", + "18 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 19 2 both correct \n", + "19 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 20 1 both correct " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ์ •๋‹ต์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ results์™€ merge\n", + "merged_df = answer_key_df.merge(\n", + " results_df,\n", + " on=['page_number', 'problem_number'],\n", + " how='left',\n", + " indicator=True\n", + ")\n", + "\n", + "# ๋น„๊ต ๊ฒฐ๊ณผ ์ปฌ๋Ÿผ ์ถ”๊ฐ€\n", + "def compare_answers(row):\n", + " \"\"\"์ •๋‹ต ๋น„๊ต\"\"\"\n", + " if row['_merge'] == 'left_only':\n", + " return 'missing' # results์— ์—†์Œ\n", + " elif pd.isna(row['predicted_answer']):\n", + " return 'none' # None์œผ๋กœ ์˜ˆ์ธก๋จ\n", + " elif str(row['predicted_answer']).strip() == str(row['correct_answer']).strip():\n", + " return 'correct' # ์ •๋‹ต\n", + " else:\n", + " return 'wrong' # ์˜ค๋‹ต\n", + "\n", + "merged_df['result'] = merged_df.apply(compare_answers, axis=1)\n", + "\n", + "print(\"\\nโœ… ์ •๋‹ต ๋น„๊ต ์™„๋ฃŒ\")\n", + "print(\"\\n๐Ÿ“Š ์ „์ฒด ๊ฒฐ๊ณผ:\")\n", + "display(merged_df.head(20))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. ์ •ํ™•๋„ ํ†ต๊ณ„" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "๐Ÿ“Š ์ •ํ™•๋„ ํ†ต๊ณ„\n", + "============================================================\n", + "\n", + "๐Ÿ“˜ ์ •๋‹ต์ง€ ๊ธฐ์ค€:\n", + " ์ด ๋ฌธ์ œ ์ˆ˜: 155๊ฐœ\n", + "\n", + "โœ… ์ •๋‹ต: 154๊ฐœ (99.35%)\n", + "โŒ ์˜ค๋‹ต: 1๊ฐœ (0.65%)\n", + "โš ๏ธ None: 0๊ฐœ (0.00%)\n", + "๐Ÿ” ๋ˆ„๋ฝ: 0๊ฐœ (0.00%)\n", + "\n", + "============================================================\n", + "๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: 99.35%\n", + "๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): 100.00%\n", + "โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„ (None ํฌํ•จ): 99.35%\n", + "============================================================\n" + ] + } + ], + "source": [ + "# ๊ฒฐ๊ณผ๋ณ„ ๊ฐœ์ˆ˜ ๊ณ„์‚ฐ\n", + "total_count = len(merged_df)\n", + "correct_count = (merged_df['result'] == 'correct').sum()\n", + "wrong_count = (merged_df['result'] == 'wrong').sum()\n", + "none_count = (merged_df['result'] == 'none').sum()\n", + "missing_count = (merged_df['result'] == 'missing').sum()\n", + "\n", + "# ์ •ํ™•๋„ ๊ณ„์‚ฐ\n", + "accuracy = correct_count / total_count * 100 if total_count > 0 else 0\n", + "\n", + "# ์ธ์‹ ์„ฑ๊ณต๋ฅ  (None ์ œ์™ธ)\n", + "recognized_count = total_count - missing_count\n", + "recognition_rate = recognized_count / total_count * 100 if total_count > 0 else 0\n", + "\n", + "# ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„\n", + "accuracy_of_recognized = correct_count / recognized_count * 100 if recognized_count > 0 else 0\n", + "\n", + "print(\"=\"*60)\n", + "print(\"๐Ÿ“Š ์ •ํ™•๋„ ํ†ต๊ณ„\")\n", + "print(\"=\"*60)\n", + "print(f\"\\n๐Ÿ“˜ ์ •๋‹ต์ง€ ๊ธฐ์ค€:\")\n", + "print(f\" ์ด ๋ฌธ์ œ ์ˆ˜: {total_count}๊ฐœ\")\n", + "print(f\"\\nโœ… ์ •๋‹ต: {correct_count}๊ฐœ ({correct_count/total_count*100:.2f}%)\")\n", + "print(f\"โŒ ์˜ค๋‹ต: {wrong_count}๊ฐœ ({wrong_count/total_count*100:.2f}%)\")\n", + "print(f\"โš ๏ธ None: {none_count}๊ฐœ ({none_count/total_count*100:.2f}%)\")\n", + "print(f\"๐Ÿ” ๋ˆ„๋ฝ: {missing_count}๊ฐœ ({missing_count/total_count*100:.2f}%)\")\n", + "print(f\"\\n{'='*60}\")\n", + "print(f\"๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: {accuracy:.2f}%\")\n", + "print(f\"๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): {recognition_rate:.2f}%\")\n", + "print(f\"โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„ (None ํฌํ•จ): {accuracy_of_recognized:.2f}%\")\n", + "print(\"=\"*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. ์‹œ๊ฐํ™”" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“Š Visualization saved: accuracy_visualization.png\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABXIAAAJNCAYAAACcOY1uAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAv99JREFUeJzs3Xd8VfX9x/H3HdlkQhIIexuQLSCgBQFBtIrWWVGxtlJ3FVexLtRqcdWt1VaUnwhaFRytWGSD7A2yCTNkkD1v7ji/Pyi3XJJAAknOzb2v5+PBw+Scc+9935sIJ+987+dYDMMwBAAAAAAAAADwW1azAwAAAAAAAAAATo0iFwAAAAAAAAD8HEUuAAAAAAAAAPg5ilwAAAAAAAAA8HMUuQAAAAAAAADg5yhyAQAAAAAAAMDPUeQCAAAAAAAAgJ+jyAUAAAAAAAAAP0eRCwAAAAAAAAB+jiIXQa1du3ayWCyyWCx6+umnvdsXLlzo3W6xWLRv3z7TMppt3759Pq/FwoULzY7k5Y9fp1O9Xk8//bR3e7t27UzLeKKPPvrIJy8AAAD8z6233uo9Xxs2bJjZcQAAJqHIhTZu3Ki77rpLPXr0UFxcnEJDQ5WcnKzhw4fr5ZdfVkFBgdkRG41hw4b5lGLH/4SHh6tNmzYaO3asZs2aZXbMOnO2Je/JRazFYlFoaKhiY2PVoUMHjRw5UpMnT9bBgwfr5wmc4MSv3a233lrvj9cQKGkBAECwqer80mKxyGazKS4uTn379tWjjz6qjIwMs6PWmboqeQ3D0L///W/dfPPN6tKli2JiYhQSEqLk5GSNGDFCU6ZM0ZEjR+oueAOpbvEOADRGdrMDwDwul0sPPvig3njjjUr7srKylJWVpQULFmjKlCmaPn26Ro0aZULKwOBwOHTw4EEdPHhQ33zzjR577DH9+c9/NjuWX3I6nXI6nSosLFRaWprmzZunZ599Vk888YSeeOIJWa3/+/1Tx44d9dJLL3k/T0hIMCOyj4SEBJ9MHTt2NDHN6fXv398nLwAAQCDyeDwqKCjQ+vXrtX79ek2bNk2rVq1S69atzY7mFw4ePKgbb7xRS5curbQvKytL8+fP1/z587Vt2zZ99NFHDR8QACCJIjeo3XvvvXrvvfe8n6ekpOi6665Ts2bNtHnzZn3xxRdyu906evSoLr/8cs2fP19DhgwxMXFlbrdbDodDkZGRZkepJD4+Xo899phcLpd27typ6dOnq6KiQpI0ZcoUPfjgg35RPPqT66+/Xuedd54KCgq0bt06/fDDD3K73XK73Xr66aeVkZGhd99913t869at9dBDD5mY+H8qKipkGIZiYmL8JlNNdO/eXd27dzc7BgAAQL04fn5ZWFio2bNna/PmzZKkjIwM/fWvf9Wrr75qckLzZWZmaujQoUpLS/Nua9++va644golJycrLy9PK1asqLLkBQA0MANBadmyZYYk75++ffsaBQUFPsfMmzfPsFqt3mO6d+9uuN1uw+12G23atPFuf+qppyrd/yOPPOLd37lzZ599GRkZxqRJk4xevXoZTZo0McLCwoyOHTsad911l7F///5K9zV+/HjvfQ0dOtTYv3+/cdNNNxlJSUmGxWIxZs2aZRiGYfzjH/8wrr32WuOcc84xmjZtatjtdiM6Otro1auX8cgjjxjZ2dmV7rtt27ZVPo8FCxb4vD5paWk1el2HDh3qvU3btm199j366KM+97l8+fJKty8oKDCef/55Y8CAAUZMTIwREhJitG7d2hg/fryxZcuWSsc7nU7jr3/9q3H++ecbsbGxhs1mMxISEoxu3boZN998szFjxgzvsWlpaT6Pv2DBgmqzjx8//rS3O/G1q+rP0KFDT/t6nfw6T5061Wf/zz//bLRv397nmO+//77a25/4dSouLjYmT55s9OnTx2jSpIlht9uNxMREo1evXsbvfvc77/089dRTp3weJ97vya/R5s2bjbFjxxoJCQmGJGP9+vWnfJ1PfKy2bdsahYWFxsSJE41WrVoZYWFhRmpqqvHmm28aHo+nRl8bwzCMqVOn+jxeVV+zqv4c/36v6vYnKi0tNV599VVj8ODBRlxcnBESEmIkJSUZY8aMMT777LPTfk337NljvP3220aPHj2MsLAwIzEx0fjtb39r5ObmnupbAwAA4Iyc6vwyPz/fCA0N9e4bPXp0lfexePFi4/rrrzdat25thIaGGtHR0cb5559vvPXWW0ZFRUWl4zdt2mSMGzfOaNu2rREaGmqEh4cbrVu3Ni666CLjj3/8o3Ho0CHvsSf/bHOq7Cee21Z1u5PP46r6c/I5f1VuuOEGn9vceeedhtPprHTczp07jU8++aTS9i+++MK49NJLjeTkZCMkJMSIi4szBg0aZLz88stGSUmJz7F1+TPJjBkzjAEDBhgRERFGXFyccc011xgHDhyo8jWr7s9x+/btMyZMmGB06tTJCA8PN8LCwoyUlBRj8ODBxgMPPGD8/PPPp30dAaAhsCI3SL3//vs+n7/44ouKiYnx2TZ8+HBdf/31mjFjhiRp69atWrJkiYYOHarx48fr2WeflSTNmDHDZ9aQYRiaOXOm9/Pf/OY33o+XL1+uK664QkePHvV5rD179uidd97R9OnT9e233+rCCy+sMnd6eroGDhxY5Uyrd955R2vXrvXZVlRUpI0bN2rjxo2aPn26Vq1apZSUlOpelnrVsmVLn8+bNWvm8/muXbs0atSoShfsOnjwoD7++GPNnDlT//d//6drr73Wu+93v/udPv74Y5/jc3NzlZubq59//lk7d+7UDTfcULdPpAGlpqbqs88+04ABA7zb/vrXv+qSSy457W1/+ctfVprZm52drezsbG3cuFFFRUU1up/qbNq0Seeff75KSkrO6Pbl5eUaPny41qxZ4922bds23Xvvvdq5c2eVI08aWkZGhkaOHKmtW7f6bM/KytL333+v77//Xp9//rlmzpwpu73qf07Gjx/vs3ojOztb//jHP7Rr1y4tWrSoXvMDAACcKDY2Vk2aNFFubq6kyufjkvSnP/1Jzz//vM+2iooKrVixQitWrNBnn32m77//XlFRUZKkn3/+Weeff75KS0t9bnN8rNqCBQs0dOjQSj8L+IsjR47os88+837eu3dvvfXWWz7jzI7r3LmzOnfu7P3c7Xbrxhtv1Oeff+5zXH5+vpYvX67ly5frH//4h+bNm6cWLVrUae4nnnjC5xyzrKxMX3zxhTZu3KhNmzYpPDy8xveVlZWl/v37Kzs722d7enq60tPT9dNPP6lLly5KTU2ts/wAcKYocoPUkiVLvB/Hx8drxIgRVR53YpF7/HZDhw7Vrbfequeee06GYWjnzp1au3at+vXrJ0latmyZDhw4IEmy2Wy65ZZbJEmFhYW68sorvSVu27Ztdf311ysiIkJffPGFtm7dqoKCAl199dXatWuXYmNjK+XZtWuXJOlXv/qVevXqpf3793uPS0pK0uWXX66OHTsqISFBNptNhw8f1meffaacnBwdPnxYzz33nN55552zfflqxe12a+fOnfrwww+92/r27atOnTr5HHPVVVd5S9zExETdeOONSkhI0A8//KCffvpJDodDt9xyi/r166cOHTqouLhYn3zyifc+rr76avXt21cFBQXav39/vZdkf/rTn7Rv3z6fE9077rjDOxO2ruaN9e/fX7169dLGjRslSYsXL5bb7ZbNZqv2Ntu2bfOWuFarVbfccou6dOmio0ePKi0tzafgHTVqlJo0aaJ3331Xe/fulSSdd955uv76673HVDUCY/369bLb7br55pvVuXNnbd++vVYnjJmZmcrPz9cdd9yhuLg4ffLJJzp06JAk6c0339TVV1+toUOH1vj+TnR8Tu+aNWt8TsxPnIU7ePDg097PuHHjfErca665Rt26ddPcuXO1fPlySdKXX36p559/Xk8++WSV97F06VKNGDFCgwcP9nk74+LFi7VixQqdf/75Z/QcAQAAaqOwsFAfffSRt8SVpOuuu87nmJkzZ/qc244ePVpDhgxRZmamPv74YxUXF2vJkiV64IEHvAtjPv74Y2+J26pVK910002KiorSoUOHtGXLFq1YsaLentPxax189tln3sUBHTp00J133uk95nTXa1iwYIEMw/B+Pn78+CpL3Ko8//zzPiXu+eefr1GjRmnbtm365z//KenYefm4ceM0f/78Gj+vmli6dKn69++v0aNHa8GCBVq2bJmkYz8vzp49WzfccINuuOEGnXvuuXr++eeVl5cnSbr44osrXfvlyy+/9Ja48fHx+s1vfqOmTZsqPT1d27dv9/nZGQBMZ/KKYJgkIiLC+3aS3r17V3vc+vXrfd56ctddd3n3DRs2zLv9wQcf9G6/6667vNvHjBnj3f766697t8fHxxs5OTnefcXFxUZiYqJ3/+uvv+7dd/JbYl577bVq85aUlBg//vij8f777xuvvvqq8dJLLxljx4713rZDhw4+x9fnaIXq/vTv39/Yt2+fz+2+/vpr736bzWbs3LnTu8/lchk9evTw7n/ggQcMwzCM3Nxc77aYmBjD4XD43KfH4zH27t3r/byuRyvU5D5P53SjFY677rrrfI7Lysqq8vbHv07r1q3zbktNTa00qsDlclX6GpxqfEFVx0gyZs+eXemYmo5WkGRMnz7d53YhISHefePGjatRtlONRjjd2IRTHXPy//uPPPKIz+s3aNAg776EhATD7XYbhlH5a3LVVVd5X/+cnBzDZrN5973xxhtVZgIAADhTJ5+LVPUnMjLSeOmllyrd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+GRVfX0iIyNrlO/ki6F9/PHHmjJliqRj4z9OvNBeQkKCunbtWqP7BQAAMMtf/vIXzZw5UwUFBZKkZ555RjfeeKNsNpuioqLUu3dv73iFnJwc/eEPf6h0PlVQUKDvv//eO+IsLS1N8fHxiouL05gxY7zn8KNGjdKvfvUrScfOx4878bxux44dys/PV1xcnAoKCvT222+f0fM6m/PYFi1a6LrrrvP+3Ld+/Xr94Q9/0GuvvVbp3WO7du3SqlWrNG7cOHXt2lUJCQnelbmffPKJfv/733tvc/I56vFzy/r4meR0Tvf6pKeny2azKTk5WcOHD/cucFq/fr23sD9w4IBycnJO+85AAKhvFLlBavDgwfr973/v/Y30mjVrlJqaquuuu07NmjXT5s2b9cUXX8jtdkuSQkND9f7771f6DeqgQYN0zjnnaPv27T5lau/evdW7d2+fY2+99VY999xzOnr0qFwul4YMGaJrr71WnTp1ksPh0I4dO7Rw4UJlZmZqwYIFtZrv2rVrV82dO1eStGnTJv36179Wamqqvv/++3q9Umxt/OEPf9Arr7ziHf/wl7/8RTfffLOsVqsuu+wypaamatu2bZKkK6+8Ur/61a/UrVs372+mFy9erP3792vq1Kne1/b8889XSkqKLrzwQqWkpCgmJkYbN270lrjS/06WYmJi1KVLF++Ygj//+c9av369ysrKzvgqsomJiQoJCfEW+H/605+0ceNGhYSEaNiwYd4CtabmzJmjo0ePqrCwUOvXr9ecOXPkcrm8++++++5KV5mtSn5+vrp166bu3btrwIABSklJUUREhJYuXeo9cZd8TyRPfFvZv/71L/3xj39Us2bN1KxZM+8qjrp22223acmSJYqLi9Mnn3zi84uQ3/3ud96P+/fvr1mzZkmSdu/erb59+yo1NVULFizw+f/uZCe/Ve7GG2/U4MGDZbVadfPNN59y1levXr00YsQIzZs3T5L04osvau/everevbv+85//+Mw5+8Mf/lDjqxsDAACYJS4uTnfffbeef/55ScfOq078xfrDDz+scePGSTp2DYuePXvq8ssvV3x8vHJycrR+/XotXbpULVq08C42+Oyzz/TUU09p2LBh6ty5s1q0aKGSkhLNmDHD53GP69+/v/fjwsJC9enTRwMGDNCyZct0+PDhM3peJ57zrV27Vn/4wx/UunVrhYaG6r777jvt7f/6179qxYoV3hWnb731lr7//ntdfvnlSk5OVm5urlauXKklS5bolltu0bhx42S1WvXAAw/oiSeekHRsBu4FF1ygUaNGafv27T7v7LzooovUq1cvSfXzM8nptGzZUrt375YkffTRR4qIiFB0dLQ6duyoq666SosXL9a4ceN0wQUXKDU1VSkpKXK73frqq6+89xEaGlrjBREAUK9Musga/IDT6TTuueee017VtWnTpsYPP/xQ7f1MmTKl0m2quxr9smXLjGbNmp32MU+8emlNrsK6a9cuIzo6utL92O12Y9y4cT7bTlTdFUxPdcXYUznxKqtt27attP+hhx7yud/PPvvMu2/Hjh1Gu3btTvvaTJ061XubsLCwUx7bvn17Iz8/33v83//+9yqP69Chg3HOOefU6AqxJ19Z9qqrrqryPqu6EvDJanJV4eNfx2effdZwu92nvP3xr9ORI0dOe58DBgwwnE6n976+/vrrKo/r3r17lV/fE1+jE53q9Xrqqae825s1a2Z07969yse86667fO4zMzPTaNq0aaXjrFarMXr06Gq/v8vLy40WLVpU+RirV682DMMwpk6dWu3tjxw5YnTr1u2Ur+PVV1/t8zqe7v+d0101GAAA4GycfC5y4rmzYRhGVlaWERkZ6XOu5/F4vPsnTZp02vPIE8/zX3jhhdMef+LPRmVlZUbnzp2rPO7SSy+t9jzqVD8TrV+/3rBarZXuLyoqqsav2759+4xBgwad9rmceA7scrmMa6+99pTHp6amGocPH/Z5rPr4meRU5+mvv/56lY932WWXGYZhGDNmzDjt8544cWKNX0sAqE8soQpidrtdb775ptavX68777xT3bp1U3R0tOx2uxITEzVs2DC9+OKL2rNnzylXQd58880+b7sJDQ31/lb7ZIMHD9bWrVv1xBNPqF+/foqJiZHNZlNcXJz69eune+65R3PnztUvfvGLWj2XTp06afHixRo1apQiIyPVpEkTDR06VPPmzdPIkSNrdV/16cEHH/QZjfD8889751F16dJFmzZt0osvvqjBgwcrPj5eNptN0dHR6tmzp373u99p1qxZPq/tu+++q9/85jfq2bOnEhMTZbfb1aRJE/Xs2VOPPPKIVq5c6TNT97e//a0++OADpaamKjQ0VM2bN9edd96pVatWnfGVWD/44AONHz9e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fWr1NkAAAACcPVbkAgAABLDi4mLt3r3b+3laWpo2bNighIQEtWnTRg8//LCuv/56/eIXv9BFF12kOXPm6Ntvv9XChQslSbGxsfrtb3+riRMnKiEhQTExMbr33ns1aNCgai90hobndDpVUFDg/fi4nJwchYWFKTIyUnPnztX06dN11113acCAASoqKtJTTz2lkpISSdKQIUNMyQ4AAICasRiGYZgdAgAAAPVj4cKFuuiiiyptHz9+vD766CNJ0ocffqgXXnhBhw4dUteuXTV58mTvrFRJKi8v14MPPqgZM2bI4XBo9OjReuedd045WuFkhYWFio2NVUFBATNy60F1X+fjnnrqKfXu3VtXXXVVlfujoqK0ZMkS9enT57T3/+ijj+ovf/nL2YcGAABArc6TWZELAAAQwIYNG6bT/d7+tttu02233Vbt/vDwcL399tt6++236zoeGtCgQYP01FNPac6cOdq7d6/y8vKUmJioiy66SE8++aS6du1qdkQAAACcAityAQAAUO9YkQsAAABUVpvzZC52BgAAAAAAAAB+jiIXAAAAAAAAAPwcRS4AAAAAAAAA+DmKXAAAAAAAAADwcxS5AAAAAAAAAODnKHIBAAAAAAAAwM9R5AIAAAAAAACAn6PIBQAAAAAAAAA/R5ELAAAAAAAAAH6OIhcAAAAAAAAA/BxFLgAAAAAAAAD4ObvZAQAAAICGcvnsq8yOAD/27ZWzzI4AAABQLVbkAn5s2LBhuv/++8/6fm699VZdeeWVZ30/AAAAAAAAMAdFLtDAbr31VlksFt1xxx2V9t19992yWCy69dZbJUlfffWVnn322Spv/5e//MVn++zZs2WxWKp8zNdff10fffRRneSviUAujuuqXAcAAAAAAKgNilzABK1bt9bMmTNVVlbm3VZeXq5PP/1Ubdq08W5LSEhQdHR0pduHh4drypQpysvLq9HjxcbGKi4u7qxzNxYVFRWVtrndbnk8HhPSAAAAAAAAnD2KXMAEffv2VevWrfXVV195t3311Vdq06aN+vTp49128urPd955R1999ZUqKipUVFSk888/37vvp59+kiRFRESoadOm6tmzp1JTUxUWFqYmTZro3HPP9bnfmJgY/eIXv1BYWJisVqtiY2P1/vvve4/Zvn27+vfvL5vNJpvNpujoaFksFp9jamLYsGG677779MgjjyghIUHNmzfX008/7XNMfn6+fv/73ys5OVnh4eE699xz9d1333n3f/nll+revbvCwsLUrl07vfLKKz63b9eunZ599lndcsstiomJ0YQJE/TRRx8pLi5O33zzjbp166awsDAdOHBADodDDz30kFq2bKmoqCgNHDhQCxcu9Lm/ZcuWadiwYYqMjFR8fLxGjx6tvLw83XrrrVq0aJFef/11WSwWWSwW7du3r1avBwAAAAAAwJmgyAVMctttt2nq1Knezz/88EP95je/qfb4NWvW6L777lPv3r01YsQITZkyRXv37tWhQ4d05MgRvfrqq5Kkbdu26Z133tGWLVt09dVXa/Pmzerdu7e2bdvmM16huLhYa9as0aRJkzRlyhQVFRXpjjvu0I4dO+R2uzV27Fht27ZNl19+uT788EO1b99ekjR58uQqV7yeyscff6yoqCitXLlSL774op555hnNnTtXkuTxeDRmzBgtW7ZMn3zyiX7++Wf95S9/kc1mkyStXbtW1113nW644QZt3rxZTz/9tJ544olKoyJefvll9erVS+vXr9cTTzwhSSotLdWUKVP097//XVu3blVSUpLuueceLV++XDNnztSmTZt07bXX6pJLLtGuXbskSRs2bNCIESPUrVs3LV++XEuXLtXll18ut9ut119/XYMGDdLtt9+uI0eO6MiRI2rdunWtXgsAAAAAAIAzYTc7ABCsbrrpJk2aNEn79++XdGwV6MyZMyutDj3uwIEDioqKUuvWrVVSUqIHH3xQX3zxhZ566indfffdcrvdko6tTv3Tn/6kkSNH6rnnnpMkderUSZmZmXrppZe883dDQ0N19dVXe1fH/vOf/9TWrVu1YMECpaWlac+ePWrXrp1mzZoli8Wili1b6uKLL9bRo0e1cOFCjRo1qsbPtWfPnnrqqackSZ07d9Zbb72lefPm6eKLL9aPP/6oVatWadu2berSpYskqUOHDt7bvvrqqxoxYoS3nO3SpYt+/vlnn+ciScOHD9eDDz7o/XzJkiVyOp1655131KtXL+9rOHXqVB04cEApKSmSpIceekhz5szR1KlT9fzzz+vFF1/Ueeedp3feecd7X927d/d+HBoaqsjISDVv3rzGzx8AAAAAAOBsUeQCJklMTNRll12mjz76SIZh6LLLLlOzZs2qPf7iiy9W27Zt9eWXXyoxMVHTp0/X5MmTdemll+qBBx5Qz549vStMV65cqRtvvNHn9gkJCVq/fr238A0JCVHPnj29+1u0aKHdu3crKytLDodDTZo00b59+7wzeg3DkHRs/uyePXtq9VxPfJzjj5WVlSXp2ArYVq1aeUvck23btk1jx4712TZkyBC99tprcrvd3pW75513XqXbhoaG+jz25s2b5Xa7Kz2Ww+FQ06ZNvXmuvfbaWj0/AAAAAACA+kaRC5jotttu0z333CNJevvtt095bHR0tNatW6dLL71UaWlpevLJJ2W1WjV8+HA9/vjjevrpp/WrX/1K3bp103fffac333xTv//9770jEU5msVgUEhLi87kk7wXBPB6P+vXrp+nTp0uSioqK1LdvX73zzjuVSuLTOfFxjj/W8ceJiIio1X1VJyoqqtK2iIgI7/OSjo2TsNlsWrt2rbcAPq5JkyZ1mgcAAAAAAKAuMSMXMNEll1yiiooKOZ1OjR49+rTH2+12paSkqHv37tq0aZP27dunMWPG6Ntvv9WKFSskHZthe+WVV8rtdmvWrFne2+bm5qpLly6VCsyqdO3aVSUlJdqxY4eSkpLUqVMn5ebmSjq2mjY2NvYMn3FlPXv21KFDh7Rz584q96empmrZsmU+25YtW1bj53KiPn36yO12KysrS506dfL5c3xUQs+ePTVv3rxq7yM0NNS7qhkAAAAAAKChUOQCJrLZbNq2bZt+/vnn05aS3333nd544w3l5uaqtLRU06ZNk8fj0ahRozRq1Cjvxc4OHDig3r17y+FwaP369dq5c6d2796tvXv36qGHHqpRrosvvlidOnWS0+nUiBEj9M477+jhhx+WJP3973/XoUOHzu6Jn2Do0KH6xS9+oauvvlpz585VWlqavv/+e82ZM0eS9OCDD2revHl69tlntXPnTn388cd66623avxcTtSlSxeNGzdOt9xyi7766iulpaVp1apVeuGFF/Svf/1LkjRp0iStXr1ad911lzZt2qTt27fr3Xff1dGjRyUdm0G8cuVK7du3T0ePHvWuLAYAAAAAAKhPFLmAyWJiYhQTE3Pa4+Li4vTVV1/phx9+0Pz58/Xee+9pxowZ6t69ux588EHvKtEuXbroww8/1G9/+1utW7dO5557rjZs2KDU1FSfi4Odis1m09dff63u3btr3bp1uu+++7R582ZJktvtrlHe2vjyyy/Vv39/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t1t//vOfNW7cOElSRkaGJCk5OdnndsnJyd59J3vhhRc0efLkStuzs7NNHcfQWi1Ne2z4v6ysLLMjAACAIFNUVPOFPgFf5BaXFMvtdstu832qLovLpERAYGBFLnDmiiuKzY4AP2XWasDPP/9c06dP16effqru3btrw4YNuv/++5WSkqLx48ef0X1OmjRJEydO9H5eWFio1q1bKzExUTExMXUVvdYO6rBpjw3/l5SUZHYEAAAQZMLDw2t8bMAXuUUlx1pti8X3bXQuK6sJgbPhocgFzliRkyIX/uXhhx/WH//4R++IhB49emj//v164YUXNH78eDVv3lySlJmZqRYtWnhvl5mZqd69e1d5n2FhYQoLC6u03Wq1ymo173q7hrhYJ6pn5vcmAAAITrU5/wiCIrfqH5ZZkQucHTejFYAzxopcnM6iRYv0r3/9S/v375cktW3bVpdddpmGDh1aL49XWlpa6QTSZrN5Vwi3b99ezZs317x587zFbWFhoVauXKk777yzXjIBAAAA8BXwRW5eQa5sVlul7ZRQwNlhRS5w5opZkYtqVFRU6Ne//rVmz54twzAUFxcn6djFzl555RVdddVVmjFjhkJCQur0cS+//HL9+c9/Vps2bdS9e3etX79er776qm677TZJx97ZdP/99+u5555T586d1b59ez3xxBNKSUnRlVdeWadZAAAAAFQt4N87dDQvp9KFziTJZWVFLnA2mJELnLliLnaGakyePFmzZs3Sgw8+qCNHjig3N1e5ubnKyMjQQw89pK+++krPPPNMnT/um2++qWuuuUZ33XWXUlNT9dBDD+n3v/+9nn32We8xjzzyiO69915NmDBB/fv3V3FxsebMmVOrmV4AAAAAzpzFMIyAHhT29GuTVVBcoJSkFJ/t6+M3qiiEFVHAmWpVmqJDkelmxwAapYTweH18yYdmx4Afat++vYYNG6apU6dWuf/WW2/VwoULtW/fvoYNVgcKCwsVGxurgoICUy92dvnsq0x7bPi/b6+cZXYEAAAQZGpznhzQK3LdbrfKK8qrHK3AjFzg7LjFilzgTBVXsCIXVTty5IgGDhxY7f6BAwcqIyOjARMBAAAA8BcBXeQ6nA653W7ZbZVHAbuYkQucFeZMA2euwlMhh9thdgz4oVatWmnhwoXV7l+0aJFatWrVcIEAAAAA+I2ALnIrKirkdrtk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79ZHH32kl156SZ999pmuvvpqXXLJJdq5c6ckaePGjZo6dary8vL00Ucf6R//+IdmzpypYDCoX//61xo7dqxuu+228PhNT09vvycSHYbVatUjjzyi3/zmNzp48OAJt7d03P7yl7/UyJEj9emnn+quu+7St771LW3fvl3S8W9AzJgxQzExMfrggw+0evVqeTweXXLJJaf81gS6p4ULF+rZZ58NX//Tn/6km2+++ZT9P/nkE33729/WQw89pO3bt+utt97ShAkTJEmHDx/WvHnztHDhQhUUFGjlypWaM2eOTNM85flO9xofDAY1e/ZsRUdHa82aNfqP//gP/ehHP2qlR45TMgEAAAB0OGvWrDElmcuXLz9ln3feece0Wq1mYWFhuG3Lli2mJHPt2rWmaZrmgw8+aNrtdrO0tLTZsZLM73znO83apk6daj7yyCPN2v7zP//T7NGjh2mapvn222+bFovF3L59+0nrefbZZ83Y2NgWP0Z0PjfeeKM5a9Ys0zRNc+LEieaFF17Y7PZRo0aZP/jBD0zTPPN4uf76683p06c3a/uXf/kXMy8vL3w9MzPTnD17drM+zz77rCnJ3LhxY7ht//79ptVqNQ8dOtSs79SpU83777/fNE3TnDdvnjl+/PhTPraJEyea99577ylvR9f39fE9ZswYc+HChaZpmuYrr7xifhmftHTc3nDDDeHroVDITE5ONp9++mnTNI+/rvbv398MhULhPo2NjabL5TLffvvtNnls6Fy+HIulpaVmVFSUuW/fPnPfvn2m0+k0y8rKzFmzZpk33nijaZrNX7tefvll0+v1mlVVVSecc/369aYkc9++fae9zy+d6TX+zTffNG02m3n48OHw7e+++64pyXzllVfO/cHjtJiRCwAAAHRA5mlmyHypoKBA6enpzWYO5uXlyefzqaCgINyWmZmppKSkE44fOXJks+ubNm3SQw89JI/HE/75coZiXV2dNm7cqF69eiknJ+c8Hhm6kiFDhjS73qNHD5WWlkrSGcdLQUGBxo8f36xt/Pjx2rlzp4LBYLjtn8epJDkcjmb3vXnzZgWDQeXk5DQbv6tWrdLu3bvD9UydOvXcHii6nZ/97Gd6/vnnm72WSi0ft18fn4ZhKDU1NfxvY9OmTdq1a5diYmLCYzU+Pl4NDQ3h8QpIUlJSki677DI999xzevbZZ3XZZZcpMTHxlP2nT5+uzMxMZWdn65vf/Kb+8pe/qK6uTpI0dOhQTZ06VYMHD9bVV1+tP/zhD2dcC/p0r/Hbt29Xenq6UlNTw7ePHj36XB8qWsgW6QIAAAAAnKhfv34yDEPbtm0773OdbGmGk7XX1NRo6dKlmjNnzgl9nU6nXC7XedeCrsVutze7bhhGeOOx1hovJxu/LpdLhmGEr9fU1MhqtWr9+vXhpRu+5PF4WrUedA8TJkzQjBkzdP/99+umm2466+NP92+jpqZGI0aM0F/+8pcTjjvZh27o3hYuXKi7775bkrRs2bLT9o2JidGGDRu0cuVKvfPOO3rggQe0ZMkSrVu3Tj6fT++++64+/PBDvfPOO/rNb36jH/3oR1qzZo2ysrJOer7TjWNEBjNyAQAAgA4oPj5eM2bM0LJly8IbkXxdRUWFcnNzdeDAAR04cCDcvnXrVlVUVCgvL++s7zM/P1/bt29X3759T/ixWCwaMmSIDh48qB07dpz0eIfD0WxGGrq3M42X3NxcrV69ulnb6tWrlZOTc0IYeybDhw9XMBhUaWnpCWP3y9liQ4YM0YoVK055DsYv/tljjz2m119/XR999FG4rTXGbX5+vnbu3Knk5OQTxmtsbGyrPgZ0fl+unfzl2spnYrPZNG3aND3++OP67LPPtG/fPr333nuSjgex48eP19KlS/Xpp5/K4XDolVdeOae6+vfvrwMHDjTbYHXdunXndC60HEEuAAAA0EEtW7ZMwWBQo0eP1ssvv6ydO3eqoKBATz31lMaOHatp06Zp8ODBmj9/vjZs2KC1a9dqwYIFmjhx4km/jn4mDzzwgF544QUtXbpUW7ZsUUFBgV566SX9+Mc/liRNnDhREyZM0Ny5c/Xuu+9q7969evPNN/XWW29JOr5Te01NjVasWKEjR46Ev86J7ulM4+W+++7TihUr9PDDD2vHjh16/vnn9dvf/vacNsnLycnR/PnztWDBAi1fvlx79+7V2rVr9eijj+pvf/ubJOn+++/XunXrdNddd+mzzz7Ttm3b9PTTT+vIkSOSjo/fNWvWaN++fTpy5AizzhB+fX3qqafCba0xbufPn6/ExETNmjVLH3zwgfbu3auVK1fq29/+9kk3WEP3ZrVaVVBQoK1bt57xw4I33nhDTz31lDZu3Kj9+/frhRdeUCgUUv/+/bVmzRo98sgj+uSTT1RYWKjly5errKxMubm551TX9OnT1adPH91444367LPPtHr16vD7ha9/YwKtiyAXAAAA6KCys7O1YcMGTZ48Wffdd58GDRqk6dOna8WKFXr66adlGIZee+01xcXFacKECZo2bZqys7P117/+9Zzub8aMGXrjjTf0zjvvaNSoURozZoyeeOIJZWZmhvu8/PLLGjVqlObNm6e8vDx9//vfD89iHDdunO68805de+21SkpK0uOPP94qzwM6r9ONl/z8fP33f/+3XnrpJQ0aNEgPPPCAHnrooXP6GrskPfvss1qwYIHuu+8+9e/fX7Nnz9a6deuUkZEh6XjY+84772jTpk0aPXq0xo4dq9dee0022/EVB7/3ve/JarUqLy9PSUlJKiwsbJXnAJ3bQw891CzUb41xGx0drffff18ZGRmaM2eOcnNzdcstt6ihoUFer7cNHgU6O6/X26Kx4fP5tHz5ck2ZMkW5ubn63e9+p//6r//SwIED5fV69f777+sb3/iGcnJy9OMf/1i//OUvdemll55TTVarVa+++qpqamo0atQo3XrrrfrRj34k6fhyTGgbhtmSXRQAAAAAAAAA4BRWr16tCy+8ULt27VKfPn0iXU6XRJALAAAAAAAA4Ky88sor8ng86tevn3bt2qV7771XcXFx+sc//hHp0rosW6QLAAAAAAAAANC5VFdX6wc/+IEKCwuVmJioadOm6Ze//GWky+rSmJELAAAAAAAAAB0cm50BAAAAAAAAQAdHkAsAAAAAAAAAHRxBLgAAAAAAAAB0cAS5AAAAAAAAANDBEeQCAAAAAAAAQAdHkAsAAAAAAAAAHRxBLgAAAAAAAAB0cAS5AAAAAAAAANDB/f9mYJnJByz0BQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "# ๊ฒฐ๊ณผ ๋ถ„ํฌ ํŒŒ์ด ์ฐจํŠธ\n", + "fig, axes = plt.subplots(1, 2, figsize=(15, 6))\n", + "\n", + "# Pie Chart 1: Overall Results\n", + "labels = ['Correct', 'Incorrect', 'None', 'Missing']\n", + "sizes = [correct_count, wrong_count, none_count, missing_count]\n", + "colors = ['#4CAF50', '#F44336', '#FF9800', '#9E9E9E']\n", + "explode = (0.1, 0, 0, 0)\n", + "\n", + "axes[0].pie(\n", + " sizes, explode=explode, labels=labels, colors=colors,\n", + " autopct='%1.1f%%', shadow=True, startangle=90\n", + ")\n", + "axes[0].set_title('Overall Result Distribution', fontsize=14, fontweight='bold')\n", + "\n", + "# Bar Chart: Counts\n", + "categories = ['Correct', 'Incorrect', 'None', 'Missing']\n", + "counts = [correct_count, wrong_count, none_count, missing_count]\n", + "axes[1].bar(categories, counts, color=colors)\n", + "axes[1].set_ylabel('Count', fontsize=12)\n", + "axes[1].set_title('Result Counts', fontsize=14, fontweight='bold')\n", + "axes[1].grid(axis='y', alpha=0.3)\n", + "\n", + "# Add value labels\n", + "for i, v in enumerate(counts):\n", + " axes[1].text(i, v + max(counts) * 0.02, str(v),\n", + " ha='center', va='bottom', fontsize=11, fontweight='bold')\n", + "\n", + "plt.tight_layout()\n", + "plt.savefig(output_dir / 'accuracy_visualization.png', dpi=300, bbox_inches='tight')\n", + "print(f\"\\n๐Ÿ“Š Visualization saved: {output_dir / 'accuracy_visualization.png'}\")\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ถ„์„" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'merged_df' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mNameError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ (์ •๋‹ต์ง€์—๋Š” ์žˆ์ง€๋งŒ results์— ์—†๋Š” ๊ฒฝ์šฐ)\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m missing_df = \u001b[43mmerged_df\u001b[49m[merged_df[\u001b[33m'\u001b[39m\u001b[33mresult\u001b[39m\u001b[33m'\u001b[39m] == \u001b[33m'\u001b[39m\u001b[33mmissing\u001b[39m\u001b[33m'\u001b[39m].copy()\n\u001b[32m 4\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m=\u001b[39m\u001b[33m\"\u001b[39m*\u001b[32m60\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m๐Ÿ” ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ถ„์„ (์ด \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlen\u001b[39m(missing_df)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m๊ฐœ)\u001b[39m\u001b[33m\"\u001b[39m)\n", + "\u001b[31mNameError\u001b[39m: name 'merged_df' is not defined" + ] + } + ], + "source": [ + "# ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ (์ •๋‹ต์ง€์—๋Š” ์žˆ์ง€๋งŒ results์— ์—†๋Š” ๊ฒฝ์šฐ)\n", + "missing_df = merged_df[merged_df['result'] == 'missing'].copy()\n", + "\n", + "print(\"=\"*60)\n", + "print(f\"๐Ÿ” ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ถ„์„ (์ด {len(missing_df)}๊ฐœ)\")\n", + "print(\"=\"*60)\n", + "\n", + "if len(missing_df) > 0:\n", + " print(\"\\n๋ˆ„๋ฝ๋œ ๋ฌธ์ œ ๋ชฉ๋ก:\")\n", + " display(missing_df[['page_number', 'problem_number', 'correct_answer']].sort_values(['page_number', 'problem_number']))\n", + " \n", + " # ํŽ˜์ด์ง€๋ณ„ ๋ˆ„๋ฝ ํ†ต๊ณ„\n", + " print(\"\\n๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ ๋ˆ„๋ฝ ํ†ต๊ณ„:\")\n", + " page_missing = missing_df.groupby('page_number').size().reset_index(name='missing_count')\n", + " page_missing = page_missing.sort_values('missing_count', ascending=False)\n", + " display(page_missing)\n", + "else:\n", + " print(\"\\nโœ… ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. None ๋‹ต์•ˆ ๋ถ„์„" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "โš ๏ธ None ๋‹ต์•ˆ ๋ถ„์„ (์ด 0๊ฐœ)\n", + "============================================================\n", + "\n", + "โœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค!\n" + ] + } + ], + "source": [ + "# None์œผ๋กœ ์ธ์‹๋œ ๋ฌธ์ œ\n", + "none_df = merged_df[merged_df['result'] == 'none'].copy()\n", + "\n", + "print(\"=\"*60)\n", + "print(f\"โš ๏ธ None ๋‹ต์•ˆ ๋ถ„์„ (์ด {len(none_df)}๊ฐœ)\")\n", + "print(\"=\"*60)\n", + "\n", + "if len(none_df) > 0:\n", + " print(\"\\nNone์œผ๋กœ ์ธ์‹๋œ ๋ฌธ์ œ ๋ชฉ๋ก:\")\n", + " display(none_df[['page_number', 'problem_number', 'correct_answer', 'image_file']].sort_values(['page_number', 'problem_number']))\n", + " \n", + " # ํŽ˜์ด์ง€๋ณ„ None ํ†ต๊ณ„\n", + " print(\"\\n๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ None ํ†ต๊ณ„:\")\n", + " page_none = none_df.groupby('page_number').size().reset_index(name='none_count')\n", + " page_none = page_none.sort_values('none_count', ascending=False)\n", + " display(page_none)\n", + "else:\n", + " print(\"\\nโœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 9. ์˜ค๋‹ต ๋ถ„์„" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "โŒ ์˜ค๋‹ต ๋ถ„์„ (์ด 1๊ฐœ)\n", + "============================================================\n", + "\n", + "์˜ค๋‹ต ๋ชฉ๋ก:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberproblem_numbercorrect_answerpredicted_answerimage_file
1131050445แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18
\n", + "
" + ], + "text/plain": [ + " page_number problem_number correct_answer predicted_answer \\\n", + "113 105 04 4 5 \n", + "\n", + " image_file \n", + "113 แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18 " + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ ์˜ค๋‹ต ํ†ต๊ณ„:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
page_numberwrong_count
01051
\n", + "
" + ], + "text/plain": [ + " page_number wrong_count\n", + "0 105 1" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# ์˜ค๋‹ต\n", + "wrong_df = merged_df[merged_df['result'] == 'wrong'].copy()\n", + "\n", + "print(\"=\"*60)\n", + "print(f\"โŒ ์˜ค๋‹ต ๋ถ„์„ (์ด {len(wrong_df)}๊ฐœ)\")\n", + "print(\"=\"*60)\n", + "\n", + "if len(wrong_df) > 0:\n", + " print(\"\\n์˜ค๋‹ต ๋ชฉ๋ก:\")\n", + " display(wrong_df[['page_number', 'problem_number', 'correct_answer', 'predicted_answer', 'image_file']].sort_values(['page_number', 'problem_number']))\n", + " \n", + " # ํŽ˜์ด์ง€๋ณ„ ์˜ค๋‹ต ํ†ต๊ณ„\n", + " print(\"\\n๐Ÿ“„ ํŽ˜์ด์ง€๋ณ„ ์˜ค๋‹ต ํ†ต๊ณ„:\")\n", + " page_wrong = wrong_df.groupby('page_number').size().reset_index(name='wrong_count')\n", + " page_wrong = page_wrong.sort_values('wrong_count', ascending=False)\n", + " display(page_wrong.head(10))\n", + "else:\n", + " print(\"\\nโœ… ์˜ค๋‹ต์ด ์—†์Šต๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 10. ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "============================================================\n", + "๐Ÿ“Š ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„\n", + "============================================================\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
totalcorrectwrongnonemissingaccuracy
page_number
1011000100.0
10022000100.0
10122000100.0
10222000100.0
10322000100.0
.....................
9522000100.0
9822000100.0
9722000100.0
9922000100.0
1055410080.0
\n", + "

96 rows ร— 6 columns

\n", + "
" + ], + "text/plain": [ + " total correct wrong none missing accuracy\n", + "page_number \n", + "10 1 1 0 0 0 100.0\n", + "100 2 2 0 0 0 100.0\n", + "101 2 2 0 0 0 100.0\n", + "102 2 2 0 0 0 100.0\n", + "103 2 2 0 0 0 100.0\n", + "... ... ... ... ... ... ...\n", + "95 2 2 0 0 0 100.0\n", + "98 2 2 0 0 0 100.0\n", + "97 2 2 0 0 0 100.0\n", + "99 2 2 0 0 0 100.0\n", + "105 5 4 1 0 0 80.0\n", + "\n", + "[96 rows x 6 columns]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "โš ๏ธ ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ํŽ˜์ด์ง€ (80% ๋ฏธ๋งŒ):\n", + "โœ… ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ 80% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋ณด์ž…๋‹ˆ๋‹ค!\n" + ] + } + ], + "source": [ + "# ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„ ๊ณ„์‚ฐ\n", + "page_stats = merged_df.groupby('page_number').agg({\n", + " 'result': 'count',\n", + "}).rename(columns={'result': 'total'})\n", + "\n", + "page_stats['correct'] = merged_df[merged_df['result'] == 'correct'].groupby('page_number').size()\n", + "page_stats['wrong'] = merged_df[merged_df['result'] == 'wrong'].groupby('page_number').size()\n", + "page_stats['none'] = merged_df[merged_df['result'] == 'none'].groupby('page_number').size()\n", + "page_stats['missing'] = merged_df[merged_df['result'] == 'missing'].groupby('page_number').size()\n", + "\n", + "page_stats = page_stats.fillna(0).astype(int)\n", + "page_stats['accuracy'] = (page_stats['correct'] / page_stats['total'] * 100).round(2)\n", + "page_stats = page_stats.sort_values('accuracy', ascending=False)\n", + "\n", + "print(\"=\"*60)\n", + "print(\"๐Ÿ“Š ํŽ˜์ด์ง€๋ณ„ ์ •ํ™•๋„\")\n", + "print(\"=\"*60)\n", + "display(page_stats)\n", + "\n", + "# ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ํŽ˜์ด์ง€\n", + "print(\"\\nโš ๏ธ ์ •ํ™•๋„๊ฐ€ ๋‚ฎ์€ ํŽ˜์ด์ง€ (80% ๋ฏธ๋งŒ):\")\n", + "low_accuracy_pages = page_stats[page_stats['accuracy'] < 80]\n", + "if len(low_accuracy_pages) > 0:\n", + " display(low_accuracy_pages)\n", + "else:\n", + " print(\"โœ… ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ 80% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋ณด์ž…๋‹ˆ๋‹ค!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 11. ๊ฒฐ๊ณผ ์ €์žฅ" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "๐Ÿ’พ ์ƒ์„ธ ๋น„๊ต ๊ฒฐ๊ณผ ์ €์žฅ: detailed_comparison.csv\n", + "๐Ÿ’พ ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„ ์ €์žฅ: page_statistics.csv\n", + "๐Ÿ’พ ์š”์•ฝ ๋ฆฌํฌํŠธ ์ €์žฅ: accuracy_summary.txt\n", + "\n", + "============================================================\n", + "โœ… ๋ชจ๋“  ๋ถ„์„์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\n", + "============================================================\n" + ] + } + ], + "source": [ + "# ์ƒ์„ธ ๊ฒฐ๊ณผ ์ €์žฅ\n", + "detailed_results_path = output_dir / \"detailed_comparison.csv\"\n", + "merged_df.to_csv(detailed_results_path, index=False, encoding='utf-8-sig')\n", + "print(f\"\\n๐Ÿ’พ ์ƒ์„ธ ๋น„๊ต ๊ฒฐ๊ณผ ์ €์žฅ: {detailed_results_path}\")\n", + "\n", + "# ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„ ์ €์žฅ\n", + "page_stats_path = output_dir / \"page_statistics.csv\"\n", + "page_stats.to_csv(page_stats_path, encoding='utf-8-sig')\n", + "print(f\"๐Ÿ’พ ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„ ์ €์žฅ: {page_stats_path}\")\n", + "\n", + "# ์š”์•ฝ ๋ฆฌํฌํŠธ ์ €์žฅ\n", + "summary_path = output_dir / \"accuracy_summary.txt\"\n", + "with open(summary_path, 'w', encoding='utf-8') as f:\n", + " f.write(\"=\"*60 + \"\\n\")\n", + " f.write(\"YOLO ๋‹ต์•ˆ ์ธ์‹ ์ •ํ™•๋„ ๋ถ„์„ ๋ณด๊ณ ์„œ\\n\")\n", + " f.write(\"=\"*60 + \"\\n\\n\")\n", + " \n", + " f.write(\"๐Ÿ“Š ์ „์ฒด ํ†ต๊ณ„\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " f.write(f\"์ด ๋ฌธ์ œ ์ˆ˜: {total_count}๊ฐœ\\n\")\n", + " f.write(f\"์ •๋‹ต: {correct_count}๊ฐœ ({correct_count/total_count*100:.2f}%)\\n\")\n", + " f.write(f\"์˜ค๋‹ต: {wrong_count}๊ฐœ ({wrong_count/total_count*100:.2f}%)\\n\")\n", + " f.write(f\"None: {none_count}๊ฐœ ({none_count/total_count*100:.2f}%)\\n\")\n", + " f.write(f\"๋ˆ„๋ฝ: {missing_count}๊ฐœ ({missing_count/total_count*100:.2f}%)\\n\\n\")\n", + " \n", + " f.write(\"=\"*60 + \"\\n\")\n", + " f.write(f\"๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: {accuracy:.2f}%\\n\")\n", + " f.write(f\"๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): {recognition_rate:.2f}%\\n\")\n", + " f.write(f\"โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„: {accuracy_of_recognized:.2f}%\\n\")\n", + " f.write(\"=\"*60 + \"\\n\\n\")\n", + " \n", + " if len(missing_df) > 0:\n", + " f.write(f\"\\n๐Ÿ” ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ: {len(missing_df)}๊ฐœ\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for _, row in missing_df.iterrows():\n", + " f.write(f\"ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}, ์ •๋‹ต {row['correct_answer']}\\n\")\n", + " \n", + " if len(none_df) > 0:\n", + " f.write(f\"\\nโš ๏ธ None ๋‹ต์•ˆ: {len(none_df)}๊ฐœ\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for _, row in none_df.head(20).iterrows():\n", + " f.write(f\"ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}, ์ •๋‹ต {row['correct_answer']}\\n\")\n", + " if len(none_df) > 20:\n", + " f.write(f\"... ์™ธ {len(none_df)-20}๊ฐœ\\n\")\n", + " \n", + " if len(wrong_df) > 0:\n", + " f.write(f\"\\nโŒ ์˜ค๋‹ต: {len(wrong_df)}๊ฐœ\\n\")\n", + " f.write(\"-\"*60 + \"\\n\")\n", + " for _, row in wrong_df.head(20).iterrows():\n", + " f.write(f\"ํŽ˜์ด์ง€ {row['page_number']}, ๋ฌธ์ œ {row['problem_number']}, ์ •๋‹ต {row['correct_answer']}, ์˜ˆ์ธก {row['predicted_answer']}\\n\")\n", + " if len(wrong_df) > 20:\n", + " f.write(f\"... ์™ธ {len(wrong_df)-20}๊ฐœ\\n\")\n", + "\n", + "print(f\"๐Ÿ’พ ์š”์•ฝ ๋ฆฌํฌํŠธ ์ €์žฅ: {summary_path}\")\n", + "\n", + "print(\"\\n\" + \"=\"*60)\n", + "print(\"โœ… ๋ชจ๋“  ๋ถ„์„์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\")\n", + "print(\"=\"*60)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 12. ์ตœ์ข… ์š”์•ฝ" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "\n", + "# ๐Ÿ“Š ์ตœ์ข… ๋ถ„์„ ์š”์•ฝ\n", + "\n", + "## ๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: **99.35%**\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ˆ ์ฃผ์š” ์ง€ํ‘œ\n", + "- **์ธ์‹ ์„ฑ๊ณต๋ฅ **: 100.00% (๋ˆ„๋ฝ ์ œ์™ธ)\n", + "- **์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„**: 99.35%\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“Š ์ƒ์„ธ ํ†ต๊ณ„\n", + "| ๊ตฌ๋ถ„ | ๊ฐœ์ˆ˜ | ๋น„์œจ |\n", + "|------|------|------|\n", + "| โœ… ์ •๋‹ต | 154๊ฐœ | 99.35% |\n", + "| โŒ ์˜ค๋‹ต | 1๊ฐœ | 0.65% |\n", + "| โš ๏ธ None | 0๊ฐœ | 0.00% |\n", + "| ๐Ÿ” ๋ˆ„๋ฝ | 0๊ฐœ | 0.00% |\n", + "| **๐Ÿ“˜ ์ „์ฒด** | **155๊ฐœ** | **100.00%** |\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ’ก ๊ฐœ์„  ํฌ์ธํŠธ\n", + "\n", + "- โŒ **์˜ค๋‹ต ๋ถ„์„**: 1๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ž˜๋ชป ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค. IoU threshold๋‚˜ ๋ชจ๋ธ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•˜์„ธ์š”.\n", + "\n", + "### ๐ŸŽ‰ ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ!\n", + "95% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค!\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ ์ƒ์„ฑ๋œ ํŒŒ์ผ\n", + "- `detailed_comparison.csv`: ์ „์ฒด ๋น„๊ต ๊ฒฐ๊ณผ\n", + "- `page_statistics.csv`: ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„\n", + "- `accuracy_summary.txt`: ์š”์•ฝ ๋ฆฌํฌํŠธ\n", + "- `accuracy_visualization.png`: ์‹œ๊ฐํ™” ์ฐจํŠธ\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Markdown, display\n", + "\n", + "summary_md = f\"\"\"\n", + "# ๐Ÿ“Š ์ตœ์ข… ๋ถ„์„ ์š”์•ฝ\n", + "\n", + "## ๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: **{accuracy:.2f}%**\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ˆ ์ฃผ์š” ์ง€ํ‘œ\n", + "- **์ธ์‹ ์„ฑ๊ณต๋ฅ **: {recognition_rate:.2f}% (๋ˆ„๋ฝ ์ œ์™ธ)\n", + "- **์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„**: {accuracy_of_recognized:.2f}%\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“Š ์ƒ์„ธ ํ†ต๊ณ„\n", + "| ๊ตฌ๋ถ„ | ๊ฐœ์ˆ˜ | ๋น„์œจ |\n", + "|------|------|------|\n", + "| โœ… ์ •๋‹ต | {correct_count}๊ฐœ | {correct_count/total_count*100:.2f}% |\n", + "| โŒ ์˜ค๋‹ต | {wrong_count}๊ฐœ | {wrong_count/total_count*100:.2f}% |\n", + "| โš ๏ธ None | {none_count}๊ฐœ | {none_count/total_count*100:.2f}% |\n", + "| ๐Ÿ” ๋ˆ„๋ฝ | {missing_count}๊ฐœ | {missing_count/total_count*100:.2f}% |\n", + "| **๐Ÿ“˜ ์ „์ฒด** | **{total_count}๊ฐœ** | **100.00%** |\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ’ก ๊ฐœ์„  ํฌ์ธํŠธ\n", + "\"\"\" \n", + "\n", + "if missing_count > 0:\n", + " summary_md += f\"\\n- ๐Ÿ” **๋ˆ„๋ฝ ๋ฌธ์ œ ํ•ด๊ฒฐ**: {missing_count}๊ฐœ ๋ฌธ์ œ๊ฐ€ results์— ์—†์Šต๋‹ˆ๋‹ค. Section ๊ฒ€์ถœ ๋ฌธ์ œ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\"\n", + "\n", + "if none_count > 0:\n", + " summary_md += f\"\\n- โš ๏ธ **None ๋‹ต์•ˆ ๊ฐœ์„ **: {none_count}๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ธ์‹๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. `none_debug_analysis.txt` ํŒŒ์ผ์„ ํ™•์ธํ•˜์„ธ์š”.\"\n", + "\n", + "if wrong_count > 0:\n", + " summary_md += f\"\\n- โŒ **์˜ค๋‹ต ๋ถ„์„**: {wrong_count}๊ฐœ ๋ฌธ์ œ์˜ ๋‹ต์•ˆ์ด ์ž˜๋ชป ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค. IoU threshold๋‚˜ ๋ชจ๋ธ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•˜์„ธ์š”.\"\n", + "\n", + "if accuracy >= 95:\n", + " summary_md += \"\\n\\n### ๐ŸŽ‰ ์šฐ์ˆ˜ํ•œ ์„ฑ๋Šฅ!\"\n", + " summary_md += \"\\n95% ์ด์ƒ์˜ ์ •ํ™•๋„๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค!\"\n", + "elif accuracy >= 90:\n", + " summary_md += \"\\n\\n### ๐Ÿ‘ ์–‘ํ˜ธํ•œ ์„ฑ๋Šฅ\"\n", + " summary_md += \"\\n90% ์ด์ƒ์˜ ์ •ํ™•๋„์ž…๋‹ˆ๋‹ค. ์กฐ๊ธˆ ๋” ๊ฐœ์„ ํ•˜๋ฉด ๋” ์ข‹์Šต๋‹ˆ๋‹ค!\"\n", + "else:\n", + " summary_md += \"\\n\\n### ๐Ÿ”ง ๊ฐœ์„  ํ•„์š”\"\n", + " summary_md += \"\\n์ •ํ™•๋„๊ฐ€ 90% ๋ฏธ๋งŒ์ž…๋‹ˆ๋‹ค. ์œ„์˜ ๊ฐœ์„  ํฌ์ธํŠธ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ๋ชจ๋ธ์„ ๊ฐœ์„ ํ•˜์„ธ์š”.\"\n", + "\n", + "summary_md += f\"\"\"\n", + "\n", + "---\n", + "\n", + "### ๐Ÿ“ ์ƒ์„ฑ๋œ ํŒŒ์ผ\n", + "- `detailed_comparison.csv`: ์ „์ฒด ๋น„๊ต ๊ฒฐ๊ณผ\n", + "- `page_statistics.csv`: ํŽ˜์ด์ง€๋ณ„ ํ†ต๊ณ„\n", + "- `accuracy_summary.txt`: ์š”์•ฝ ๋ฆฌํฌํŠธ\n", + "- `accuracy_visualization.png`: ์‹œ๊ฐํ™” ์ฐจํŠธ\n", + "\"\"\"\n", + "\n", + "display(Markdown(summary_md))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ocr", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.13" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/ai-service/test/yolo_resnet_answer/answers/accuracy_summary.txt b/ai-service/test/yolo_resnet_answer/answers/accuracy_summary.txt new file mode 100644 index 0000000..ee95d3b --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/accuracy_summary.txt @@ -0,0 +1,22 @@ +============================================================ +YOLO ๋‹ต์•ˆ ์ธ์‹ ์ •ํ™•๋„ ๋ถ„์„ ๋ณด๊ณ ์„œ +============================================================ + +๐Ÿ“Š ์ „์ฒด ํ†ต๊ณ„ +------------------------------------------------------------ +์ด ๋ฌธ์ œ ์ˆ˜: 155๊ฐœ +์ •๋‹ต: 154๊ฐœ (99.35%) +์˜ค๋‹ต: 1๊ฐœ (0.65%) +None: 0๊ฐœ (0.00%) +๋ˆ„๋ฝ: 0๊ฐœ (0.00%) + +============================================================ +๐ŸŽฏ ์ „์ฒด ์ •ํ™•๋„: 99.35% +๐Ÿ“ ์ธ์‹ ์„ฑ๊ณต๋ฅ  (๋ˆ„๋ฝ ์ œ์™ธ): 100.00% +โœจ ์ธ์‹๋œ ๊ฒƒ ์ค‘ ์ •ํ™•๋„: 99.35% +============================================================ + + +โŒ ์˜ค๋‹ต: 1๊ฐœ +------------------------------------------------------------ +ํŽ˜์ด์ง€ 105, ๋ฌธ์ œ 04, ์ •๋‹ต 4, ์˜ˆ์ธก 5 diff --git a/ai-service/test/yolo_resnet_answer/answers/answer.txt b/ai-service/test/yolo_resnet_answer/answers/answer.txt new file mode 100644 index 0000000..db6a69c --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/answer.txt @@ -0,0 +1,290 @@ +9, 01, 4 +10, 02, 4 +11, 03, 3 +12, 04, 5 +13, 05, 4 +15, 01, 1 +16, 02, 3 +17, 03, 5 +18, 04, 5 +19, 05, 5 +21, 01, 3 +22, 02, 1 +23, 03, 1 +24, 04, 5 +25, 05, 5 +27, 01, 1 +28, 02, 5 +29, 03, 5 +30, 04, 1 +31, 05, 3 +33, 01, 3 +34, 02, 4 +35, 03, 3 +36, 04, 5 +37, 05, 2 +39, 01, 4 +40, 02, 4 +41, 03, 4 +42, 04, 3 +43, 05, 3 +45, 01, 3 +46, 02, 1 +47, 03, 4 +48, 04, 2 +49, 05, 2 +51, 01, 1 +52, 02, 3 +53, 03, 1 +54, 04, 2 +55, 05, 4 +57, 01, 4 +58, 02, 3 +59, 03, 4 +60, 04, 4 +61, 05, 3 +63, 01, 4 +64, 02, 3 +65, 03, 2 +66, 04, 4 +67, 05, 4 +69, 01, 3 +70, 02, 5 +71, 03, 5 +72, 04, 4 +73, 05, 3 +75, 01, 4 +76, 02, 4 +77, 03, 2 +78, 04, 3 +79, 05, 2 +83, 01, 5 +83, 02, 1 +85, 03, 4 +85, 04, 5 +85, 05, 2 +88, 01, 1 +88, 02, 3 +88, 03, 2 +88, 04, 5 +88, 05, 2 +89, 06, 3 +89, 07, 2 +89, 08, 3 +89, 09, 2 +89, 10, 4 +90, 11, 5 +90, 12, 1 +90, 13, 1 +90, 14, 3 +90, 15, 4 +91, 16, 5 +91, 17, 3 +91, 18, 5 +92, 19, 1 +92, 20, 2 +93, 21, 1 +93, 22, 1 +94, 23, 2 +94, 24, 1 +95, 25, 5 +95, 26, 4 +96, 27, 4 +96, 28, 5 +97, 29, 4 +97, 30, 3 +98, 31, 1 +98, 32, 3 +99, 33, 2 +99, 34, 1 +100, 35, 3 +100, 36, 4 +101, 37, 5 +101, 38, 4 +102, 39, 4 +102, 40, 1 +103, 41, 4 +103, 42, 5 +104, 43, 5 +104, 44, 3 +104, 45, 2 +105, 01, 2 +105, 02, 3 +105, 03, 3 +105, 04, 4 +105, 05, 2 +106, 06, 4 +106, 07, 5 +106, 08, 3 +106, 09, 5 +106, 10, 4 +107, 11, 2 +107, 12, 1 +107, 13, 1 +107, 14, 1 +107, 15, 3 +108, 16, 4 +108, 17, 4 +108, 18, 5 +109, 19, 1 +109, 20, 3 +110, 21, 5 +110, 22, 1 +111, 23, 5 +111, 24, 2 +112, 25, 4 +112, 26, 2 +113, 27, 4 +113, 28, 4 +114, 29, 3 +114, 30, 4 +115, 31, 2 +115, 32, 2 +116, 33, 1 +116, 34, 1 +117, 35, 3 +117, 36, 2 +118, 37, 5 +118, 38, 3 +119, 39, 3 +119, 40, 4 +120, 41, 4 +120, 42, 4 +121, 43, 4 +121, 44, 2 +121, 45, 5 +122, 01, 5 +122, 02, 3 +122, 03, 2 +122, 04, 5 +122, 05, 3 +123, 06, 3 +123, 07, 1 +123, 08, 4 +123, 09, 4 +123, 10, 3 +124, 11, 5 +124, 12, 4 +124, 13, 5 +124, 14, 3 +124, 15, 5 +125, 16, 3 +125, 17, 4 +125, 18, 1 +126, 19, 2 +126, 20, 1 +127, 21, 2 +127, 22, 1 +128, 23, 1 +128, 24, 1 +129, 25, 5 +129, 26, 4 +130, 27, 4 +130, 28, 5 +131, 29, 3 +131, 30, 4 +132, 31, 2 +132, 32, 2 +133, 33, 3 +133, 34, 1 +134, 35, 4 +134, 36, 4 +135, 37, 2 +135, 38, 5 +136, 39, 4 +136, 40, 1 +137, 41, 2 +137, 42, 5 +138, 43, 5 +138, 44, 3 +138, 45, 4 +139, 01, 1 +139, 02, 2 +139, 03, 5 +139, 04, 3 +139, 05, 1 +140, 06, 5 +140, 07, 2 +140, 08, 5 +140, 09, 5 +140, 10, 1 +141, 11, 1 +141, 12, 2 +141, 13, 4 +141, 14, 5 +141, 15, 2 +142, 16, 1 +142, 17, 3 +142, 18, 3 +143, 19, 2 +143, 20, 4 +144, 21, 4 +144, 22, 1 +145, 23, 4 +145, 24, 2 +146, 25, 5 +146, 26, 5 +147, 27, 4 +147, 28, 3 +148, 29, 4 +148, 30, 3 +149, 31, 4 +149, 32, 2 +150, 33, 4 +150, 34, 2 +151, 35, 4 +151, 36, 4 +152, 37, 3 +152, 38, 3 +153, 39, 3 +153, 40, 1 +154, 41, 1 +154, 42, 5 +155, 43, 2 +155, 44, 2 +155, 45, 2 +156, 01, 1 +156, 02, 1 +156, 03, 3 +156, 04, 3 +156, 05, 3 +157, 06, 2 +157, 07, 4 +157, 08, 4 +157, 09, 4 +157, 10, 4 +158, 11, 1 +158, 12, 2 +158, 13, 4 +158, 14, 5 +158, 15, 5 +159, 16, 4 +159, 17, 3 +159, 18, 5 +160, 19, 3 +160, 20, 1 +161, 21, 3 +161, 22, 2 +162, 23, 1 +162, 24, 1 +163, 25, 3 +163, 26, 4 +164, 27, 4 +164, 28, 5 +165, 29, 4 +165, 30, 5 +166, 31, 2 +166, 32, 5 +167, 33, 3 +167, 34, 2 +168, 35, 4 +168, 36, 5 +169, 37, 1 +169, 38, 3 +170, 39, 2 +170, 40, 2 +171, 41, 5 +171, 42, 5 +172, 43, 2 +172, 44, 2 +172, 45, 3 \ No newline at end of file diff --git a/ai-service/test/yolo_resnet_answer/answers/crop_failure_analysis.txt b/ai-service/test/yolo_resnet_answer/answers/crop_failure_analysis.txt new file mode 100644 index 0000000..e8355dc --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/crop_failure_analysis.txt @@ -0,0 +1,6 @@ +================================================================================ +Section Crop ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„ +================================================================================ + +โœ… ๋ชจ๋“  Section์ด ์ •์ƒ์ ์œผ๋กœ crop๋˜์—ˆ์Šต๋‹ˆ๋‹ค! + diff --git a/ai-service/test/yolo_resnet_answer/answers/detailed_comparison.csv b/ai-service/test/yolo_resnet_answer/answers/detailed_comparison.csv new file mode 100644 index 0000000..cda1db9 --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/detailed_comparison.csv @@ -0,0 +1,156 @@ +๏ปฟpage_number,problem_number,correct_answer,image_file,predicted_answer,_merge,result +9,01,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1,1,both,correct +10,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2,2,both,correct +11,03,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3,2,both,correct +12,04,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4,4,both,correct +13,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5,1,both,correct +15,01,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6,4,both,correct +16,02,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7,5,both,correct +17,03,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8,1,both,correct +18,04,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9,3,both,correct +19,05,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10,2,both,correct +21,01,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11,1,both,correct +22,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 12,2,both,correct +23,03,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 13,4,both,correct +24,04,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14,1,both,correct +25,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 15,1,both,correct +27,01,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 16,3,both,correct +28,02,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 17,4,both,correct +29,03,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 18,4,both,correct +30,04,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 19,2,both,correct +31,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 20,1,both,correct +33,01,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 21,5,both,correct +34,02,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 22,1,both,correct +35,03,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 23,2,both,correct +36,04,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 24,1,both,correct +37,05,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 25,3,both,correct +39,01,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 26,2,both,correct +40,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 27,2,both,correct +41,03,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 28,5,both,correct +42,04,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 29,1,both,correct +43,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 30,1,both,correct +45,01,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 31,2,both,correct +46,02,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 32,5,both,correct +47,03,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 33,2,both,correct +48,04,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 34,3,both,correct +49,05,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 35,4,both,correct +51,01,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 36,5,both,correct +52,02,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 37,1,both,correct +53,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 38,3,both,correct +54,04,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 39,4,both,correct +55,05,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 40,1,both,correct +57,01,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 41,1,both,correct +58,02,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 42,5,both,correct +59,03,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 43,1,both,correct +60,04,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 44,5,both,correct +61,05,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 45,4,both,correct +63,01,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 46,2,both,correct +64,02,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 47,4,both,correct +65,03,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 48,5,both,correct +66,04,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 49,1,both,correct +67,05,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 50,5,both,correct +69,01,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 51,5,both,correct +70,02,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 52,4,both,correct +71,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 53,3,both,correct +72,04,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 54,5,both,correct +73,05,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 55,5,both,correct +75,01,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 56,3,both,correct +76,02,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 57,5,both,correct +77,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 58,3,both,correct +78,04,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 59,2,both,correct +79,05,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 60,3,both,correct +83,01,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62,4,both,correct +83,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62,2,both,correct +85,03,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64,5,both,correct +85,04,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64,3,both,correct +85,05,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64,4,both,correct +88,01,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,4,both,correct +88,02,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,2,both,correct +88,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,3,both,correct +88,04,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,3,both,correct +88,05,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1,3,both,correct +89,06,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,4,both,correct +89,07,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,3,both,correct +89,08,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,1,both,correct +89,09,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,4,both,correct +89,10,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2,2,both,correct +90,11,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,4,both,correct +90,12,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,3,both,correct +90,13,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,3,both,correct +90,14,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,2,both,correct +90,15,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3,3,both,correct +91,16,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4,3,both,correct +91,17,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4,2,both,correct +91,18,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4,3,both,correct +92,19,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5,4,both,correct +92,20,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5,3,both,correct +93,21,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6,5,both,correct +93,22,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6,4,both,correct +94,23,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7,3,both,correct +94,24,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7,2,both,correct +95,25,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8,2,both,correct +95,26,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8,5,both,correct +96,27,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9,5,both,correct +96,28,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9,2,both,correct +97,29,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10,3,both,correct +97,30,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10,2,both,correct +98,31,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11,3,both,correct +98,32,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11,5,both,correct +99,33,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12,3,both,correct +99,34,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12,4,both,correct +100,35,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13,4,both,correct +100,36,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13,3,both,correct +101,37,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14,2,both,correct +101,38,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14,5,both,correct +102,39,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15,3,both,correct +102,40,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15,2,both,correct +103,41,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16,5,both,correct +103,42,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16,2,both,correct +104,43,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17,4,both,correct +104,44,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17,2,both,correct +104,45,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17,1,both,correct +105,01,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,2,both,correct +105,02,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,3,both,correct +105,03,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,3,both,correct +105,04,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,5,both,wrong +105,05,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18,2,both,correct +106,06,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,4,both,correct +106,07,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,5,both,correct +106,08,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,3,both,correct +106,09,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,5,both,correct +106,10,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19,4,both,correct +107,11,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,2,both,correct +107,12,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,1,both,correct +107,13,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,1,both,correct +107,14,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,1,both,correct +107,15,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20,3,both,correct +108,16,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21,4,both,correct +108,17,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21,4,both,correct +108,18,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21,5,both,correct +109,19,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22,1,both,correct +109,20,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22,3,both,correct +110,21,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23,5,both,correct +110,22,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23,1,both,correct +111,23,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24,5,both,correct +111,24,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24,2,both,correct +112,25,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25,4,both,correct +112,26,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25,2,both,correct +113,27,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26,4,both,correct +113,28,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26,4,both,correct +114,29,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27,3,both,correct +114,30,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27,4,both,correct +115,31,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28,2,both,correct +115,32,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28,2,both,correct +116,33,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29,1,both,correct +116,34,1,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29,1,both,correct +117,35,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30,3,both,correct +117,36,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30,2,both,correct +118,37,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31,5,both,correct +118,38,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31,3,both,correct +119,39,3,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32,3,both,correct +119,40,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32,4,both,correct +120,41,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33,4,both,correct +120,42,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33,4,both,correct +121,43,4,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34,4,both,correct +121,44,2,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34,2,both,correct +121,45,5,แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34,5,both,correct diff --git a/ai-service/test/yolo_resnet_answer/answers/missing_sections_analysis.txt b/ai-service/test/yolo_resnet_answer/answers/missing_sections_analysis.txt new file mode 100644 index 0000000..ad429e8 --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/missing_sections_analysis.txt @@ -0,0 +1,5 @@ +================================================================================ +๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ Section ๋ถ„์„ +================================================================================ + +โœ… ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ๋ฌธ์ œ ์ˆ˜๊ฐ€ ๋‹ต์ง€์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค! diff --git a/ai-service/test/yolo_resnet_answer/answers/none_debug_analysis.txt b/ai-service/test/yolo_resnet_answer/answers/none_debug_analysis.txt new file mode 100644 index 0000000..9584d89 --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/none_debug_analysis.txt @@ -0,0 +1,5 @@ +================================================================================ +None ๋‹ต์•ˆ ๋””๋ฒ„๊น… ๋ถ„์„ +================================================================================ + +โœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค! ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค. diff --git a/ai-service/test/yolo_resnet_answer/answers/page_statistics.csv b/ai-service/test/yolo_resnet_answer/answers/page_statistics.csv new file mode 100644 index 0000000..9eb6a3d --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/page_statistics.csv @@ -0,0 +1,97 @@ +๏ปฟpage_number,total,correct,wrong,none,missing,accuracy +10,1,1,0,0,0,100.0 +100,2,2,0,0,0,100.0 +101,2,2,0,0,0,100.0 +102,2,2,0,0,0,100.0 +103,2,2,0,0,0,100.0 +104,3,3,0,0,0,100.0 +106,5,5,0,0,0,100.0 +107,5,5,0,0,0,100.0 +110,2,2,0,0,0,100.0 +108,3,3,0,0,0,100.0 +109,2,2,0,0,0,100.0 +11,1,1,0,0,0,100.0 +112,2,2,0,0,0,100.0 +111,2,2,0,0,0,100.0 +113,2,2,0,0,0,100.0 +114,2,2,0,0,0,100.0 +121,3,3,0,0,0,100.0 +115,2,2,0,0,0,100.0 +116,2,2,0,0,0,100.0 +117,2,2,0,0,0,100.0 +118,2,2,0,0,0,100.0 +119,2,2,0,0,0,100.0 +12,1,1,0,0,0,100.0 +120,2,2,0,0,0,100.0 +17,1,1,0,0,0,100.0 +13,1,1,0,0,0,100.0 +15,1,1,0,0,0,100.0 +16,1,1,0,0,0,100.0 +19,1,1,0,0,0,100.0 +18,1,1,0,0,0,100.0 +21,1,1,0,0,0,100.0 +22,1,1,0,0,0,100.0 +60,1,1,0,0,0,100.0 +23,1,1,0,0,0,100.0 +24,1,1,0,0,0,100.0 +25,1,1,0,0,0,100.0 +27,1,1,0,0,0,100.0 +28,1,1,0,0,0,100.0 +29,1,1,0,0,0,100.0 +30,1,1,0,0,0,100.0 +31,1,1,0,0,0,100.0 +33,1,1,0,0,0,100.0 +34,1,1,0,0,0,100.0 +35,1,1,0,0,0,100.0 +36,1,1,0,0,0,100.0 +37,1,1,0,0,0,100.0 +39,1,1,0,0,0,100.0 +40,1,1,0,0,0,100.0 +41,1,1,0,0,0,100.0 +42,1,1,0,0,0,100.0 +43,1,1,0,0,0,100.0 +45,1,1,0,0,0,100.0 +46,1,1,0,0,0,100.0 +47,1,1,0,0,0,100.0 +48,1,1,0,0,0,100.0 +49,1,1,0,0,0,100.0 +51,1,1,0,0,0,100.0 +52,1,1,0,0,0,100.0 +53,1,1,0,0,0,100.0 +54,1,1,0,0,0,100.0 +55,1,1,0,0,0,100.0 +57,1,1,0,0,0,100.0 +58,1,1,0,0,0,100.0 +59,1,1,0,0,0,100.0 +79,1,1,0,0,0,100.0 +61,1,1,0,0,0,100.0 +63,1,1,0,0,0,100.0 +64,1,1,0,0,0,100.0 +65,1,1,0,0,0,100.0 +66,1,1,0,0,0,100.0 +67,1,1,0,0,0,100.0 +69,1,1,0,0,0,100.0 +70,1,1,0,0,0,100.0 +71,1,1,0,0,0,100.0 +72,1,1,0,0,0,100.0 +73,1,1,0,0,0,100.0 +75,1,1,0,0,0,100.0 +76,1,1,0,0,0,100.0 +77,1,1,0,0,0,100.0 +78,1,1,0,0,0,100.0 +92,2,2,0,0,0,100.0 +83,2,2,0,0,0,100.0 +85,3,3,0,0,0,100.0 +88,5,5,0,0,0,100.0 +89,5,5,0,0,0,100.0 +9,1,1,0,0,0,100.0 +90,5,5,0,0,0,100.0 +91,3,3,0,0,0,100.0 +96,2,2,0,0,0,100.0 +93,2,2,0,0,0,100.0 +94,2,2,0,0,0,100.0 +95,2,2,0,0,0,100.0 +98,2,2,0,0,0,100.0 +97,2,2,0,0,0,100.0 +99,2,2,0,0,0,100.0 +105,5,4,1,0,0,80.0 diff --git a/ai-service/test/yolo_resnet_answer/answers/resnet_fallback_analysis.txt b/ai-service/test/yolo_resnet_answer/answers/resnet_fallback_analysis.txt new file mode 100644 index 0000000..27c6733 --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/resnet_fallback_analysis.txt @@ -0,0 +1,6 @@ +================================================================================ +ResNet Fallback ์‚ฌ์šฉ ํ†ต๊ณ„ +================================================================================ + +โœ… ResNet Fallback์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. + ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ YOLO๋กœ ์ •์ƒ ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค. diff --git a/ai-service/test/yolo_resnet_answer/answers/results_summary.txt b/ai-service/test/yolo_resnet_answer/answers/results_summary.txt new file mode 100644 index 0000000..5bbf232 --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/results_summary.txt @@ -0,0 +1,155 @@ +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 1, 88, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10, 97, 29, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 10, 97, 30, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11, 98, 32, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 11, 98, 31, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12, 99, 34, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 12, 99, 33, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13, 100, 35, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 13, 100, 36, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14, 101, 37, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 14, 101, 38, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15, 102, 40, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 15, 102, 39, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16, 103, 41, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 16, 103, 42, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17, 104, 43, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17, 104, 44, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 17, 104, 45, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 04, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 02, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 05, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 18, 105, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 09, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 06, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 07, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 10, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 19, 106, 08, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 09, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 06, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 07, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 10, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 2, 89, 08, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 14, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 11, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 12, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 13, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 20, 107, 15, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21, 108, 18, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21, 108, 16, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 21, 108, 17, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22, 109, 20, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 22, 109, 19, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23, 110, 21, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 23, 110, 22, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24, 111, 24, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 24, 111, 23, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25, 112, 25, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 25, 112, 26, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26, 113, 27, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 26, 113, 28, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27, 114, 30, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 27, 114, 29, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28, 115, 32, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 28, 115, 31, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29, 116, 34, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 29, 116, 33, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 14, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 11, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 12, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 15, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 3, 90, 13, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30, 117, 35, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 30, 117, 36, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31, 118, 37, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 31, 118, 38, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32, 119, 39, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 32, 119, 40, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33, 120, 41, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 33, 120, 42, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34, 121, 43, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34, 121, 44, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 34, 121, 45, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4, 91, 18, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4, 91, 16, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 4, 91, 17, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5, 92, 20, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 5, 92, 19, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6, 93, 22, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 6, 93, 21, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7, 94, 24, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 7, 94, 23, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8, 95, 26, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 8, 95, 25, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9, 96, 28, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‰แ…ตแ†ฏแ„Œแ…ฅแ†ซ แ„†แ…ฉแ„‹แ…ดแ„€แ…ฉแ„‰แ…ก) - 9, 96, 27, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 1, 9, 01, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 10, 19, 05, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 11, 21, 01, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 12, 22, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 13, 23, 03, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 14, 24, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 15, 25, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 16, 27, 01, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 17, 28, 02, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 18, 29, 03, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 19, 30, 04, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 2, 10, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 20, 31, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 21, 33, 01, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 22, 34, 02, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 23, 35, 03, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 24, 36, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 25, 37, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 26, 39, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 27, 40, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 28, 41, 03, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 29, 42, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 3, 11, 03, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 30, 43, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 31, 45, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 32, 46, 02, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 33, 47, 03, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 34, 48, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 35, 49, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 36, 51, 01, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 37, 52, 02, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 38, 53, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 39, 54, 04, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 4, 12, 04, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 40, 55, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 41, 57, 01, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 42, 58, 02, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 43, 59, 03, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 44, 60, 04, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 45, 61, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 46, 63, 01, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 47, 64, 02, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 48, 65, 03, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 49, 66, 04, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 5, 13, 05, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 50, 67, 05, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 51, 69, 01, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 52, 70, 02, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 53, 71, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 54, 72, 04, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 55, 73, 05, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 56, 75, 01, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 57, 76, 02, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 58, 77, 03, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 59, 78, 04, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 6, 15, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 60, 79, 05, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62, 83, 01, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 62, 83, 02, 2 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64, 85, 03, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64, 85, 04, 3 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 64, 85, 05, 4 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 7, 16, 02, 5 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 8, 17, 03, 1 +แ„’แ…กแ†จแ„‰แ…ขแ†ผแ„‹แ…ต แ„‘แ…ฎแ†ซ แ„†แ…ฎแ†ซแ„Œแ…ฆ(แ„‹แ…ฒแ„’แ…งแ†ผแ„‘แ…งแ†ซ) - 9, 18, 04, 3 diff --git a/ai-service/test/yolo_resnet_answer/answers/yolo_answer.txt b/ai-service/test/yolo_resnet_answer/answers/yolo_answer.txt new file mode 100644 index 0000000..4d5bf1a --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/answers/yolo_answer.txt @@ -0,0 +1,155 @@ +9, 01, 1 +10, 02, 2 +11, 03, 2 +12, 04, 4 +13, 05, 1 +15, 01, 4 +16, 02, 5 +17, 03, 1 +18, 04, 3 +19, 05, 2 +21, 01, 1 +22, 02, 2 +23, 03, 4 +24, 04, 1 +25, 05, 1 +27, 01, 3 +28, 02, 4 +29, 03, 4 +30, 04, 2 +31, 05, 1 +33, 01, 5 +34, 02, 1 +35, 03, 2 +36, 04, 1 +37, 05, 3 +39, 01, 2 +40, 02, 2 +41, 03, 5 +42, 04, 1 +43, 05, 1 +45, 01, 2 +46, 02, 5 +47, 03, 2 +48, 04, 3 +49, 05, 4 +51, 01, 5 +52, 02, 1 +53, 03, 3 +54, 04, 4 +55, 05, 1 +57, 01, 1 +58, 02, 5 +59, 03, 1 +60, 04, 5 +61, 05, 4 +63, 01, 2 +64, 02, 4 +65, 03, 5 +66, 04, 1 +67, 05, 5 +69, 01, 5 +70, 02, 4 +71, 03, 3 +72, 04, 5 +73, 05, 5 +75, 01, 3 +76, 02, 5 +77, 03, 3 +78, 04, 2 +79, 05, 3 +83, 01, 4 +83, 02, 2 +85, 03, 5 +85, 04, 3 +85, 05, 4 +88, 01, 4 +88, 02, 2 +88, 03, 3 +88, 04, 3 +88, 05, 3 +89, 06, 4 +89, 07, 3 +89, 08, 1 +89, 09, 4 +89, 10, 2 +90, 11, 4 +90, 12, 3 +90, 13, 3 +90, 14, 2 +90, 15, 3 +91, 16, 3 +91, 17, 2 +91, 18, 3 +92, 19, 4 +92, 20, 3 +93, 21, 5 +93, 22, 4 +94, 23, 3 +94, 24, 2 +95, 25, 2 +95, 26, 5 +96, 27, 5 +96, 28, 2 +97, 29, 3 +97, 30, 2 +98, 31, 3 +98, 32, 5 +99, 33, 3 +99, 34, 4 +100, 35, 4 +100, 36, 3 +101, 37, 2 +101, 38, 5 +102, 39, 3 +102, 40, 2 +103, 41, 5 +103, 42, 2 +104, 43, 4 +104, 44, 2 +104, 45, 1 +105, 01, 2 +105, 02, 3 +105, 03, 3 +105, 04, 4 +105, 05, 2 +106, 06, 4 +106, 07, 5 +106, 08, 3 +106, 09, 5 +106, 10, 4 +107, 11, 2 +107, 12, 1 +107, 13, 1 +107, 14, 1 +107, 15, 3 +108, 16, 4 +108, 17, 4 +108, 18, 5 +109, 19, 1 +109, 20, 3 +110, 21, 5 +110, 22, 1 +111, 23, 5 +111, 24, 2 +112, 25, 4 +112, 26, 2 +113, 27, 4 +113, 28, 4 +114, 29, 3 +114, 30, 4 +115, 31, 2 +115, 32, 2 +116, 33, 1 +116, 34, 1 +117, 35, 3 +117, 36, 2 +118, 37, 5 +118, 38, 3 +119, 39, 3 +119, 40, 4 +120, 41, 4 +120, 42, 4 +121, 43, 4 +121, 44, 2 +121, 45, 5 \ No newline at end of file diff --git a/ai-service/test/yolo_resnet_answer/yolo_test.py b/ai-service/test/yolo_resnet_answer/yolo_test.py new file mode 100644 index 0000000..44110be --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/yolo_test.py @@ -0,0 +1,704 @@ +# yolo_test.py +import logging +import time +from pathlib import Path +from test.yolo_resnet_answer.yolo_test_crop import HierarchicalCropPipeline + +# === ๋กœ๊น… ์„ค์ • === +current_dir = Path(__file__).parent +log_file = current_dir / "ocr_results.log" + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s" +) +logger = logging.getLogger(__name__) + +# ํŒŒ์ผ ์ถœ๋ ฅ ์ถ”๊ฐ€ (utf-8 ์ธ์ฝ”๋”ฉ) +file_handler = logging.FileHandler(log_file, encoding="utf-8") +file_handler.setLevel(logging.INFO) +file_formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") +file_handler.setFormatter(file_formatter) +logger.addHandler(file_handler) + +logger.info(f"โœ… ๋กœ๊ทธ ํŒŒ์ผ์ด '{log_file}'๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.") + + +def main(): + """๋ฉ”์ธ ์‹คํ—˜ ํ•จ์ˆ˜""" + total_start_time = time.time() + + # ๊ฒฝ๋กœ ์„ค์ • + input_images_dir = current_dir / "images" / "exp_images" + output_dir = current_dir / "images" / "test_results" + model_dir_1104 = current_dir.parent.parent / "models" / "Detection" / "legacy" / "Model_routing_1104" + model_dir_1004 = current_dir.parent.parent / "models" / "Detection" / "legacy" / "Model_routing_1004" + resnet_model_path = current_dir.parent.parent / "models" / "Classification" / "answer_1_resnet.pth" # โœจ ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ ์ถ”๊ฐ€ + + # ๋‹ต์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ + answer_key_path = current_dir / "answers" / "answer.txt" + + # ๋‹ต์ง€ ํŒŒ์ผ์ด ์—†์œผ๋ฉด None์œผ๋กœ ์„ค์ • (๋ชจ๋“  ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ) + if not answer_key_path.exists(): + logger.warning(f"๋‹ต์ง€ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {answer_key_path}") + logger.warning("๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.") + answer_key_path = None + + logger.info("=" * 60) + logger.info("๊ณ„์ธต์  ํฌ๋กญ ํŒŒ์ดํ”„๋ผ์ธ (๊ฐœ์„  ๋ฒ„์ „ + ResNet Fallback) ์‹คํ—˜ ์‹œ์ž‘") + logger.info("=" * 60) + logger.info(f"์ž…๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ: {input_images_dir}") + logger.info(f"์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ: {output_dir}") + logger.info(f"1104 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ: {model_dir_1104}") + logger.info(f"1004 ๋ชจ๋ธ ๋””๋ ‰ํ† ๋ฆฌ: {model_dir_1004}") + logger.info(f"ResNet ๋ชจ๋ธ: {resnet_model_path}") # โœจ ResNet ๊ฒฝ๋กœ ๋กœ๊ทธ + logger.info(f"๋‹ต์ง€ ํŒŒ์ผ: {answer_key_path}") + + # ํŒŒ์ดํ”„๋ผ์ธ ์ดˆ๊ธฐํ™” (ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ ์ „๋‹ฌ) + pipeline = HierarchicalCropPipeline( + str(model_dir_1104), + str(model_dir_1004), + section_padding=50, + answer_key_path=str(answer_key_path) if answer_key_path else None, + resnet_model_path=str(resnet_model_path) if resnet_model_path.exists() else None # โœจ ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ ์ถ”๊ฐ€ + ) + + # ์ด๋ฏธ์ง€ ํŒŒ์ผ ์ˆ˜์ง‘ + image_extensions = [".jpg", ".jpeg", ".png", ".bmp"] + image_files = [] + for ext in image_extensions: + image_files.extend(input_images_dir.glob(f"*{ext}")) + image_files.extend(input_images_dir.glob(f"*{ext.upper()}")) + + image_files = sorted(image_files) + logger.info(f"\n์ฒ˜๋ฆฌํ•  ์ด๋ฏธ์ง€: {len(image_files)}๊ฐœ") + + if not image_files: + logger.warning(f"์ž…๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ์— ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค: {input_images_dir}") + return + + # ๊ฐ ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ + all_results = [] + skipped_pages = [] + + for idx, image_path in enumerate(image_files): + logger.info(f"\n\n{'#' * 60}") + logger.info(f"[{idx + 1}/{len(image_files)}] ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์ค‘: {Path(image_path).name}") + logger.info(f"{'#' * 60}") + + try: + result = pipeline.process_page(str(image_path), output_dir) + + if result is None: + # ๋‹ต์ง€์— ์—†๋Š” ํŽ˜์ด์ง€ + skipped_pages.append(Path(image_path).name) + logger.info(f"โญ๏ธ ํŽ˜์ด์ง€ ๊ฑด๋„ˆ๋œ€ (๋‹ต์ง€์— ์—†์Œ)") + else: + all_results.append(result) + logger.info(f"โœ… ํŽ˜์ด์ง€ '{result['page_name']}' ์ฒ˜๋ฆฌ ์™„๋ฃŒ: {result['processing_time']:.2f}์ดˆ") + except Exception as e: + logger.error(f"์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ ์‹คํŒจ: {image_path}") + logger.error(f"์—๋Ÿฌ: {e}", exc_info=True) + continue + + total_end_time = time.time() + total_processing_time = total_end_time - total_start_time + + # ์š”์•ฝ ๋ฐ ๊ฒฐ๊ณผ ์ €์žฅ + print_summary(all_results, skipped_pages, output_dir, total_processing_time) + save_results_txt(all_results, output_dir) + save_none_analysis(all_results, output_dir) + save_resnet_fallback_analysis(all_results, output_dir) # โœจ ResNet fallback ํ†ต๊ณ„ ์ถ”๊ฐ€ + save_crop_failure_analysis(all_results, output_dir) + check_missing_sections_against_answer_key(all_results, output_dir, pipeline.answer_key) + + +def save_results_txt(all_results: list, output_dir: Path): + """ + TXT ํŒŒ์ผ์— ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ์ธ์‹๋œ ๋‹ต์„ ํ•œ ์ค„์”ฉ ์ €์žฅ + """ + txt_path = output_dir.parent.parent / "answers" / "results_summary.txt" + output_dir.mkdir(parents=True, exist_ok=True) + + if not all_results: + logger.warning("โš ๏ธ ์ €์žฅํ•  ๊ฒฐ๊ณผ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.") + return + + with open(txt_path, "w", encoding="utf-8") as f: + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + for section in sections: + problem_number = section.get("problem_number_ocr", "") + answer_number = section.get("answer_number", "") + + # ์ด๋ฏธ์ง€ ํŒŒ์ผ๋ช…, ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ๋ฌธ์ œ ๋ฒˆํ˜ธ, ๋‹ต ๋ฒˆํ˜ธ๋ฅผ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ํ•œ ์ค„์— ์ž‘์„ฑ + line = f"{page_name}, {page_num_ocr}, {problem_number}, {answer_number}\n" + f.write(line) + + logger.info(f"\n๐Ÿ“„ TXT ๊ฒฐ๊ณผ ์ €์žฅ ์™„๋ฃŒ: {txt_path}") + + # ์ด ๋ผ์ธ ์ˆ˜ ๊ณ„์‚ฐ + total_lines = sum(len(r.get("sections", [])) for r in all_results) + logger.info(f"์ด {total_lines}๊ฐœ ๋ฌธ์ œ ๊ฒฐ๊ณผ๊ฐ€ ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") + + # None ๋‹ต์•ˆ ํ†ต๊ณ„ + none_count = 0 + resnet_used_count = 0 # โœจ ResNet ์‚ฌ์šฉ ํšŸ์ˆ˜ + for result in all_results: + for section in result.get("sections", []): + if section.get("answer_number") is None: + none_count += 1 + if section.get("used_resnet_fallback", False): # โœจ ResNet fallback ์‚ฌ์šฉ ์—ฌ๋ถ€ + resnet_used_count += 1 + + logger.info(f"None ๋‹ต์•ˆ: {none_count}๊ฐœ ({none_count/total_lines*100:.1f}%)") + logger.info(f"ResNet Fallback ์‚ฌ์šฉ: {resnet_used_count}๊ฐœ ({resnet_used_count/total_lines*100:.1f}%)") # โœจ + + +def save_none_analysis(all_results: list, output_dir: Path): + """ + None์œผ๋กœ ์ €์žฅ๋œ ๋‹ต์•ˆ์˜ ์ƒ์„ธ ๋””๋ฒ„๊น… ์ •๋ณด๋ฅผ ๋ณ„๋„ ํŒŒ์ผ๋กœ ์ €์žฅ + """ + analysis_path = output_dir.parent.parent / "answers" / "none_debug_analysis.txt" + + none_cases = [] + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + for section in sections: + if section.get("answer_number") is None: + debug_info = section.get("debug_info", {}) + none_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'section_idx': section.get('section_idx'), + 'problem_number': section.get('problem_number_ocr'), + 'debug_info': debug_info, + 'section_crop_path': section.get('section_crop_path'), + 'problem_crop_path': section.get('problem_crop_path'), + 'used_resnet_fallback': section.get('used_resnet_fallback', False), # โœจ + 'resnet_failed': section.get('resnet_failed', False) # โœจ + }) + + if not none_cases: + logger.info("โœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค!") + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("None ๋‹ต์•ˆ ๋””๋ฒ„๊น… ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write("โœ… None ๋‹ต์•ˆ์ด ์—†์Šต๋‹ˆ๋‹ค! ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n") + return + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("None ๋‹ต์•ˆ ๋””๋ฒ„๊น… ๋ถ„์„ (ResNet Fallback ํฌํ•จ)\n") + f.write("=" * 80 + "\n\n") + f.write(f"์ด {len(none_cases)}๊ฐœ์˜ None ๋‹ต์•ˆ ๋ฐœ๊ฒฌ\n\n") + + # ์›์ธ๋ณ„ ํ†ต๊ณ„ + answer_1_missing = sum(1 for case in none_cases if case['debug_info'].get('answer_1_count', 0) == 0) + class_missing = sum(1 for case in none_cases if case['debug_info'].get('class_count', 0) == 0) + iou_zero = sum(1 for case in none_cases + if case['debug_info'].get('answer_1_count', 0) > 0 + and case['debug_info'].get('class_count', 0) > 0 + and case['debug_info'].get('best_iou', 0) == 0) + resnet_tried = sum(1 for case in none_cases if case['used_resnet_fallback']) # โœจ + resnet_failed = sum(1 for case in none_cases if case['resnet_failed']) # โœจ + + f.write("๐Ÿ“Š ์›์ธ๋ณ„ ํ†ต๊ณ„:\n") + f.write(f" - answer_1 ๋ฏธ๊ฒ€์ถœ: {answer_1_missing}๊ฐœ ({answer_1_missing/len(none_cases)*100:.1f}%)\n") + f.write(f" - ์ˆซ์ž(1-5) ๋ฏธ๊ฒ€์ถœ: {class_missing}๊ฐœ ({class_missing/len(none_cases)*100:.1f}%)\n") + f.write(f" - IoU 0 (์œ„์น˜ ๋ถˆ์ผ์น˜): {iou_zero}๊ฐœ ({iou_zero/len(none_cases)*100:.1f}%)\n") + f.write(f" - ResNet Fallback ์‹œ๋„: {resnet_tried}๊ฐœ ({resnet_tried/len(none_cases)*100:.1f}%)\n") # โœจ + f.write(f" - ResNet๋„ ์‹คํŒจ: {resnet_failed}๊ฐœ ({resnet_failed/len(none_cases)*100:.1f}%)\n") # โœจ + f.write("\n") + + for i, case in enumerate(none_cases, 1): + f.write(f"\n{'='*80}\n") + f.write(f"[{i}] ํŽ˜์ด์ง€: {case['page_name']} (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: {case['page_num']})\n") + f.write(f" Section: {case['section_idx']}, ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['problem_number']}\n") + f.write(f"{'-'*80}\n") + + debug = case['debug_info'] + answer_1_count = debug.get('answer_1_count', 0) + class_count = debug.get('class_count', 0) + best_iou = debug.get('best_iou', 0.0) + + f.write(f" ๐Ÿ“‹ ๊ฒ€์ถœ ์ •๋ณด:\n") + f.write(f" answer_1 ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {answer_1_count}\n") + f.write(f" ์ˆซ์ž(1-5) ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {class_count}\n") + f.write(f" ์ตœ๊ณ  IoU: {best_iou:.4f}\n") + f.write(f" ResNet Fallback ์‹œ๋„: {'์˜ˆ' if case['used_resnet_fallback'] else '์•„๋‹ˆ์˜ค'}\n") # โœจ + if case['used_resnet_fallback']: + f.write(f" ResNet ๊ฒฐ๊ณผ: {'์‹คํŒจ' if case['resnet_failed'] else '์„ฑ๊ณตํ–ˆ์œผ๋‚˜ None'}\n") # โœจ + f.write("\n") + + # ์›์ธ ๋ถ„์„ + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + if answer_1_count == 0: + f.write(f" โŒ answer_1์ด ๊ฒ€์ถœ๋˜์ง€ ์•Š์Œ (1104 ๋ชจ๋ธ ๋ฌธ์ œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: 1104 ๋ชจ๋ธ ์žฌํ•™์Šต ๋˜๋Š” confidence threshold ์กฐ์ •\n") + if case['used_resnet_fallback']: + f.write(f" โœจ ResNet Fallback์ด ์‹œ๋„๋˜์—ˆ์œผ๋‚˜ ์‹คํŒจ\n") + elif class_count == 0: + f.write(f" โŒ ์ˆซ์ž(1-5)๊ฐ€ ๊ฒ€์ถœ๋˜์ง€ ์•Š์Œ (1104 ๋ชจ๋ธ ๋ฌธ์ œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: 1104 ๋ชจ๋ธ ์žฌํ•™์Šต ๋˜๋Š” confidence threshold ์กฐ์ •\n") + if case['used_resnet_fallback']: + f.write(f" โœจ ResNet Fallback์ด ์‹œ๋„๋˜์—ˆ์œผ๋‚˜ ์‹คํŒจ\n") + elif best_iou == 0.0: + f.write(f" โŒ IoU๊ฐ€ 0 (answer_1๊ณผ ์ˆซ์ž์˜ ์œ„์น˜๊ฐ€ ๊ฒน์น˜์ง€ ์•Š์Œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: \n") + f.write(f" 1. section padding์„ 50 โ†’ 70 ๋˜๋Š” 100์œผ๋กœ ์ฆ๊ฐ€\n") + f.write(f" 2. ๊ฒ€์ถœ ์œ„์น˜๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์„ ๊ฐ€๋Šฅ์„ฑ โ†’ ๋ชจ๋ธ ์žฌํ•™์Šต\n") + if case['used_resnet_fallback']: + f.write(f" โœจ ResNet Fallback์ด ์‹œ๋„๋˜์—ˆ์œผ๋‚˜ ์‹คํŒจ\n") + else: + f.write(f" โš ๏ธ ์›์ธ ๋ถˆ๋ช… (๋””๋ฒ„๊น… ํ•„์š”)\n") + if case['used_resnet_fallback']: + f.write(f" โœจ ResNet Fallback์ด ์‹œ๋„๋˜์—ˆ์œผ๋‚˜ ์‹คํŒจ\n") + + # IoU ์ƒ์„ธ ์ •๋ณด + iou_details = debug.get('iou_details', []) + if iou_details: + f.write(f"\n ๐Ÿ“ IoU ์ƒ์„ธ ์ •๋ณด:\n") + for detail in iou_details: + f.write(f" - ์ˆซ์ž {detail['class']}: IoU = {detail['iou']:.4f}, bbox = {detail['bbox']}\n") + + # ํŒŒ์ผ ๊ฒฝ๋กœ + f.write(f"\n ๐Ÿ“ ๊ด€๋ จ ํŒŒ์ผ:\n") + f.write(f" Section ์ด๋ฏธ์ง€: {case['section_crop_path']}\n") + if case['problem_crop_path']: + f.write(f" ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€: {case['problem_crop_path']}\n") + else: + f.write(f" ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€: (๋ฏธ์ƒ์„ฑ - ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ)\n") + + logger.info(f"๐Ÿ“Š None ๋””๋ฒ„๊น… ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + logger.info(f" ์ด {len(none_cases)}๊ฐœ None ์ผ€์ด์Šค ๋ถ„์„") + logger.info(f" ์›์ธ๋ณ„: answer_1 ๋ฏธ๊ฒ€์ถœ={answer_1_missing}, ์ˆซ์ž ๋ฏธ๊ฒ€์ถœ={class_missing}, IoU=0={iou_zero}") + logger.info(f" ResNet ์‹œ๋„={resnet_tried}, ResNet ์‹คํŒจ={resnet_failed}") # โœจ + + +def save_resnet_fallback_analysis(all_results: list, output_dir: Path): + """ + โœจ ResNet Fallback ์‚ฌ์šฉ ํ†ต๊ณ„๋ฅผ ๋ณ„๋„ ํŒŒ์ผ๋กœ ์ €์žฅ + """ + analysis_path = output_dir.parent.parent / "answers" / "resnet_fallback_analysis.txt" + + resnet_cases = [] + total_sections = 0 + + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + total_sections += len(sections) + + for section in sections: + if section.get("used_resnet_fallback", False): + resnet_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'section_idx': section.get('section_idx'), + 'problem_number': section.get('problem_number_ocr'), + 'yolo_answer': None, # YOLO๋Š” None + 'resnet_answer': section.get('answer_number'), + 'resnet_confidence': section.get('resnet_confidence', 0.0), + 'resnet_failed': section.get('resnet_failed', False), + 'section_crop_path': section.get('section_crop_path') + }) + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("ResNet Fallback ์‚ฌ์šฉ ํ†ต๊ณ„\n") + f.write("=" * 80 + "\n\n") + + if not resnet_cases: + f.write("โœ… ResNet Fallback์ด ์‚ฌ์šฉ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.\n") + f.write(" ๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ YOLO๋กœ ์ •์ƒ ์ธ์‹๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n") + logger.info("โœ… ResNet Fallback ์‚ฌ์šฉ ์—†์Œ") + return + + resnet_success = [c for c in resnet_cases if not c['resnet_failed'] and c['resnet_answer'] is not None] + resnet_failed = [c for c in resnet_cases if c['resnet_failed'] or c['resnet_answer'] is None] + + f.write(f"์ด Section ์ˆ˜: {total_sections}๊ฐœ\n") + f.write(f"ResNet Fallback ์‚ฌ์šฉ: {len(resnet_cases)}๊ฐœ ({len(resnet_cases)/total_sections*100:.1f}%)\n\n") + + f.write(f"๐Ÿ“Š ResNet ๊ฒฐ๊ณผ:\n") + f.write(f" - ์„ฑ๊ณต: {len(resnet_success)}๊ฐœ ({len(resnet_success)/len(resnet_cases)*100:.1f}%)\n") + f.write(f" - ์‹คํŒจ: {len(resnet_failed)}๊ฐœ ({len(resnet_failed)/len(resnet_cases)*100:.1f}%)\n\n") + + if resnet_success: + f.write(f"\n{'='*80}\n") + f.write(f"ResNet ์„ฑ๊ณต ์ผ€์ด์Šค ({len(resnet_success)}๊ฐœ)\n") + f.write(f"{'='*80}\n") + + for i, case in enumerate(resnet_success, 1): + f.write(f"\n[{i}] ํŽ˜์ด์ง€: {case['page_name']} (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: {case['page_num']})\n") + f.write(f" Section: {case['section_idx']}, ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['problem_number']}\n") + f.write(f" ResNet ๋‹ต์•ˆ: {case['resnet_answer']}\n") + f.write(f" ResNet Confidence: {case['resnet_confidence']:.4f}\n") + f.write(f" Section ์ด๋ฏธ์ง€: {case['section_crop_path']}\n") + + if resnet_failed: + f.write(f"\n{'='*80}\n") + f.write(f"ResNet ์‹คํŒจ ์ผ€์ด์Šค ({len(resnet_failed)}๊ฐœ)\n") + f.write(f"{'='*80}\n") + + for i, case in enumerate(resnet_failed, 1): + f.write(f"\n[{i}] ํŽ˜์ด์ง€: {case['page_name']} (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: {case['page_num']})\n") + f.write(f" Section: {case['section_idx']}, ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['problem_number']}\n") + f.write(f" ResNet ๊ฒฐ๊ณผ: ์‹คํŒจ (None)\n") + f.write(f" Section ์ด๋ฏธ์ง€: {case['section_crop_path']}\n") + + logger.info(f"๐Ÿ“Š ResNet Fallback ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + logger.info(f" ResNet ์‚ฌ์šฉ: {len(resnet_cases)}๊ฐœ (์„ฑ๊ณต={len(resnet_success)}, ์‹คํŒจ={len(resnet_failed)})") + + +def save_crop_failure_analysis(all_results: list, output_dir: Path): + """ + Section crop ์‹คํŒจ ์ผ€์ด์Šค๋ฅผ ๋ถ„์„ํ•˜์—ฌ ๋ณ„๋„ ํŒŒ์ผ๋กœ ์ €์žฅ + + ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ ๋ชฉ๋ก์„ ๊ฒ€์ฆ + """ + analysis_path = output_dir.parent.parent / "answers" / "crop_failure_analysis.txt" + + crop_failure_cases = [] + total_expected_sections = 0 + total_actual_files = 0 + duplicate_removed_count = 0 # ์ค‘๋ณต ์ œ๊ฑฐ ๊ฐœ์ˆ˜ + + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + # ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ ํ™•์ธ + sections_dir = output_dir / page_name / "sections" + actual_files = [] + if sections_dir.exists(): + actual_files = sorted(sections_dir.glob("section_*.jpg")) + total_actual_files += len(actual_files) + + total_expected_sections += len(sections) + + for section in sections: + if not section.get("crop_success", True): + crop_failure_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'section_idx': section.get('section_idx'), + 'failure_reason': section.get('crop_failure_reason', 'unknown'), + 'debug_info': section.get('debug_info', {}), + 'expected_path': section.get('section_crop_path') + }) + + # ์˜ˆ์ƒ ๊ฐœ์ˆ˜์™€ ์‹ค์ œ ํŒŒ์ผ ๊ฐœ์ˆ˜๊ฐ€ ๋‹ค๋ฅธ ๊ฒฝ์šฐ ๊ฒฝ๊ณ  + if len(sections) != len(actual_files): + logger.warning(f"โš ๏ธ ํŽ˜์ด์ง€ '{page_name}': ์˜ˆ์ƒ section ๊ฐœ์ˆ˜({len(sections)}) โ‰  ์‹ค์ œ ํŒŒ์ผ ๊ฐœ์ˆ˜({len(actual_files)})") + logger.warning(f" ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ: {[f.name for f in actual_files]}") + + # ๋ˆ„๋ฝ๋œ section ์ฐพ๊ธฐ + expected_indices = set(s.get('section_idx') for s in sections) + actual_indices = set(int(f.stem.split('_')[1]) for f in actual_files if f.stem.startswith('section_')) + missing_indices = expected_indices - actual_indices + + if missing_indices: + logger.error(f" โŒ ๋ˆ„๋ฝ๋œ section ์ธ๋ฑ์Šค: {sorted(missing_indices)}") + + # ๋ˆ„๋ฝ๋œ section์„ failure case์— ์ถ”๊ฐ€ + for idx in missing_indices: + matching_sections = [s for s in sections if s.get('section_idx') == idx] + if matching_sections: + section = matching_sections[0] + if section.get('crop_success', True): # crop_success=True์ธ๋ฐ ํŒŒ์ผ์ด ์—†๋Š” ๊ฒฝ์šฐ + crop_failure_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'section_idx': idx, + 'failure_reason': 'file_not_found_despite_success', + 'debug_info': section.get('debug_info', {}), + 'expected_path': section.get('section_crop_path') + }) + + logger.info(f"\n๐Ÿ“Š Section ํŒŒ์ผ ๊ฒ€์ฆ:") + logger.info(f" ์˜ˆ์ƒ section ์ด ๊ฐœ์ˆ˜: {total_expected_sections}") + logger.info(f" ์‹ค์ œ ์ €์žฅ๋œ ํŒŒ์ผ ๊ฐœ์ˆ˜: {total_actual_files}") + logger.info(f" ์ค‘๋ณต ์ œ๊ฑฐ๋œ section: {duplicate_removed_count}๊ฐœ") + + if total_expected_sections != total_actual_files: + logger.error(f" โŒ ๋ถˆ์ผ์น˜ ๋ฐœ๊ฒฌ: {total_expected_sections - total_actual_files}๊ฐœ ํŒŒ์ผ ๋ˆ„๋ฝ") + else: + logger.info(f" โœ… ๋ชจ๋“  section ํŒŒ์ผ์ด ์ •์ƒ์ ์œผ๋กœ ์ €์žฅ๋จ") + + if not crop_failure_cases: + logger.info("โœ… Section crop ์‹คํŒจ ์ผ€์ด์Šค๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค!") + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("Section Crop ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + if total_expected_sections == total_actual_files: + f.write("โœ… ๋ชจ๋“  Section์ด ์ •์ƒ์ ์œผ๋กœ crop๋˜์—ˆ์Šต๋‹ˆ๋‹ค!\n\n") + if duplicate_removed_count > 0: + f.write(f"๐Ÿ“Š ์ค‘๋ณต ์ œ๊ฑฐ ํ†ต๊ณ„:\n") + f.write(f" - ์ค‘๋ณต์œผ๋กœ ์ œ๊ฑฐ๋œ section: {duplicate_removed_count}๊ฐœ\n") + f.write(f" - ๊ฐ™์€ ๋ฌธ์ œ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ง„ section ์ค‘ ๋” ํฐ ๊ฒƒ๋งŒ ์„ ํƒ๋จ\n") + else: + f.write(f"โš ๏ธ ์ผ๋ถ€ ํŒŒ์ผ์ด ๋ˆ„๋ฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n") + f.write(f" ์˜ˆ์ƒ: {total_expected_sections}๊ฐœ\n") + f.write(f" ์‹ค์ œ: {total_actual_files}๊ฐœ\n") + f.write(f" ๋ˆ„๋ฝ: {total_expected_sections - total_actual_files}๊ฐœ\n") + if duplicate_removed_count > 0: + f.write(f"\n๐Ÿ“Š ์ค‘๋ณต ์ œ๊ฑฐ ํ†ต๊ณ„:\n") + f.write(f" - ์ค‘๋ณต์œผ๋กœ ์ œ๊ฑฐ๋œ section: {duplicate_removed_count}๊ฐœ\n") + return + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("Section Crop ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write(f"์ด {len(crop_failure_cases)}๊ฐœ์˜ Section crop ์‹คํŒจ ๋ฐœ๊ฒฌ\n") + + if duplicate_removed_count > 0: + f.write(f"\n๐Ÿ“Š ์ค‘๋ณต ์ œ๊ฑฐ ํ†ต๊ณ„:\n") + f.write(f" - ์ค‘๋ณต์œผ๋กœ ์ œ๊ฑฐ๋œ section: {duplicate_removed_count}๊ฐœ\n") + f.write(f" - ๊ฐ™์€ ๋ฌธ์ œ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ง„ section ์ค‘ ๋” ํฐ ๊ฒƒ๋งŒ ์„ ํƒ๋จ\n") + + f.write("\n") + + # ์›์ธ๋ณ„ ํ†ต๊ณ„ + failure_reasons = {} + for case in crop_failure_cases: + reason = case['failure_reason'] + failure_reasons[reason] = failure_reasons.get(reason, 0) + 1 + + f.write("๐Ÿ“Š ์‹คํŒจ ์›์ธ๋ณ„ ํ†ต๊ณ„:\n") + for reason, count in failure_reasons.items(): + f.write(f" - {reason}: {count}๊ฐœ ({count/len(crop_failure_cases)*100:.1f}%)\n") + f.write("\n") + + for i, case in enumerate(crop_failure_cases, 1): + f.write(f"\n{'='*80}\n") + f.write(f"[{i}] ํŽ˜์ด์ง€: {case['page_name']} (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: {case['page_num']})\n") + f.write(f" Section: {case['section_idx']}\n") + f.write(f"{'-'*80}\n") + + f.write(f" โŒ ์‹คํŒจ ์›์ธ: {case['failure_reason']}\n\n") + + debug = case['debug_info'] + + # ์›์ธ๋ณ„ ์ƒ์„ธ ์ •๋ณด (๊ธฐ์กด ์ฝ”๋“œ ์œ ์ง€) + if case['failure_reason'] == 'invalid_bbox': + f.write(f" ๐Ÿ“‹ Bbox ์ •๋ณด:\n") + f.write(f" ์›๋ณธ bbox: {debug.get('original_bbox', 'N/A')}\n") + f.write(f" Bbox ๋„ˆ๋น„: {debug.get('bbox_width', 'N/A'):.1f}\n") + f.write(f" Bbox ๋†’์ด: {debug.get('bbox_height', 'N/A'):.1f}\n") + f.write(f" ์ด๋ฏธ์ง€ ํฌ๊ธฐ: {debug.get('image_size', 'N/A')}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โŒ Section bbox๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์Šต๋‹ˆ๋‹ค (x2 <= x1 or y2 <= y1)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. 1004 ๋ชจ๋ธ์˜ Section ๊ฒ€์ถœ์ด ์ž˜๋ชป๋จ โ†’ ๋ชจ๋ธ ์žฌํ•™์Šต ํ•„์š”\n") + f.write(f" 2. Post-processing ์˜ค๋ฅ˜ โ†’ bbox ์กฐ์ • ๋กœ์ง ํ™•์ธ\n") + # ... (๋‚˜๋จธ์ง€ ์›์ธ๋ณ„ ๋ถ„์„์€ ๊ธฐ์กด ์ฝ”๋“œ์™€ ๋™์ผํ•˜๋ฏ€๋กœ ์ƒ๋žต) + + logger.info(f"๐Ÿ“Š Crop ์‹คํŒจ ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + logger.info(f" ์ด {len(crop_failure_cases)}๊ฐœ ์‹คํŒจ ์ผ€์ด์Šค ๋ถ„์„") + + +def check_missing_sections_against_answer_key(all_results: list, output_dir: Path, answer_key: dict): + """ + ๋‹ต์ง€์™€ ์‹ค์ œ ์ฒ˜๋ฆฌ๋œ section์„ ๋น„๊ตํ•˜์—ฌ ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋ƒ„ + """ + if not answer_key: + logger.info("๋‹ต์ง€๊ฐ€ ์—†์–ด ๋ˆ„๋ฝ ๊ฒ€์ถœ์„ ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + return + + analysis_path = output_dir.parent.parent / "answers" / "missing_sections_analysis.txt" + + missing_cases = [] + + for result in all_results: + page_name = result.get("page_name", "") + page_num_ocr = result.get("page_number_ocr", "") + sections = result.get("sections", []) + + # ๋‹ต์ง€์—์„œ ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ๋ฌธ์ œ ๊ฐœ์ˆ˜ ํ™•์ธ + if page_num_ocr not in answer_key: + logger.warning(f"ํŽ˜์ด์ง€ {page_num_ocr}๊ฐ€ ๋‹ต์ง€์— ์—†์Šต๋‹ˆ๋‹ค.") + continue + + expected_problems = answer_key[page_num_ocr] + expected_count = len(expected_problems) + actual_count = len(sections) + + logger.info(f"ํŽ˜์ด์ง€ {page_num_ocr}: ๋‹ต์ง€ ๋ฌธ์ œ ์ˆ˜={expected_count}, ์‹ค์ œ section ์ˆ˜={actual_count}") + + if expected_count != actual_count: + logger.error(f"โŒ ํŽ˜์ด์ง€ {page_num_ocr}: ๋ฌธ์ œ ์ˆ˜ ๋ถˆ์ผ์น˜!") + logger.error(f" ์˜ˆ์ƒ: {expected_count}๊ฐœ, ์‹ค์ œ: {actual_count}๊ฐœ") + logger.error(f" ์ฐจ์ด: {expected_count - actual_count}๊ฐœ") + + # ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ + expected_problem_numbers = set(p['problem'] for p in expected_problems) + actual_problem_numbers = set(s.get('problem_number_ocr') for s in sections if s.get('problem_number_ocr')) + + # OCR ์‹คํŒจ๋กœ ์ธํ•œ ๋ˆ„๋ฝ๋„ ๊ณ ๋ ค + missing_problems = [] + for exp_prob in expected_problem_numbers: + found = False + for act_prob in actual_problem_numbers: + if act_prob and str(exp_prob) == str(act_prob): + found = True + break + if not found: + missing_problems.append(exp_prob) + + if missing_problems: + logger.error(f" ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๋ฒˆํ˜ธ: {sorted(missing_problems)}") + + missing_cases.append({ + 'page_name': page_name, + 'page_num': page_num_ocr, + 'expected_count': expected_count, + 'actual_count': actual_count, + 'difference': expected_count - actual_count, + 'expected_problems': sorted(expected_problem_numbers), + 'actual_problems': sorted(actual_problem_numbers), + 'missing_problems': sorted(missing_problems), + 'sections': sections + }) + + if not missing_cases: + logger.info("โœ… ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ๋ฌธ์ œ ์ˆ˜๊ฐ€ ๋‹ต์ง€์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค!") + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ Section ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write("โœ… ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ๋ฌธ์ œ ์ˆ˜๊ฐ€ ๋‹ต์ง€์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค!\n") + return + + with open(analysis_path, "w", encoding="utf-8") as f: + f.write("=" * 80 + "\n") + f.write("๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ Section ๋ถ„์„\n") + f.write("=" * 80 + "\n\n") + f.write(f"์ด {len(missing_cases)}๊ฐœ ํŽ˜์ด์ง€์—์„œ ๋ถˆ์ผ์น˜ ๋ฐœ๊ฒฌ\n\n") + + total_missing = sum(case['difference'] for case in missing_cases if case['difference'] > 0) + total_extra = sum(-case['difference'] for case in missing_cases if case['difference'] < 0) + + f.write(f"๐Ÿ“Š ์ „์ฒด ํ†ต๊ณ„:\n") + f.write(f" - ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ (๋‹ต์ง€๋ณด๋‹ค ์ ์Œ): {total_missing}๊ฐœ\n") + f.write(f" - ์ดˆ๊ณผ ๊ฒ€์ถœ (๋‹ต์ง€๋ณด๋‹ค ๋งŽ์Œ): {total_extra}๊ฐœ\n\n") + + for i, case in enumerate(missing_cases, 1): + f.write(f"\n{'='*80}\n") + f.write(f"[{i}] ํŽ˜์ด์ง€: {case['page_name']} (ํŽ˜์ด์ง€๋ฒˆํ˜ธ: {case['page_num']})\n") + f.write(f"{'-'*80}\n") + + f.write(f" ๐Ÿ“Š ๋ฌธ์ œ ์ˆ˜:\n") + f.write(f" ๋‹ต์ง€ ์˜ˆ์ƒ: {case['expected_count']}๊ฐœ\n") + f.write(f" ์‹ค์ œ ๊ฒ€์ถœ: {case['actual_count']}๊ฐœ\n") + f.write(f" ์ฐจ์ด: {case['difference']:+d}๊ฐœ\n\n") + + if case['difference'] > 0: + f.write(f" โŒ ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ:\n") + f.write(f" ๋‹ต์ง€ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['expected_problems']}\n") + f.write(f" ์‹ค์ œ ์ธ์‹๋œ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['actual_problems']}\n") + f.write(f" ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['missing_problems']}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + + # Section crop ์‹คํŒจ ํ™•์ธ + failed_crops = [s for s in case['sections'] if not s.get('crop_success', True)] + if failed_crops: + f.write(f" โŒ {len(failed_crops)}๊ฐœ Section crop ์‹คํŒจ\n") + for s in failed_crops: + f.write(f" - Section {s.get('section_idx')}: {s.get('crop_failure_reason')}\n") + + # Section ์ž์ฒด๊ฐ€ ๊ฒ€์ถœ ์•ˆ ๋จ + if case['actual_count'] < case['expected_count']: + not_detected = case['expected_count'] - case['actual_count'] + f.write(f" โŒ {not_detected}๊ฐœ Section์ด ๊ฒ€์ถœ๋˜์ง€ ์•Š์Œ (1004 ๋ชจ๋ธ ๋ฌธ์ œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. 1004 ๋ชจ๋ธ์˜ Section ๊ฒ€์ถœ ์žฌํ•™์Šต\n") + f.write(f" 2. Confidence threshold ์กฐ์ • (ํ˜„์žฌ ๊ฐ’ ํ™•์ธ ํ•„์š”)\n") + f.write(f" 3. ์ด๋ฏธ์ง€ ํ’ˆ์งˆ ํ™•์ธ (ํ•ด์ƒ๋„, ์„ ๋ช…๋„)\n") + + # ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ์‹คํŒจ + ocr_failures = [s for s in case['sections'] if not s.get('problem_number_ocr')] + if ocr_failures: + f.write(f" โš ๏ธ {len(ocr_failures)}๊ฐœ ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ์‹คํŒจ\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: OCR ๋ชจ๋ธ ๊ฐœ์„  ๋˜๋Š” ์ „์ฒ˜๋ฆฌ ์ถ”๊ฐ€\n") + + elif case['difference'] < 0: + f.write(f" โš ๏ธ ์ดˆ๊ณผ ๊ฒ€์ถœ (๋‹ต์ง€๋ณด๋‹ค ๋งŽ์Œ):\n") + f.write(f" ๋‹ต์ง€ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['expected_problems']}\n") + f.write(f" ์‹ค์ œ ์ธ์‹๋œ ๋ฌธ์ œ๋ฒˆํ˜ธ: {case['actual_problems']}\n\n") + + f.write(f" ๐Ÿ” ์›์ธ ๋ถ„์„:\n") + f.write(f" โš ๏ธ Section์ด ๊ณผ๋‹ค ๊ฒ€์ถœ๋จ (1004 ๋ชจ๋ธ ๋ฌธ์ œ)\n") + f.write(f" โ†’ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•:\n") + f.write(f" 1. NMS (Non-Maximum Suppression) threshold ์กฐ์ •\n") + f.write(f" 2. Confidence threshold ์ƒํ–ฅ ์กฐ์ •\n") + f.write(f" 3. ์ค‘๋ณต ๊ฒ€์ถœ ํ•„ํ„ฐ๋ง ๋กœ์ง ์ถ”๊ฐ€\n") + + logger.info(f"๐Ÿ“Š ๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ ๋ถ„์„ ์ €์žฅ ์™„๋ฃŒ: {analysis_path}") + logger.info(f" ๋ถˆ์ผ์น˜ ํŽ˜์ด์ง€: {len(missing_cases)}๊ฐœ") + logger.info(f" ๋ˆ„๋ฝ๋œ ๋ฌธ์ œ: {total_missing}๊ฐœ") + logger.info(f" ์ดˆ๊ณผ ๊ฒ€์ถœ: {total_extra}๊ฐœ") + + +def print_summary(all_results: list, skipped_pages: list, output_dir: Path, total_processing_time: float): + """์‹คํ—˜ ๊ฒฐ๊ณผ ์š”์•ฝ ์ถœ๋ ฅ""" + logger.info("\n\n" + "=" * 60) + logger.info("์ „์ฒด ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ์š”์•ฝ (ResNet Fallback ํฌํ•จ)") + logger.info("=" * 60) + + total_pages = len(all_results) + total_sections = sum(len(r.get("sections", [])) for r in all_results) + total_crop_failures = sum(r.get("crop_failure_count", 0) for r in all_results) + + # โœจ ResNet ์‚ฌ์šฉ ํ†ต๊ณ„ + total_resnet_used = 0 + total_resnet_success = 0 + for result in all_results: + for section in result.get("sections", []): + if section.get("used_resnet_fallback", False): + total_resnet_used += 1 + if section.get("answer_number") is not None: + total_resnet_success += 1 + + logger.info(f" ์ฒ˜๋ฆฌ๋œ ํŽ˜์ด์ง€ ์ˆ˜: {total_pages}") + logger.info(f" ๊ฑด๋„ˆ๋›ด ํŽ˜์ด์ง€ ์ˆ˜: {len(skipped_pages)}") + if skipped_pages: + logger.info(f" ๊ฑด๋„ˆ๋›ด ํŽ˜์ด์ง€: {', '.join(skipped_pages)}") + logger.info(f" ์ด Section ์ˆ˜: {total_sections}") + logger.info(f" Section crop ์‹คํŒจ: {total_crop_failures}๊ฐœ") + logger.info(f" ResNet Fallback ์‚ฌ์šฉ: {total_resnet_used}๊ฐœ ({total_resnet_used/total_sections*100:.1f}%)") # โœจ + logger.info(f" ResNet ์„ฑ๊ณต: {total_resnet_success}๊ฐœ / {total_resnet_used}๊ฐœ") # โœจ + logger.info(f" ์ „์ฒด ์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {total_processing_time:.2f}์ดˆ ({total_processing_time / 60:.2f}๋ถ„)") + + if all_results: + avg_time = sum(r.get("processing_time", 0.0) for r in all_results) / len(all_results) + logger.info(f" ํŽ˜์ด์ง€๋‹น ํ‰๊ท  ์ฒ˜๋ฆฌ ์‹œ๊ฐ„: {avg_time:.2f}์ดˆ") + + logger.info(f"\n๐Ÿ“ ๊ฒฐ๊ณผ TXT: {output_dir.parent.parent / 'answers' / 'results_summary.txt'}") + logger.info(f"๐Ÿ“Š None ๋””๋ฒ„๊น…: {output_dir.parent.parent / 'answers' / 'none_debug_analysis.txt'}") + logger.info(f"๐Ÿ“Š ResNet Fallback ๋ถ„์„: {output_dir.parent.parent / 'answers' / 'resnet_fallback_analysis.txt'}") # โœจ + logger.info(f"๐Ÿ“Š Crop ์‹คํŒจ ๋ถ„์„: {output_dir.parent.parent / 'answers' / 'crop_failure_analysis.txt'}") + logger.info(f"๐Ÿ“Š ๋‹ต์ง€ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ ๋ถ„์„: {output_dir.parent.parent / 'answers' / 'missing_sections_analysis.txt'}") + logger.info(f"๐Ÿ“ ๋กœ๊ทธ ํŒŒ์ผ: {log_file}") + logger.info("=" * 60) + logger.info("๋ชจ๋“  ์‹คํ—˜์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.") + logger.info("=" * 60) + + +if __name__ == "__main__": + main() + +# ํŒŒ์ผ ์‹คํ–‰: python -m test.yolo_resnet_answer.yolo_test \ No newline at end of file diff --git a/ai-service/test/yolo_resnet_answer/yolo_test_crop.py b/ai-service/test/yolo_resnet_answer/yolo_test_crop.py new file mode 100644 index 0000000..3e7fe51 --- /dev/null +++ b/ai-service/test/yolo_resnet_answer/yolo_test_crop.py @@ -0,0 +1,1110 @@ +# yolo_test_crop.py +import logging +import time +import os +from pathlib import Path +from typing import Dict, List, Tuple, Optional +import cv2 +import numpy as np +import torch +import torch.nn as nn +from torchvision import transforms +from models.Detection.legacy.Model_routing_1104.run_routed_inference import RoutedInference as RoutedInference_1104 +from models.Detection.legacy.Model_routing_1004.run_routed_inference import RoutedInference as RoutedInference_1004 +from models.Recognition.ocr import OCRModel + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + + +class ResNetClassifier: + """ResNet ๊ธฐ๋ฐ˜ ๋‹ต์•ˆ ๋ถ„๋ฅ˜ ๋ชจ๋ธ (1-5 ๋ถ„๋ฅ˜)""" + + def __init__(self, model_path: str, device: str = 'cuda'): + """ + Args: + model_path: ResNet ๋ชจ๋ธ ๊ฐ€์ค‘์น˜ ํŒŒ์ผ ๊ฒฝ๋กœ (.pth) + device: 'cuda' ๋˜๋Š” 'cpu' + """ + self.device = torch.device(device if torch.cuda.is_available() else 'cpu') + self.model = self._load_model(model_path) + self.transform = self._get_transform() + + logger.info(f"โœ… ResNet ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ: {model_path}") + logger.info(f" ๋””๋ฐ”์ด์Šค: {self.device}") + + def _load_model(self, model_path: str): + """ResNet ๋ชจ๋ธ ๋กœ๋“œ - ์ปค์Šคํ…€ ๊ตฌ์กฐ""" + import torch.nn as nn + + # ์ปค์Šคํ…€ ResNet18 ๊ตฌ์กฐ (shortcut ์‚ฌ์šฉ, grayscale ์ž…๋ ฅ) + class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, in_channels, out_channels, stride=1): + super(BasicBlock, self).__init__() + self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(out_channels) + self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(out_channels) + + self.shortcut = nn.Sequential() + if stride != 1 or in_channels != out_channels: + self.shortcut = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(out_channels) + ) + + def forward(self, x): + out = torch.relu(self.bn1(self.conv1(x))) + out = self.bn2(self.conv2(out)) + out += self.shortcut(x) + out = torch.relu(out) + return out + + class CustomResNet18(nn.Module): + def __init__(self, num_classes=5): + super(CustomResNet18, self).__init__() + # Grayscale ์ž…๋ ฅ (1 ์ฑ„๋„) + self.conv1 = nn.Conv2d(1, 64, kernel_size=3, stride=1, padding=1, bias=False) + self.bn1 = nn.BatchNorm2d(64) + + # ResNet18 ๊ตฌ์กฐ + self.layer1 = self._make_layer(64, 64, 2, stride=1) + self.layer2 = self._make_layer(64, 128, 2, stride=2) + self.layer3 = self._make_layer(128, 256, 2, stride=2) + self.layer4 = self._make_layer(256, 512, 2, stride=2) + + self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(512, num_classes) + + def _make_layer(self, in_channels, out_channels, num_blocks, stride): + layers = [] + layers.append(BasicBlock(in_channels, out_channels, stride)) + for _ in range(1, num_blocks): + layers.append(BasicBlock(out_channels, out_channels, 1)) + return nn.Sequential(*layers) + + def forward(self, x): + out = torch.relu(self.bn1(self.conv1(x))) + out = self.layer1(out) + out = self.layer2(out) + out = self.layer3(out) + out = self.layer4(out) + out = self.avgpool(out) + out = out.view(out.size(0), -1) + out = self.fc(out) + return out + + # ๋ชจ๋ธ ์ƒ์„ฑ + model = CustomResNet18(num_classes=5) + + # ๊ฐ€์ค‘์น˜ ๋กœ๋“œ (PyTorch 2.6+ ํ˜ธํ™˜) + try: + checkpoint = torch.load(model_path, map_location=self.device, weights_only=False) + except TypeError: + checkpoint = torch.load(model_path, map_location=self.device) + + # state_dict ์ถ”์ถœ + if isinstance(checkpoint, dict): + if 'model_state_dict' in checkpoint: + state_dict = checkpoint['model_state_dict'] + elif 'state_dict' in checkpoint: + state_dict = checkpoint['state_dict'] + else: + state_dict = checkpoint + else: + state_dict = checkpoint + + model.load_state_dict(state_dict) + model.to(self.device) + model.eval() + + return model + + def _get_transform(self): + """์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ ๋ณ€ํ™˜ - MNIST ์Šคํƒ€์ผ""" + return transforms.Compose([ + transforms.ToPILImage(), + transforms.Grayscale(num_output_channels=1), # Grayscale ๋ณ€ํ™˜ + transforms.Resize((28, 28)), # MNIST ํฌ๊ธฐ + transforms.ToTensor(), + transforms.Normalize(mean=[0.1307], std=[0.3081]) # MNIST ์ •๊ทœํ™” + ]) + + def predict(self, image_path: str) -> Tuple[Optional[str], float]: + """ + ์ด๋ฏธ์ง€์—์„œ ๋‹ต์•ˆ ๋ฒˆํ˜ธ ์˜ˆ์ธก + + Args: + image_path: ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ + + Returns: + Tuple[Optional[str], float]: (์˜ˆ์ธก๋œ ๋‹ต์•ˆ ๋ฒˆํ˜ธ '1'-'5', ์‹ ๋ขฐ๋„) + """ + try: + # ์ด๋ฏธ์ง€ ๋กœ๋“œ (BGR) + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return None, 0.0 + + # RGB๋กœ ๋ณ€ํ™˜ (PIL์€ RGB๋ฅผ ๊ธฐ๋Œ€) + image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) + + # ์ „์ฒ˜๋ฆฌ (Grayscale ๋ณ€ํ™˜ ํฌํ•จ) + input_tensor = self.transform(image_rgb).unsqueeze(0).to(self.device) + + # ์ถ”๋ก  + with torch.no_grad(): + outputs = self.model(input_tensor) + probabilities = torch.softmax(outputs, dim=1) + confidence, predicted = torch.max(probabilities, 1) + + # ๊ฒฐ๊ณผ ๋ณ€ํ™˜ (0-4 โ†’ 1-5) + answer = str(predicted.item() + 1) + conf = confidence.item() + + logger.info(f"ResNet ์˜ˆ์ธก: ๋‹ต์•ˆ={answer}, ์‹ ๋ขฐ๋„={conf:.4f}") + + return answer, conf + + except Exception as e: + logger.error(f"ResNet ์˜ˆ์ธก ์‹คํŒจ: {e}", exc_info=True) + return None, 0.0 + + +class HierarchicalCropPipeline: + """๊ณ„์ธต์  ํฌ๋กญ ํŒŒ์ดํ”„๋ผ์ธ: ํŽ˜์ด์ง€ โ†’ Section โ†’ ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ ์ •๋‹ต (answer_1 crop ํ›„ ResNet ๋ถ„๋ฅ˜)""" + + def __init__(self, model_dir_1104: str, model_dir_1004: str, + section_padding: int = 50, + answer_key_path: Optional[str] = None, + resnet_model_path: Optional[str] = None): + """ + Args: + model_dir_1104: 1104 ๋ชจ๋ธ ๊ฒฝ๋กœ + model_dir_1004: 1004 ๋ชจ๋ธ ๊ฒฝ๋กœ + section_padding: Section crop ์‹œ ์ถ”๊ฐ€ํ•  ์—ฌ๋ฐฑ (ํ”ฝ์…€). ๊ธฐ๋ณธ๊ฐ’ 50 + answer_key_path: ๋‹ต์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ (txt ํŒŒ์ผ) + resnet_model_path: ResNet ๋ชจ๋ธ ๊ฒฝ๋กœ (.pth ํŒŒ์ผ) + """ + self.router_1104 = RoutedInference_1104(model_dir_1104) # ๋‹ต์•ˆ ์ถ”๋ก ์šฉ + self.router_1004 = RoutedInference_1004(model_dir_1004) # ํฌ๋กญ์šฉ (ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section) + self.ocr = OCRModel() + self.section_padding = section_padding + + # โœจ ResNet ๋ชจ๋ธ ์ดˆ๊ธฐํ™” + self.resnet_classifier = None + if resnet_model_path and os.path.exists(resnet_model_path): + try: + self.resnet_classifier = ResNetClassifier(resnet_model_path) + logger.info("โœ… ResNet ๋ถ„๋ฅ˜ ๋ชจ๋ธ ๋กœ๋“œ ์„ฑ๊ณต") + except Exception as e: + logger.error(f"โŒ ResNet ๋ชจ๋ธ ๋กœ๋“œ ์‹คํŒจ: {e}") + logger.warning("ResNet ๋ถ„๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + else: + if resnet_model_path: + logger.warning(f"ResNet ๋ชจ๋ธ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {resnet_model_path}") + logger.info("ResNet ๋ถ„๋ฅ˜ ์—†์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.") + + # ๋‹ต์ง€ ๋กœ๋“œ + self.answer_key = self._load_answer_key(answer_key_path) if answer_key_path else None + + logger.info("HierarchicalCropPipeline ์ดˆ๊ธฐํ™” (๋‘ ๊ฐœ์˜ ๋ชจ๋ธ + OCR ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ)") + logger.info(" - 1104 ๋ชจ๋ธ: ๋‹ต์•ˆ ์ถ”๋ก ์šฉ (answer_1 ๊ฒ€์ถœ)") + logger.info(" - 1004 ๋ชจ๋ธ: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ํฌ๋กญ์šฉ") + logger.info(f" - Section padding: {section_padding}px") + logger.info(f" - ResNet ๋ถ„๋ฅ˜: {'์‚ฌ์šฉ ๊ฐ€๋Šฅ' if self.resnet_classifier else '์‚ฌ์šฉ ๋ถˆ๊ฐ€'}") + if self.answer_key: + logger.info(f" - ๋‹ต์ง€ ๋กœ๋“œ ์™„๋ฃŒ: {len(self.answer_key)}๊ฐœ ํŽ˜์ด์ง€") + + def _load_answer_key(self, answer_key_path: str) -> Dict[str, List[Dict]]: + """๋‹ต์ง€ ํŒŒ์ผ ๋กœ๋“œ + + ํŒŒ์ผ ํ˜•์‹: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, ์ •๋‹ต + ์˜ˆ: 1, 1, 3 + + Returns: + Dict[str, List[Dict]]: {ํŽ˜์ด์ง€๋ฒˆํ˜ธ: [{'problem': ๋ฌธ์ œ๋ฒˆํ˜ธ, 'answer': ์ •๋‹ต}, ...]} + """ + answer_key = {} + try: + with open(answer_key_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line: + continue + + parts = [p.strip() for p in line.split(',')] + if len(parts) >= 3: + page_num = parts[0] + problem_num = parts[1] + answer = parts[2] + + if page_num not in answer_key: + answer_key[page_num] = [] + + answer_key[page_num].append({ + 'problem': problem_num, + 'answer': answer + }) + + logger.info(f"๋‹ต์ง€ ๋กœ๋“œ ์™„๋ฃŒ: {answer_key_path}") + for page, problems in answer_key.items(): + logger.info(f" ํŽ˜์ด์ง€ {page}: {len(problems)}๊ฐœ ๋ฌธ์ œ") + + except Exception as e: + logger.error(f"๋‹ต์ง€ ๋กœ๋“œ ์‹คํŒจ: {e}") + return {} + + return answer_key + + def is_valid_page(self, page_number: Optional[str]) -> bool: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๊ฐ€ ๋‹ต์ง€์— ์žˆ๋Š”์ง€ ํ™•์ธ + + Args: + page_number: OCR๋กœ ์ธ์‹๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ + + Returns: + bool: ๋‹ต์ง€์— ์žˆ์œผ๋ฉด True, ๋‹ต์ง€๊ฐ€ ์—†๊ฑฐ๋‚˜ ํŽ˜์ด์ง€๊ฐ€ ์—†์œผ๋ฉด True (๊ธฐ๋ณธ ์ฒ˜๋ฆฌ) + """ + if self.answer_key is None: + # ๋‹ต์ง€๊ฐ€ ์—†์œผ๋ฉด ๋ชจ๋“  ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ + return True + + if page_number is None: + logger.warning("ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + return False + + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ •๊ทœํ™” (๊ณต๋ฐฑ ์ œ๊ฑฐ, ๋ฌธ์ž์—ด ๋ณ€ํ™˜) + page_number_normalized = str(page_number).strip() + + is_valid = page_number_normalized in self.answer_key + + if not is_valid: + logger.warning(f"ํŽ˜์ด์ง€ {page_number}๋Š” ๋‹ต์ง€์— ์—†์Šต๋‹ˆ๋‹ค. ๊ฑด๋„ˆ๋œ๋‹ˆ๋‹ค.") + else: + logger.info(f"ํŽ˜์ด์ง€ {page_number}๋Š” ๋‹ต์ง€์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜๋ฆฌ๋ฅผ ๊ณ„์†ํ•ฉ๋‹ˆ๋‹ค.") + + return is_valid + + def calculate_iou(self, bbox1: List[float], bbox2: List[float]) -> float: + """๋‘ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค์˜ IoU(Intersection over Union) ๊ณ„์‚ฐ + + Args: + bbox1: [x1, y1, x2, y2] + bbox2: [x1, y1, x2, y2] + + Returns: + float: IoU ๊ฐ’ (0.0 ~ 1.0) + """ + x1_1, y1_1, x2_1, y2_1 = bbox1 + x1_2, y1_2, x2_2, y2_2 = bbox2 + + # ๊ฒน์น˜๋Š” ์˜์—ญ ๊ณ„์‚ฐ + x1_i = max(x1_1, x1_2) + y1_i = max(y1_1, y1_2) + x2_i = min(x2_1, x2_2) + y2_i = min(y2_1, y2_2) + + if x2_i <= x1_i or y2_i <= y1_i: + return 0.0 + + # Intersection ๋ฉด์  + intersection = (x2_i - x1_i) * (y2_i - y1_i) + + # ๊ฐ ๋ฐ•์Šค์˜ ๋ฉด์  + area1 = (x2_1 - x1_1) * (y2_1 - y1_1) + area2 = (x2_2 - x1_2) * (y2_2 - y1_2) + + # Union ๋ฉด์  + union = area1 + area2 - intersection + + if union == 0: + return 0.0 + + return intersection / union + + def expand_bbox_with_padding(self, bbox: List[float], padding: int, img_width: int, img_height: int) -> List[int]: + """๋ฐ”์šด๋”ฉ ๋ฐ•์Šค์— padding์„ ์ถ”๊ฐ€ํ•˜๋˜, ์ด๋ฏธ์ง€ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์ง€ ์•Š๋„๋ก ์ฒ˜๋ฆฌ + + Args: + bbox: [x1, y1, x2, y2] + padding: ์ถ”๊ฐ€ํ•  ์—ฌ๋ฐฑ (ํ”ฝ์…€) + img_width: ์ด๋ฏธ์ง€ ๋„ˆ๋น„ + img_height: ์ด๋ฏธ์ง€ ๋†’์ด + + Returns: + List[int]: ํ™•์žฅ๋œ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + """ + x1, y1, x2, y2 = bbox + + # Padding ์ถ”๊ฐ€ + x1_expanded = max(0, int(x1 - padding)) + y1_expanded = max(0, int(y1 - padding)) + x2_expanded = min(img_width, int(x2 + padding)) + y2_expanded = min(img_height, int(y2 + padding)) + + return [x1_expanded, y1_expanded, x2_expanded, y2_expanded] + + def is_bbox_near_section_boundary(self, bbox: List[float], section_bbox: List[float], threshold: int = 30) -> bool: + """๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ•์Šค๊ฐ€ section ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์žˆ๋Š”์ง€ ํ™•์ธ + + Args: + bbox: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + section_bbox: Section ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + threshold: ๊ฒฝ๊ณ„๋กœ ๊ฐ„์ฃผํ•  ๊ฑฐ๋ฆฌ (ํ”ฝ์…€) + + Returns: + bool: ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์žˆ์œผ๋ฉด True + """ + bx1, by1, bx2, by2 = bbox + sx1, sy1, sx2, sy2 = section_bbox + + # ์ƒํ•˜์ขŒ์šฐ ๊ฒฝ๊ณ„์™€์˜ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ + dist_top = abs(by1 - sy1) + dist_bottom = abs(by2 - sy2) + dist_left = abs(bx1 - sx1) + dist_right = abs(bx2 - sx2) + + # ํ•˜๋‚˜๋ผ๋„ threshold ์ด๋‚ด์ด๋ฉด ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜๋กœ ํŒ๋‹จ + return min(dist_top, dist_bottom, dist_left, dist_right) < threshold + + def visualize_section_detection(self, image_path: str, section_bbox: List[float], + section_idx: int, output_dir: Path, page_name: str, + detections_1104: List[Dict], section_padding: int = 50): + """Section ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐํ™”ํ•˜์—ฌ ์ €์žฅ (๋””๋ฒ„๊น…์šฉ) + โœจ section, answer_1, 1-5 ๋ชจ๋“  ๊ฒ€์ถœ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐํ™” + + Args: + image_path: ์›๋ณธ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + section_bbox: Section ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค [x1, y1, x2, y2] + section_idx: Section ์ธ๋ฑ์Šค + output_dir: ์ถœ๋ ฅ ๋””๋ ‰ํ† ๋ฆฌ + page_name: ํŽ˜์ด์ง€ ์ด๋ฆ„ + detections_1104: 1104 ๋ชจ๋ธ์˜ ๊ฒ€์ถœ ๊ฒฐ๊ณผ (answer_1, 1-5) + section_padding: Section padding ๊ฐ’ + """ + image = cv2.imread(image_path) + if image is None: + return + + h, w = image.shape[:2] + sx1, sy1, sx2, sy2 = section_bbox + + # Section ํ™•์žฅ ์˜์—ญ ๊ณ„์‚ฐ + sx1_exp = max(0, int(sx1 - section_padding)) + sy1_exp = max(0, int(sy1 - section_padding)) + sx2_exp = min(w, int(sx2 + section_padding)) + sy2_exp = min(h, int(sy2 + section_padding)) + + # Section bbox ๊ทธ๋ฆฌ๊ธฐ (์›๋ณธ - ์ดˆ๋ก์ƒ‰) + x1, y1, x2, y2 = map(int, section_bbox) + cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 3) + label = f"Section {section_idx}" + cv2.putText(image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) + + # Section ํ™•์žฅ ์˜์—ญ ๊ทธ๋ฆฌ๊ธฐ (์ ์„  - ์—ฐ๋‘์ƒ‰) + cv2.rectangle(image, (sx1_exp, sy1_exp), (sx2_exp, sy2_exp), (100, 255, 100), 2) + cv2.putText(image, f"Expanded (+{section_padding}px)", + (sx1_exp, sy1_exp - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (100, 255, 100), 2) + + # ์ƒ‰์ƒ ์ •์˜ + colors = { + 'answer_1': (255, 0, 0), # ๋นจ๊ฐ• + '1': (0, 0, 255), # ํŒŒ๋ž‘ + '2': (255, 165, 0), # ์ฃผํ™ฉ + '3': (255, 255, 0), # ๋…ธ๋ž‘ + '4': (255, 0, 255), # ์žํ™ + '5': (0, 255, 255) # ์ฒญ๋ก + } + + # Section ๋‚ด์˜ answer_1๊ณผ ์ˆซ์ž ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๊ทธ๋ฆฌ๊ธฐ + for det in detections_1104: + class_name = det['class_name'] + if class_name not in colors: + continue + + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + + # ํ™•์žฅ๋œ Section ์˜์—ญ ๋‚ด์— ์žˆ๋Š”์ง€ ํ™•์ธ + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + # ๋ฐ”์šด๋”ฉ ๋ฐ•์Šค ๊ทธ๋ฆฌ๊ธฐ + color = colors[class_name] + x1, y1, x2, y2 = map(int, det['bbox']) + cv2.rectangle(image, (x1, y1), (x2, y2), color, 2) + + # ๋ผ๋ฒจ (ํด๋ž˜์Šค๋ช… + ์‹ ๋ขฐ๋„) + conf = det['confidence'] + label = f"{class_name}: {conf:.2f}" + + # ํ…์ŠคํŠธ ๋ฐฐ๊ฒฝ + (text_w, text_h), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2) + cv2.rectangle(image, (x1, y1 - text_h - 5), (x1 + text_w, y1), color, -1) + + # ํ…์ŠคํŠธ + cv2.putText(image, label, (x1, y1 - 5), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2) + + # ๋ฒ”๋ก€ ์ถ”๊ฐ€ + legend_y = 30 + legend_x = w - 200 + cv2.rectangle(image, (legend_x - 10, 10), (w - 10, 200), (255, 255, 255), -1) + cv2.rectangle(image, (legend_x - 10, 10), (w - 10, 200), (0, 0, 0), 2) + + cv2.putText(image, "Legend:", (legend_x, legend_y), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2) + legend_y += 25 + + for class_name, color in colors.items(): + cv2.rectangle(image, (legend_x, legend_y - 10), (legend_x + 15, legend_y + 5), color, -1) + cv2.putText(image, class_name, (legend_x + 20, legend_y), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1) + legend_y += 20 + + # ์ €์žฅ + debug_dir = output_dir / page_name / "debug" + debug_dir.mkdir(parents=True, exist_ok=True) + + save_path = debug_dir / f"section_{section_idx:02d}_detection_visual.jpg" + cv2.imwrite(str(save_path), image) + logger.info(f"โœจ Section ๊ฒ€์ถœ ์‹œ๊ฐํ™” ์ €์žฅ (answer_1 + 1-5 ํฌํ•จ): {save_path}") + + def crop_page_number(self, image_path: str, detections_1004: List[Dict], output_dir: Path) -> Tuple[Optional[str], Optional[str]]: + """ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ํฌ๋กญํ•˜๊ณ  OCR๋กœ ์ธ์‹ (1004 ๋ชจ๋ธ ์‚ฌ์šฉ) + + Returns: + Tuple[Optional[str], Optional[str]]: (ํฌ๋กญ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ, ์ธ์‹๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ) + """ + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return None, None + + page_num_detections = [d for d in detections_1004 if d['class_name'] == 'page_number'] + + if not page_num_detections: + logger.warning(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ: {image_path}") + return None, None + + # ์‹ ๋ขฐ๋„ ๊ฐ€์žฅ ๋†’์€ ๊ฒƒ ์„ ํƒ + best_det = max(page_num_detections, key=lambda x: x['confidence']) + x1, y1, x2, y2 = map(int, best_det['bbox']) + + h, w = image.shape[:2] + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 <= x1 or y2 <= y1: + logger.warning(f"์ž˜๋ชป๋œ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐ•์Šค: {best_det['bbox']}") + return None, None + + # ํฌ๋กญ ๋ฐ ์ €์žฅ + cropped = image[y1:y2, x1:x2] + page_num_dir = output_dir / "page_numbers" + page_num_dir.mkdir(parents=True, exist_ok=True) + + image_name = Path(image_path).stem + save_path = page_num_dir / f"{image_name}_page_number.jpg" + cv2.imwrite(str(save_path), cropped) + + # OCR๋กœ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ธ์‹ + recognized_number = self.ocr.extract_number(str(save_path)) + + logger.info(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ crop ์™„๋ฃŒ (1004 ๋ชจ๋ธ): {save_path}") + logger.info(f"ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ OCR ๊ฒฐ๊ณผ: '{recognized_number}'") + + return str(save_path), recognized_number + + def classify_answer_with_resnet(self, answer_1_crop_path: str, section_idx: int) -> Tuple[Optional[str], float, bool]: + """ + โœจ answer_1 crop ์ด๋ฏธ์ง€๋ฅผ ResNet์œผ๋กœ ๋ถ„๋ฅ˜ + + Args: + answer_1_crop_path: answer_1 crop ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + section_idx: Section ์ธ๋ฑ์Šค + + Returns: + Tuple[Optional[str], float, bool]: (์˜ˆ์ธก ๋‹ต์•ˆ, ์‹ ๋ขฐ๋„, ์‹คํŒจ ์—ฌ๋ถ€) + """ + if self.resnet_classifier is None: + logger.warning(f"Section {section_idx}: ResNet ๋ชจ๋ธ์ด ์—†์–ด ๋ถ„๋ฅ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + return None, 0.0, True + + if not os.path.exists(answer_1_crop_path): + logger.error(f"Section {section_idx}: answer_1 ์ด๋ฏธ์ง€๊ฐ€ ์—†์–ด ResNet์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {answer_1_crop_path}") + return None, 0.0, True + + logger.info(f"Section {section_idx}: โœจ ResNet ๋ถ„๋ฅ˜ ์‹œ๋„ ์ค‘...") + + try: + answer, confidence = self.resnet_classifier.predict(answer_1_crop_path) + + if answer is None: + logger.warning(f"Section {section_idx}: ResNet ์˜ˆ์ธก ์‹คํŒจ") + return None, 0.0, True + + logger.info(f"Section {section_idx}: โœ… ResNet ์˜ˆ์ธก ์„ฑ๊ณต - ๋‹ต์•ˆ={answer}, ์‹ ๋ขฐ๋„={confidence:.4f}") + return answer, confidence, False + + except Exception as e: + logger.error(f"Section {section_idx}: ResNet ์˜ˆ์ธก ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ: {e}") + return None, 0.0, True + + def process_single_section(self, original_image_path: str, section_idx: int, + page_name: str, output_dir: Path, + section_bbox: List[float], detections_1004: List[Dict], + detections_1104: List[Dict]) -> Dict: + """์„น์…˜ ๋‚ด์˜ ๋ฌธ์ œ๋ฒˆํ˜ธ์™€ ์ •๋‹ต์„ ์ถ”๋ก  + โœจ ์ƒˆ๋กœ์šด ๋ฐฉ์‹: answer_1 crop ํ›„ ResNet ๋ถ„๋ฅ˜ + + Returns: + Dict: {'section_idx', 'problem_number_ocr', 'answer_number', 'section_crop_path', 'problem_crop_path', + 'answer_1_crop_path', 'crop_success', 'crop_failure_reason', 'used_resnet', 'resnet_confidence', 'resnet_failed'} + """ + sx1, sy1, sx2, sy2 = section_bbox + image = cv2.imread(original_image_path) + h, w = image.shape[:2] + + # Section bbox ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if sx2 <= sx1 or sy2 <= sy1: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ์ž˜๋ชป๋œ bbox [{sx1:.1f}, {sy1:.1f}, {sx2:.1f}, {sy2:.1f}]") + logger.error(f" bbox ๋„ˆ๋น„: {sx2 - sx1:.1f}, ๋†’์ด: {sy2 - sy1:.1f}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'invalid_bbox', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False, + 'debug_info': { + 'original_bbox': section_bbox, + 'bbox_width': sx2 - sx1, + 'bbox_height': sy2 - sy1, + 'image_size': (w, h) + } + } + + # Section ์ด๋ฏธ์ง€ ํฌ๋กญ ์‹œ padding ์ถ”๊ฐ€ + expanded_section_bbox = self.expand_bbox_with_padding( + [sx1, sy1, sx2, sy2], + self.section_padding, + w, h + ) + sx1_exp, sy1_exp, sx2_exp, sy2_exp = expanded_section_bbox + + # ํ™•์žฅ๋œ bbox ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if sx2_exp <= sx1_exp or sy2_exp <= sy1_exp: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ์ž˜๋ชป๋œ ํ™•์žฅ bbox [{sx1_exp}, {sy1_exp}, {sx2_exp}, {sy2_exp}]") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'invalid_expanded_bbox', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False, + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'padding': self.section_padding, + 'image_size': (w, h) + } + } + + # Crop ์‹คํ–‰ + try: + section_cropped = image[sy1_exp:sy2_exp, sx1_exp:sx2_exp] + + # Crop๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ ํ™•์ธ + crop_h, crop_w = section_cropped.shape[:2] + if crop_h == 0 or crop_w == 0: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: ํฌ๋กญ๋œ ์ด๋ฏธ์ง€ ํฌ๊ธฐ๊ฐ€ 0") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'zero_size_crop', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False, + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h) + } + } + + section_dir = output_dir / page_name / "sections" + section_dir.mkdir(parents=True, exist_ok=True) + + section_crop_path = section_dir / f"section_{section_idx:02d}.jpg" + + # ํŒŒ์ผ ์ €์žฅ + write_success = cv2.imwrite(str(section_crop_path), section_cropped) + + if not write_success or not section_crop_path.exists(): + logger.error(f"โŒ Section {section_idx} ํŒŒ์ผ ์ €์žฅ ์‹คํŒจ: {section_crop_path}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': 'file_write_failed', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False + } + + logger.info(f"โœ… Section {section_idx} ์ด๋ฏธ์ง€ ์ €์žฅ ์„ฑ๊ณต (padding {self.section_padding}px ์ถ”๊ฐ€): {section_crop_path}") + + except Exception as e: + logger.error(f"โŒ Section {section_idx} CROP ์‹คํŒจ: {e}") + return { + 'section_idx': section_idx, + 'problem_number_ocr': None, + 'answer_number': None, + 'section_crop_path': None, + 'problem_crop_path': None, + 'answer_1_crop_path': None, + 'crop_success': False, + 'crop_failure_reason': f'exception: {str(e)}', + 'used_resnet': False, + 'resnet_confidence': 0.0, + 'resnet_failed': False + } + + # 1004 ๋ชจ๋ธ์—์„œ ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ (ํ™•์žฅ๋œ ์˜์—ญ ๊ธฐ์ค€) + section_dets_1004 = [] + for det in detections_1004: + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + # ํ™•์žฅ๋œ ์˜์—ญ ๋‚ด์—์„œ ๊ฒ€์ถœ (padding ๊ณ ๋ ค) + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + if det['class_name'] == 'problem_number': + section_dets_1004.append(det) + # ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜ ์—ฌ๋ถ€ ์ฒดํฌ + if self.is_bbox_near_section_boundary(det['bbox'], [sx1, sy1, sx2, sy2]): + logger.warning(f"Section {section_idx}: ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ ๊ฒฝ๊ณ„ ๊ทผ์ฒ˜์— ์œ„์น˜ (padding์œผ๋กœ ๋ณด์ •)") + + # ๋””๋ฒ„๊น…: ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ ๊ฒฐ๊ณผ + logger.info(f"Section {section_idx}: 1004 ๋ชจ๋ธ ๋ฌธ์ œ๋ฒˆํ˜ธ ๊ฒ€์ถœ ๊ฐœ์ˆ˜ = {len(section_dets_1004)}") + if section_dets_1004: + for i, det in enumerate(section_dets_1004): + logger.info(f" ๋ฌธ์ œ๋ฒˆํ˜ธ {i+1}: confidence={det['confidence']:.3f}, bbox={det['bbox']}") + + # 1104 ๋ชจ๋ธ์—์„œ answer_1๊ณผ ์ˆซ์ž(1-5) ๊ฒ€์ถœ (ํ™•์žฅ๋œ ์˜์—ญ ๊ธฐ์ค€) + section_dets_1104 = [] + for det in detections_1104: + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + if sx1_exp <= cx <= sx2_exp and sy1_exp <= cy <= sy2_exp: + if det['class_name'] in ['answer_1', '1', '2', '3', '4', '5']: + section_dets_1104.append(det) + + # ๋””๋ฒ„๊น…: answer_1 ๊ฒ€์ถœ ๊ฒฐ๊ณผ + answer_1_dets = [d for d in section_dets_1104 if d['class_name'] == 'answer_1'] + + logger.info(f"Section {section_idx}: 1104 ๋ชจ๋ธ answer_1 ๊ฒ€์ถœ ๊ฐœ์ˆ˜ = {len(answer_1_dets)}") + if answer_1_dets: + for i, det in enumerate(answer_1_dets): + logger.info(f" answer_1 {i+1}: confidence={det['confidence']:.3f}, bbox={det['bbox']}") + + # ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ๋ฐ ์ด๋ฏธ์ง€ ์ €์žฅ (1004 ๋ชจ๋ธ ๊ฒฐ๊ณผ ์‚ฌ์šฉ) + problem_ocr = None + problem_crop_path = None + if section_dets_1004: + best_det = max(section_dets_1004, key=lambda x: x['confidence']) + x1, y1, x2, y2 = map(int, best_det['bbox']) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped = image[y1:y2, x1:x2] + + # Problem number ์ด๋ฏธ์ง€ ์ €์žฅ + problem_dir = output_dir / page_name / "problem_numbers" + problem_dir.mkdir(parents=True, exist_ok=True) + problem_crop_path = problem_dir / f"section_{section_idx:02d}_problem_number.jpg" + cv2.imwrite(str(problem_crop_path), cropped) + logger.info(f"Section {section_idx} ๋ฌธ์ œ๋ฒˆํ˜ธ ์ด๋ฏธ์ง€ ์ €์žฅ: {problem_crop_path}") + + # OCR ์ˆ˜ํ–‰ + problem_ocr = self.ocr.extract_number(str(problem_crop_path)) + logger.info(f"Section {section_idx} ๋ฌธ์ œ๋ฒˆํ˜ธ OCR ๊ฒฐ๊ณผ: '{problem_ocr}'") + else: + logger.warning(f"Section {section_idx}: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ") + + # โœจ ์ƒˆ๋กœ์šด ๋ฐฉ์‹: answer_1 crop ํ›„ ResNet ๋ถ„๋ฅ˜ + YOLO IoU ๊ฒ€์ฆ + best_answer = None + used_resnet = False + resnet_confidence = 0.0 + resnet_failed = False + answer_1_crop_path = None + yolo_iou_verification = None # YOLO IoU ๊ฒ€์ฆ ๊ฒฐ๊ณผ + + if answer_1_dets: + # answer_1์„ crop + best_det = max(answer_1_dets, key=lambda x: x['confidence']) + answer_1_bbox = best_det['bbox'] + x1, y1, x2, y2 = map(int, answer_1_bbox) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped_answer_1 = image[y1:y2, x1:x2] + + # answer_1 ์ด๋ฏธ์ง€ ์ €์žฅ + answer_dir = output_dir / page_name / "answers" + answer_dir.mkdir(parents=True, exist_ok=True) + answer_1_crop_path = answer_dir / f"section_{section_idx:02d}_answer_1.jpg" + cv2.imwrite(str(answer_1_crop_path), cropped_answer_1) + logger.info(f"Section {section_idx} answer_1 ์ด๋ฏธ์ง€ ์ €์žฅ: {answer_1_crop_path}") + + # ResNet์œผ๋กœ ๋ถ„๋ฅ˜ + answer, conf, failed = self.classify_answer_with_resnet(str(answer_1_crop_path), section_idx) + + if not failed and answer is not None: + # โœจ YOLO IoU๋กœ ๊ฒ€์ฆ + number_dets = [d for d in section_dets_1104 if d['class_name'] in ['1', '2', '3', '4', '5']] + + if number_dets: + # ๊ฐ ์ˆซ์ž์™€์˜ IoU ๊ณ„์‚ฐ + iou_results = [] + for det in number_dets: + iou = self.calculate_iou(answer_1_bbox, det['bbox']) + iou_results.append({ + 'number': det['class_name'], + 'iou': iou, + 'confidence': det['confidence'] + }) + + # IoU๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ์ˆซ์ž + best_iou_result = max(iou_results, key=lambda x: x['iou']) + yolo_best_number = best_iou_result['number'] + yolo_best_iou = best_iou_result['iou'] + + logger.info(f"Section {section_idx}: YOLO IoU ๊ฒ€์ฆ") + logger.info(f" ResNet ์˜ˆ์ธก: {answer} (์‹ ๋ขฐ๋„: {conf:.4f})") + logger.info(f" YOLO ์ตœ๊ณ  IoU: {yolo_best_number} (IoU: {yolo_best_iou:.4f})") + + # IoU ๊ฒฐ๊ณผ ์ €์žฅ + for result in sorted(iou_results, key=lambda x: x['iou'], reverse=True): + logger.info(f" - {result['number']}: IoU={result['iou']:.4f}, Conf={result['confidence']:.3f}") + + yolo_iou_verification = { + 'yolo_best': yolo_best_number, + 'yolo_iou': yolo_best_iou, + 'resnet_pred': answer, + 'resnet_conf': conf, + 'all_ious': iou_results + } + + # โœจ ๋ถˆ์ผ์น˜ ์‹œ ๊ฒฝ๊ณ  + ResNet ์‹ ๋ขฐ๋„๊ฐ€ ๋‚ฎ์œผ๋ฉด YOLO ์‚ฌ์šฉ + if answer != yolo_best_number: + logger.warning(f"โš ๏ธ Section {section_idx}: ResNet({answer}) โ‰  YOLO IoU({yolo_best_number})") + + # ResNet ์‹ ๋ขฐ๋„๊ฐ€ ๋‚ฎ๊ณ (70% ์ดํ•˜) IoU๊ฐ€ ๋†’์œผ๋ฉด(0.3 ์ด์ƒ) YOLO ๊ฒฐ๊ณผ ์‚ฌ์šฉ + if conf < 0.70 and yolo_best_iou > 0.3: + logger.warning(f" โ†’ ResNet ์‹ ๋ขฐ๋„ ๋‚ฎ์Œ({conf:.2f}), YOLO ๊ฒฐ๊ณผ({yolo_best_number}) ์‚ฌ์šฉ") + best_answer = yolo_best_number + else: + logger.info(f" โ†’ ResNet ์‹ ๋ขฐ๋„ ๋†’์Œ({conf:.2f}), ResNet ๊ฒฐ๊ณผ({answer}) ์œ ์ง€") + best_answer = answer + else: + logger.info(f"โœ… Section {section_idx}: ResNet๊ณผ YOLO IoU ์ผ์น˜ ({answer})") + best_answer = answer + else: + # ์ˆซ์ž ๊ฒ€์ถœ ์•ˆ ๋จ - ResNet๋งŒ ์‚ฌ์šฉ + logger.warning(f"Section {section_idx}: YOLO ์ˆซ์ž ๋ฏธ๊ฒ€์ถœ, ResNet๋งŒ ์‚ฌ์šฉ") + best_answer = answer + + resnet_confidence = conf + used_resnet = True + resnet_failed = False + logger.info(f"Section {section_idx}: โœ… ์ตœ์ข… ๋‹ต์•ˆ={best_answer}") + else: + resnet_failed = True + used_resnet = True + logger.warning(f"Section {section_idx}: โŒ ResNet ๋ถ„๋ฅ˜ ์‹คํŒจ") + else: + logger.warning(f"Section {section_idx}: answer_1 bbox๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Œ") + resnet_failed = True + else: + logger.warning(f"Section {section_idx}: answer_1์ด ๊ฒ€์ถœ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.") + resnet_failed = True + + # Section ๊ฒ€์ถœ ์‹œ๊ฐํ™” ์ €์žฅ (โœจ ๋ชจ๋“  ๊ฒ€์ถœ ์ •๋ณด ํฌํ•จ) + self.visualize_section_detection(original_image_path, section_bbox, section_idx, + output_dir, page_name, section_dets_1104, self.section_padding) + + return { + 'section_idx': section_idx, + 'problem_number_ocr': problem_ocr, + 'answer_number': best_answer, + 'section_crop_path': str(section_crop_path), + 'problem_crop_path': str(problem_crop_path) if problem_crop_path else None, + 'answer_1_crop_path': str(answer_1_crop_path) if answer_1_crop_path else None, + 'crop_success': True, + 'is_boundary_issue': len(section_dets_1004) > 0 and any( + self.is_bbox_near_section_boundary(d['bbox'], [sx1, sy1, sx2, sy2]) + for d in section_dets_1004 + ), + 'used_resnet': used_resnet, + 'resnet_confidence': resnet_confidence, + 'resnet_failed': resnet_failed, + 'yolo_iou_verification': yolo_iou_verification, # โœจ YOLO ๊ฒ€์ฆ ์ •๋ณด + 'debug_info': { + 'original_bbox': section_bbox, + 'expanded_bbox': expanded_section_bbox, + 'crop_size': (crop_w, crop_h), + 'image_size': (w, h), + 'answer_1_count': len(answer_1_dets) + } + } + + def filter_duplicate_sections(self, image_path: str, section_detections: List[Dict], + detections_1004: List[Dict]) -> List[Dict]: + """ + ์ค‘๋ณต๋œ section์„ ํ•„ํ„ฐ๋ง (๊ฐ™์€ problem_number๋ฅผ ๊ฐ€์ง„ section ์ค‘ ๋” ํฐ ๊ฒƒ ์„ ํƒ) + + Args: + image_path: ์›๋ณธ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + section_detections: section ๊ฒ€์ถœ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ + detections_1004: 1004 ๋ชจ๋ธ์˜ ์ „์ฒด ๊ฒ€์ถœ ๊ฒฐ๊ณผ + + Returns: + ํ•„ํ„ฐ๋ง๋œ section ๋ฆฌ์ŠคํŠธ + """ + if len(section_detections) <= 1: + return section_detections + + image = cv2.imread(image_path) + if image is None: + logger.error(f"์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: {image_path}") + return section_detections + + h, w = image.shape[:2] + + # ๊ฐ section์— ๋Œ€ํ•ด problem_number ์ฐพ๊ธฐ + section_with_problem = [] + + for idx, section in enumerate(section_detections): + sx1, sy1, sx2, sy2 = section['bbox'] + section_area = (sx2 - sx1) * (sy2 - sy1) + + # ํ•ด๋‹น section ๋‚ด์˜ problem_number ์ฐพ๊ธฐ + problem_numbers = [] + for det in detections_1004: + if det['class_name'] != 'problem_number': + continue + + dx1, dy1, dx2, dy2 = det['bbox'] + cx, cy = (dx1 + dx2) / 2, (dy1 + dy2) / 2 + + # Section ์˜์—ญ ๋‚ด์— ์žˆ๋Š”์ง€ ํ™•์ธ + if sx1 <= cx <= sx2 and sy1 <= cy <= sy2: + problem_numbers.append(det) + + # ๊ฐ€์žฅ ์‹ ๋ขฐ๋„ ๋†’์€ problem_number ์‚ฌ์šฉ + if problem_numbers: + best_problem = max(problem_numbers, key=lambda x: x['confidence']) + + # OCR๋กœ ๋ฌธ์ œ๋ฒˆํ˜ธ ์ธ์‹ (์ž„์‹œ) + x1, y1, x2, y2 = map(int, best_problem['bbox']) + x1, y1 = max(0, x1), max(0, y1) + x2, y2 = min(w, x2), min(h, y2) + + if x2 > x1 and y2 > y1: + cropped = image[y1:y2, x1:x2] + # OCR ๋ชจ๋ธ์ด numpy array๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธ + try: + problem_ocr = self.ocr.extract_number(cropped) + except: + # ์ž„์‹œ ํŒŒ์ผ๋กœ ์ €์žฅ ํ›„ OCR + import tempfile + with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmp: + cv2.imwrite(tmp.name, cropped) + problem_ocr = self.ocr.extract_number(tmp.name) + os.unlink(tmp.name) + else: + problem_ocr = None + else: + problem_ocr = None + + section_with_problem.append({ + 'section': section, + 'original_index': idx, + 'problem_number_ocr': problem_ocr, + 'section_area': section_area, + 'bbox': section['bbox'] + }) + + # problem_number๋ณ„๋กœ ๊ทธ๋ฃนํ™” + problem_groups = {} + no_problem_sections = [] + + for item in section_with_problem: + problem_num = item['problem_number_ocr'] + + if problem_num is None or problem_num == '': + # ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ ์—†๋Š” section์€ ๋ณ„๋„ ์ฒ˜๋ฆฌ + no_problem_sections.append(item) + else: + if problem_num not in problem_groups: + problem_groups[problem_num] = [] + problem_groups[problem_num].append(item) + + # ์ค‘๋ณต ์ œ๊ฑฐ: ๊ฐ ๊ทธ๋ฃน์—์„œ ๊ฐ€์žฅ ํฐ section ์„ ํƒ + filtered_sections = [] + removed_count = 0 + + for problem_num, items in problem_groups.items(): + if len(items) > 1: + # ๋ฉด์ ์ด ๊ฐ€์žฅ ํฐ section ์„ ํƒ + largest = max(items, key=lambda x: x['section_area']) + filtered_sections.append(largest['section']) + + removed_count += len(items) - 1 + + logger.warning(f"โš ๏ธ ๋ฌธ์ œ๋ฒˆํ˜ธ '{problem_num}': {len(items)}๊ฐœ section ๊ฒ€์ถœ๋จ") + logger.warning(f" ๊ฐ€์žฅ ํฐ section ์„ ํƒ (๋ฉด์ : {largest['section_area']:.1f})") + + # ์ œ๊ฑฐ๋œ section๋“ค ๋กœ๊ทธ + for item in items: + if item != largest: + logger.warning(f" - ์ œ๊ฑฐ: Section index {item['original_index']}, " + f"๋ฉด์ ={item['section_area']:.1f}, bbox={item['bbox']}") + else: + filtered_sections.append(items[0]['section']) + + # ๋ฌธ์ œ๋ฒˆํ˜ธ๊ฐ€ ์—†๋Š” section๋“ค ์ถ”๊ฐ€ + for item in no_problem_sections: + filtered_sections.append(item['section']) + logger.warning(f"โš ๏ธ Section index {item['original_index']}: ๋ฌธ์ œ๋ฒˆํ˜ธ ๋ฏธ๊ฒ€์ถœ (ํฌํ•จ)") + + if removed_count > 0: + logger.info(f"โœ‚๏ธ ์ค‘๋ณต ํ•„ํ„ฐ๋ง: {removed_count}๊ฐœ section ์ œ๊ฑฐ๋จ") + logger.info(f" ํ•„ํ„ฐ๋ง ์ „: {len(section_detections)}๊ฐœ โ†’ ํ•„ํ„ฐ๋ง ํ›„: {len(filtered_sections)}๊ฐœ") + + # y ์ขŒํ‘œ ๊ธฐ์ค€์œผ๋กœ ์žฌ์ •๋ ฌ + filtered_sections = sorted(filtered_sections, key=lambda x: x['bbox'][1]) + + return filtered_sections + + def process_page(self, image_path: str, output_dir: Path) -> Optional[Dict]: + """ํŽ˜์ด์ง€ ์ฒ˜๋ฆฌ: 1104 ๋ชจ๋ธ๋กœ answer_1 ๊ฒ€์ถœ, ResNet์œผ๋กœ ๋ถ„๋ฅ˜ + + Returns: + Optional[Dict]: ํŽ˜์ด์ง€๊ฐ€ ๋‹ต์ง€์— ์žˆ์œผ๋ฉด ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜, ์—†์œผ๋ฉด None + """ + start_time = time.time() + + # 1004 ๋ชจ๋ธ: ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ๊ฒ€์ถœ + logger.info("1004 ๋ชจ๋ธ ์‹คํ–‰ ์ค‘ (ํŽ˜์ด์ง€๋ฒˆํ˜ธ, ๋ฌธ์ œ๋ฒˆํ˜ธ, section ๊ฒ€์ถœ)...") + result_1004 = self.router_1004.route_infer_single_image(image_path) + detections_1004 = result_1004['detections'] + + # Section ๊ฒ€์ถœ ํ†ต๊ณ„ + section_detections = [d for d in detections_1004 if d['class_name'] == 'section'] + logger.info(f"1004 ๋ชจ๋ธ Section ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {len(section_detections)}") + + if not section_detections: + logger.error(f"โŒ Section์ด ํ•˜๋‚˜๋„ ๊ฒ€์ถœ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค!") + logger.error(f" 1004 ๋ชจ๋ธ ์ „์ฒด ๊ฒ€์ถœ ๊ฐœ์ˆ˜: {len(detections_1004)}") + logger.error(f" ๊ฒ€์ถœ๋œ ํด๋ž˜์Šค: {set(d['class_name'] for d in detections_1004)}") + + # ๊ฒ€์ถœ๋œ ํด๋ž˜์Šค๋ณ„ ๊ฐœ์ˆ˜ ์ถœ๋ ฅ + class_counts = {} + for det in detections_1004: + class_name = det['class_name'] + class_counts[class_name] = class_counts.get(class_name, 0) + 1 + + logger.error(f" ํด๋ž˜์Šค๋ณ„ ๊ฒ€์ถœ ๊ฐœ์ˆ˜:") + for class_name, count in sorted(class_counts.items()): + logger.error(f" - {class_name}: {count}๊ฐœ") + else: + for i, det in enumerate(section_detections): + bbox = det['bbox'] + conf = det['confidence'] + logger.info(f" Section {i}: confidence={conf:.3f}, bbox=[{bbox[0]:.1f}, {bbox[1]:.1f}, {bbox[2]:.1f}, {bbox[3]:.1f}]") + + page_name = Path(image_path).stem + page_output_dir = output_dir / page_name + page_output_dir.mkdir(parents=True, exist_ok=True) + + # ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ OCR (1004 ๋ชจ๋ธ ์‚ฌ์šฉ) + page_num_path, page_num_ocr = self.crop_page_number(image_path, detections_1004, page_output_dir) + + # ๋‹ต์ง€ ํ•„ํ„ฐ๋ง: ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๊ฐ€ ๋‹ต์ง€์— ์—†์œผ๋ฉด ๊ฑด๋„ˆ๋›ฐ๊ธฐ + if not self.is_valid_page(page_num_ocr): + logger.info(f"ํŽ˜์ด์ง€ '{page_name}' (ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ: {page_num_ocr})๋Š” ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") + return None + + # 1104 ๋ชจ๋ธ: answer_1 ๊ฒ€์ถœ์šฉ + logger.info("1104 ๋ชจ๋ธ ์‹คํ–‰ ์ค‘ (answer_1 ๊ฒ€์ถœ)...") + result_1104 = self.router_1104.route_infer_single_image(image_path) + detections_1104 = result_1104['detections'] + + # Section ์˜์—ญ ๊ฒ€์ถœ (1004 ๋ชจ๋ธ ์‚ฌ์šฉ) + logger.info(f"ํŽ˜์ด์ง€ '{page_name}': {len(section_detections)}๊ฐœ Section ๊ฒ€์ถœ (ํ•„ํ„ฐ๋ง ์ „)") + + # ์ค‘๋ณต section ํ•„ํ„ฐ๋ง + section_detections = self.filter_duplicate_sections(image_path, section_detections, detections_1004) + + # ์ •๋ ฌ (y ์ขŒํ‘œ ๊ธฐ์ค€) + section_detections = sorted(section_detections, key=lambda x: x['bbox'][1]) + + logger.info(f"ํŽ˜์ด์ง€ '{page_name}': {len(section_detections)}๊ฐœ Section ์ฒ˜๋ฆฌ (ํ•„ํ„ฐ๋ง ํ›„)") + + page_result = [] + crop_failure_count = 0 + + for idx, det in enumerate(section_detections): + section_bbox = det['bbox'] + section_result = self.process_single_section( + image_path, idx, page_name, output_dir, section_bbox, + detections_1004, detections_1104 + ) + page_result.append(section_result) + + if not section_result.get('crop_success', True): + crop_failure_count += 1 + + end_time = time.time() + + # Crop ์‹คํŒจ ํ†ต๊ณ„ + if crop_failure_count > 0: + logger.warning(f"โš ๏ธ ํŽ˜์ด์ง€ '{page_name}': {crop_failure_count}๊ฐœ Section crop ์‹คํŒจ") + + return { + "image_path": image_path, + "page_name": page_name, + "page_number_ocr": page_num_ocr, + "sections": page_result, + "processing_time": end_time - start_time, + "total_sections": len(section_detections), + "crop_failure_count": crop_failure_count + } \ No newline at end of file diff --git a/ai-service/utils/__init__.py b/ai-service/utils/__init__.py new file mode 100644 index 0000000..a05a910 --- /dev/null +++ b/ai-service/utils/__init__.py @@ -0,0 +1 @@ +# ์œ ํ‹ธ๋ฆฌํ‹ฐ ํŒจํ‚ค์ง€ diff --git a/ai-service/yolov8n.pt b/ai-service/yolov8n.pt new file mode 100644 index 0000000..0db4ca4 Binary files /dev/null and b/ai-service/yolov8n.pt differ diff --git a/ai-service/yolov8s.pt b/ai-service/yolov8s.pt new file mode 100644 index 0000000..90b4a2c Binary files /dev/null and b/ai-service/yolov8s.pt differ diff --git a/bugreport-sdk_gphone64_arm64-BP41.250822.007-2025-11-12-13-15-52.zip b/bugreport-sdk_gphone64_arm64-BP41.250822.007-2025-11-12-13-15-52.zip new file mode 100644 index 0000000..38ec517 Binary files /dev/null and b/bugreport-sdk_gphone64_arm64-BP41.250822.007-2025-11-12-13-15-52.zip differ diff --git a/bugreport-sdk_gphone64_arm64-BP41.250822.007-2025-11-12-13-17-37.zip b/bugreport-sdk_gphone64_arm64-BP41.250822.007-2025-11-12-13-17-37.zip new file mode 100644 index 0000000..ce71844 Binary files /dev/null and b/bugreport-sdk_gphone64_arm64-BP41.250822.007-2025-11-12-13-17-37.zip differ diff --git a/docs/CURSOR_SETUP.md b/docs/CURSOR_SETUP.md new file mode 100644 index 0000000..0b74193 --- /dev/null +++ b/docs/CURSOR_SETUP.md @@ -0,0 +1,100 @@ +# Cursor AI ์„ค์ • ๊ฐ€์ด๋“œ + +## Figma MCP ์„œ๋ฒ„ ์„ค์ • + +Cursor AI์—์„œ Figma ๋””์ž์ธ์„ ์ฝ๊ณ  ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋„๋ก MCP(Model Context Protocol) ์„œ๋ฒ„๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. + +### 1. Figma API ํ‚ค ๋ฐœ๊ธ‰ + +1. [Figma ๊ณ„์ • ์„ค์ •](https://www.figma.com/settings)์œผ๋กœ ์ด๋™ +2. **Personal Access Tokens** ์„น์…˜ ์ฐพ๊ธฐ +3. **Generate new token** ํด๋ฆญ +4. ํ† ํฐ ์ด๋ฆ„ ์ž…๋ ฅ (์˜ˆ: "Gradi Development") +5. ์ƒ์„ฑ๋œ ํ† ํฐ ๋ณต์‚ฌ (โš ๏ธ ํ•œ ๋ฒˆ๋งŒ ํ‘œ์‹œ๋˜๋ฏ€๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€!) + +### 2. MCP ์„ค์ • ํŒŒ์ผ ์ƒ์„ฑ + +ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์—์„œ ๋‹ค์Œ ๋ช…๋ น ์‹คํ–‰: + +```bash +# .cursor ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ (์ด๋ฏธ ์žˆ์œผ๋ฉด ์ƒ๋žต) +mkdir -p .cursor + +# ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ ๋ณต์‚ฌ +cp .cursor/mcp.json.example .cursor/mcp.json +``` + +### 3. API ํ‚ค ์„ค์ • + +`.cursor/mcp.json` ํŒŒ์ผ์„ ์—ด๊ณ  `YOUR_FIGMA_API_KEY_HERE`๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์€ API ํ‚ค๋กœ ๊ต์ฒด: + +```json +{ + "mcpServers": { + "Figma": { + "command": "npx", + "args": ["-y", "figma-developer-mcp", "--stdio"], + "env": { + "FIGMA_API_KEY": "figd_YOUR_ACTUAL_API_KEY_HERE", + "FIGMA_FILE_KEY": "lzHEWBZmLDENjELGjlRkyB", + "FIGMA_NODE_ID": "2001:405" + } + } + } +} +``` + +### 4. Cursor ์žฌ์‹œ์ž‘ + +- Cursor๋ฅผ ์™„์ „ํžˆ ์ข…๋ฃŒํ•˜๊ณ  ๋‹ค์‹œ ์‹œ์ž‘ +- ๋˜๋Š” Cursor ๋ช…๋ น ํŒ”๋ ˆํŠธ(`Cmd+Shift+P` / `Ctrl+Shift+P`)์—์„œ "Reload Window" ์‹คํ–‰ + +### 5. ์„ค์ • ํ™•์ธ + +Cursor AI ์ฑ„ํŒ…์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ…Œ์ŠคํŠธ: + +``` +@https://www.figma.com/design/lzHEWBZmLDENjELGjlRkyB/Gradi?node-id=2001-405 +์ด ๋””์ž์ธ์„ ํ™•์ธํ•ด์ค˜ +``` + +## ์ฃผ์˜์‚ฌํ•ญ + +โš ๏ธ **๋ณด์•ˆ ์ค‘์š”!** + +- `.cursor/mcp.json` ํŒŒ์ผ์€ ๊ฐœ์ธ API ํ‚ค๋ฅผ ํฌํ•จํ•˜๋ฏ€๋กœ **์ ˆ๋Œ€ Git์— ์ปค๋ฐ‹ํ•˜์ง€ ๋งˆ์„ธ์š”** +- `.cursor/` ๋””๋ ‰ํ† ๋ฆฌ๋Š” ์ด๋ฏธ `.gitignore`์— ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค +- API ํ‚ค๋Š” ํŒ€์›๋“ค๊ณผ ์ง์ ‘ ๊ณต์œ ํ•˜์ง€ ๋ง๊ณ , ๊ฐ์ž ๋ฐœ๊ธ‰๋ฐ›์•„ ์‚ฌ์šฉํ•˜์„ธ์š” +- API ํ‚ค๊ฐ€ ๋…ธ์ถœ๋œ ๊ฒฝ์šฐ ์ฆ‰์‹œ Figma ์„ค์ •์—์„œ ํ•ด๋‹น ํ† ํฐ์„ ์‚ญ์ œํ•˜๊ณ  ์ƒˆ๋กœ ๋ฐœ๊ธ‰๋ฐ›์œผ์„ธ์š” + +## ํ”„๋กœ์ ํŠธ ์ •๋ณด + +- **Figma ํŒŒ์ผ**: [Gradi Design](https://www.figma.com/design/lzHEWBZmLDENjELGjlRkyB/Gradi) +- **File Key**: `lzHEWBZmLDENjELGjlRkyB` +- **Node ID**: `2001:405` (๊ธฐ๋ณธ๊ฐ’) + +## ๋ฌธ์ œ ํ•ด๊ฒฐ + +### MCP ์„œ๋ฒ„๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ + +1. Node.js๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ (`node --version`) +2. `npx` ๋ช…๋ น์–ด๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธ +3. Cursor๋ฅผ ์™„์ „ํžˆ ์žฌ์‹œ์ž‘ +4. API ํ‚ค๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธ + +### "Invalid API key" ์˜ค๋ฅ˜ + +- Figma์—์„œ API ํ‚ค๋ฅผ ์ƒˆ๋กœ ๋ฐœ๊ธ‰๋ฐ›๊ณ  ๊ต์ฒด +- API ํ‚ค ์•ž์— `figd_` ์ ‘๋‘์‚ฌ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ + +### ๊ถŒํ•œ ์˜ค๋ฅ˜ + +- Figma ํŒŒ์ผ์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธ +- ํŒ€ ๊ด€๋ฆฌ์ž์—๊ฒŒ ํŒŒ์ผ ์ ‘๊ทผ ๊ถŒํ•œ ์š”์ฒญ + +## ์ฐธ๊ณ  ์ž๋ฃŒ + +- [Figma Developer API Documentation](https://www.figma.com/developers/api) +- [MCP Protocol Specification](https://modelcontextprotocol.io/) + + diff --git a/frontend/.dart_tool/dartpad/web_plugin_registrant.dart b/frontend/.dart_tool/dartpad/web_plugin_registrant.dart new file mode 100644 index 0000000..fd546bf --- /dev/null +++ b/frontend/.dart_tool/dartpad/web_plugin_registrant.dart @@ -0,0 +1,8 @@ +// Flutter web plugin registrant file. +// +// Generated file. Do not edit. +// + +// ignore_for_file: type=lint + +void registerPlugins() {} diff --git a/frontend/.dart_tool/extension_discovery/README.md b/frontend/.dart_tool/extension_discovery/README.md new file mode 100644 index 0000000..9dc6757 --- /dev/null +++ b/frontend/.dart_tool/extension_discovery/README.md @@ -0,0 +1,31 @@ +Extension Discovery Cache +========================= + +This folder is used by `package:extension_discovery` to cache lists of +packages that contains extensions for other packages. + +DO NOT USE THIS FOLDER +---------------------- + + * Do not read (or rely) the contents of this folder. + * Do write to this folder. + +If you're interested in the lists of extensions stored in this folder use the +API offered by package `extension_discovery` to get this information. + +If this package doesn't work for your use-case, then don't try to read the +contents of this folder. It may change, and will not remain stable. + +Use package `extension_discovery` +--------------------------------- + +If you want to access information from this folder. + +Feel free to delete this folder +------------------------------- + +Files in this folder act as a cache, and the cache is discarded if the files +are older than the modification time of `.dart_tool/package_config.json`. + +Hence, it should never be necessary to clear this cache manually, if you find a +need to do please file a bug. diff --git a/frontend/.dart_tool/extension_discovery/vs_code.json b/frontend/.dart_tool/extension_discovery/vs_code.json new file mode 100644 index 0000000..807169b --- /dev/null +++ b/frontend/.dart_tool/extension_discovery/vs_code.json @@ -0,0 +1 @@ +{"version":2,"entries":[{"package":"gradi_frontend","rootUri":"../","packageUri":"lib/"}]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/.filecache b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/.filecache new file mode 100644 index 0000000..b6e741f --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/.filecache @@ -0,0 +1 @@ +{"version":2,"files":[{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/typography.dart","hash":"d4335eeb3dd8ee5df4498661b368ebea"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart","hash":"c93eab1631a5606c8ba301346fa8e483"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart","hash":"72b6519b69dfbf0f2959b7e590bea0bf"},{"path":"/Users/downy/flutter/packages/flutter/lib/rendering.dart","hash":"4bd3950a0bf4a9f9b09f97594e363d36"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart","hash":"32a40215ba4c55ed5bb5e9795e404937"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart","hash":"648a6cdab2fd44688152ab1b016e5e9c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart","hash":"d6f045db9bd5b72180157d44fee9fbfc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart","hash":"ea5bbc17f187d311ef6dcfa764927c9d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE","hash":"d2e1c26363672670d1aa5cc58334a83b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart","hash":"54c7f23362a7e78be04b113d00022090"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart","hash":"38861aee0e2ba92ec8005a64746c0d10"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart","hash":"3d925b9cf0a12dd519256aa23a4e3512"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart","hash":"61137458bbcab0dfb643d5d50a5ae80f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart","hash":"732535ba697d95c80d1215c0879477f1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/debug.dart","hash":"17fec0de01669e6234ccb93fc1d171f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart","hash":"ed28f6ca17f72062078193cc8053f1bb"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_error_page.dart","hash":"e37c8fa15f36d437bea3fbbba34bc410"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart","hash":"954effbd324f486a6948427c605454e8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart","hash":"aed826e965e4aa2fdb3466d39e33d824"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart","hash":"4a7b03b0c037b260c1a321f7aaa8b6ff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart","hash":"7504c44d1fa6150901dd65ec78877be0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart","hash":"608be960e670661114e97b498d6a6473"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_verification_page.dart","hash":"7c5b83f5ae6c761626702706494109b7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart","hash":"9b61320422b3f577a77f50badebd040f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart","hash":"d69cd05d9de1731242d357de56893a6f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart","hash":"4133ed8c1bb408e9cad637892e49a8fb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart","hash":"38c93c95cb266619fd6cf7de928884db"},{"path":"/Users/downy/flutter/packages/flutter/lib/foundation.dart","hash":"84939e70d6b7b36e8098dd0cda8cbb2a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart","hash":"eca4f0ff81b2d3a801b6c61d80bc211c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart","hash":"5ee4b9f196c81041c45d27e3b2d33d88"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart","hash":"ce4bfd9659d667457cc3ada513fae71e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart","hash":"008b3ea4691331636bbea9e057357ceb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart","hash":"ef1ff22066328de1e83b8180592a470f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart","hash":"d98495bcbc301290a10e6d1dfc255d69"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart","hash":"fb2be6f27b32bb1ab12dd6aea8c5ecda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart","hash":"c02d47d7f7e95654d3eb9b795e416dda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart","hash":"f5e7b04452b0066dff82aec6597afdc5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart","hash":"92901585628d81f7bb3d578fd6d6657d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart","hash":"83bb40406ac73bcd194c621137ed0349"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart","hash":"f45f530a8be1596d7ffd25719c66c87e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart","hash":"6cf1ca324535366e2ea214049ffc9918"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart","hash":"3d892f04e5e34b591f8afa5dcbcee96d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart","hash":"f7bbc690baa3db88e9a15522b9c2f139"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart","hash":"62e0b7dc1550fd71644c5cc94797eee1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart","hash":"056355e344c26558a3591f2f8574e4e5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart","hash":"0938e0447f447ceb7d16477a0213ce2c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/login_page.dart","hash":"ecd32349ac1bf2f81631ac9c22fa9f68"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart","hash":"094b2c03ad4e0ef5bc1144e281142b2e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart","hash":"7692ca5e3a50523edceb59e80a6205a1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart","hash":"1dab3723527db6a19410ed34b6acaeed"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart","hash":"c56930c2b2b0e2c0c606af3f7686ebf2"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart","hash":"03849876382098601edd9248d621b1f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart","hash":"ebafc07567edebe5e176f39360b09f52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart","hash":"481e435dd11c202a9d2293db5b58b179"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart","hash":"fb76e9ed5173ac1ae6a6f43288581808"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart","hash":"63ea4f418d2305e0cf2c18a773821f9b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart","hash":"1b20a6e406ca8e79675b2ebd9b362d10"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart","hash":"e88b0574946e5926fde7dd4de1ef3b0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart","hash":"52f779d8f66642da5db6810754b0ba5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart","hash":"eaef2926557480e27a3ce92f89de68b7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart","hash":"a47062dc6143c80c485bcfc7a06b9490"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart","hash":"bdc22e9e77382045196b5aafd42b5e55"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart","hash":"0ee043f9e3f8fc817bc6bb354731879d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart","hash":"dbb0bb20c79bcea9397c34e3620c56c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart","hash":"e05529d31a09e4c86cde70483824fa10"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart","hash":"c8564aa311746f4047cd02e26ff4df75"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart","hash":"b5b9320ef8cd47d81a68063558c1ed4d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart","hash":"d891dabfc112fbaa77f11a249d547179"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart","hash":"7ffb6e525c28a185f737e3e6f198f694"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart","hash":"21496c39aba7bb1435e82558fc3dc9f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart","hash":"727e4f662a828d4611c731f330a3d79a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart","hash":"efad3646c2aadca0c462ae31919205ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart","hash":"c8a14f8ecb364849dcdd8c67e1299fb3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart","hash":"290ff7e27e670467d4f520e320ed9660"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart","hash":"efbedb75be354b65520bce3f0855b8db"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart","hash":"24cd1bed27dc8cfdc2d00045c1b85b53"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart","hash":"82c3c4fb48c5ca81b7002e6d539e915f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/motion.dart","hash":"505f6c9750f9390c9e9e4d881092cef4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart","hash":"ecc072620f2a72e685360292690c8a68"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart","hash":"f250acad4dd6cca43362a7d548a97aa5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart","hash":"4b50828d394e7fe1a1198468175270d9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart","hash":"280be2dbc10de2dd1913281d29e1b29f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart","hash":"7821d01f98c559fcbec46a41b4df7ebf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart","hash":"af4bf4aa827f5ac651aed6fb7b9a038e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart","hash":"1506ba940aec506086f3093420336467"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart","hash":"fc5d931b0e52f2fbd5ba118ca7f34467"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart","hash":"ca2e098cce59851623bf60c022a3bad1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE","hash":"5bd4f0c87c75d94b51576389aeaef297"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart","hash":"b815d11a718e0a4d6dec5341e2af4c02"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart","hash":"21494fec4563fdcefa3d28fad8ffd12b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart","hash":"46826fe180ac83f5855d6126ad250b81"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart","hash":"e4eb87da41119742a2dcbcdbc39c7a96"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart","hash":"bd3f0349089d88d3cd79ffed23e9163b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart","hash":"c7627484ec7f4005dae2321f6de6768e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart","hash":"94235ba74c3f3ad26e22c4b40538ce07"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart","hash":"c4b5de17270534014eb846299d500eb5"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/fonts/MaterialIcons-Regular.otf","hash":"e7069dfd19b331be16bed984668fe080"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart","hash":"61d3c1705094ee0ea6c465e47b457198"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart","hash":"ae53c1bc8f95419bee08ba4fde0e173e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart","hash":"1357b049a06aa8a7413982e814b87ab5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart","hash":"c5e44030289c2c25b26c5b3aa843b3cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart","hash":"985cf5499dc6e521191985f55245a22c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart","hash":"4b495ff6681b3a7dda3f098bf9ecc77d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart","hash":"5486e2ea9b0b005e5d5295e6c41ad3c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart","hash":"05ab01a88b45fe10a762dc3068e7e1dd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart","hash":"90a1a95cfd75677cfe6295f0bad3a3e9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart","hash":"b3eacd047eaec8b4b214d8d35f471f06"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build_result.json","hash":"1f8e8e6dbc6166b50ef81df96e58f812"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/FontManifest.json","hash":"dc3d03800ccca4601324923c0b1d6d57"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart","hash":"0c520a6b1ab38e0f294c3ddbc2ec9737"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart","hash":"77d5759abfee21d18803f19b603da875"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart","hash":"123520ee3a48eebf4ba444e93436bb1a"},{"path":"/Users/downy/flutter/packages/flutter/LICENSE","hash":"1d84cf16c48e571923f837136633a265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart","hash":"90f70ffdd26c85d735fbedd47d5ad80b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data","hash":"c8760dd22936a794d8412e15baab1397"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart","hash":"7c8b701267e773fa9293eb10736e0ca7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart","hash":"a004396fa64ff2163b438ad88d1003f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart","hash":"62cbf59e5c816c224ef5eaf803fc877b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart","hash":"2aacf74fb08ed144ee859c99233588ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart","hash":"11b4d96c7383b017773d65cb2843d887"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart","hash":"fa8eb6909c6c4c0ced2ac0ec5a69f640"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart","hash":"b6bcae6974bafba60ad95f20c12c72b9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE","hash":"4cb782b79f6fc5792728e331e81a3558"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart","hash":"be66f00d2c9bb816f4236dd0f92bff55"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart","hash":"964f3ee4853c34a4695db0c7e063eaa3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE","hash":"901fb8012bd0bea60fea67092c26b918"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart","hash":"0b3ae865c8e82bcd0c94aa60cdd8237f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart","hash":"5a41dbb4425fcc9ce228f1db68360c1e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart","hash":"c517fb54b3d66b22988ad7c8d07c6f53"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart","hash":"db4d348cc51cfecc2c86a34122b48806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart","hash":"83df4f6e4084a06a4f98c27a524cc505"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart","hash":"edbd68eb36df4f06299204439c771edd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/arc.dart","hash":"511ff5c6f0e454b22943906697db172f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart","hash":"eca5aa939aa9722ead4b6c347fb4d11a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart","hash":"1303bc77ad63625069f2d23afc73f523"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart","hash":"2b76d589cc052dc9ef928ddba5382a4b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart","hash":"6326660aedecbaed7a342070ba74de13"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart","hash":"cdb411d670a094822c46ead81fc1c4f7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart","hash":"c9111e47389ee4b70aab720435a2a2df"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","hash":"6ba0fd71cc6cd9c1581ddcd360fec1ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/gestures.dart","hash":"ac772288a52f82606f20d68636327e34"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart","hash":"6297da5be01fb7c0d5c4aaffe7a27a50"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart","hash":"7bd8137185bc07516a1869d2065efe0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart","hash":"028eb8497ffa66b6d051c09361dc19f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart","hash":"89b2eba11b385c32cad8745bfba9798b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart","hash":"e6069a6342a49cdb410fbccfbe4e8557"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icons.dart","hash":"32b222420709e8e40d12f6ea9fc0041e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart","hash":"ec48414c6983150c30241ba7128634fa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart","hash":"530c4f96f1475cc4e4128ffedd705028"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart","hash":"0ff55be19444856c892e701c475b20f6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart","hash":"9f069b0f65439fc693626369d779c95e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart","hash":"57d74766f36a3d72789bc7466ae44dba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart","hash":"dd109d67b92b9fbe6e0051f0c890c903"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE","hash":"175792518e4ac015ab6696d16c4f607e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart","hash":"2936a409e1029ec52f7c0003f4db18c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart","hash":"eb115c2e8f0ff170bf26a44efd1b5c05"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart","hash":"ac172606bd706d958c4fe83218c60125"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE","hash":"83228a1ae32476770262d4ff2ac6f984"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart","hash":"7da554c3a69a1c2d019202e3f63331c5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart","hash":"e7b2de136a99cf5253477d4fb4138394"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart","hash":"d3ac4a3d093bab7e3c97e51db9e4218f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart","hash":"73089c9737db54a05691e09bc9fc1bcd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart","hash":"74c42b320d58fca1c02c22c577c5fdf7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart","hash":"c39101179f8bdf0b2116c1f40a3acc25"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart","hash":"b45f6f4ad67efa5c374cabc278ede26a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart","hash":"ddf1bde8f4b9706d5769690b7819e5d4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/banner.dart","hash":"576f65e88d664b3c39aa0e07825b29a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart","hash":"0b630cc8a66d79c161a58858593ae1ae"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart","hash":"8830333c78de58ad9df05d396b651ef7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart","hash":"6c54f90e0db5f42a13be6b3efeb4a04d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart","hash":"ae36c7cc9b21f98bedf401f2d67a0fd4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart","hash":"ae42d99121b00899d038edc753e0b23c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart","hash":"68c724edcc385ae2764308632abb76b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart","hash":"3ce88fe27ca35ed2f5b7a333d43676e1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart","hash":"37f181e3096dc69dc408bf7d07fcd39a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart","hash":"a6d730f196620dffe89ac987b96ef6c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart","hash":"3188cef277d7af7b79cfeb3286289551"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart","hash":"7088cc45b21c93be6b42dc748fc3a29a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart","hash":"0cf5ebf6593fabf6bb7dfb9d82db735b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart","hash":"153fd637fe660527ff42e1be068d99ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart","hash":"a29f0df228136549b7364fcae4093031"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart","hash":"b7525dbbd1c51211c6edc9ea544a62e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart","hash":"3fce8e0c4d9b3cb4e3dbc168f41a132e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart","hash":"e6852aa16faf9c357899f250d80a91a9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart","hash":"b9c13cdd078c3b28c3392f0d6d5d647b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart","hash":"998487b87817cbb87019455d4abfaed8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart","hash":"57f09243c4e3f4099a10951225c6d1ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart","hash":"2f426329cad3640d8a125303c3509018"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart","hash":"e3d917994e875601c2dadaf62de546f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart","hash":"9bc30281f42d8003b7f9d636ebc8bfc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart","hash":"3e0eaeb97804d1bc93e6c6088aa351b7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart","hash":"99b4d15f76889687c07a41b43911cc39"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart","hash":"700328ab0177ddfd9a003a8c15619c1a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart","hash":"204fb623e2b782051e9bcb6e320e97c0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart","hash":"0c9bd1af5747fd55e7488c731ad32dee"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/App.framework/App","hash":"4ddef20d7f3b2634c55e3f2903db42b7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart","hash":"d44c6aa2c95d66ec45eeb0bd0df79cee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart","hash":"2150550461fec00b57e9b9110f8fde94"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart","hash":"00ec0dfac52c24607bbdffd84060d019"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart","hash":"34c5e6ba4664d331c977bdc010aad709"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search.dart","hash":"3798784648f57e129514c1cb6f534612"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","hash":"b93248a553f9e8bc17f1065929d5934b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart","hash":"e324dd19cc02a1bf47bf7cc545dcca79"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart","hash":"40dec7d9dd1c5150bf10ef4b46cc36c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart","hash":"7146d1c18ac515c3fd3465cd4a7f7a34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart","hash":"82604e7dbb83dc8f66f5ec9d0962378b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart","hash":"734e496890e84ac4195229409538f700"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart","hash":"0bc80db5885f9d8ecc0f80ddab6fe8b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart","hash":"98772211ffa69a8340f8088cd7193398"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart","hash":"1afc30ded179cb07f059c7b3a5dee3fc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart","hash":"940daf4491e3ab2e15d7eac5d6ce6b23"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart","hash":"30c8c6264748aba97477a1c81c8fb9d1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart","hash":"0d86d4ba2e01e5e62f80fcf3e872f561"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart","hash":"b5bd9d15c10929b4a63ea0df649e2d52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app.dart","hash":"5b539c57fb0cbea66a99efbc8239e590"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart","hash":"4a4b67b573e2338cf03cb704b2c18f04"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart","hash":"c7fe678fd3ad24ff5928e24dff4367b5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart","hash":"fb23ec509c4792802accd10fa7c8a6b0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart","hash":"853b1406f2756bef671f6d57135606f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart","hash":"a6ce313fc162c7c4402e1979454559a8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart","hash":"21a43efc5058f6132660bba47766b26b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart","hash":"5c3b7996bd913451665c9b1634098d83"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart","hash":"8b525140e1bf7268e1681a62c7640eea"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date.dart","hash":"f36568b4288388242cb6f7775cb60c42"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart","hash":"7514fc34af698a2ef36a68486f7340d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart","hash":"3e8df17480fcb123b3cdc775ca88dd89"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart","hash":"58b9bc8a40fd3e2f7d9d380d0c2d420f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart","hash":"b972c32590c642256132827def0b9923"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart","hash":"2cb2b1aac78bff7cc9be5f0a45aaa94b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart","hash":"e14417c43b6cb787f11bebd1c39280cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/card.dart","hash":"90d9d45eef80ac53b194a71da4e10975"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart","hash":"5979a1b66500c09f65550fab874ee847"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart","hash":"00c9e1f53ab22efcb34cca55fc46b4cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart","hash":"d7eb1678ec74acd9857a4193fd62ed5b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart","hash":"66df4fe41752a6a990878623e36a3ad2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart","hash":"0b55082ca3ffb2bec57cbd8c61db5977"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart","hash":"b7c2cc8260bb9ff9a961390b92e93294"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart","hash":"c06267b6c315a5e40f28feb6019de223"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart","hash":"527d9250e523e442bc07faadf2cb1741"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart","hash":"93d025adfc0409629c51036cb0fdc085"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart","hash":"2af013984ccce4c43e3024da472560d7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart","hash":"5b92fc2fdb9b39ca8d3072d08f9f2356"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart","hash":"991024814d51967a20be5851be93a8e3"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/macos.dart","hash":"70f90b6f7f94bd884b80c93370249057"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart","hash":"8bb5842ab79616954e268adb624dc6fb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart","hash":"206ef1a664f500f173416d5634d95c8b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart","hash":"9d437a8fcd0a5c0ad90aa6e31d66834c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart","hash":"945227f3863339e388d92c2b3bfbf673"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart","hash":"166147b7bee5919995e69f8ca3e69d17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart","hash":"5c3150272dcfc4b6d488ba16b0b21594"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/native_assets.json","hash":"f3a664e105b4f792c6c7fe4e4d22c398"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart","hash":"75abcdfe5d010a07b1833f1a2c48fa73"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart","hash":"07664903d8026f2514b29b786a27f318"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/constants.dart","hash":"2c6facdb1b63e687304c4b2852f6ef4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart","hash":"ea7754f2c684266799d36538300b6ffa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart","hash":"ccd754ed5584fb2b22056464dbfc9b37"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart","hash":"64c347128324802ec3aa6618f5723cc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart","hash":"7dc8dec32ceed4732299990cedf383dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart","hash":"035b8d3642fa73c21eafbee7851cc85d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart","hash":"5e054086533f32f7181757a17890ae56"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart","hash":"d2386b256656121d501a16234b008e2b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart","hash":"f20071b459b9bbb98083efedeaf02777"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart","hash":"7c12bdd660d493a20f3d692be2cafe20"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart","hash":"28464c209a2293d3d4e5549539e1a751"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart","hash":"2663ff02a467c826925672bcaf6bcf66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart","hash":"01d9ad3c8c89b65f3180229081a95952"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_reset_page.dart","hash":"41bf789782d48659f7ca6e45facda66a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart","hash":"3bc33c65fa44a57d13430fdedef82bc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart","hash":"2fbba4502156d66db0a739144ccce9a0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart","hash":"f64029b4f4dbdc0bc61a4b8787975a94"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart","hash":"c390764eafafcc20c2e51225ce144ba8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart","hash":"0b8f9e0997c003bc97a462a2c70b91ab"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart","hash":"30d771880c8dbd68ea8e5d4a55c778c5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart","hash":"89dc3f84db2cd1ea37e349fdb1de09bb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart","hash":"a2ab6e0f334e5a28af29766b82f7f4b0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart","hash":"8f77cb7be1dbf41ca0fdf069ac69a215"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart","hash":"9c169d41e4740bbc21d0ce33bc753119"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart","hash":"8e0fc402506b32a335e86f7fef97f06e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart","hash":"625e266fbab1e46e06c8d7d211a5828e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart","hash":"7abc7e5212374d29bfe5372de563f53c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart","hash":"ef951139f9f55dc5b330d20e15d4fd0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/cupertino.dart","hash":"21e240878a582ab39a490e6ac330c645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart","hash":"b0c6844b0af0cd0539060a0bfcbe3713"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart","hash":"65a04fd24f938030b7271b61a59f9a39"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart","hash":"acfc0a55deec22276e085dae6197833a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart","hash":"ab7af0d1396dfa5930adaf0357fdc1cd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart","hash":"0c9897499d9ef356aa9886423cdf96e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart","hash":"a8fdf31698b305c9fdad63aa7a990766"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_page.dart","hash":"2ce24519841df9363e89f8b6079196f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart","hash":"d195153a8c01a0392b38e3b9adc672d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart","hash":"0c32f2e835bc0f32a6b146dd73be8555"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart","hash":"7bbb6aab4e83fc272886a39c92157201"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart","hash":"d8060c05b658b8065bc0bfdff6e4f229"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart","hash":"0d9e952ceaa817539df84d30e876c4ee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart","hash":"f3747e025d835d0ff5cfd904d925dea2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart","hash":"11df661a909009a918e6eec82d13e3ff"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart","hash":"4d43f0629755f06d4df0b1a6ef75ef59"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_error_page.dart","hash":"d716566f0e4bcecfbd506ed8fbc94f0a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart","hash":"7536ace8732469863c97185648bb15a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart","hash":"be94b8f65e9d89867287dabe5ea1dff1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart","hash":"7018ea64a9aab18f27a10711285d7573"},{"path":"/Users/downy/flutter/packages/flutter/lib/physics.dart","hash":"6e29d5e69c5745a45214fe14da377c1a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart","hash":"9be021a3c68f7ef171b79893e7b4fcd0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json","hash":"df62efaa9988c4a5a579afc9bec56ad9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart","hash":"78e53d9a4963c0d19c5ea355a0946e5d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart","hash":"0949b8197a6069783a78f4bb0a373fb0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_result_page.dart","hash":"e3aa62898dde049a1dbc84bd7d3f8392"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart","hash":"7db055846295bfe7d5e376765ab0d106"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart","hash":"a1186c224201e7d203404a4270938040"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart","hash":"8e7e80b0f55481814454154289581855"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart","hash":"d35b72b249d19f54a4cd6f22ff3299e9"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart","hash":"e9b0c1f2903ca05a29681459603679c1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart","hash":"f44bbe72c4c7393277c42d5fc27b3b2b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart","hash":"5c96449c2a494ea8f3a50ecc3ba9af74"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart","hash":"fab8d6d1b0e81315a3d78131394d31e6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart","hash":"b76ebf453c4f7a78139f5c52af57fda3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart","hash":"f0d920fb2a472e43514830b20d401806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart","hash":"30ff1bba22f8f5d5442537740196fdcf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart","hash":"5893c7d3910e8924bd2dccc8837775c7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart","hash":"b092b123c7d8046443429a9cd72baa9a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart","hash":"87bcefcfff19652ad296ec7005799840"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart","hash":"a5d0509a39803ffb48cae2803cd4f4bd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart","hash":"14ee798b10cb318d96667b32b245f21f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart","hash":"0db5f597f1cc6570937e6c88511af3a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart","hash":"cd0db51c646e4809e09bdeb76ec931b7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart","hash":"790dc5e1e0b058d13efbd42a3f46498e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart","hash":"a11383c33c4fdc8d2cdc091f50d17e93"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart","hash":"6c6dfd5ba4546c1f32201555d6cff215"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.json","hash":"2efbb41d7877d10aac9d091f58ccd7b9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart","hash":"5b894ae18be3e2442a34288833184ca9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart","hash":"2ad27cdee5e6fe69626594543bd0e7c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart","hash":"04ad97adf4dc5676764aa8d7aad857f9"},{"path":"/Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf","hash":"e7069dfd19b331be16bed984668fe080"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart","hash":"e4ee21048ab83cc50d61ac3784afa9f5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart","hash":"daa0c9b859ed1959e6085188a703f387"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart","hash":"3fab1c4c90dce6d5451027be460e81fc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart","hash":"de161004250e30098d14049bdf54ce38"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart","hash":"3fd33becc9141d8a690c4205c72c5d40"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart","hash":"ed11d553b999afddfd85ca57540af7d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart","hash":"0e2afa27a9682352d434c10d20ffdc7f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart","hash":"b5d89661ccc877d87e555c5ee9e5ac81"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart","hash":"2458910beb2b4f3b177a7db027cf7d34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart","hash":"e5b4b18b359c9703926f723a1b8dd4ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart","hash":"2a374faf6587ee0a408c4097b5ed7a6e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart","hash":"61dd7991c06ba3bae351fee9a80c64e1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart","hash":"2122907e49766bb1f044ae97841c2b86"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart","hash":"44b3c2a3d6e67a3213a49cce58fed932"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart","hash":"4a73924a7083f5e9d700ada6f2b53098"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart","hash":"110b9903c2673d2ae6f626dee25c45f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart","hash":"bbc7eccdbd8472a2180e0dffce323bb9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart","hash":"b9abba31a48a9c2caee10ef52c5c1d0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/divider.dart","hash":"400da5c3ae6b8c8cf1ad20c796ce413b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart","hash":"9c23e23bd2cb8afe39b51de3545ab2ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart","hash":"98f725d06ba20a1032cb8770d00d7fca"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart","hash":"74708cb40b7b102b8e65ae54a0b644be"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart","hash":"16d2669eba65e0d92613a0aef0a169d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart","hash":"feacc941aea1ec8b3a30601915b7d353"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart","hash":"5061e0737e2db44e82d8a8c12f328a48"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart","hash":"a85856ccbb262dd4c1207418f8bc7801"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart","hash":"7711f4b6c3574cec77169f2d2c35ee3d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart","hash":"a88e90675c4b55522b3e9226f0135237"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart","hash":"02139a0e85c6b42bceaf3377d2aee3de"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart","hash":"3eb1458ae1a271dbe202030d5b8f0852"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart","hash":"e556497953d1ee6cd5d7058d92d4e052"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/page.dart","hash":"c5bf16620e9021a14d7fdd8d605e611a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart","hash":"5d30df9a71208100cd9e649ec1f21f69"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart","hash":"2346472ec1cfdb77f3b27d3b7af72d4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart","hash":"6b6d593e4facdae2c82b9133fa8e69e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart","hash":"aaace37762c25bcd679c2ab09129db12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart","hash":"597d897c972c255ade7307dfcc2e5524"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart","hash":"6566a35ff0dea9376debf257bdb08fba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart","hash":"2ca785b09f831ebde51eca8654fd23b2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart","hash":"325ce403b3634a9c45bd705d91ed31a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart","hash":"eabd3dc33b1a3a2966fa68f6efeb6bce"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart","hash":"6edb3eb5d6e5b289f28ce2fb68047e91"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE","hash":"3323850953be5c35d320c2035aad1a87"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart","hash":"ae1f6fe977a287d316ee841eadf00c2b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart","hash":"a0816d2682f6a93a6bf602f6be7cebe1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart","hash":"026b1fa8f1d7ff0d7c1a6e1afb2e75ca"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart","hash":"ac08cb84358e3b08fc1edebf575d7f19"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/Info.plist","hash":"b45cb164061cc52bb44c41072df15bce"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart","hash":"5f5c07df31f7d37780708976065ac8d3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart","hash":"b0851d75151b4ad4d87a1443d2041382"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart","hash":"be0a77cf3f0463f3dacd09ec596d9002"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart","hash":"61d7b16669f075a39023fed8967fbdb9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart","hash":"cdef014561140d05b803ce8d9d85e02e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart","hash":"41f7bdb7d1eb3c86c21489902221b859"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart","hash":"16df2ff0536b2302a883fbb0edcca164"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart","hash":"5bbe4c9f8221f331ef61519909f5cc54"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart","hash":"a6adbe3868e017441360895c35fd6aa2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart","hash":"daeb052f1089d4e84d8a22acf56c1da2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart","hash":"d2694042e337ac1f2d99602c25be195a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart","hash":"ceca25b48ef58dff53262c111c0dc9e7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart","hash":"81bf43e01741bf8b9df15ec37ffbc9ea"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart","hash":"7050c8c94b55eb51260ca54708b460fa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart","hash":"e40877daa15509fcbd3e465d246dbc09"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart","hash":"24d6b5d55c0b41213c9bb4b2342764f9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart","hash":"be096140df774ec827218c6fe69b80e5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart","hash":"210d4d542d997e93c121b4dc814b95cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE","hash":"83228a1ae32476770262d4ff2ac6f984"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart","hash":"603b7b0647b2f77517d6e5cf1d073e5a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart","hash":"9a12cf2a3549924510006db4651a1743"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart","hash":"3fa7a3bafbab98c305119475eb004a06"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart","hash":"95545fdf17c2014df41408bad8115997"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart","hash":"bbc54fca40953c4a17c12bf45c349c77"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart","hash":"105813825251a3235085757d723ae97c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart","hash":"b6a30b7ed48f83f446db37577b30e62e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart","hash":"7c2c3a23031810f7aa97f4d2f016330d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart","hash":"72aa3452833246a4d22c084e75fb93c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart","hash":"c66e615feaae8abf62893d4eaeef0ed6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart","hash":"16f71d097900371eb87d706863a8469c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart","hash":"97199777cf058b891c9752cda55662be"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart","hash":"09973ba0a94d2d819052c0544dcdce70"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart","hash":"4ba0a4163d73b3df00db62013fb0604e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart","hash":"0f2a1a61119c0bef3eaf52c47a2ebcf4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart","hash":"c0da8171c63f0ab4e822dd094fc2c595"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart","hash":"27c61344ce9c31ab29dff9add7511263"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart","hash":"d3b949a1e7578291493af5fd28846314"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart","hash":"7c07d5cc739ae29abcfbf6343ae84fdf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NOTICES.Z","hash":"862e870c60451a8a00efd52a040da3f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart","hash":"69be6215ea4781ec3da1e389b321cad4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart","hash":"18223495a47aa96889552c9834042729"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart","hash":"e6223733c9eef59b2de24c02463b272a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart","hash":"80eec0865406718828ef0dccff8154ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart","hash":"702f8b87ec7fc125312d9ff64434e7cc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE","hash":"22aea0b7487320a5aeef22c3f2dfc977"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart","hash":"1099a5c5ee8ae0d01e2dd7d07c3edf90"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart","hash":"92e6028556e74c1dc297e332b473f78e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button.dart","hash":"d7a239f8b80f844857527c2012e4fa1c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart","hash":"91e808d781743242114a756dec8f2cbf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart","hash":"8a99afa0c4ef5aabfdf6ef2a4afcc8c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart","hash":"13be7153ef162d162d922f19eb99f341"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart","hash":"3405e08e614528c3c17afc561d056964"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart","hash":"a7424dc75f961325d400c58f0e946ba2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart","hash":"d0911329ae74edbd7f6ad6a89e0703f8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart","hash":"a73883c523a61b1393b5e8c66de884c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart","hash":"6f6fb24055973d0370e30a78ca69db89"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart","hash":"2c582bec6fc77f68c975f84d2252ed8d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart","hash":"a340eddbf129cfd60e2c67db33c6003e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart","hash":"af5377d18db2f18bd4ac0ec35ed7d308"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart","hash":"06455706949396049309d1cc90b76efd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart","hash":"157d1983388ff7abc75e862b5231aa28"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart","hash":"35bf7179f32e4ab5b13e9d9ec2abbe86"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart","hash":"fa0d3415d04242864a0c411fceeaabd8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart","hash":"997f4b4e6bf9981e307f46f08fa90b82"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart","hash":"38e17b28106d00f831c56d4e78ca7421"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart","hash":"9c9f1e70fac06b3e87bb33ece047c4cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart","hash":"596fb2e55b1ff1662e4bd67461fdc89d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart","hash":"cbbb174cb00bf954fdc9e2854517dbd9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart","hash":"72804f9d34b9a247c43d6cc575527370"},{"path":"/Users/downy/flutter/packages/flutter/lib/widgets.dart","hash":"0d4b8c16e7b8e4d8baf6fca9161c7e56"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart","hash":"3ed378957409718f644078da99891428"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart","hash":"21f4467f19bac7f0fe6f0e730ab10fda"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart","hash":"205bb888a773c736206a9f2c84c8fd92"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart","hash":"9f2eb24284aeaa1bacc5629ddb55b287"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart","hash":"50062b12181ce59a75a26727cacaf5cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart","hash":"aef544fef0ced7679e0edaf5f8d036b7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart","hash":"121fcbdc1af81a0fd804490f85357fa0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/debug.dart","hash":"0575a78fbb39a292302737868752da77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart","hash":"5fe5b5ed3ec92338a01f24258b6070a3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart","hash":"3dc9f56e0fb2e949ac4c68187162c0a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart","hash":"bbc9542eb5e3c4701c24bc1268b8165c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart","hash":"1e30703fc6d5663dea611a3c783b21aa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart","hash":"aff8f09b64bc316bf514d7a58be4131f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/reset_password_page.dart","hash":"c6c25d7b97a963970c56d6c22f41c295"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart","hash":"0073f703be7f7ddbd7f04d1b740f35c6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart","hash":"62dce337eb5905e15da1113e7ba50806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart","hash":"44d59e37041b6305018f70012fef7d52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart","hash":"d1d1398bda204825136843ad63735067"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart","hash":"866257a42b6b721549b351382b365c47"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart","hash":"9f8b50d98e75350b41d40fee06a9d7ed"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart","hash":"46e577ec532e21029e9cee153d7ca434"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart","hash":"a6350a577e531a76d89b24942fca3073"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart","hash":"bca928191c274201a95a3b9474582b31"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart","hash":"2083695b7b9150b87307af446032ba45"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart","hash":"9beb119d4e1dad544bc4004db5aa3a95"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart","hash":"5843b4750179f6099d443212b76f04a2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart","hash":"c0cf85f80b79542d2b0e1a00547d7310"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart","hash":"ad4f49532706bd4252a8383731d0e349"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart","hash":"a2c7734430a38c6f25a3e99f10aa19fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart","hash":"a2eb984b374f7375264ed4b139a0eb03"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart","hash":"3623c605586d2e37af23d6b746721bd7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart","hash":"3e4d53a860279f33b4e7c6b1d9957a51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart","hash":"b0b28dbb0d6b26d142ff99ecbd5d8187"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart","hash":"135373d55120d14b786fdabe98c9c64b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart","hash":"f209fe925dbbe18566facbfe882fdcb0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart","hash":"4b5d82ddeb09bc46ae0e980616ce0109"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/theme.dart","hash":"4ccdd5e6210285f9baf09909e7d4f593"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart","hash":"a79a6f9bb06c7d6dc5fb74ac53dce31b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart","hash":"1f437276972808bf4cf722440da1b231"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart","hash":"db4a14227247e2524e46f6b0dd9da267"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/shaders/ink_sparkle.frag","hash":"6cd606d3e368485de4ee213b4887f8a0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart","hash":"b09ffd962fcbee7d3403b54155e33047"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE","hash":"3b954371d922e30c595d3f72f54bb6e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart","hash":"0ddbbba088a930cb7ae5b5920ce346cf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart","hash":"f77f6a903d346f842a7fe474e427d6a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart","hash":"ed59d68fc74e5f7be21e0d7fc1c7242a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart","hash":"24094ce9de1b9222a8d6548d3c01045a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart","hash":"9298606a388e3adb5f1bbe88ae45b1e6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart","hash":"e5a3ca065f292c0f0b0cca0a55df41aa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart","hash":"ae85856265742b6237ed0cb67c4364af"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart","hash":"e45c87e4aadaebf7ba449f4c60929928"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart","hash":"6618a55cdb528b43addda36642363d96"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart","hash":"9e8b56ffe3de97538d012849a1afa5ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart","hash":"4250bd72ef305d1f376e96cc6b994778"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart","hash":"f54f6b61b175b0a37d51ff3ac8b8c800"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart","hash":"a06bb87266e0bac30a263d7182aaf68c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart","hash":"0f70aaa46e42cb439dcc5a21fba00f44"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart","hash":"0fa4800227413041d2699ed47918c7f7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart","hash":"d9d777d58bfe8521d1cee4c60700de58"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart","hash":"777aca422776ac8e4455ccc7958f7972"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart","hash":"154bcb3658f38871192c3955ebccb00a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart","hash":"fb2c02d4f540edce4651227e18a35d19"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart","hash":"3c1bedbe57228c35f8421d813a7237ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart","hash":"1b5af29e062854d33f5e4c81c2bdf11c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart","hash":"458f3bf784829a083098291a97123e81"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart","hash":"229f98ffbc538c9813ef41d9f707f00a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart","hash":"904ebe4c195d2036f989a5e1c3c6052d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart","hash":"6f18c18a1a5649f27b6e0c29dfba4dc9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart","hash":"4c5df57cfe2a6a2bc0d7462330344982"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart","hash":"9c053b0efcabd70996cc27e9d6c9303e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart","hash":"a8c03fde31609e92e69be46cf798cbd7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart","hash":"55675ef4bbddffa94d962bd52b3088ca"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart","hash":"03001d3ddae80bbf1f35c5e70e0d93e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart","hash":"294ddb67f660c73c07b9ec37562840cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider.dart","hash":"1962877d0f77e2d3d7ebadbb093d4997"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart","hash":"9645e1d88d63387bb98a35849f4cbe53"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart","hash":"95bedb83cd5b163e43b554086b016380"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart","hash":"2a10c15764942d10992468122feea62f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart","hash":"4a4e74da2f12d15dddf3cddd0628372f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart","hash":"d1e0e0c2904bd9e5145d919296eeb580"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart","hash":"34a4d340931147322eaddc77fdc65c22"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart","hash":"e1648c3accd2c87d0897e5454a387c3c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart","hash":"c7fd5a3a7f809d37cfe6af2af573d097"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/about.dart","hash":"1a8cf97475fa611bd193041415e8220f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart","hash":"56a59615d1fa716ece6eff8304f7bd34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart","hash":"7592e5df71403552b6109cb4fe946eee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart","hash":"29befe23f841cf5dd2dc7df24c13d88d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart","hash":"b29e302994b1b0ea5029734406101b8e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart","hash":"f90beedee11a434d706e3152bfb2fd15"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart","hash":"d857a3ae7f599cc71f41689ffcf1fc5b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart","hash":"6b3b758749ea0e06a43533073febcb66"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart","hash":"8dfd28d2164bbd446b480491aace196c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart","hash":"d74d8acd1490e1db907df61d756d2c71"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart","hash":"b1da6e4c330ab79eb371fb535a8fb7cd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart","hash":"4349dd08c33e677b65d9e00f13c35d2e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart","hash":"de7fb154b9b151b81a78d43ade695365"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart","hash":"66272a6751b167051ba879724cfe5749"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart","hash":"34485853c65233b4daedcede2ade0c69"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart","hash":"951bd729c13e8dd03a7f4edd8b10c06d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart","hash":"5da121a0d3087e7cf021bfcdeb247b77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart","hash":"b266a6c412cb5bbd5355fc22a3be3f84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart","hash":"391dfdeb37052a0c52eb8adbc96bffc1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart","hash":"f7b4c0027cecafcb6711746922663d7c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart","hash":"d74cafcf507b38e3f3094c6d5ed94a9d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart","hash":"9a023a5d9b2c849e9c7fd9e16db1e7e2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart","hash":"d70df86ce471e8470438627a65b2824b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart","hash":"75f947f0ba87a0789a3ef91542bbc82c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart","hash":"fe766313e73046aa145217de64ca7760"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart","hash":"a056a48864751b648133bf4d0886134a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart","hash":"8a39bdc324d0ff25097784bd98333c08"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/chip.dart","hash":"926a78bbb0d20acd22028c14ca8b8071"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/password_reset_success_page.dart","hash":"2f03381a7e5a528c9c93709cd957942d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart","hash":"91d8303ca1ccc72eccc1ae636c7825ed"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart","hash":"bf6d84f8802d83e64fe83477c83752b4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart","hash":"974d0c452808a1c68d61285d0bd16b28"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart","hash":"44c1268c1ecafd3b4cd06ab573f6779a"},{"path":"/Users/downy/flutter/packages/flutter/lib/animation.dart","hash":"29a29ed9169067da757990e05a1476ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart","hash":"3167bedcdf6eb73bb3355fc778c69ab2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart","hash":"a6c467b3086118863463a925df22d187"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart","hash":"2675cdf47e408031206cc9c215200004"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart","hash":"36bb3dc8435f5085b78c2972f8efe90d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart","hash":"dbdbd9870586c8dd46ec4dbec96fade8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart","hash":"8d05e0330774daca2ab93f307ded78f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart","hash":"12143f732513790cd579481704256dcd"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/signup_page.dart","hash":"d885a7ec888c21805996c1bfd82bb026"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart","hash":"c7cc72c1e40d30770550bfc16b13ef40"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart","hash":"a8f2c6aa382890a1bb34572bd2d264aa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart","hash":"6efba60755f63ff2efc82c76d3a50222"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart","hash":"1f131d7f971396d52ce5fe78ae6a8a83"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart","hash":"1268762fa54412a0d265cb57a14cba84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart","hash":"19c24981d3d862f7206e587073eaae67"},{"path":"/Users/downy/flutter/bin/cache/engine.stamp","hash":"f41d9e32b73e3888e8d66a99b615a8d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart","hash":"d33374c0857b9ee8927c22a5d269de9b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart","hash":"6486bc074c81ec57bdafc82e6a64683a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart","hash":"08c3fd9ed1607d3a707ffe9b3532218a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart","hash":"7e45468116224ee318aa9b1f210cab12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart","hash":"bd6d122c12d867a991bd2fd36a3c46a8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart","hash":"cc6cce102fab186d0e7a063d0d917504"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart","hash":"06078529e4523830f3ad70e0aab603d0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart","hash":"77900a31d721da1722fe34c455a00d3f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart","hash":"f487ad099842793e5deeebcc3a8048cb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart","hash":"bc3c12f9555c86aa11866996e60c0ec9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart","hash":"73d5607bd6f5dccf91add39e25ad157d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE","hash":"2d0c70561d7f1d35b4ccc7df9158beed"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart","hash":"eaf5aa7cf4fe19db30724f637b38257a"},{"path":"/Users/downy/flutter/packages/flutter/lib/semantics.dart","hash":"4b784d6e4f290bd6d5a1f38bfb5701d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart","hash":"c761b80666ae3a0a349cef1131f4413d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart","hash":"f5b38c21bf580c89610a8b58c65aae00"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart","hash":"3d71d8940be022672282ed70f0cbb8c6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart","hash":"8ac28b43cbabd2954dafb72dc9a58f01"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart","hash":"6cae6900e82c94905cc2aaefd806f8eb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart","hash":"f949f49484067589ef08e13a892f3101"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart","hash":"0fbec63144acf1cb9e5d3a3d462e244b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart","hash":"ca959e5242b0f3616ee4b630b9866a51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart","hash":"e3127548d819af5ec9ecb10b5732b28e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart","hash":"e9a141d0ed4d585b165b7fcacc3874d1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart","hash":"dc667b5b278c7b8a2191913ac49e33d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart","hash":"eafe83db9186e4fbb802d857e4bb42ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/binding.dart","hash":"064a460171599d3d2a4596a5d1ea2b00"},{"path":"/Users/downy/flutter/packages/flutter/lib/material.dart","hash":"79c87aaef3dd490ff1c43fad2f2f6e8e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart","hash":"ff5d66c50ec833a263625d39f0c195b9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart","hash":"184d3b79d275d28cd02745b455041ee6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart","hash":"f6d7d6477016f1f991e57b2cbeef7292"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart","hash":"8fde18d2ef5c741e3b748bbc854d6b17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart","hash":"58feb628edda8670acd9b4c4db589918"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart","hash":"f158ffadca730ab601c60307ba31a5e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart","hash":"20051c4912af535e0a8362fb1e93f423"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart","hash":"caf148b76c44a3f0f1bd6055ddbb8f5e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart","hash":"207aa61e81c77c54342772a6367af334"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.bin","hash":"693635b5258fe5f1cda720cf224f158c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart","hash":"5de15d7a41897996ef485c087ef4245b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart","hash":"9ad11b4bdb179abe4ccb587eb0e2aebc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart","hash":"56e9b43aa79d6b888e779ad7905c1617"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart","hash":"4d6c8c8185327af9d064a1fbeab18fa1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart","hash":"fda1d4b1be4a584133638117945d3dff"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart","hash":"b698617b81ba534ca60cdb6dee762fff"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin","hash":"d2ff816d5520e84128e4e6fbf6b2714b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag","hash":"a0e89676ccae6cf3669483d52fa61075"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart","hash":"4935fd96677780d631f23a75e7009534"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart","hash":"0672d853d5097a03eddc7dbe558eeabd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart","hash":"43ef2382f5e86c859817da872279301e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart","hash":"d4252f423175e5c21fca23dc24154b84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart","hash":"6f02e150859b1047ec04ffa4a924f90a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE","hash":"175792518e4ac015ab6696d16c4f607e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart","hash":"f56109c40e6fe9e53f9c6ad021d25ff5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart","hash":"2aec07fe4a1cd25aa500e5e22f365800"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart","hash":"605dcc1d6bd5023fc0b651a625076ca8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart","hash":"5176206f3155513053dda23b0c32fc8c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart","hash":"edd2f9cabffc7ea6a5a9497a1b1beccd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart","hash":"986845a7043505c19753e1d499d49a4a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart","hash":"ab177cf671fb7bab974d9c08618a677c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart","hash":"c9cd996cea2334f644c74ebbdb41f7f5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart","hash":"13c8dcc201f970674db72fbbd0505581"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart","hash":"270de9c98f9c1284da0a6af9176ee1f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart","hash":"920b63c794849c8a7a0f03f23314bbb1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart","hash":"dc2cfe4408f094916cd5eb1d294d1f2f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart","hash":"8a7e3b181572ed50e923e5dc05a7533d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart","hash":"289e5bbf4975b43a1bc7510306854b34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart","hash":"d161560a01cd02902c87f5decd590cfa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart","hash":"e79db1a382e61436ed81f9f47dc06d7a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart","hash":"1542c76e7b3e366d393fcb2c3bc601d5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart","hash":"89b2bd5c8fc199b582eb9f10973f97b4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart","hash":"e792b35686d28f5a239264b5b791c0cd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart","hash":"395f07418a28b12b0ed665f32270d702"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart","hash":"92868012710ac163590ba05c788c0816"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart","hash":"555fcdeebbe6517cde1cdd95133cabd7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart","hash":"c4d13715583d2c97acba184a3e821151"},{"path":"/Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE","hash":"4fd63b752aa4c209c7c0bdd1ee5f8a10"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart","hash":"1205ed5e14a59c237c712b8a495b1981"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart","hash":"73189b511058625710f6e09c425c4278"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart","hash":"53d7a28895126d1b4c472405e2876fb0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart","hash":"8a60b4ed49f146296d6896973154e1d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart","hash":"3cddcab8b952545bc05a5c1475a06c9d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart","hash":"85cf42bafb7c0646bd7a99379649da29"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart","hash":"9ffd4af5e11781c62ed4e40fdf15b182"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart","hash":"269af8ca7030ccfd9c868fe9af8a6b0a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart","hash":"ed5548873fcf5a0a5614fc52139600b8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart","hash":"7ebcf3ce26dea573af17627d822e9759"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart","hash":"f64837679a1abb526e942b166db5c244"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart","hash":"965c702e5f0b6ba27c6292cf3a602781"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart","hash":"d3eb6373e2fd626717b8de7cbf19cd8c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart","hash":"b3a6dd250e09b61bffbc04a767f0c920"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart","hash":"3c8d2d2b73f69d670141d376642e5252"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart","hash":"6a612ac4de579506fd1b806fac3fe062"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart","hash":"ad139ffd36c17bbb2c069eb50b2ec5af"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart","hash":"78f6899dd22a8086e573217b5538f98c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart","hash":"b062a8e2dade00779072d1c37846d161"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart","hash":"59b6b74779849bf5b836b84bb362b99b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart","hash":"cb454929d7810d3ee5aa5fc28283d3fd"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/common.dart","hash":"b9127267cdd2de6c1285a11eac48d269"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart","hash":"546a4af6d99fa77922a881e2f131c1f3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart","hash":"553c5e7dc9700c1fa053cd78c1dcd60a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart","hash":"f3d29b37515ed98685cd81aa319dd254"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart","hash":"5577ef7cd41e467cc247a42b677f93c9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart","hash":"79c35fba64a91629072a76526adb9aa7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart","hash":"107c33a245427bf0f05e21c250653dc6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart","hash":"6be1e6f404dc5206ea2b4fa512c45dc3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart","hash":"de17df889317f7a54961ea540cf4b807"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart","hash":"8b15d222f5742b46bf55a4ef4cbfd6e0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time.dart","hash":"872d879ea43b6b56c6feb519cc12d5a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/colors.dart","hash":"f59aed120736d81640750c612c8cfe5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart","hash":"f94061e9a635be75dd8e38eab352c344"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart","hash":"ef5fc00d685cd2a36c4de80e1c7e3a8f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart","hash":"ea7c9cbd710872ba6d1b93050936bea7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart","hash":"85b908f2e50b980d5cab7f458371f430"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart","hash":"1fd7c932679011d491315ff136d13822"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart","hash":"15a20afe634cea8448869b051ad52b3c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart","hash":"cc4a516908b08edff4fade47d6945e5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart","hash":"d7a6c07c0b77c6d7e5f71ff3d28b86bd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart","hash":"4da7ecc08c07abdd0226004f30973748"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart","hash":"9d1525a634d27c83e1637a512a198b4f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_verification_page.dart","hash":"33a4dc3ffcd0422c059be5eba86df863"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart","hash":"785eedcc96fa6a4fcc7c81a8736a7427"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart","hash":"3ee18da390e16ca65f2ef168adb8a1ef"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart","hash":"c679063104d2f24639459c8ab3eed77a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart","hash":"cf63ef7fb2873f43a2b2e25485734429"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart","hash":"1e2afd780c32baef8cedd0eb9c4dee6d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart","hash":"faf4d014b3617ede3150f80eba25e3b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart","hash":"12580e996c5cb68c4e80588f6dd9f235"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart","hash":"cb49e0d1c096a600c37190f5a40cbecb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart","hash":"6d0b38802aff8cbe310e72f1a62750d6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart","hash":"9ea1746a0f17f049b99a29f2f74e62ee"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_page.dart","hash":"585aa4b6d2918190224cc3072e4ca6ea"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart","hash":"36fc598c656490ab430ca1be5fb909e8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart","hash":"f6c6b31745eec54a45d25ffe6e5d7816"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart","hash":"a93ae192d60f10b56cf1659d2123bc95"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart","hash":"38fcdd2be2a4d0ecbbe01cc03cd03e96"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart","hash":"a74b5a39115ffd608a19cad9309e6a31"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart","hash":"838c8a1a376a7c9c3fb3424927bcc75e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart","hash":"4eede9144b4c0e4b14bd426654183174"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart","hash":"c3ccb5b6cd3df44e6587a4f04dd6a4e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart","hash":"d2372e0fb5a584dcd1304d52e64d3f17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart","hash":"e6467427260f3274e8424d691615ca5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart","hash":"e4a32acbcd5da5e636d429dc167fc5f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart","hash":"b39287c180e3ac3047fc5dba3a44a524"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart","hash":"bf50f61746b9744a0e2d45a88815288f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart","hash":"9f5e8439ef3cbfa84f76922ec3580363"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart","hash":"47ccb32c843b4075a001e612853b2a31"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart","hash":"632d3c730c9b6e4f46d9c0459c53ca9c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart","hash":"58678829e383937c51f539f2ad67fc17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart","hash":"5aa51467523e637443dec44f6c7b1e6c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart","hash":"1adcc56e3affffb23739c7c9d8a5fca0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart","hash":"a2350d9426fefa6d657868d9e59eac7b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart","hash":"9434ff8aa06e13d5981ed6ec15eceb64"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart","hash":"87f0b72f24e05d2d3f4b0f1b4709eb51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart","hash":"3ee6304161ca2993b303a8074557fe66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart","hash":"2d2cd1fbe11b3e587475449fa04ad4eb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart","hash":"85814d14dae3bc1d159edd0a4bef48e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material.dart","hash":"5c93305f52983c3f2be825bf54ebbd78"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart","hash":"89aeee125822690cbd46b2ff43c76ec1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart","hash":"5d8e29422039d9dcce6908b427814d80"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart","hash":"cad4582fa75bf25d887c787f8bb92d04"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart","hash":"900a13c9fcd73f4e8e3d069d76af6ffa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart","hash":"b1bb8356cca8b86afca314ab4898a527"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart","hash":"5692636576c4bec471fd3a1275f08525"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart","hash":"67d16e841606c4e5355211fe15a2dbfd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart","hash":"c8f69577793923bfda707dcbb48a08b1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart","hash":"3431f50e7abf9e27af232de10193931a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart","hash":"11fc97acd20679368ae2eaa698c6f130"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart","hash":"151d12284cf607a6e984aa31fe766faa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart","hash":"74939c971de1eb61ef05a7eb5056cc20"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart","hash":"a3bdbf775c61477db47c508f513688e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart","hash":"b80f25d51570eededff370f0c2b94c38"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart","hash":"075310a7fe661b71e9a583aab7ed4869"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart","hash":"c069ad8b31e18adb75c27530f218957a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart","hash":"787093e38fffbbd356129a373907124c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart","hash":"b78c67723942ac5480c158576c1247e3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart","hash":"62f852a5f85345e608cdc7b62a689202"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart","hash":"fe2489ea57393e2508d17e99b05f9c99"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart","hash":"62d88517fa4f29f5f3bcec07ba6e1b62"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart","hash":"484481ff93d08a930ecfcf6907acf691"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart","hash":"8e286948f2eaa63514196c1e4c91666c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart","hash":"d72a4ddaf6162d8b897954e02b4a2a4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart","hash":"0ae47d8943764c9c7d362c57d6227526"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart","hash":"63db75c602690371aef0f83279a929d7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/curves.dart","hash":"4aeb4635d84df42e6f220aba366af7d9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart","hash":"ee36aadc3fac54d5659c94c6aadcd007"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart","hash":"db799bf48af97b7c0edc93ad96b4a6da"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart","hash":"34ebb85f7f2122d2e1265626cf252781"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart","hash":"dbf4f1e95289bc83e42f6b35d9f19ebe"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart","hash":"b4b0fd902f4b9b1baf13a2e5e14807da"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart","hash":"dd510cd97dc23d22aebc7b60affd6329"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart","hash":"eb9b3bf513b18ddaf0057f3877439d9b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart","hash":"dcef90946d14527736cde04a54d334db"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart","hash":"42212bb3508502e1b011bd783d51ea78"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart","hash":"6987c3474a94dd1c4ff8f8540212f16b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart","hash":"5265b4bdec5c90bfd2937f140f3ba8fc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart","hash":"8d0306ecedceab52f23b17a0694e7842"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart","hash":"a2aa815908f2e15493e374b9380e558a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart","hash":"101ff6d49da9d3040faf0722153efee7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart","hash":"78ce7527fa364df47ba0e611f4531c2c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart","hash":"377fef989628d5fbcb306e46a03b7a12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart","hash":"fe750f835c7dc27ef38ee2fdb486a6ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart","hash":"d390b15ecef4289db88a4545e359bc8a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart","hash":"816a5cf300a6461fe2e7e8ca8a66a709"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/app.dill","hash":"d2ff816d5520e84128e4e6fbf6b2714b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart","hash":"b2015570257a2a6579f231937e7dea0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart","hash":"f8275b74f8f83272b8a8d1a79d5b2253"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart","hash":"4e04af41f89adf9231bad1579f5bb9a1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart","hash":"77e3a9ed54e0497465a4346f273bcccf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart","hash":"8dea906a9b8773920b6d1ccea59807bf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart","hash":"97c7266e528b6f706b08b4ad340006d2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart","hash":"200da5ba0b0cee2bca1acd1c4d772118"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart","hash":"4c09fb1ea4651f47d1a0a67ba3b31886"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart","hash":"4c13b34211e2b17645a6a5cd8defbe0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart","hash":"04451542afc67a74282bd56d7ee454f5"},{"path":"/Users/downy/flutter/packages/flutter/lib/painting.dart","hash":"4bd60bd8ede4b9dad954493d26d3e586"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart","hash":"43ba7557388f413902313df64e072389"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE","hash":"d53c45c14285d5ae1612c4146c90050b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart","hash":"b4ab536e0cb6945296bb962bc1e9a3f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/services.dart","hash":"29ae1507a6ec4c2ffae469a10e505bda"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart","hash":"cccaa1a390453623404ad2f98ba719c9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/App","hash":"4ddef20d7f3b2634c55e3f2903db42b7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart","hash":"32f33f52f1a1e1b0911dbbfa4dd7785a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart","hash":"168bedc5b96bb6fea46c5b5aa43addd1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart","hash":"14acfddcb9e62f0de6f82d28e22c22f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart","hash":"2d18e0064b57f514fab5c3abc06ace0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart","hash":"cd3f0ebbc282b839928f5fe3ad12c779"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart","hash":"b16458199371a46aeb93979e747962a3"},{"path":"/Users/downy/flutter/packages/flutter/lib/scheduler.dart","hash":"95d8d1f6a859205f5203384e2d38173a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart","hash":"29439c1f30cb2958458664e1e6e40289"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart","hash":"51fa10cf30bde630913ff4c6e40723ba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart","hash":"31d8245447d51dba20c81f00b214fb36"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart","hash":"c6da76a71962267cab91aadde5b59426"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart","hash":"f7b9c7a2d1589badb0b796029090d0d5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart","hash":"df699735e3bcd730f16ce377d562f787"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart","hash":"bfb39b98783e4013d9fe5006de40874d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart","hash":"5275d424aba5c931a30e6bd3e467027d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart","hash":"984acd55714db5ebfdcab5aeb55467fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart","hash":"81d01d8cecc6783526e350800988db74"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart","hash":"18ad2d48b68dc9b514fde418b7acb599"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart","hash":"cb0d5b80330326e301ab4d49952b2f34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart","hash":"f01b78dd243cdceae98d62e7429f3d04"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart","hash":"40587a28640d3c90ad2e52fdfbcd7520"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart","hash":"15439eaa12b927b0e9a42b9d168e3371"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart","hash":"9eb1b00e42fadb0be56354c8bc9feb4c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart","hash":"f12f9a9b8bb504f4617bfd1c00d403f0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart","hash":"f301af2d0392296f456363085becbf47"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart","hash":"8fa0c1ec158277156da896110a03d968"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart","hash":"a0936682931bc884c5052e9f49bf8829"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart","hash":"aad5ba4c4076b74ded1d769dc1edbceb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/badge.dart","hash":"134441e2b4b42a7b2ee012ce48910557"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart","hash":"f179ed2f20226c436293849c724b2c4d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data","hash":"b8ee00883037778797bf5949230f40a6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart","hash":"e76d7da2d8f4281119d176fdcc04b991"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart","hash":"063f2360bd47faba2c178ce7da715d92"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart","hash":"b7b71e22b53d4d100702d2ba7a7130db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart","hash":"5b04f80518a8417cb87a0aec07dacf4f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart","hash":"dc196a3f1d514347c5f7da6e197b384d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart","hash":"393c6d8b9c1a038b62a418fadf8c69c9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart","hash":"5b98d0be4d89f1274c832a4c340ab315"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart","hash":"af709d56567f1923ade761542e8dd796"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart","hash":"600a92f02eb307032e6cedc6c5f104f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart","hash":"6c0e97a3b04c9819fe935659014f92e8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart","hash":"f49291d1bc73b109df4c162db10003d2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart","hash":"1fc94d5523beb1dda68dd704b8f99bd8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart","hash":"53b9028402187f878713225b48bdd5bb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart","hash":"f60846aa76dab98607aa06c9bd6cf1dd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart","hash":"43268fa3ac45f3c527c72fc3822b9cb2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio.dart","hash":"1e0f99d28825c416ceb5f264b6af7fdc"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NativeAssetsManifest.json","hash":"f3a664e105b4f792c6c7fe4e4d22c398"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart","hash":"fa2a57b3b873fb7db4b8b961735e4ca3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart","hash":"e4da90bb20b3980a03665a080c87a098"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart","hash":"21e56afda1f096f0425a34987708ed56"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart","hash":"0976264b99a1702a5d74e9acb841b775"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart","hash":"6a9dc1f0e0e14fc0ef5efb4c3c1e8a77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart","hash":"5be90cbe4bbf72b0264413e4ccb5c275"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart","hash":"a64e270c19c9e9ed0c5d9a17e0c4a5d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart","hash":"04c960ae6d770135bb0b6acf14b134a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart","hash":"622fb5559ef551a734f0ebae8660485e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart","hash":"8986177ba204a808c603c35260601cce"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart","hash":"1d8fa1cee64f2d791002749fabe23e2e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart","hash":"547eac441130505674f44bf786aee606"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart","hash":"625b4ed63675ca8ffe8c11d0469bdd9f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE","hash":"3c68a7c20b2296875f67e431093dd99e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart","hash":"617fb0bcef7162a860ca76636507117f"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","hash":"0864ad73108959b573b007ab6025d731"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart","hash":"83fc222e671ddaa7fdb3868c0acaba0a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart","hash":"d828c4334e98a12974d90e38d48db9f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart","hash":"d67712d7f3394870d88650dc0baf5855"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart","hash":"aaf8cbac74b7b5a3a487d5ddfc2bcdbc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart","hash":"73f043194b9c158454e55b3cafbdb395"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart","hash":"a1e4de51bdb32e327bf559008433ab46"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart","hash":"2a08c219491feeb1c8e9b9d492ffce44"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart","hash":"cd6b036d4e6b746161846a50d182c0b5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart","hash":"bf365ded028510087ed69c227bda0d52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart","hash":"a36981329a77de46168efd089c4102e2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart","hash":"38570a2af41c2f9a4632e2af3b42ffe7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart","hash":"2b2a74f1e45f48fed04eab35ae3c85d7"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/FlutterMacOS.framework/Versions/A/FlutterMacOS","hash":"905751619daaee0e40417eb1da83c5c7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart","hash":"7cbeab73e95bd7561ac8b9519c579ffb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart","hash":"8cff8c004f57019314d3fe8176de4043"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart","hash":"56a764067b45a1a7cb6b7f186f54e43a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart","hash":"13c9680b76d03cbd8c23463259d8deb1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart","hash":"dd518cb667f5a97b3456d53571512bba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart","hash":"b15a3573191a80dfb78fd6a729390c0e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart","hash":"9011b30a404dec657806a780b55d0610"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart","hash":"9d273d5a3c1851b0313cd949e7f84355"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart","hash":"c83781cf0c38883486f707cddbb96773"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart","hash":"374ee130942948f52e47681818bd315e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart","hash":"5c9195780e56985cc88956aab0887ab3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart","hash":"25dd0d36ba8109e3199faf508b41d633"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf","hash":"b93248a553f9e8bc17f1065929d5934b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch.dart","hash":"721c2d087f423a3293f5314804ae66a5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart","hash":"0d8aed1407088c73788f25ffba071cc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart","hash":"49f335e51e1a6242ba8ab55b48de9d92"}]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/App.framework/App b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/App.framework/App new file mode 100755 index 0000000..d4a09ca Binary files /dev/null and b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/App.framework/App differ diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/app.dill b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/app.dill new file mode 100644 index 0000000..0342f33 Binary files /dev/null and b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/app.dill differ diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build.d b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build.d new file mode 100644 index 0000000..fa44b0d --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build_result.json: \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build.stamp b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build.stamp new file mode 100644 index 0000000..433f1f2 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build_result.json","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build_result.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build_result.json b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build_result.json new file mode 100644 index 0000000..0d218ca --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/dart_build_result.json @@ -0,0 +1 @@ +{"dependencies":[],"code_assets":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_app.cc b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_app.cc new file mode 100644 index 0000000..8fef9f5 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_app.cc @@ -0,0 +1 @@ +static const int Moo = 88; diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_macos_bundle_flutter_assets.stamp b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_macos_bundle_flutter_assets.stamp new file mode 100644 index 0000000..31ec302 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_macos_bundle_flutter_assets.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/App.framework/App","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/app.dill","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf","/Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf","/Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/native_assets.json","/Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE","/Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE","/Users/downy/flutter/packages/flutter/LICENSE"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/App","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/Info.plist","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/fonts/MaterialIcons-Regular.otf","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/FontManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NOTICES.Z","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NativeAssetsManifest.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_macos_framework.stamp b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_macos_framework.stamp new file mode 100644 index 0000000..f842519 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_macos_framework.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/macos.dart"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/App.framework/App"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_unpack_macos.stamp b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_unpack_macos.stamp new file mode 100644 index 0000000..e555531 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/debug_unpack_macos.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/macos.dart","/Users/downy/flutter/bin/cache/engine.stamp"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/FlutterMacOS.framework/Versions/A/FlutterMacOS"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/flutter_assets.d b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/flutter_assets.d new file mode 100644 index 0000000..707192c --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/flutter_assets.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf /Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/fonts/MaterialIcons-Regular.otf /Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/shaders/ink_sparkle.frag /Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.json /Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.bin /Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/FontManifest.json /Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NOTICES.Z /Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NativeAssetsManifest.json: /Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml /Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf /Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf /Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/native_assets.json /Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE /Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE /Users/downy/flutter/packages/flutter/LICENSE \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/gen_dart_plugin_registrant.stamp b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/gen_dart_plugin_registrant.stamp new file mode 100644 index 0000000..b2a917b --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/gen_dart_plugin_registrant.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/gen_localizations.stamp b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/gen_localizations.stamp new file mode 100644 index 0000000..1b2d28c --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/gen_localizations.stamp @@ -0,0 +1 @@ +{"inputs":[],"outputs":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/install_code_assets.d b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/install_code_assets.d new file mode 100644 index 0000000..d9676ed --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/install_code_assets.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/native_assets.json: \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/install_code_assets.stamp b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/install_code_assets.stamp new file mode 100644 index 0000000..0358419 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/install_code_assets.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/native_assets.json","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/native_assets.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/kernel_snapshot_program.d b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/kernel_snapshot_program.d new file mode 100644 index 0000000..07fdab1 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/kernel_snapshot_program.d @@ -0,0 +1 @@ +/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/app.dill: /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart /Users/downy/flutter/packages/flutter/lib/animation.dart /Users/downy/flutter/packages/flutter/lib/cupertino.dart /Users/downy/flutter/packages/flutter/lib/foundation.dart /Users/downy/flutter/packages/flutter/lib/gestures.dart /Users/downy/flutter/packages/flutter/lib/material.dart /Users/downy/flutter/packages/flutter/lib/painting.dart /Users/downy/flutter/packages/flutter/lib/physics.dart /Users/downy/flutter/packages/flutter/lib/rendering.dart /Users/downy/flutter/packages/flutter/lib/scheduler.dart /Users/downy/flutter/packages/flutter/lib/semantics.dart /Users/downy/flutter/packages/flutter/lib/services.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart /Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart /Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart /Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart /Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart /Users/downy/flutter/packages/flutter/lib/src/material/about.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/app.dart /Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/arc.dart /Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart /Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/badge.dart /Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/banner.dart /Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/button.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/card.dart /Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart /Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart /Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart /Users/downy/flutter/packages/flutter/lib/src/material/colors.dart /Users/downy/flutter/packages/flutter/lib/src/material/constants.dart /Users/downy/flutter/packages/flutter/lib/src/material/curves.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/date.dart /Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/debug.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart /Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/divider.dart /Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart /Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/material/material.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart /Users/downy/flutter/packages/flutter/lib/src/material/motion.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart /Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/page.dart /Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart /Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart /Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart /Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart /Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart /Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart /Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/search.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart /Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart /Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart /Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/material/time.dart /Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart /Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart /Users/downy/flutter/packages/flutter/lib/src/material/typography.dart /Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart /Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart /Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart /Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart /Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart /Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart /Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart /Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart /Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart /Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart /Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart /Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart /Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart /Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart /Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart /Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart /Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart /Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart /Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart /Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart /Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart /Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart /Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart /Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart /Users/downy/flutter/packages/flutter/lib/src/services/binding.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart /Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart /Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart /Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart /Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart /Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart /Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/debug.dart /Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart /Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart /Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart /Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart /Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart /Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart /Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart /Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart /Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart /Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart /Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart /Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart /Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart /Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart /Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart /Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart /Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart /Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart /Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart /Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart /Users/downy/flutter/packages/flutter/lib/widgets.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_error_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_result_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_verification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_error_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_reset_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_verification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/login_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/password_reset_success_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/reset_password_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/signup_page.dart diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/kernel_snapshot_program.stamp b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/kernel_snapshot_program.stamp new file mode 100644 index 0000000..52d554b --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/kernel_snapshot_program.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/common.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart","/Users/downy/flutter/packages/flutter/lib/animation.dart","/Users/downy/flutter/packages/flutter/lib/cupertino.dart","/Users/downy/flutter/packages/flutter/lib/foundation.dart","/Users/downy/flutter/packages/flutter/lib/gestures.dart","/Users/downy/flutter/packages/flutter/lib/material.dart","/Users/downy/flutter/packages/flutter/lib/painting.dart","/Users/downy/flutter/packages/flutter/lib/physics.dart","/Users/downy/flutter/packages/flutter/lib/rendering.dart","/Users/downy/flutter/packages/flutter/lib/scheduler.dart","/Users/downy/flutter/packages/flutter/lib/semantics.dart","/Users/downy/flutter/packages/flutter/lib/services.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/about.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/arc.dart","/Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart","/Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/badge.dart","/Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/banner.dart","/Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/card.dart","/Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart","/Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/material/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/material/curves.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/divider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart","/Users/downy/flutter/packages/flutter/lib/src/material/motion.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart","/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/page.dart","/Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart","/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart","/Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart","/Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart","/Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart","/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart","/Users/downy/flutter/packages/flutter/lib/src/material/typography.dart","/Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/services/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart","/Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart","/Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart","/Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart","/Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart","/Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart","/Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart","/Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart","/Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart","/Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart","/Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart","/Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart","/Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart","/Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart","/Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart","/Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart","/Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart","/Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart","/Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart","/Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart","/Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart","/Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart","/Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart","/Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart","/Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart","/Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart","/Users/downy/flutter/packages/flutter/lib/widgets.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_error_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_result_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_verification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_error_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_reset_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_verification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/login_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/password_reset_success_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/reset_password_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/signup_page.dart"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/app.dill","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/app.dill"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/native_assets.json b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/native_assets.json new file mode 100644 index 0000000..523bfc7 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/native_assets.json @@ -0,0 +1 @@ +{"format-version":[1,0,0],"native-assets":{}} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/outputs.json b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/outputs.json new file mode 100644 index 0000000..92a8ea6 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/2d26c7ca5f60643a0af4db97aa35d08d/outputs.json @@ -0,0 +1 @@ +["/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/FlutterMacOS.framework/Versions/A/FlutterMacOS","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/App","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/Info.plist","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/fonts/MaterialIcons-Regular.otf","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/FontManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NOTICES.Z","/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NativeAssetsManifest.json"] \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/.filecache b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/.filecache new file mode 100644 index 0000000..0d01e49 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/.filecache @@ -0,0 +1 @@ +{"version":2,"files":[{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/typography.dart","hash":"d4335eeb3dd8ee5df4498661b368ebea"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart","hash":"c93eab1631a5606c8ba301346fa8e483"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart","hash":"72b6519b69dfbf0f2959b7e590bea0bf"},{"path":"/Users/downy/flutter/packages/flutter/lib/rendering.dart","hash":"4bd3950a0bf4a9f9b09f97594e363d36"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart","hash":"648a6cdab2fd44688152ab1b016e5e9c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart","hash":"ea5bbc17f187d311ef6dcfa764927c9d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE","hash":"d2e1c26363672670d1aa5cc58334a83b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart","hash":"54c7f23362a7e78be04b113d00022090"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart","hash":"38861aee0e2ba92ec8005a64746c0d10"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart","hash":"3d925b9cf0a12dd519256aa23a4e3512"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/tools/shader_compiler.dart","hash":"57b58eaf8484f5be3274077f5af029f8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart","hash":"61137458bbcab0dfb643d5d50a5ae80f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/Info.plist","hash":"6016705a3f184806962ca5a00032c556"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart","hash":"732535ba697d95c80d1215c0879477f1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/debug.dart","hash":"17fec0de01669e6234ccb93fc1d171f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart","hash":"ed28f6ca17f72062078193cc8053f1bb"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_error_page.dart","hash":"9268b14346ec737d9fcb71813e7ab30a"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/darwin.dart","hash":"8e0517e25fde2e092795b066ba2b7310"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart","hash":"954effbd324f486a6948427c605454e8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart","hash":"aed826e965e4aa2fdb3466d39e33d824"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart","hash":"4a7b03b0c037b260c1a321f7aaa8b6ff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart","hash":"7504c44d1fa6150901dd65ec78877be0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart","hash":"608be960e670661114e97b498d6a6473"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_verification_page.dart","hash":"e58dd47f15bb9a329afb5a3ec75529c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart","hash":"9b61320422b3f577a77f50badebd040f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart","hash":"d69cd05d9de1731242d357de56893a6f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart","hash":"4133ed8c1bb408e9cad637892e49a8fb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart","hash":"38c93c95cb266619fd6cf7de928884db"},{"path":"/Users/downy/flutter/packages/flutter/lib/foundation.dart","hash":"84939e70d6b7b36e8098dd0cda8cbb2a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart","hash":"eca4f0ff81b2d3a801b6c61d80bc211c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart","hash":"5ee4b9f196c81041c45d27e3b2d33d88"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart","hash":"ce4bfd9659d667457cc3ada513fae71e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart","hash":"008b3ea4691331636bbea9e057357ceb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart","hash":"ef1ff22066328de1e83b8180592a470f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart","hash":"d98495bcbc301290a10e6d1dfc255d69"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart","hash":"fb2be6f27b32bb1ab12dd6aea8c5ecda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart","hash":"f5e7b04452b0066dff82aec6597afdc5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart","hash":"92901585628d81f7bb3d578fd6d6657d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart","hash":"83bb40406ac73bcd194c621137ed0349"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart","hash":"f45f530a8be1596d7ffd25719c66c87e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart","hash":"6cf1ca324535366e2ea214049ffc9918"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart","hash":"3d892f04e5e34b591f8afa5dcbcee96d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart","hash":"f7bbc690baa3db88e9a15522b9c2f139"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart","hash":"62e0b7dc1550fd71644c5cc94797eee1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart","hash":"056355e344c26558a3591f2f8574e4e5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart","hash":"0938e0447f447ceb7d16477a0213ce2c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/login_page.dart","hash":"ce6d0c2416e80f6d279d2d4acf395187"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart","hash":"094b2c03ad4e0ef5bc1144e281142b2e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart","hash":"7692ca5e3a50523edceb59e80a6205a1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart","hash":"1dab3723527db6a19410ed34b6acaeed"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart","hash":"c56930c2b2b0e2c0c606af3f7686ebf2"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart","hash":"03849876382098601edd9248d621b1f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart","hash":"ebafc07567edebe5e176f39360b09f52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart","hash":"481e435dd11c202a9d2293db5b58b179"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart","hash":"63ea4f418d2305e0cf2c18a773821f9b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart","hash":"e88b0574946e5926fde7dd4de1ef3b0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart","hash":"52f779d8f66642da5db6810754b0ba5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart","hash":"eaef2926557480e27a3ce92f89de68b7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart","hash":"a47062dc6143c80c485bcfc7a06b9490"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart","hash":"0ee043f9e3f8fc817bc6bb354731879d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart","hash":"dbb0bb20c79bcea9397c34e3620c56c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart","hash":"e05529d31a09e4c86cde70483824fa10"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart","hash":"c8564aa311746f4047cd02e26ff4df75"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart","hash":"b5b9320ef8cd47d81a68063558c1ed4d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart","hash":"d891dabfc112fbaa77f11a249d547179"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart","hash":"7ffb6e525c28a185f737e3e6f198f694"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart","hash":"21496c39aba7bb1435e82558fc3dc9f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart","hash":"727e4f662a828d4611c731f330a3d79a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart","hash":"efad3646c2aadca0c462ae31919205ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart","hash":"c8a14f8ecb364849dcdd8c67e1299fb3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart","hash":"290ff7e27e670467d4f520e320ed9660"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart","hash":"24cd1bed27dc8cfdc2d00045c1b85b53"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart","hash":"ce02f18f5e43b6e21b9013a8d4bf275d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/motion.dart","hash":"505f6c9750f9390c9e9e4d881092cef4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart","hash":"ecc072620f2a72e685360292690c8a68"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart","hash":"f250acad4dd6cca43362a7d548a97aa5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart","hash":"4b50828d394e7fe1a1198468175270d9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart","hash":"280be2dbc10de2dd1913281d29e1b29f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart","hash":"7821d01f98c559fcbec46a41b4df7ebf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart","hash":"af4bf4aa827f5ac651aed6fb7b9a038e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart","hash":"1506ba940aec506086f3093420336467"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart","hash":"fc5d931b0e52f2fbd5ba118ca7f34467"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart","hash":"ca2e098cce59851623bf60c022a3bad1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE","hash":"5bd4f0c87c75d94b51576389aeaef297"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart","hash":"b815d11a718e0a4d6dec5341e2af4c02"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart","hash":"21494fec4563fdcefa3d28fad8ffd12b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart","hash":"46826fe180ac83f5855d6126ad250b81"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart","hash":"e4eb87da41119742a2dcbcdbc39c7a96"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart","hash":"bd3f0349089d88d3cd79ffed23e9163b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart","hash":"c7627484ec7f4005dae2321f6de6768e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart","hash":"94235ba74c3f3ad26e22c4b40538ce07"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart","hash":"61d3c1705094ee0ea6c465e47b457198"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart","hash":"ae53c1bc8f95419bee08ba4fde0e173e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart","hash":"1357b049a06aa8a7413982e814b87ab5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart","hash":"c5e44030289c2c25b26c5b3aa843b3cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart","hash":"985cf5499dc6e521191985f55245a22c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart","hash":"5486e2ea9b0b005e5d5295e6c41ad3c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart","hash":"05ab01a88b45fe10a762dc3068e7e1dd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart","hash":"90a1a95cfd75677cfe6295f0bad3a3e9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart","hash":"b3eacd047eaec8b4b214d8d35f471f06"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart","hash":"0c520a6b1ab38e0f294c3ddbc2ec9737"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart","hash":"77d5759abfee21d18803f19b603da875"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart","hash":"123520ee3a48eebf4ba444e93436bb1a"},{"path":"/Users/downy/flutter/packages/flutter/LICENSE","hash":"1d84cf16c48e571923f837136633a265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart","hash":"90f70ffdd26c85d735fbedd47d5ad80b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart","hash":"7c8b701267e773fa9293eb10736e0ca7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart","hash":"62cbf59e5c816c224ef5eaf803fc877b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart","hash":"2aacf74fb08ed144ee859c99233588ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart","hash":"11b4d96c7383b017773d65cb2843d887"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart","hash":"fa8eb6909c6c4c0ced2ac0ec5a69f640"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart","hash":"b6bcae6974bafba60ad95f20c12c72b9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE","hash":"4cb782b79f6fc5792728e331e81a3558"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart","hash":"be66f00d2c9bb816f4236dd0f92bff55"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart","hash":"964f3ee4853c34a4695db0c7e063eaa3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE","hash":"901fb8012bd0bea60fea67092c26b918"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart","hash":"0b3ae865c8e82bcd0c94aa60cdd8237f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart","hash":"5a41dbb4425fcc9ce228f1db68360c1e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart","hash":"db4d348cc51cfecc2c86a34122b48806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart","hash":"83df4f6e4084a06a4f98c27a524cc505"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart","hash":"edbd68eb36df4f06299204439c771edd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/arc.dart","hash":"511ff5c6f0e454b22943906697db172f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart","hash":"eca5aa939aa9722ead4b6c347fb4d11a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart","hash":"1303bc77ad63625069f2d23afc73f523"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart","hash":"2b76d589cc052dc9ef928ddba5382a4b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart","hash":"c9111e47389ee4b70aab720435a2a2df"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","hash":"a4839923171dbf950b0147fcaf04963f"},{"path":"/Users/downy/flutter/packages/flutter/lib/gestures.dart","hash":"ac772288a52f82606f20d68636327e34"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart","hash":"6297da5be01fb7c0d5c4aaffe7a27a50"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart","hash":"7bd8137185bc07516a1869d2065efe0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart","hash":"028eb8497ffa66b6d051c09361dc19f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart","hash":"89b2eba11b385c32cad8745bfba9798b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icons.dart","hash":"32b222420709e8e40d12f6ea9fc0041e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart","hash":"ec48414c6983150c30241ba7128634fa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart","hash":"530c4f96f1475cc4e4128ffedd705028"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart","hash":"0ff55be19444856c892e701c475b20f6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart","hash":"9f069b0f65439fc693626369d779c95e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart","hash":"57d74766f36a3d72789bc7466ae44dba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart","hash":"dd109d67b92b9fbe6e0051f0c890c903"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE","hash":"175792518e4ac015ab6696d16c4f607e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart","hash":"2936a409e1029ec52f7c0003f4db18c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart","hash":"eb115c2e8f0ff170bf26a44efd1b5c05"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart","hash":"ac172606bd706d958c4fe83218c60125"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE","hash":"83228a1ae32476770262d4ff2ac6f984"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart","hash":"7da554c3a69a1c2d019202e3f63331c5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart","hash":"e7b2de136a99cf5253477d4fb4138394"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart","hash":"d3ac4a3d093bab7e3c97e51db9e4218f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart","hash":"73089c9737db54a05691e09bc9fc1bcd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart","hash":"74c42b320d58fca1c02c22c577c5fdf7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart","hash":"b45f6f4ad67efa5c374cabc278ede26a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart","hash":"ddf1bde8f4b9706d5769690b7819e5d4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/banner.dart","hash":"576f65e88d664b3c39aa0e07825b29a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart","hash":"0b630cc8a66d79c161a58858593ae1ae"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart","hash":"6c54f90e0db5f42a13be6b3efeb4a04d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart","hash":"ae36c7cc9b21f98bedf401f2d67a0fd4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart","hash":"68c724edcc385ae2764308632abb76b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart","hash":"3ce88fe27ca35ed2f5b7a333d43676e1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart","hash":"37f181e3096dc69dc408bf7d07fcd39a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart","hash":"a6d730f196620dffe89ac987b96ef6c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart","hash":"3188cef277d7af7b79cfeb3286289551"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart","hash":"7088cc45b21c93be6b42dc748fc3a29a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart","hash":"0cf5ebf6593fabf6bb7dfb9d82db735b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart","hash":"153fd637fe660527ff42e1be068d99ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart","hash":"a29f0df228136549b7364fcae4093031"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart","hash":"b7525dbbd1c51211c6edc9ea544a62e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart","hash":"3fce8e0c4d9b3cb4e3dbc168f41a132e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart","hash":"65c2963f9227a1da6c2fd07cebad42cf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart","hash":"998487b87817cbb87019455d4abfaed8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart","hash":"57f09243c4e3f4099a10951225c6d1ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart","hash":"2f426329cad3640d8a125303c3509018"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart","hash":"e3d917994e875601c2dadaf62de546f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart","hash":"9bc30281f42d8003b7f9d636ebc8bfc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart","hash":"3e0eaeb97804d1bc93e6c6088aa351b7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart","hash":"99b4d15f76889687c07a41b43911cc39"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart","hash":"700328ab0177ddfd9a003a8c15619c1a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart","hash":"204fb623e2b782051e9bcb6e320e97c0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart","hash":"0c9bd1af5747fd55e7488c731ad32dee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart","hash":"d44c6aa2c95d66ec45eeb0bd0df79cee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart","hash":"2150550461fec00b57e9b9110f8fde94"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart","hash":"00ec0dfac52c24607bbdffd84060d019"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart","hash":"34c5e6ba4664d331c977bdc010aad709"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search.dart","hash":"3798784648f57e129514c1cb6f534612"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart","hash":"e324dd19cc02a1bf47bf7cc545dcca79"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart","hash":"40dec7d9dd1c5150bf10ef4b46cc36c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart","hash":"7146d1c18ac515c3fd3465cd4a7f7a34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart","hash":"82604e7dbb83dc8f66f5ec9d0962378b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart","hash":"734e496890e84ac4195229409538f700"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart","hash":"0bc80db5885f9d8ecc0f80ddab6fe8b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart","hash":"98772211ffa69a8340f8088cd7193398"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart","hash":"efcedeafa68d685da38d68896a5547ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart","hash":"940daf4491e3ab2e15d7eac5d6ce6b23"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart","hash":"30c8c6264748aba97477a1c81c8fb9d1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart","hash":"b5bd9d15c10929b4a63ea0df649e2d52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app.dart","hash":"5b539c57fb0cbea66a99efbc8239e590"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart","hash":"4a4b67b573e2338cf03cb704b2c18f04"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart","hash":"c7fe678fd3ad24ff5928e24dff4367b5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart","hash":"fb23ec509c4792802accd10fa7c8a6b0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart","hash":"853b1406f2756bef671f6d57135606f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart","hash":"a6ce313fc162c7c4402e1979454559a8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart","hash":"21a43efc5058f6132660bba47766b26b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart","hash":"5c3b7996bd913451665c9b1634098d83"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart","hash":"8b525140e1bf7268e1681a62c7640eea"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date.dart","hash":"f36568b4288388242cb6f7775cb60c42"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart","hash":"7514fc34af698a2ef36a68486f7340d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart","hash":"3e8df17480fcb123b3cdc775ca88dd89"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart","hash":"58b9bc8a40fd3e2f7d9d380d0c2d420f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart","hash":"b972c32590c642256132827def0b9923"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart","hash":"2cb2b1aac78bff7cc9be5f0a45aaa94b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart","hash":"e14417c43b6cb787f11bebd1c39280cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/card.dart","hash":"90d9d45eef80ac53b194a71da4e10975"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart","hash":"5979a1b66500c09f65550fab874ee847"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart","hash":"00c9e1f53ab22efcb34cca55fc46b4cf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json","hash":"f3a664e105b4f792c6c7fe4e4d22c398"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart","hash":"d7eb1678ec74acd9857a4193fd62ed5b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart","hash":"0b55082ca3ffb2bec57cbd8c61db5977"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart","hash":"66df4fe41752a6a990878623e36a3ad2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart","hash":"c06267b6c315a5e40f28feb6019de223"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart","hash":"527d9250e523e442bc07faadf2cb1741"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart","hash":"93d025adfc0409629c51036cb0fdc085"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart","hash":"2af013984ccce4c43e3024da472560d7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart","hash":"5b92fc2fdb9b39ca8d3072d08f9f2356"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart","hash":"991024814d51967a20be5851be93a8e3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart","hash":"8bb5842ab79616954e268adb624dc6fb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart","hash":"206ef1a664f500f173416d5634d95c8b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart","hash":"9d437a8fcd0a5c0ad90aa6e31d66834c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart","hash":"945227f3863339e388d92c2b3bfbf673"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart","hash":"166147b7bee5919995e69f8ca3e69d17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart","hash":"5c3150272dcfc4b6d488ba16b0b21594"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart","hash":"75abcdfe5d010a07b1833f1a2c48fa73"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart","hash":"07664903d8026f2514b29b786a27f318"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/constants.dart","hash":"2c6facdb1b63e687304c4b2852f6ef4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart","hash":"ea7754f2c684266799d36538300b6ffa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart","hash":"ccd754ed5584fb2b22056464dbfc9b37"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart","hash":"64c347128324802ec3aa6618f5723cc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart","hash":"7dc8dec32ceed4732299990cedf383dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart","hash":"035b8d3642fa73c21eafbee7851cc85d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart","hash":"d2386b256656121d501a16234b008e2b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart","hash":"f20071b459b9bbb98083efedeaf02777"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart","hash":"7c12bdd660d493a20f3d692be2cafe20"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart","hash":"28464c209a2293d3d4e5549539e1a751"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart","hash":"2663ff02a467c826925672bcaf6bcf66"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart","hash":"3bc33c65fa44a57d13430fdedef82bc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart","hash":"2fbba4502156d66db0a739144ccce9a0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart","hash":"f64029b4f4dbdc0bc61a4b8787975a94"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart","hash":"c390764eafafcc20c2e51225ce144ba8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart","hash":"0b8f9e0997c003bc97a462a2c70b91ab"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart","hash":"30d771880c8dbd68ea8e5d4a55c778c5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart","hash":"a2ab6e0f334e5a28af29766b82f7f4b0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart","hash":"8f77cb7be1dbf41ca0fdf069ac69a215"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart","hash":"9c169d41e4740bbc21d0ce33bc753119"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart","hash":"8e0fc402506b32a335e86f7fef97f06e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart","hash":"625e266fbab1e46e06c8d7d211a5828e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.json","hash":"2efbb41d7877d10aac9d091f58ccd7b9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart","hash":"7abc7e5212374d29bfe5372de563f53c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart","hash":"ef951139f9f55dc5b330d20e15d4fd0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/cupertino.dart","hash":"21e240878a582ab39a490e6ac330c645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart","hash":"b0c6844b0af0cd0539060a0bfcbe3713"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart","hash":"65a04fd24f938030b7271b61a59f9a39"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart","hash":"ab7af0d1396dfa5930adaf0357fdc1cd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart","hash":"0c9897499d9ef356aa9886423cdf96e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart","hash":"a8fdf31698b305c9fdad63aa7a990766"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_page.dart","hash":"cce7c7cae980c4c4774b41e73bd85214"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart","hash":"d195153a8c01a0392b38e3b9adc672d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart","hash":"0c32f2e835bc0f32a6b146dd73be8555"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart","hash":"7bbb6aab4e83fc272886a39c92157201"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart","hash":"d8060c05b658b8065bc0bfdff6e4f229"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart","hash":"0d9e952ceaa817539df84d30e876c4ee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart","hash":"f3747e025d835d0ff5cfd904d925dea2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart","hash":"11df661a909009a918e6eec82d13e3ff"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart","hash":"4d43f0629755f06d4df0b1a6ef75ef59"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_error_page.dart","hash":"7449d1fb4505ff8577fb8f19aef19565"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart","hash":"7536ace8732469863c97185648bb15a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart","hash":"be94b8f65e9d89867287dabe5ea1dff1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart","hash":"7018ea64a9aab18f27a10711285d7573"},{"path":"/Users/downy/flutter/packages/flutter/lib/physics.dart","hash":"6e29d5e69c5745a45214fe14da377c1a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart","hash":"9be021a3c68f7ef171b79893e7b4fcd0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/kernel_blob.bin","hash":"f4091c4ed02e66469c9f3b8a935fe8f9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json","hash":"2778e46651a3423266ac6e950331da65"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart","hash":"78e53d9a4963c0d19c5ea355a0946e5d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart","hash":"0949b8197a6069783a78f4bb0a373fb0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_result_page.dart","hash":"1f271c755537ad153a6e0d91cbbd8999"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart","hash":"7db055846295bfe7d5e376765ab0d106"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart","hash":"a1186c224201e7d203404a4270938040"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart","hash":"8e7e80b0f55481814454154289581855"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart","hash":"d35b72b249d19f54a4cd6f22ff3299e9"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart","hash":"e9b0c1f2903ca05a29681459603679c1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart","hash":"f44bbe72c4c7393277c42d5fc27b3b2b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart","hash":"5c96449c2a494ea8f3a50ecc3ba9af74"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart","hash":"f0d920fb2a472e43514830b20d401806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart","hash":"30ff1bba22f8f5d5442537740196fdcf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart","hash":"b092b123c7d8046443429a9cd72baa9a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart","hash":"a5d0509a39803ffb48cae2803cd4f4bd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart","hash":"14ee798b10cb318d96667b32b245f21f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart","hash":"0db5f597f1cc6570937e6c88511af3a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart","hash":"cd0db51c646e4809e09bdeb76ec931b7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart","hash":"790dc5e1e0b058d13efbd42a3f46498e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart","hash":"a11383c33c4fdc8d2cdc091f50d17e93"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart","hash":"6c6dfd5ba4546c1f32201555d6cff215"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/ephemeral/flutter_lldbinit","hash":"4c0c8550624ce117572c484ae3e7d9ce"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart","hash":"5b894ae18be3e2442a34288833184ca9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart","hash":"2ad27cdee5e6fe69626594543bd0e7c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart","hash":"04ad97adf4dc5676764aa8d7aad857f9"},{"path":"/Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf","hash":"e7069dfd19b331be16bed984668fe080"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart","hash":"e4ee21048ab83cc50d61ac3784afa9f5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart","hash":"daa0c9b859ed1959e6085188a703f387"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart","hash":"3fab1c4c90dce6d5451027be460e81fc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart","hash":"de161004250e30098d14049bdf54ce38"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart","hash":"3fd33becc9141d8a690c4205c72c5d40"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart","hash":"ed11d553b999afddfd85ca57540af7d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart","hash":"0e2afa27a9682352d434c10d20ffdc7f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart","hash":"b5d89661ccc877d87e555c5ee9e5ac81"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart","hash":"2458910beb2b4f3b177a7db027cf7d34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart","hash":"e5b4b18b359c9703926f723a1b8dd4ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart","hash":"2a374faf6587ee0a408c4097b5ed7a6e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart","hash":"61dd7991c06ba3bae351fee9a80c64e1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart","hash":"2122907e49766bb1f044ae97841c2b86"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart","hash":"44b3c2a3d6e67a3213a49cce58fed932"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart","hash":"4a73924a7083f5e9d700ada6f2b53098"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart","hash":"110b9903c2673d2ae6f626dee25c45f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart","hash":"bbc7eccdbd8472a2180e0dffce323bb9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/divider.dart","hash":"400da5c3ae6b8c8cf1ad20c796ce413b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart","hash":"9c23e23bd2cb8afe39b51de3545ab2ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart","hash":"98f725d06ba20a1032cb8770d00d7fca"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart","hash":"74708cb40b7b102b8e65ae54a0b644be"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart","hash":"16d2669eba65e0d92613a0aef0a169d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart","hash":"feacc941aea1ec8b3a30601915b7d353"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart","hash":"5061e0737e2db44e82d8a8c12f328a48"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart","hash":"a85856ccbb262dd4c1207418f8bc7801"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart","hash":"7711f4b6c3574cec77169f2d2c35ee3d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart","hash":"a88e90675c4b55522b3e9226f0135237"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart","hash":"02139a0e85c6b42bceaf3377d2aee3de"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart","hash":"3eb1458ae1a271dbe202030d5b8f0852"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart","hash":"e556497953d1ee6cd5d7058d92d4e052"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/page.dart","hash":"c5bf16620e9021a14d7fdd8d605e611a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart","hash":"5d30df9a71208100cd9e649ec1f21f69"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart","hash":"2346472ec1cfdb77f3b27d3b7af72d4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart","hash":"6b6d593e4facdae2c82b9133fa8e69e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart","hash":"aaace37762c25bcd679c2ab09129db12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart","hash":"597d897c972c255ade7307dfcc2e5524"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart","hash":"6566a35ff0dea9376debf257bdb08fba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart","hash":"2ca785b09f831ebde51eca8654fd23b2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart","hash":"325ce403b3634a9c45bd705d91ed31a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart","hash":"eabd3dc33b1a3a2966fa68f6efeb6bce"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart","hash":"6edb3eb5d6e5b289f28ce2fb68047e91"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE","hash":"3323850953be5c35d320c2035aad1a87"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart","hash":"ae1f6fe977a287d316ee841eadf00c2b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart","hash":"a0816d2682f6a93a6bf602f6be7cebe1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart","hash":"026b1fa8f1d7ff0d7c1a6e1afb2e75ca"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart","hash":"ac08cb84358e3b08fc1edebf575d7f19"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart","hash":"b0851d75151b4ad4d87a1443d2041382"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart","hash":"be0a77cf3f0463f3dacd09ec596d9002"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart","hash":"61d7b16669f075a39023fed8967fbdb9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart","hash":"cdef014561140d05b803ce8d9d85e02e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart","hash":"41f7bdb7d1eb3c86c21489902221b859"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart","hash":"3ad1a3d4aae097a927cfef18aea6f500"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart","hash":"5bbe4c9f8221f331ef61519909f5cc54"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart","hash":"a6adbe3868e017441360895c35fd6aa2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart","hash":"d2694042e337ac1f2d99602c25be195a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart","hash":"ceca25b48ef58dff53262c111c0dc9e7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart","hash":"81bf43e01741bf8b9df15ec37ffbc9ea"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin","hash":"693635b5258fe5f1cda720cf224f158c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart","hash":"e40877daa15509fcbd3e465d246dbc09"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart","hash":"24d6b5d55c0b41213c9bb4b2342764f9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart","hash":"be096140df774ec827218c6fe69b80e5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart","hash":"210d4d542d997e93c121b4dc814b95cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE","hash":"83228a1ae32476770262d4ff2ac6f984"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart","hash":"77f6ca8fc03e4edc47032b2817f4f41b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart","hash":"603b7b0647b2f77517d6e5cf1d073e5a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart","hash":"9a12cf2a3549924510006db4651a1743"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart","hash":"3fa7a3bafbab98c305119475eb004a06"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart","hash":"95545fdf17c2014df41408bad8115997"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart","hash":"bbc54fca40953c4a17c12bf45c349c77"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart","hash":"b6a30b7ed48f83f446db37577b30e62e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart","hash":"7c2c3a23031810f7aa97f4d2f016330d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart","hash":"c66e615feaae8abf62893d4eaeef0ed6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart","hash":"16f71d097900371eb87d706863a8469c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart","hash":"97199777cf058b891c9752cda55662be"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart","hash":"09973ba0a94d2d819052c0544dcdce70"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart","hash":"4ba0a4163d73b3df00db62013fb0604e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart","hash":"0f2a1a61119c0bef3eaf52c47a2ebcf4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart","hash":"c0da8171c63f0ab4e822dd094fc2c595"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart","hash":"27c61344ce9c31ab29dff9add7511263"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart","hash":"d3b949a1e7578291493af5fd28846314"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart","hash":"7c07d5cc739ae29abcfbf6343ae84fdf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart","hash":"69be6215ea4781ec3da1e389b321cad4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart","hash":"18223495a47aa96889552c9834042729"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter","hash":"f1c60559f84cf00569963b4e5196015d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart","hash":"0f4b1315998b2d9df09de914c81a7a86"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart","hash":"80eec0865406718828ef0dccff8154ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart","hash":"702f8b87ec7fc125312d9ff64434e7cc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE","hash":"22aea0b7487320a5aeef22c3f2dfc977"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart","hash":"1099a5c5ee8ae0d01e2dd7d07c3edf90"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart","hash":"92e6028556e74c1dc297e332b473f78e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button.dart","hash":"d7a239f8b80f844857527c2012e4fa1c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart","hash":"91e808d781743242114a756dec8f2cbf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart","hash":"8a99afa0c4ef5aabfdf6ef2a4afcc8c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart","hash":"13be7153ef162d162d922f19eb99f341"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart","hash":"3405e08e614528c3c17afc561d056964"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/isolate_snapshot_data","hash":"c8760dd22936a794d8412e15baab1397"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart","hash":"a7424dc75f961325d400c58f0e946ba2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart","hash":"d0911329ae74edbd7f6ad6a89e0703f8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart","hash":"a73883c523a61b1393b5e8c66de884c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart","hash":"6f6fb24055973d0370e30a78ca69db89"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart","hash":"2c582bec6fc77f68c975f84d2252ed8d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart","hash":"a340eddbf129cfd60e2c67db33c6003e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart","hash":"af5377d18db2f18bd4ac0ec35ed7d308"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart","hash":"06455706949396049309d1cc90b76efd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart","hash":"35bf7179f32e4ab5b13e9d9ec2abbe86"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart","hash":"fa0d3415d04242864a0c411fceeaabd8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart","hash":"997f4b4e6bf9981e307f46f08fa90b82"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart","hash":"38e17b28106d00f831c56d4e78ca7421"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart","hash":"9c9f1e70fac06b3e87bb33ece047c4cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart","hash":"596fb2e55b1ff1662e4bd67461fdc89d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart","hash":"cbbb174cb00bf954fdc9e2854517dbd9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart","hash":"72804f9d34b9a247c43d6cc575527370"},{"path":"/Users/downy/flutter/packages/flutter/lib/widgets.dart","hash":"0d4b8c16e7b8e4d8baf6fca9161c7e56"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart","hash":"3ed378957409718f644078da99891428"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart","hash":"21f4467f19bac7f0fe6f0e730ab10fda"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart","hash":"205bb888a773c736206a9f2c84c8fd92"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart","hash":"50062b12181ce59a75a26727cacaf5cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart","hash":"aef544fef0ced7679e0edaf5f8d036b7"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json","hash":"dc3d03800ccca4601324923c0b1d6d57"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart","hash":"121fcbdc1af81a0fd804490f85357fa0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/debug.dart","hash":"0575a78fbb39a292302737868752da77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart","hash":"5fe5b5ed3ec92338a01f24258b6070a3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart","hash":"3dc9f56e0fb2e949ac4c68187162c0a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart","hash":"bbc9542eb5e3c4701c24bc1268b8165c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart","hash":"1e30703fc6d5663dea611a3c783b21aa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart","hash":"aff8f09b64bc316bf514d7a58be4131f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/reset_password_page.dart","hash":"4fe1eb2c4ed0ccec4c3b987f5a9a0adf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart","hash":"0073f703be7f7ddbd7f04d1b740f35c6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart","hash":"62dce337eb5905e15da1113e7ba50806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart","hash":"44d59e37041b6305018f70012fef7d52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart","hash":"d1d1398bda204825136843ad63735067"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart","hash":"866257a42b6b721549b351382b365c47"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart","hash":"9f8b50d98e75350b41d40fee06a9d7ed"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart","hash":"46e577ec532e21029e9cee153d7ca434"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart","hash":"a6350a577e531a76d89b24942fca3073"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart","hash":"bca928191c274201a95a3b9474582b31"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart","hash":"2083695b7b9150b87307af446032ba45"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart","hash":"9beb119d4e1dad544bc4004db5aa3a95"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart","hash":"5843b4750179f6099d443212b76f04a2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart","hash":"c0cf85f80b79542d2b0e1a00547d7310"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart","hash":"ad4f49532706bd4252a8383731d0e349"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart","hash":"a2c7734430a38c6f25a3e99f10aa19fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart","hash":"a2eb984b374f7375264ed4b139a0eb03"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart","hash":"3623c605586d2e37af23d6b746721bd7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart","hash":"3e4d53a860279f33b4e7c6b1d9957a51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart","hash":"b0b28dbb0d6b26d142ff99ecbd5d8187"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart","hash":"135373d55120d14b786fdabe98c9c64b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart","hash":"f209fe925dbbe18566facbfe882fdcb0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart","hash":"4b5d82ddeb09bc46ae0e980616ce0109"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/theme.dart","hash":"4ccdd5e6210285f9baf09909e7d4f593"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart","hash":"a79a6f9bb06c7d6dc5fb74ac53dce31b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart","hash":"1f437276972808bf4cf722440da1b231"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart","hash":"db4a14227247e2524e46f6b0dd9da267"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart","hash":"b09ffd962fcbee7d3403b54155e33047"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE","hash":"3b954371d922e30c595d3f72f54bb6e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart","hash":"0ddbbba088a930cb7ae5b5920ce346cf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart","hash":"f77f6a903d346f842a7fe474e427d6a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart","hash":"ed59d68fc74e5f7be21e0d7fc1c7242a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart","hash":"24094ce9de1b9222a8d6548d3c01045a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart","hash":"9298606a388e3adb5f1bbe88ae45b1e6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart","hash":"e5a3ca065f292c0f0b0cca0a55df41aa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart","hash":"ae85856265742b6237ed0cb67c4364af"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart","hash":"e45c87e4aadaebf7ba449f4c60929928"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/vm_snapshot_data","hash":"b8ee00883037778797bf5949230f40a6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart","hash":"6618a55cdb528b43addda36642363d96"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart","hash":"9e8b56ffe3de97538d012849a1afa5ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart","hash":"4250bd72ef305d1f376e96cc6b994778"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart","hash":"f54f6b61b175b0a37d51ff3ac8b8c800"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart","hash":"a06bb87266e0bac30a263d7182aaf68c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart","hash":"0f70aaa46e42cb439dcc5a21fba00f44"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart","hash":"0fa4800227413041d2699ed47918c7f7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart","hash":"d9d777d58bfe8521d1cee4c60700de58"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/app.dill","hash":"f4091c4ed02e66469c9f3b8a935fe8f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart","hash":"777aca422776ac8e4455ccc7958f7972"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart","hash":"154bcb3658f38871192c3955ebccb00a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart","hash":"3c1bedbe57228c35f8421d813a7237ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart","hash":"1b5af29e062854d33f5e4c81c2bdf11c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart","hash":"458f3bf784829a083098291a97123e81"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart","hash":"229f98ffbc538c9813ef41d9f707f00a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart","hash":"904ebe4c195d2036f989a5e1c3c6052d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart","hash":"6f18c18a1a5649f27b6e0c29dfba4dc9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart","hash":"4c5df57cfe2a6a2bc0d7462330344982"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart","hash":"9c053b0efcabd70996cc27e9d6c9303e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart","hash":"a8c03fde31609e92e69be46cf798cbd7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart","hash":"55675ef4bbddffa94d962bd52b3088ca"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart","hash":"03001d3ddae80bbf1f35c5e70e0d93e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart","hash":"294ddb67f660c73c07b9ec37562840cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider.dart","hash":"1962877d0f77e2d3d7ebadbb093d4997"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart","hash":"9645e1d88d63387bb98a35849f4cbe53"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart","hash":"95bedb83cd5b163e43b554086b016380"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart","hash":"2a10c15764942d10992468122feea62f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart","hash":"4a4e74da2f12d15dddf3cddd0628372f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart","hash":"d1e0e0c2904bd9e5145d919296eeb580"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart","hash":"34a4d340931147322eaddc77fdc65c22"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart","hash":"e1648c3accd2c87d0897e5454a387c3c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart","hash":"c7fd5a3a7f809d37cfe6af2af573d097"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/about.dart","hash":"1a8cf97475fa611bd193041415e8220f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart","hash":"56a59615d1fa716ece6eff8304f7bd34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart","hash":"7592e5df71403552b6109cb4fe946eee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart","hash":"29befe23f841cf5dd2dc7df24c13d88d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/AppDelegate.swift","hash":"303ca46dbd58544be7b816861d70a27c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart","hash":"b29e302994b1b0ea5029734406101b8e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart","hash":"f90beedee11a434d706e3152bfb2fd15"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart","hash":"d857a3ae7f599cc71f41689ffcf1fc5b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart","hash":"6b3b758749ea0e06a43533073febcb66"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart","hash":"8dfd28d2164bbd446b480491aace196c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart","hash":"d74d8acd1490e1db907df61d756d2c71"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart","hash":"b1da6e4c330ab79eb371fb535a8fb7cd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart","hash":"4349dd08c33e677b65d9e00f13c35d2e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart","hash":"de7fb154b9b151b81a78d43ade695365"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart","hash":"66272a6751b167051ba879724cfe5749"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart","hash":"34485853c65233b4daedcede2ade0c69"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart","hash":"951bd729c13e8dd03a7f4edd8b10c06d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart","hash":"5da121a0d3087e7cf021bfcdeb247b77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart","hash":"b266a6c412cb5bbd5355fc22a3be3f84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart","hash":"391dfdeb37052a0c52eb8adbc96bffc1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart","hash":"f7b4c0027cecafcb6711746922663d7c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart","hash":"d74cafcf507b38e3f3094c6d5ed94a9d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart","hash":"9a023a5d9b2c849e9c7fd9e16db1e7e2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart","hash":"d70df86ce471e8470438627a65b2824b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart","hash":"75f947f0ba87a0789a3ef91542bbc82c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart","hash":"fe766313e73046aa145217de64ca7760"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart","hash":"a056a48864751b648133bf4d0886134a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart","hash":"8a39bdc324d0ff25097784bd98333c08"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/chip.dart","hash":"926a78bbb0d20acd22028c14ca8b8071"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart","hash":"91d8303ca1ccc72eccc1ae636c7825ed"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart","hash":"bf6d84f8802d83e64fe83477c83752b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart","hash":"44c1268c1ecafd3b4cd06ab573f6779a"},{"path":"/Users/downy/flutter/packages/flutter/lib/animation.dart","hash":"29a29ed9169067da757990e05a1476ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart","hash":"3167bedcdf6eb73bb3355fc778c69ab2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart","hash":"a6c467b3086118863463a925df22d187"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart","hash":"2675cdf47e408031206cc9c215200004"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart","hash":"36bb3dc8435f5085b78c2972f8efe90d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart","hash":"79cb5cb16bf09b65cc08e5ecd482668f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart","hash":"8d05e0330774daca2ab93f307ded78f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart","hash":"12143f732513790cd579481704256dcd"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/signup_page.dart","hash":"297f13bb091ef12bc666475e3618557c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart","hash":"c7cc72c1e40d30770550bfc16b13ef40"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart","hash":"6efba60755f63ff2efc82c76d3a50222"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart","hash":"1f131d7f971396d52ce5fe78ae6a8a83"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart","hash":"1268762fa54412a0d265cb57a14cba84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart","hash":"19c24981d3d862f7206e587073eaae67"},{"path":"/Users/downy/flutter/bin/cache/engine.stamp","hash":"f41d9e32b73e3888e8d66a99b615a8d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart","hash":"d33374c0857b9ee8927c22a5d269de9b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart","hash":"6486bc074c81ec57bdafc82e6a64683a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart","hash":"08c3fd9ed1607d3a707ffe9b3532218a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart","hash":"7e45468116224ee318aa9b1f210cab12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart","hash":"bd6d122c12d867a991bd2fd36a3c46a8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart","hash":"cc6cce102fab186d0e7a063d0d917504"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart","hash":"06078529e4523830f3ad70e0aab603d0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart","hash":"77900a31d721da1722fe34c455a00d3f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart","hash":"f487ad099842793e5deeebcc3a8048cb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart","hash":"bc3c12f9555c86aa11866996e60c0ec9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart","hash":"73d5607bd6f5dccf91add39e25ad157d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE","hash":"2d0c70561d7f1d35b4ccc7df9158beed"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart","hash":"eaf5aa7cf4fe19db30724f637b38257a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/App","hash":"743e364be5d8ff4991c8fa1ed02b7065"},{"path":"/Users/downy/flutter/packages/flutter/lib/semantics.dart","hash":"4b784d6e4f290bd6d5a1f38bfb5701d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart","hash":"c761b80666ae3a0a349cef1131f4413d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart","hash":"f5b38c21bf580c89610a8b58c65aae00"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart","hash":"3d71d8940be022672282ed70f0cbb8c6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart","hash":"8ac28b43cbabd2954dafb72dc9a58f01"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart","hash":"6cae6900e82c94905cc2aaefd806f8eb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart","hash":"f949f49484067589ef08e13a892f3101"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart","hash":"0fbec63144acf1cb9e5d3a3d462e244b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart","hash":"ca959e5242b0f3616ee4b630b9866a51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart","hash":"e3127548d819af5ec9ecb10b5732b28e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart","hash":"e9a141d0ed4d585b165b7fcacc3874d1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart","hash":"dc667b5b278c7b8a2191913ac49e33d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart","hash":"eafe83db9186e4fbb802d857e4bb42ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/binding.dart","hash":"064a460171599d3d2a4596a5d1ea2b00"},{"path":"/Users/downy/flutter/packages/flutter/lib/material.dart","hash":"79c87aaef3dd490ff1c43fad2f2f6e8e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart","hash":"ff5d66c50ec833a263625d39f0c195b9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart","hash":"f6d7d6477016f1f991e57b2cbeef7292"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart","hash":"8fde18d2ef5c741e3b748bbc854d6b17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart","hash":"58feb628edda8670acd9b4c4db589918"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart","hash":"20051c4912af535e0a8362fb1e93f423"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/Info.plist","hash":"3e84ffd77b8e1d46de0dec59f05dfec4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart","hash":"207aa61e81c77c54342772a6367af334"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart","hash":"5de15d7a41897996ef485c087ef4245b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart","hash":"9ad11b4bdb179abe4ccb587eb0e2aebc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart","hash":"56e9b43aa79d6b888e779ad7905c1617"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart","hash":"4d6c8c8185327af9d064a1fbeab18fa1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart","hash":"fda1d4b1be4a584133638117945d3dff"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart","hash":"b698617b81ba534ca60cdb6dee762fff"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag","hash":"a0e89676ccae6cf3669483d52fa61075"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart","hash":"4935fd96677780d631f23a75e7009534"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart","hash":"0672d853d5097a03eddc7dbe558eeabd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart","hash":"43ef2382f5e86c859817da872279301e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart","hash":"d4252f423175e5c21fca23dc24154b84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart","hash":"6f02e150859b1047ec04ffa4a924f90a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE","hash":"175792518e4ac015ab6696d16c4f607e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart","hash":"f56109c40e6fe9e53f9c6ad021d25ff5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart","hash":"2aec07fe4a1cd25aa500e5e22f365800"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart","hash":"605dcc1d6bd5023fc0b651a625076ca8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart","hash":"5176206f3155513053dda23b0c32fc8c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart","hash":"edd2f9cabffc7ea6a5a9497a1b1beccd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart","hash":"986845a7043505c19753e1d499d49a4a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart","hash":"ab177cf671fb7bab974d9c08618a677c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart","hash":"c9cd996cea2334f644c74ebbdb41f7f5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart","hash":"270de9c98f9c1284da0a6af9176ee1f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart","hash":"920b63c794849c8a7a0f03f23314bbb1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart","hash":"dc2cfe4408f094916cd5eb1d294d1f2f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart","hash":"289e5bbf4975b43a1bc7510306854b34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart","hash":"d161560a01cd02902c87f5decd590cfa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart","hash":"e79db1a382e61436ed81f9f47dc06d7a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart","hash":"1542c76e7b3e366d393fcb2c3bc601d5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart","hash":"89b2bd5c8fc199b582eb9f10973f97b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart","hash":"92868012710ac163590ba05c788c0816"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart","hash":"555fcdeebbe6517cde1cdd95133cabd7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart","hash":"c4d13715583d2c97acba184a3e821151"},{"path":"/Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE","hash":"4fd63b752aa4c209c7c0bdd1ee5f8a10"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart","hash":"1205ed5e14a59c237c712b8a495b1981"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart","hash":"73189b511058625710f6e09c425c4278"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart","hash":"53d7a28895126d1b4c472405e2876fb0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart","hash":"8a60b4ed49f146296d6896973154e1d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart","hash":"3cddcab8b952545bc05a5c1475a06c9d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart","hash":"85cf42bafb7c0646bd7a99379649da29"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart","hash":"9ffd4af5e11781c62ed4e40fdf15b182"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart","hash":"269af8ca7030ccfd9c868fe9af8a6b0a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart","hash":"ed5548873fcf5a0a5614fc52139600b8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart","hash":"7ebcf3ce26dea573af17627d822e9759"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart","hash":"965c702e5f0b6ba27c6292cf3a602781"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart","hash":"d3eb6373e2fd626717b8de7cbf19cd8c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart","hash":"b3a6dd250e09b61bffbc04a767f0c920"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart","hash":"3c8d2d2b73f69d670141d376642e5252"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart","hash":"6a612ac4de579506fd1b806fac3fe062"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart","hash":"78f6899dd22a8086e573217b5538f98c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart","hash":"59b6b74779849bf5b836b84bb362b99b"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/common.dart","hash":"b9127267cdd2de6c1285a11eac48d269"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart","hash":"546a4af6d99fa77922a881e2f131c1f3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart","hash":"553c5e7dc9700c1fa053cd78c1dcd60a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart","hash":"f3d29b37515ed98685cd81aa319dd254"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart","hash":"5577ef7cd41e467cc247a42b677f93c9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart","hash":"79c35fba64a91629072a76526adb9aa7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart","hash":"107c33a245427bf0f05e21c250653dc6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart","hash":"6be1e6f404dc5206ea2b4fa512c45dc3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart","hash":"de17df889317f7a54961ea540cf4b807"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart","hash":"8b15d222f5742b46bf55a4ef4cbfd6e0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build_result.json","hash":"1f8e8e6dbc6166b50ef81df96e58f812"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time.dart","hash":"872d879ea43b6b56c6feb519cc12d5a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/colors.dart","hash":"f59aed120736d81640750c612c8cfe5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart","hash":"f94061e9a635be75dd8e38eab352c344"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart","hash":"ef5fc00d685cd2a36c4de80e1c7e3a8f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart","hash":"ea7c9cbd710872ba6d1b93050936bea7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart","hash":"85b908f2e50b980d5cab7f458371f430"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart","hash":"1fd7c932679011d491315ff136d13822"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart","hash":"15a20afe634cea8448869b051ad52b3c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart","hash":"cc4a516908b08edff4fade47d6945e5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart","hash":"d7a6c07c0b77c6d7e5f71ff3d28b86bd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart","hash":"4da7ecc08c07abdd0226004f30973748"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_verification_page.dart","hash":"e0f27f61afff2be10976874908f57d03"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart","hash":"785eedcc96fa6a4fcc7c81a8736a7427"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart","hash":"3ee18da390e16ca65f2ef168adb8a1ef"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart","hash":"c679063104d2f24639459c8ab3eed77a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart","hash":"cf63ef7fb2873f43a2b2e25485734429"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart","hash":"1e2afd780c32baef8cedd0eb9c4dee6d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart","hash":"faf4d014b3617ede3150f80eba25e3b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart","hash":"12580e996c5cb68c4e80588f6dd9f235"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart","hash":"cb49e0d1c096a600c37190f5a40cbecb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart","hash":"6d0b38802aff8cbe310e72f1a62750d6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart","hash":"9ea1746a0f17f049b99a29f2f74e62ee"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_page.dart","hash":"5dce658426051f256e8d8d07ba4d5a8d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart","hash":"36fc598c656490ab430ca1be5fb909e8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart","hash":"f6c6b31745eec54a45d25ffe6e5d7816"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart","hash":"38fcdd2be2a4d0ecbbe01cc03cd03e96"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart","hash":"a74b5a39115ffd608a19cad9309e6a31"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart","hash":"838c8a1a376a7c9c3fb3424927bcc75e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart","hash":"4eede9144b4c0e4b14bd426654183174"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart","hash":"c3ccb5b6cd3df44e6587a4f04dd6a4e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart","hash":"d2372e0fb5a584dcd1304d52e64d3f17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart","hash":"e6467427260f3274e8424d691615ca5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart","hash":"e4a32acbcd5da5e636d429dc167fc5f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart","hash":"b39287c180e3ac3047fc5dba3a44a524"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart","hash":"bf50f61746b9744a0e2d45a88815288f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart","hash":"9f5e8439ef3cbfa84f76922ec3580363"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart","hash":"47ccb32c843b4075a001e612853b2a31"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart","hash":"632d3c730c9b6e4f46d9c0459c53ca9c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart","hash":"58678829e383937c51f539f2ad67fc17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart","hash":"5aa51467523e637443dec44f6c7b1e6c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart","hash":"a2350d9426fefa6d657868d9e59eac7b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart","hash":"9434ff8aa06e13d5981ed6ec15eceb64"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart","hash":"87f0b72f24e05d2d3f4b0f1b4709eb51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart","hash":"3ee6304161ca2993b303a8074557fe66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart","hash":"2d2cd1fbe11b3e587475449fa04ad4eb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart","hash":"85814d14dae3bc1d159edd0a4bef48e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material.dart","hash":"5c93305f52983c3f2be825bf54ebbd78"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart","hash":"89aeee125822690cbd46b2ff43c76ec1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart","hash":"5d8e29422039d9dcce6908b427814d80"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart","hash":"cad4582fa75bf25d887c787f8bb92d04"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart","hash":"900a13c9fcd73f4e8e3d069d76af6ffa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart","hash":"b1bb8356cca8b86afca314ab4898a527"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/App.framework/App","hash":"1cd3604d8ff6e3f6caf4c32361dd63f9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart","hash":"67d16e841606c4e5355211fe15a2dbfd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart","hash":"c8f69577793923bfda707dcbb48a08b1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart","hash":"3431f50e7abf9e27af232de10193931a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart","hash":"11fc97acd20679368ae2eaa698c6f130"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart","hash":"74939c971de1eb61ef05a7eb5056cc20"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart","hash":"a3bdbf775c61477db47c508f513688e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart","hash":"075310a7fe661b71e9a583aab7ed4869"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart","hash":"c069ad8b31e18adb75c27530f218957a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart","hash":"787093e38fffbbd356129a373907124c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart","hash":"b78c67723942ac5480c158576c1247e3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart","hash":"62f852a5f85345e608cdc7b62a689202"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart","hash":"fe2489ea57393e2508d17e99b05f9c99"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart","hash":"484481ff93d08a930ecfcf6907acf691"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart","hash":"8e286948f2eaa63514196c1e4c91666c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart","hash":"d72a4ddaf6162d8b897954e02b4a2a4c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/status_bar.dart","hash":"14cbcec8bf62556f14de5f0a8801305c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart","hash":"0ae47d8943764c9c7d362c57d6227526"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart","hash":"63db75c602690371aef0f83279a929d7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/curves.dart","hash":"4aeb4635d84df42e6f220aba366af7d9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z","hash":"05b316ee5958e4f6365d52d5cc65cdbb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart","hash":"ee36aadc3fac54d5659c94c6aadcd007"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart","hash":"db799bf48af97b7c0edc93ad96b4a6da"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart","hash":"34ebb85f7f2122d2e1265626cf252781"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart","hash":"187e3c5f97da92aa1a41087435aa42d3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart","hash":"dd510cd97dc23d22aebc7b60affd6329"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart","hash":"eb9b3bf513b18ddaf0057f3877439d9b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart","hash":"42212bb3508502e1b011bd783d51ea78"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart","hash":"6987c3474a94dd1c4ff8f8540212f16b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart","hash":"8d0306ecedceab52f23b17a0694e7842"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart","hash":"a2aa815908f2e15493e374b9380e558a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart","hash":"78ce7527fa364df47ba0e611f4531c2c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart","hash":"377fef989628d5fbcb306e46a03b7a12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart","hash":"fe750f835c7dc27ef38ee2fdb486a6ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart","hash":"d390b15ecef4289db88a4545e359bc8a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart","hash":"816a5cf300a6461fe2e7e8ca8a66a709"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart","hash":"f8275b74f8f83272b8a8d1a79d5b2253"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart","hash":"4e04af41f89adf9231bad1579f5bb9a1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart","hash":"77e3a9ed54e0497465a4346f273bcccf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart","hash":"8dea906a9b8773920b6d1ccea59807bf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart","hash":"97c7266e528b6f706b08b4ad340006d2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart","hash":"200da5ba0b0cee2bca1acd1c4d772118"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart","hash":"4c09fb1ea4651f47d1a0a67ba3b31886"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart","hash":"4c13b34211e2b17645a6a5cd8defbe0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart","hash":"04451542afc67a74282bd56d7ee454f5"},{"path":"/Users/downy/flutter/packages/flutter/lib/painting.dart","hash":"4bd60bd8ede4b9dad954493d26d3e586"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart","hash":"43ba7557388f413902313df64e072389"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","hash":"b93248a553f9e8bc17f1065929d5934b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart","hash":"b4ab536e0cb6945296bb962bc1e9a3f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/services.dart","hash":"29ae1507a6ec4c2ffae469a10e505bda"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart","hash":"cccaa1a390453623404ad2f98ba719c9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart","hash":"32f33f52f1a1e1b0911dbbfa4dd7785a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart","hash":"14acfddcb9e62f0de6f82d28e22c22f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart","hash":"2d18e0064b57f514fab5c3abc06ace0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart","hash":"cd3f0ebbc282b839928f5fe3ad12c779"},{"path":"/Users/downy/flutter/packages/flutter/lib/scheduler.dart","hash":"95d8d1f6a859205f5203384e2d38173a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart","hash":"29439c1f30cb2958458664e1e6e40289"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart","hash":"51fa10cf30bde630913ff4c6e40723ba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart","hash":"31d8245447d51dba20c81f00b214fb36"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart","hash":"c6da76a71962267cab91aadde5b59426"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag","hash":"6cd606d3e368485de4ee213b4887f8a0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart","hash":"f7b9c7a2d1589badb0b796029090d0d5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart","hash":"df699735e3bcd730f16ce377d562f787"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart","hash":"984acd55714db5ebfdcab5aeb55467fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart","hash":"81d01d8cecc6783526e350800988db74"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart","hash":"18ad2d48b68dc9b514fde418b7acb599"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart","hash":"cb0d5b80330326e301ab4d49952b2f34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart","hash":"f01b78dd243cdceae98d62e7429f3d04"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart","hash":"40587a28640d3c90ad2e52fdfbcd7520"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart","hash":"9eb1b00e42fadb0be56354c8bc9feb4c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart","hash":"f12f9a9b8bb504f4617bfd1c00d403f0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart","hash":"f301af2d0392296f456363085becbf47"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart","hash":"8fa0c1ec158277156da896110a03d968"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart","hash":"a0936682931bc884c5052e9f49bf8829"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart","hash":"aad5ba4c4076b74ded1d769dc1edbceb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/badge.dart","hash":"134441e2b4b42a7b2ee012ce48910557"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/AppFrameworkInfo.plist","hash":"3e84ffd77b8e1d46de0dec59f05dfec4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart","hash":"e76d7da2d8f4281119d176fdcc04b991"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart","hash":"063f2360bd47faba2c178ce7da715d92"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart","hash":"b7b71e22b53d4d100702d2ba7a7130db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart","hash":"5b04f80518a8417cb87a0aec07dacf4f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart","hash":"dc196a3f1d514347c5f7da6e197b384d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart","hash":"393c6d8b9c1a038b62a418fadf8c69c9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart","hash":"5b98d0be4d89f1274c832a4c340ab315"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart","hash":"af709d56567f1923ade761542e8dd796"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart","hash":"600a92f02eb307032e6cedc6c5f104f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart","hash":"6c0e97a3b04c9819fe935659014f92e8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart","hash":"f49291d1bc73b109df4c162db10003d2"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/native_assets.json","hash":"f3a664e105b4f792c6c7fe4e4d22c398"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart","hash":"1fc94d5523beb1dda68dd704b8f99bd8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart","hash":"53b9028402187f878713225b48bdd5bb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart","hash":"f60846aa76dab98607aa06c9bd6cf1dd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio.dart","hash":"1e0f99d28825c416ceb5f264b6af7fdc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart","hash":"fa2a57b3b873fb7db4b8b961735e4ca3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart","hash":"e4da90bb20b3980a03665a080c87a098"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart","hash":"21e56afda1f096f0425a34987708ed56"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart","hash":"0976264b99a1702a5d74e9acb841b775"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart","hash":"6a9dc1f0e0e14fc0ef5efb4c3c1e8a77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart","hash":"5be90cbe4bbf72b0264413e4ccb5c275"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart","hash":"a64e270c19c9e9ed0c5d9a17e0c4a5d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart","hash":"04c960ae6d770135bb0b6acf14b134a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart","hash":"622fb5559ef551a734f0ebae8660485e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart","hash":"1d8fa1cee64f2d791002749fabe23e2e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart","hash":"547eac441130505674f44bf786aee606"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart","hash":"625b4ed63675ca8ffe8c11d0469bdd9f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE","hash":"3c68a7c20b2296875f67e431093dd99e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart","hash":"617fb0bcef7162a860ca76636507117f"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","hash":"0864ad73108959b573b007ab6025d731"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart","hash":"83fc222e671ddaa7fdb3868c0acaba0a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart","hash":"d828c4334e98a12974d90e38d48db9f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart","hash":"d67712d7f3394870d88650dc0baf5855"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart","hash":"aaf8cbac74b7b5a3a487d5ddfc2bcdbc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart","hash":"73f043194b9c158454e55b3cafbdb395"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart","hash":"2a08c219491feeb1c8e9b9d492ffce44"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart","hash":"cd6b036d4e6b746161846a50d182c0b5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart","hash":"bf365ded028510087ed69c227bda0d52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart","hash":"a36981329a77de46168efd089c4102e2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart","hash":"38570a2af41c2f9a4632e2af3b42ffe7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart","hash":"2b2a74f1e45f48fed04eab35ae3c85d7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart","hash":"7cbeab73e95bd7561ac8b9519c579ffb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart","hash":"8cff8c004f57019314d3fe8176de4043"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart","hash":"56a764067b45a1a7cb6b7f186f54e43a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart","hash":"13c9680b76d03cbd8c23463259d8deb1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart","hash":"dd518cb667f5a97b3456d53571512bba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart","hash":"b15a3573191a80dfb78fd6a729390c0e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf","hash":"e7069dfd19b331be16bed984668fe080"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart","hash":"c83781cf0c38883486f707cddbb96773"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart","hash":"374ee130942948f52e47681818bd315e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart","hash":"5c9195780e56985cc88956aab0887ab3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart","hash":"25dd0d36ba8109e3199faf508b41d633"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf","hash":"b93248a553f9e8bc17f1065929d5934b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch.dart","hash":"721c2d087f423a3293f5314804ae66a5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart","hash":"0d8aed1407088c73788f25ffba071cc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart","hash":"49f335e51e1a6242ba8ab55b48de9d92"}]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/App.framework/App b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/App.framework/App new file mode 100755 index 0000000..697eaf1 Binary files /dev/null and b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/App.framework/App differ diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/IssueLaunchRootViewControllerAccess.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/IssueLaunchRootViewControllerAccess.stamp new file mode 100644 index 0000000..5cba3c0 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/IssueLaunchRootViewControllerAccess.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart","/Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/AppDelegate.swift"],"outputs":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/app.dill b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/app.dill new file mode 100644 index 0000000..38d4298 Binary files /dev/null and b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/app.dill differ diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build.d b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build.d new file mode 100644 index 0000000..d34d527 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build_result.json: \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build.stamp new file mode 100644 index 0000000..08f99a4 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build_result.json","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build_result.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build_result.json b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build_result.json new file mode 100644 index 0000000..0d218ca --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/dart_build_result.json @@ -0,0 +1 @@ +{"dependencies":[],"code_assets":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_ios_bundle_flutter_assets.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_ios_bundle_flutter_assets.stamp new file mode 100644 index 0000000..793416e --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_ios_bundle_flutter_assets.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/app.dill","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/App.framework/App","/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/tools/shader_compiler.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","/Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/Info.plist","/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/AppFrameworkInfo.plist","/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf","/Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf","/Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/native_assets.json","/Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE","/Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE","/Users/downy/flutter/packages/flutter/LICENSE"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/vm_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/isolate_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/kernel_blob.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/App","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/Info.plist","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_ios_lldb_init.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_ios_lldb_init.stamp new file mode 100644 index 0000000..5100359 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_ios_lldb_init.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/darwin.dart"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/ephemeral/flutter_lldbinit"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_universal_framework.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_universal_framework.stamp new file mode 100644 index 0000000..f809c2e --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_universal_framework.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/App.framework/App"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_unpack_ios.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_unpack_ios.stamp new file mode 100644 index 0000000..a6e77ca --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/debug_unpack_ios.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart","/Users/downy/flutter/bin/cache/engine.stamp"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/flutter_assets.d b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/flutter_assets.d new file mode 100644 index 0000000..dd83375 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/flutter_assets.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.json /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json: /Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml /Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/Info.plist /Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/AppFrameworkInfo.plist /Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf /Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf /Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/native_assets.json /Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE /Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE /Users/downy/flutter/packages/flutter/LICENSE \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/gen_dart_plugin_registrant.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/gen_dart_plugin_registrant.stamp new file mode 100644 index 0000000..b2a917b --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/gen_dart_plugin_registrant.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/gen_localizations.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/gen_localizations.stamp new file mode 100644 index 0000000..1b2d28c --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/gen_localizations.stamp @@ -0,0 +1 @@ +{"inputs":[],"outputs":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/install_code_assets.d b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/install_code_assets.d new file mode 100644 index 0000000..b5d3c61 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/install_code_assets.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/native_assets.json: \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/install_code_assets.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/install_code_assets.stamp new file mode 100644 index 0000000..3d8f73a --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/install_code_assets.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/native_assets.json","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/native_assets.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/kernel_snapshot_program.d b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/kernel_snapshot_program.d new file mode 100644 index 0000000..12f4d61 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/kernel_snapshot_program.d @@ -0,0 +1 @@ +/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/app.dill: /Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart /Users/downy/flutter/packages/flutter/lib/material.dart /Users/downy/flutter/packages/flutter/lib/services.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/about.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/app.dart /Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/arc.dart /Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart /Users/downy/flutter/packages/flutter/lib/src/material/badge.dart /Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/banner.dart /Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/button.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/card.dart /Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart /Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart /Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart /Users/downy/flutter/packages/flutter/lib/src/material/colors.dart /Users/downy/flutter/packages/flutter/lib/src/material/constants.dart /Users/downy/flutter/packages/flutter/lib/src/material/curves.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/date.dart /Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/debug.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart /Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/divider.dart /Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart /Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/material/material.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart /Users/downy/flutter/packages/flutter/lib/src/material/motion.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart /Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/page.dart /Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart /Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart /Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart /Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart /Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart /Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart /Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/search.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart /Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart /Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart /Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/material/time.dart /Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart /Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart /Users/downy/flutter/packages/flutter/lib/src/material/typography.dart /Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart /Users/downy/flutter/packages/flutter/lib/widgets.dart /Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart /Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart /Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart /Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart /Users/downy/flutter/packages/flutter/lib/src/services/binding.dart /Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/debug.dart /Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart /Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart /Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart /Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart /Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart /Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart /Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart /Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart /Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart /Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart /Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart /Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart /Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart /Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart /Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart /Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart /Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart /Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart /Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart /Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/login_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/signup_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_error_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_verification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_result_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_error_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_verification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/reset_password_page.dart /Users/downy/flutter/packages/flutter/lib/cupertino.dart /Users/downy/flutter/packages/flutter/lib/foundation.dart /Users/downy/flutter/packages/flutter/lib/scheduler.dart /Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart /Users/downy/flutter/packages/flutter/lib/rendering.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart /Users/downy/flutter/packages/flutter/lib/animation.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart /Users/downy/flutter/packages/flutter/lib/gestures.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart /Users/downy/flutter/packages/flutter/lib/painting.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart /Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/status_bar.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart /Users/downy/flutter/packages/flutter/lib/semantics.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart /Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart /Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart /Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart /Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart /Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart /Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart /Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart /Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart /Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart /Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart /Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart /Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart /Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart /Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart /Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart /Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart /Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart /Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart /Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart /Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart /Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart /Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart /Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart /Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart /Users/downy/flutter/packages/flutter/lib/physics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart /Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart /Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart /Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/kernel_snapshot_program.stamp b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/kernel_snapshot_program.stamp new file mode 100644 index 0000000..d7d9ca2 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/kernel_snapshot_program.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/common.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart","/Users/downy/flutter/packages/flutter/lib/material.dart","/Users/downy/flutter/packages/flutter/lib/services.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/about.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/arc.dart","/Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart","/Users/downy/flutter/packages/flutter/lib/src/material/badge.dart","/Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/banner.dart","/Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/card.dart","/Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart","/Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/material/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/material/curves.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/divider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart","/Users/downy/flutter/packages/flutter/lib/src/material/motion.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart","/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/page.dart","/Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart","/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart","/Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart","/Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart","/Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart","/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart","/Users/downy/flutter/packages/flutter/lib/src/material/typography.dart","/Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart","/Users/downy/flutter/packages/flutter/lib/widgets.dart","/Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart","/Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart","/Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart","/Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart","/Users/downy/flutter/packages/flutter/lib/src/services/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart","/Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart","/Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart","/Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart","/Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart","/Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart","/Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart","/Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart","/Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart","/Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart","/Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart","/Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart","/Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart","/Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart","/Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart","/Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart","/Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart","/Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart","/Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart","/Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/login_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/signup_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_error_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_verification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_result_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_error_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_verification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/reset_password_page.dart","/Users/downy/flutter/packages/flutter/lib/cupertino.dart","/Users/downy/flutter/packages/flutter/lib/foundation.dart","/Users/downy/flutter/packages/flutter/lib/scheduler.dart","/Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart","/Users/downy/flutter/packages/flutter/lib/rendering.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart","/Users/downy/flutter/packages/flutter/lib/animation.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart","/Users/downy/flutter/packages/flutter/lib/gestures.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart","/Users/downy/flutter/packages/flutter/lib/painting.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/status_bar.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart","/Users/downy/flutter/packages/flutter/lib/semantics.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart","/Users/downy/flutter/packages/flutter/lib/physics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/app.dill","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/app.dill"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/native_assets.json b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/native_assets.json new file mode 100644 index 0000000..523bfc7 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/native_assets.json @@ -0,0 +1 @@ +{"format-version":[1,0,0],"native-assets":{}} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/outputs.json b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/outputs.json new file mode 100644 index 0000000..39983c2 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/35d5982584e852f462f5cbd0f0d73cf9/outputs.json @@ -0,0 +1 @@ +["/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/ephemeral/flutter_lldbinit","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/vm_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/isolate_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/kernel_blob.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/App","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/Info.plist","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json"] \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/.filecache b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/.filecache new file mode 100644 index 0000000..1010997 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/.filecache @@ -0,0 +1 @@ +{"version":2,"files":[{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/cache.dart","hash":"27e508023821ad3aadd30156d20a229c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/typography.dart","hash":"d4335eeb3dd8ee5df4498661b368ebea"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/types.dart","hash":"f4d93b039bc86c4a156848d06fbc2917"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart","hash":"c93eab1631a5606c8ba301346fa8e483"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart","hash":"72b6519b69dfbf0f2959b7e590bea0bf"},{"path":"/Users/downy/flutter/packages/flutter/lib/rendering.dart","hash":"4bd3950a0bf4a9f9b09f97594e363d36"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart","hash":"32a40215ba4c55ed5bb5e9795e404937"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/digit.dart","hash":"fc5bd8041afab0229dff18f2011a51a5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart","hash":"648a6cdab2fd44688152ab1b016e5e9c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/builder.dart","hash":"edd1157c0a6badd18824781de14280e6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart","hash":"d6f045db9bd5b72180157d44fee9fbfc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_read_buffer.dart","hash":"fd517e61edeaf09f9e4cf9e9ba8af13c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart","hash":"ea5bbc17f187d311ef6dcfa764927c9d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/LICENSE","hash":"e8b32b6d7c1328dfb1968caef8249452"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_page.dart","hash":"40bd83521b764e8bc5f3a8acf5e60f9e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE","hash":"d2e1c26363672670d1aa5cc58334a83b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart","hash":"54c7f23362a7e78be04b113d00022090"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart","hash":"38861aee0e2ba92ec8005a64746c0d10"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/timeout.dart","hash":"6665bae4ddca65609834735a7f24c95f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart","hash":"3d925b9cf0a12dd519256aa23a4e3512"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/resolvable.dart","hash":"f7329cc0811af555900320e49bd9686f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Home_selected.svg","hash":"f78d02a831d5135b07c39aaadc50bfca"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart","hash":"61137458bbcab0dfb643d5d50a5ae80f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/intersection_result.dart","hash":"0cd5a938f3a3bf96aa0d7353906eace6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb3.dart","hash":"ec3a274c8e6537ec92c8d5f877a670ae"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart","hash":"732535ba697d95c80d1215c0879477f1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/exceptions.dart","hash":"ad84ac2c0607f2ca46d74eb0facbca3f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/debug.dart","hash":"17fec0de01669e6234ccb93fc1d171f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart","hash":"ed28f6ca17f72062078193cc8053f1bb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart","hash":"954effbd324f486a6948427c605454e8"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/main_navigation_page.dart","hash":"8f154668e618c75d3821a005aba27a4e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart","hash":"aed826e965e4aa2fdb3466d39e33d824"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid_windows.dart","hash":"659cff14f1665a31dec63407d7839624"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/sphere.dart","hash":"8b2f2f630b059eae09aa7e46fc3137b2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/map.dart","hash":"822f0a79dfd6a3c997d2b898ec420b97"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart","hash":"4a7b03b0c037b260c1a321f7aaa8b6ff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart","hash":"7504c44d1fa6150901dd65ec78877be0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/method_channel/method_channel_file_selector.dart","hash":"331caab132b93f55efc7e79e6849c229"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart","hash":"608be960e670661114e97b498d6a6473"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/loaders.dart","hash":"69d071a3792f36aaf595067b248c5952"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart","hash":"9b61320422b3f577a77f50badebd040f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart","hash":"d69cd05d9de1731242d357de56893a6f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspect.dart","hash":"1d43aa18b7cd09879287a4e8ba5ea5ef"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart","hash":"6a8aecb412af6e981bc3d4817b82f7d2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart","hash":"38c93c95cb266619fd6cf7de928884db"},{"path":"/Users/downy/flutter/packages/flutter/lib/foundation.dart","hash":"84939e70d6b7b36e8098dd0cda8cbb2a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart","hash":"eca4f0ff81b2d3a801b6c61d80bc211c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart","hash":"5ee4b9f196c81041c45d27e3b2d33d88"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/location.dart","hash":"17db713e9a12494613ca23ad84def9c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart","hash":"ce4bfd9659d667457cc3ada513fae71e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_app.dart","hash":"209399f0e6f16675c3f087b8eb17087b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/optimize.dart","hash":"ebd9dcbeebab7ad717e6f7efb6a47f0f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quad.dart","hash":"375711cedfc8dfb78018a282ba880296"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart","hash":"008b3ea4691331636bbea9e057357ceb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/retrieve_type.dart","hash":"299d2603043fd7b764e47fb1829b6175"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart","hash":"ef1ff22066328de1e83b8180592a470f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/initialization_settings.dart","hash":"84dbd0aa38844da5b7a683c754582df9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_2.dart","hash":"312e69b666cc1e860274006e86688bf9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart","hash":"d98495bcbc301290a10e6d1dfc255d69"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart","hash":"fb2be6f27b32bb1ab12dd6aea8c5ecda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart","hash":"c02d47d7f7e95654d3eb9b795e416dda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/firebase_messaging_platform_interface.dart","hash":"feb2a618792357be2682e61fdab02d6a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart","hash":"f5e7b04452b0066dff82aec6597afdc5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart","hash":"92901585628d81f7bb3d578fd6d6657d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart","hash":"83bb40406ac73bcd194c621137ed0349"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/colors.dart","hash":"07fa95aca6c82e2f15c0007388cef3a6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document.dart","hash":"8fd257a17e57f8c7a9e9c3c5d77df78b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart","hash":"f45f530a8be1596d7ffd25719c66c87e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/named.dart","hash":"7d9a75e0bd8e5c9b49ad6c0816666b4a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/LICENSE","hash":"d2e1c26363672670d1aa5cc58334a83b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/list.dart","hash":"69c4980a512a91477aa1a6289583342b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart","hash":"6cf1ca324535366e2ea214049ffc9918"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/LICENSE","hash":"619f69d64af6f097877e92ac5f67f329"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspectable.dart","hash":"a8d03ee07caa5c7bca8609694786bbf0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart","hash":"3d892f04e5e34b591f8afa5dcbcee96d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build_result.json","hash":"1f8e8e6dbc6166b50ef81df96e58f812"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_unselected.svg","hash":"dee348e2202f671e34773695f6a38cc8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart","hash":"f7bbc690baa3db88e9a15522b9c2f139"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart","hash":"62e0b7dc1550fd71644c5cc94797eee1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart","hash":"056355e344c26558a3591f2f8574e4e5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart","hash":"0938e0447f447ceb7d16477a0213ce2c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_visitor.dart","hash":"61e938fe770ed7331e39f1dda1b64dd4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart","hash":"094b2c03ad4e0ef5bc1144e281142b2e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_core_exceptions.dart","hash":"bc949707cfd60ff573b48a27b02f6756"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_success_page.dart","hash":"d1d30b68037cbdc2e7f022540303e5ef"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart","hash":"7692ca5e3a50523edceb59e80a6205a1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart","hash":"1dab3723527db6a19410ed34b6acaeed"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart","hash":"2ff3d9ddebd8dd6545b4ef0dfaf76184"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart","hash":"10cb76c02997cab59c925fe8bfbfd8f1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart","hash":"ebafc07567edebe5e176f39360b09f52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart","hash":"481e435dd11c202a9d2293db5b58b179"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_buffer.dart","hash":"22acb270c1bb267ee16b3d64a3faa825"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart","hash":"fb76e9ed5173ac1ae6a6f43288581808"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart","hash":"63ea4f418d2305e0cf2c18a773821f9b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart","hash":"1b20a6e406ca8e79675b2ebd9b362d10"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart","hash":"e88b0574946e5926fde7dd4de1ef3b0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart","hash":"eaef2926557480e27a3ce92f89de68b7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart","hash":"52f779d8f66642da5db6810754b0ba5c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/null_mapping.dart","hash":"4bc463f9c4b5496d8918b58070c10515"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart","hash":"a47062dc6143c80c485bcfc7a06b9490"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/LICENSE","hash":"46158b74167f78e44896e35a92c7c5e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart","hash":"bdc22e9e77382045196b5aafd42b5e55"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart","hash":"dbb0bb20c79bcea9397c34e3620c56c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart","hash":"0ee043f9e3f8fc817bc6bb354731879d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart","hash":"e05529d31a09e4c86cde70483824fa10"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart","hash":"c8564aa311746f4047cd02e26ff4df75"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart","hash":"b5b9320ef8cd47d81a68063558c1ed4d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/pattern.dart","hash":"d881c458d06573eb887bdf0f3ce9f586"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/src/messaging.dart","hash":"d0210310f0eb42949d15a2995dac586f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/single_character.dart","hash":"8db9443001d816c1f89abdf5bc0e7c7e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart","hash":"d891dabfc112fbaa77f11a249d547179"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_value.dart","hash":"2aef91d8cd008f57a605919dba2b095b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart","hash":"7ffb6e525c28a185f737e3e6f198f694"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/token.dart","hash":"89176d8be6120f2900340b369ce80cd8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart","hash":"21496c39aba7bb1435e82558fc3dc9f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart","hash":"727e4f662a828d4611c731f330a3d79a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart","hash":"efad3646c2aadca0c462ae31919205ad"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_unselected.svg","hash":"1dd3756cbc8b5a94ddcb9057a1ddf364"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart","hash":"c8a14f8ecb364849dcdd8c67e1299fb3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart","hash":"290ff7e27e670467d4f520e320ed9660"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart","hash":"efbedb75be354b65520bce3f0855b8db"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart","hash":"24cd1bed27dc8cfdc2d00045c1b85b53"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart","hash":"e1396042533b733f081ced0923a94cdf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_home.png","hash":"9479f3d4c7e70fc2c423c8f358e2dc92"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/motion.dart","hash":"505f6c9750f9390c9e9e4d881092cef4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart","hash":"ecc072620f2a72e685360292690c8a68"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart","hash":"3bcc95d3183f101e656079052017f57d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/dtd/external_id.dart","hash":"3598a401936c6a9e0a645251fba246f9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/ffi.dart","hash":"ae66b0cbdfe2e2a5a99c5dfa48fd5399"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart","hash":"4b50828d394e7fe1a1198468175270d9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart","hash":"280be2dbc10de2dd1913281d29e1b29f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart","hash":"7821d01f98c559fcbec46a41b4df7ebf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart","hash":"1506ba940aec506086f3093420336467"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart","hash":"af4bf4aa827f5ac651aed6fb7b9a038e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart","hash":"fc5d931b0e52f2fbd5ba118ca7f34467"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_7.dart","hash":"e7f41e9640a11f484fe97a34fd0c6fe4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_value.dart","hash":"21beb4ff2c06d1edc806270e0bfac51f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart","hash":"ca2e098cce59851623bf60c022a3bad1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/lost_data_response.dart","hash":"08f9da8824c26449b9df1c0e674ef2cb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE","hash":"5bd4f0c87c75d94b51576389aeaef297"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix4.dart","hash":"48ec0166ccbd3f834b89d19fcf8bf2e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart","hash":"b815d11a718e0a4d6dec5341e2af4c02"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart","hash":"21494fec4563fdcefa3d28fad8ffd12b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart","hash":"46826fe180ac83f5855d6126ad250b81"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/ray.dart","hash":"81926da83d9ea41cd5ad389174aa96dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart","hash":"e4eb87da41119742a2dcbcdbc39c7a96"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart","hash":"bd3f0349089d88d3cd79ffed23e9163b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/platform_info.dart","hash":"81e7d988ce6f8a20230e61cdac83f21f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_peer.dart","hash":"681b70272ec68e757f2394c9e7fa9398"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart","hash":"c7627484ec7f4005dae2321f6de6768e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart","hash":"94235ba74c3f3ad26e22c4b40538ce07"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart","hash":"c4b5de17270534014eb846299d500eb5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/timezone.dart","hash":"f8c5df6155feb71c22fdca5ea2d10a53"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart","hash":"61d3c1705094ee0ea6c465e47b457198"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterable.dart","hash":"f0db904cb4051a93b08f326f9f4ded00"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/clipping_optimizer.dart","hash":"6a0f3ad096e056352806cf44a29f4dd3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart","hash":"1357b049a06aa8a7413982e814b87ab5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart","hash":"ae53c1bc8f95419bee08ba4fde0e173e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart","hash":"985cf5499dc6e521191985f55245a22c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart","hash":"c5e44030289c2c25b26c5b3aa843b3cc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/storage.dart","hash":"3032f1c2edfd44ab46f3b4673c5c8deb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/clock.dart","hash":"84ad21db5ba97deb809b65697546e39c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/args-2.7.0/LICENSE","hash":"d26b134ce6925adbbb07c08b02583fb8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart","hash":"4b495ff6681b3a7dda3f098bf9ecc77d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart","hash":"05ab01a88b45fe10a762dc3068e7e1dd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart","hash":"5486e2ea9b0b005e5d5295e6c41ad3c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart","hash":"90a1a95cfd75677cfe6295f0bad3a3e9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/bitmap.dart","hash":"30207bb624460e743b557f58e7b39479"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart","hash":"b3eacd047eaec8b4b214d8d35f471f06"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/error_helpers.dart","hash":"ef40ba86423f614b2b841a3a11478937"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_signal.dart","hash":"8596b58c127792783625b4b22a4d023c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart","hash":"0c520a6b1ab38e0f294c3ddbc2ec9737"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/pragma.dart","hash":"6fc8c606a9db58715ea15f5ee1e062fb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart","hash":"77d5759abfee21d18803f19b603da875"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart","hash":"123520ee3a48eebf4ba444e93436bb1a"},{"path":"/Users/downy/flutter/packages/flutter/LICENSE","hash":"1d84cf16c48e571923f837136633a265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart","hash":"90f70ffdd26c85d735fbedd47d5ad80b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/image_picker_platform_interface.dart","hash":"340bfb4c1c748a6b1b9bc91b523d0237"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_6.dart","hash":"3c158ce6f79d219073cbe23a7fe48595"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern.dart","hash":"2108c716fd8198fa3a319a1ec6cadc9d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/declaration.dart","hash":"79198336b26da3116eb3cf2258e9f72b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart","hash":"7c8b701267e773fa9293eb10736e0ca7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart","hash":"a004396fa64ff2163b438ad88d1003f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart","hash":"62cbf59e5c816c224ef5eaf803fc877b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart","hash":"2aacf74fb08ed144ee859c99233588ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart","hash":"11b4d96c7383b017773d65cb2843d887"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart","hash":"fa8eb6909c6c4c0ced2ac0ec5a69f640"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart","hash":"b6bcae6974bafba60ad95f20c12c72b9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/vertices.dart","hash":"5db8a9ae89b9f40979a35f8c0eb56638"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE","hash":"4cb782b79f6fc5792728e331e81a3558"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/following.dart","hash":"7f4a5458515781cb38e39651bfdd2f04"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/letter.dart","hash":"3b849eb1eb50df2663eeecd3801e3193"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/LICENSE","hash":"6eb17212266d6f143295fbec385617aa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart","hash":"be66f00d2c9bb816f4236dd0f92bff55"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_Blacklabel.png","hash":"2a1292ee675efd8f5b3b072a648a0aeb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart","hash":"964f3ee4853c34a4695db0c7e063eaa3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE","hash":"901fb8012bd0bea60fea67092c26b918"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart","hash":"0b3ae865c8e82bcd0c94aa60cdd8237f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/LICENSE","hash":"fcc4d991b068e4103c4ef152baf65fb3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart","hash":"5a41dbb4425fcc9ce228f1db68360c1e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/where.dart","hash":"30325626c486da5b0b5e6ca9d6a6d337"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/notification_settings_page.dart","hash":"4aaf1341462afc8acd645202c945b79f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/initialization_settings.dart","hash":"150f91352c1070fd5f15a65ba10e9cda"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_detail_page.dart","hash":"87e1d4f79f197cb95a25c56b0ef920bf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/nav_workbook.png","hash":"72c5af6bfaa9a9ae4e20a77548c4f6c4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/trim.dart","hash":"37b4a8b2d509ad6dd3f486053edecb3c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/listener.dart","hash":"a84e929eb69f77beaea9aaa61a1623ed"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart","hash":"c517fb54b3d66b22988ad7c8d07c6f53"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart","hash":"db4d348cc51cfecc2c86a34122b48806"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/visitor.dart","hash":"87e0c94a0dd945f819a8bd24a9ac5e67"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart","hash":"83df4f6e4084a06a4f98c27a524cc505"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/tz_datetime_mapper.dart","hash":"2f6d6663f131dd0e24f37f58530342c6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_parent.dart","hash":"a7ac3293430577fa9c028b0df6607fa4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/src/messages.g.dart","hash":"d631809a6f4e20b7aa9ea7e17a6581de"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart","hash":"edbd68eb36df4f06299204439c771edd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/arc.dart","hash":"511ff5c6f0e454b22943906697db172f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart","hash":"eca5aa939aa9722ead4b6c347fb4d11a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart","hash":"1303bc77ad63625069f2d23afc73f523"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart","hash":"2b76d589cc052dc9ef928ddba5382a4b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart","hash":"6326660aedecbaed7a342070ba74de13"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/flutter_local_notifications.dart","hash":"6911901b1e6f800a6d433577dd9b93a6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart","hash":"cdb411d670a094822c46ead81fc1c4f7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/method_channel_messaging.dart","hash":"32607e48ff8d5b1dca4d9aaed5c65cab"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart","hash":"c9111e47389ee4b70aab720435a2a2df"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_client.dart","hash":"6b3c8cd4c0677edeb4fb8c22d923657c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","hash":"dac22fca3e7d3a8dea390391c26464dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/gestures.dart","hash":"ac772288a52f82606f20d68636327e34"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart","hash":"6297da5be01fb7c0d5c4aaffe7a27a50"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/lib/plugin_platform_interface.dart","hash":"8e49d86f5f9c801960f1d579ca210eab"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/image_picker_android.dart","hash":"70e88a3e2ff97b5acfa273e5964271ae"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart","hash":"7bd8137185bc07516a1869d2065efe0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart","hash":"028eb8497ffa66b6d051c09361dc19f3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/epsilon.dart","hash":"b9283cabc57ae94b3c75f147903751fa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart","hash":"89b2eba11b385c32cad8745bfba9798b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/resolver.dart","hash":"129621686dbf25bd8492f93ee01aede9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart","hash":"e6069a6342a49cdb410fbccfbe4e8557"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icons.dart","hash":"32b222420709e8e40d12f6ea9fc0041e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/_debug_io.dart","hash":"118b6a62408f796e238c61d271e5146f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart","hash":"ec48414c6983150c30241ba7128634fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/tag_exception.dart","hash":"65fe1b7c956a57db85d24838ab970d2d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart","hash":"530c4f96f1475cc4e4128ffedd705028"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart","hash":"0ff55be19444856c892e701c475b20f6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart","hash":"9f069b0f65439fc693626369d779c95e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_dialog_options.dart","hash":"c7a750b73798e6fbab221eff051e22c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart","hash":"57d74766f36a3d72789bc7466ae44dba"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/visitor.dart","hash":"27780bbb98adce3f00386fc6223bf2c9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches.dart","hash":"5ba6e004392bbc498c40ccb026b0a845"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/token.dart","hash":"007b05bbaaa5af831aed126b4db596e5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_encoder.dart","hash":"af7b5d8de0c9d9df88cdffcae9d7c959"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart","hash":"dd109d67b92b9fbe6e0051f0c890c903"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE","hash":"175792518e4ac015ab6696d16c4f607e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart","hash":"2936a409e1029ec52f7c0003f4db18c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart","hash":"eb115c2e8f0ff170bf26a44efd1b5c05"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart","hash":"ac172606bd706d958c4fe83218c60125"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2026.jpg","hash":"c1da37a2c4aa0902d24a0325e5014df5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/range.dart","hash":"8319b5c0133f9badc667b37194fa492d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/base.dart","hash":"45de232761192d4a3d0ad379ca89ebfc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/node.dart","hash":"2da1c79b8281803ba4c3b68c61e7cbc2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE","hash":"83228a1ae32476770262d4ff2ac6f984"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_error_page.dart","hash":"706ef200d552a72ad468ccb74518d0fe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart","hash":"e7b2de136a99cf5253477d4fb4138394"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart","hash":"7da554c3a69a1c2d019202e3f63331c5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart","hash":"d3ac4a3d093bab7e3c97e51db9e4218f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart","hash":"73089c9737db54a05691e09bc9fc1bcd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart","hash":"74c42b320d58fca1c02c22c577c5fdf7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart","hash":"c39101179f8bdf0b2116c1f40a3acc25"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_unselected.svg","hash":"276234b99389b2bcc7bdc79c22df0e55"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart","hash":"b45f6f4ad67efa5c374cabc278ede26a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart","hash":"ddf1bde8f4b9706d5769690b7819e5d4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/reference.dart","hash":"1253a1a49f9d6789e547fbb5a9301d3d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/banner.dart","hash":"576f65e88d664b3c39aa0e07825b29a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart","hash":"0b630cc8a66d79c161a58858593ae1ae"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart","hash":"6c54f90e0db5f42a13be6b3efeb4a04d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart","hash":"8830333c78de58ad9df05d396b651ef7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart","hash":"ae42d99121b00899d038edc753e0b23c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart","hash":"ae36c7cc9b21f98bedf401f2d67a0fd4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart","hash":"68c724edcc385ae2764308632abb76b4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/lib/image_picker_windows.dart","hash":"fbe2834efbf133b1b0b0ad8be7ea499d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/choice.dart","hash":"404ec528c031ebc7486f12477b06de28"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart","hash":"3ce88fe27ca35ed2f5b7a333d43676e1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/LICENSE","hash":"038c3f869f408e1194eda71cafcca6f0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/NativeAssetsManifest.json","hash":"f3a664e105b4f792c6c7fe4e4d22c398"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/separated.dart","hash":"70a35c4e76561a207bce18013ed087c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart","hash":"a6d730f196620dffe89ac987b96ef6c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart","hash":"37f181e3096dc69dc408bf7d07fcd39a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/dbus.dart","hash":"59ba4a85ea18ab7b3030f370a0e93450"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_flutter_local_notifications.dart","hash":"610a95b3eab95b5d9ccb03edc03818b5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart","hash":"3188cef277d7af7b79cfeb3286289551"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart","hash":"7088cc45b21c93be6b42dc748fc3a29a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart","hash":"0cf5ebf6593fabf6bb7dfb9d82db735b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart","hash":"153fd637fe660527ff42e1be068d99ac"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/reference.dart","hash":"f25bbc73708cc35ac55836cbea772849"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart","hash":"a29f0df228136549b7364fcae4093031"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_text_style_information.dart","hash":"e1c112a7342a7ee3110a1c2df175b89d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart","hash":"b7525dbbd1c51211c6edc9ea544a62e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart","hash":"3fce8e0c4d9b3cb4e3dbc168f41a132e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart","hash":"5d8d6684175fbdcb66d313aa7c93f5e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_exception.dart","hash":"7cb7fe22378ec39b40d4b519d0928d80"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart","hash":"b9c13cdd078c3b28c3392f0d6d5d647b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/homework_status_page.dart","hash":"a79358bd23738f5ba5cf1498b393df27"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel_group.dart","hash":"9a2704474807a196e3a72883d73b5be2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/types.dart","hash":"98947dc53131e00bf0eb82564931fabf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart","hash":"998487b87817cbb87019455d4abfaed8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart","hash":"2f426329cad3640d8a125303c3509018"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart","hash":"57f09243c4e3f4099a10951225c6d1ec"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/style_information.dart","hash":"9787d9b12ea9461874ea0faa9cccf9db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/flutter_local_notifications_plugin.dart","hash":"c9b70f4004e9ec7f0856ecc0e45430bc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart","hash":"e3d917994e875601c2dadaf62de546f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart","hash":"9bc30281f42d8003b7f9d636ebc8bfc2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid_linux.dart","hash":"cc4abe2eecf823ea14c55f9c5c09e203"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart","hash":"3e0eaeb97804d1bc93e6c6088aa351b7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart","hash":"99b4d15f76889687c07a41b43911cc39"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart","hash":"700328ab0177ddfd9a003a8c15619c1a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/interruption_level.dart","hash":"3667c2cba3e0537e66b40353a1482487"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector2.dart","hash":"6860d784322e97b761960551131a565d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart","hash":"204fb623e2b782051e9bcb6e320e97c0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart","hash":"0c9bd1af5747fd55e7488c731ad32dee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart","hash":"d44c6aa2c95d66ec45eeb0bd0df79cee"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2024.jpg","hash":"bac3e7ec19ff9a3512b243743484c706"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Upload_image_unselected.svg","hash":"276234b99389b2bcc7bdc79c22df0e55"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart","hash":"2150550461fec00b57e9b9110f8fde94"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_selected.svg","hash":"b5a02676b50172a80c155f0104471695"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart","hash":"00ec0dfac52c24607bbdffd84060d019"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart","hash":"34c5e6ba4664d331c977bdc010aad709"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search.dart","hash":"3798784648f57e129514c1cb6f534612"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart","hash":"e324dd19cc02a1bf47bf7cc545dcca79"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_page.dart","hash":"f28a774baf869ad89f779c824c00c245"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart","hash":"40dec7d9dd1c5150bf10ef4b46cc36c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart","hash":"7146d1c18ac515c3fd3465cd4a7f7a34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart","hash":"82604e7dbb83dc8f66f5ec9d0962378b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart","hash":"734e496890e84ac4195229409538f700"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart","hash":"0bc80db5885f9d8ecc0f80ddab6fe8b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart","hash":"98772211ffa69a8340f8088cd7193398"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/with_parent.dart","hash":"5e97dbe19781055ba2585ce570bc4643"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart","hash":"f35a027c2538224fe2e64e2eb36a71c5"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/app.dill","hash":"994a2b74027bd49309cb785feb4da341"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/expression.dart","hash":"79503c7448238b77502c169788e26dbf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart","hash":"940daf4491e3ab2e15d7eac5d6ce6b23"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart","hash":"30c8c6264748aba97477a1c81c8fb9d1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart","hash":"0d86d4ba2e01e5e62f80fcf3e872f561"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart","hash":"b5bd9d15c10929b4a63ea0df649e2d52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app.dart","hash":"5b539c57fb0cbea66a99efbc8239e590"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart","hash":"4a4b67b573e2338cf03cb704b2c18f04"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_save_location.dart","hash":"3c21d269eae774b7e06b8adbe73aa18e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart","hash":"c7fe678fd3ad24ff5928e24dff4367b5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart","hash":"fb23ec509c4792802accd10fa7c8a6b0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_details.dart","hash":"f61c50d40c00ac96c595ea0b2682937c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart","hash":"853b1406f2756bef671f6d57135606f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart","hash":"a6ce313fc162c7c4402e1979454559a8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart","hash":"21a43efc5058f6132660bba47766b26b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart","hash":"5c3b7996bd913451665c9b1634098d83"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart","hash":"8b525140e1bf7268e1681a62c7640eea"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/reset_password_page.dart","hash":"fb2e6cdb72e5a96214cdfffad347c369"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/LICENSE","hash":"387ff7f9f31f23c3cf5b17f261a091bc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/LICENSE","hash":"46158b74167f78e44896e35a92c7c5e0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/shaders/ink_sparkle.frag","hash":"8af2b6b4632d42b4e1701ecda1a3448a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","hash":"b93248a553f9e8bc17f1065929d5934b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/AssetManifest.bin","hash":"98c24403bb02b04545f78b7c2ca41c25"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/doctype.dart","hash":"a0ff9321b483226cdbe4773e33779715"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_Blacklabel.png","hash":"2a1292ee675efd8f5b3b072a648a0aeb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/tzdb.dart","hash":"01c25b2dabe912c532a94956c2e40c8f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date.dart","hash":"f36568b4288388242cb6f7775cb60c42"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart","hash":"7514fc34af698a2ef36a68486f7340d8"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/bottom_nav_all.png","hash":"9479f3d4c7e70fc2c423c8f358e2dc92"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/context.dart","hash":"6f1cce384d53a00c3d6e036e78554066"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/person.dart","hash":"a0f12d72bbc64d6edba6d1174d5603e9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart","hash":"3e8df17480fcb123b3cdc775ca88dd89"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_LightSsen.png","hash":"5ae53d61eeb9909a8c892ca39defd1f5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart","hash":"58b9bc8a40fd3e2f7d9d380d0c2d420f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart","hash":"b972c32590c642256132827def0b9923"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart","hash":"2cb2b1aac78bff7cc9be5f0a45aaa94b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_unselected.svg","hash":"22f085ac90f93a6cbfea8c2c872edc30"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart","hash":"e14417c43b6cb787f11bebd1c39280cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/card.dart","hash":"90d9d45eef80ac53b194a71da4e10975"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/data.dart","hash":"d7fab9eeba6ce2b3fae0a93d5622ac93"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart","hash":"5979a1b66500c09f65550fab874ee847"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart","hash":"00c9e1f53ab22efcb34cca55fc46b4cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/callback_dispatcher.dart","hash":"5239ca253366a3b71796f8e9d2baf065"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart","hash":"d7eb1678ec74acd9857a4193fd62ed5b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart","hash":"66df4fe41752a6a990878623e36a3ad2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart","hash":"0b55082ca3ffb2bec57cbd8c61db5977"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart","hash":"b7c2cc8260bb9ff9a961390b92e93294"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase.dart","hash":"81402c8eea37df800d379c88bdcf6f44"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/simple_name.dart","hash":"208d1ef7a6cc2445551b3138139613bd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart","hash":"527d9250e523e442bc07faadf2cb1741"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart","hash":"c06267b6c315a5e40f28feb6019de223"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_8.dart","hash":"5f0138a157edf46a36bd960b7eaa9885"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/src/messages.g.dart","hash":"f381ed91de52f40a7dff4d2f0f3f6d4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart","hash":"93d025adfc0409629c51036cb0fdc085"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/continuous_learning_detail_page.dart","hash":"0aff4cfd6dc7a7698a63b2bec1cffeab"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart","hash":"2af013984ccce4c43e3024da472560d7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/not.dart","hash":"6bb47d3d823202b76bef61c1ccce067c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart","hash":"5b92fc2fdb9b39ca8d3072d08f9f2356"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart","hash":"991024814d51967a20be5851be93a8e3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/greedy.dart","hash":"01b051da3c61c872efd639af5fa0f4f7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart","hash":"8bb5842ab79616954e268adb624dc6fb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart","hash":"206ef1a664f500f173416d5634d95c8b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math.dart","hash":"4181db4115c5cbbf774171b3cde1542e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/letter.dart","hash":"4165baac3466972c71160f4aa15cd185"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart","hash":"9d437a8fcd0a5c0ad90aa6e31d66834c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart","hash":"945227f3863339e388d92c2b3bfbf673"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/settable.dart","hash":"442a233329c158bcfbb129ccea0fe8ca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/grammar.dart","hash":"9467e21c572f79ad7a41afb250e26905"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart","hash":"5c3150272dcfc4b6d488ba16b0b21594"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart","hash":"166147b7bee5919995e69f8ca3e69d17"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_client.dart","hash":"3bc24109049f63bedd0393f75bc23503"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_parsing.dart","hash":"ce49b6015a5f5b5bb716420efbef22c9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/builder.dart","hash":"9e5f67e1d8edbcd97531a8377e706d71"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase_app.dart","hash":"fc8837c1b0c22211799e9412e64b08a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart","hash":"75abcdfe5d010a07b1833f1a2c48fa73"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart","hash":"8b4d7c15da02f61ba78cdade9d3e7374"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast.dart","hash":"dc379ed249557649f50b9c27d0033be6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterator.dart","hash":"4c92351d347c52a00797317aa487600f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart","hash":"07664903d8026f2514b29b786a27f318"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/kernel_blob.bin","hash":"994a2b74027bd49309cb785feb4da341"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart","hash":"ccd754ed5584fb2b22056464dbfc9b37"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/constants.dart","hash":"2c6facdb1b63e687304c4b2852f6ef4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart","hash":"ea7754f2c684266799d36538300b6ffa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_for_web-3.1.0/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix2.dart","hash":"5a770014b927807d1ef52e7b6e287897"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/media_style_information.dart","hash":"4fe97d87eee37e8a1dddc5230ebbf9ce"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart","hash":"64c347128324802ec3aa6618f5723cc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart","hash":"7dc8dec32ceed4732299990cedf383dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart","hash":"035b8d3642fa73c21eafbee7851cc85d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart","hash":"5e054086533f32f7181757a17890ae56"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart","hash":"d2386b256656121d501a16234b008e2b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/icon.dart","hash":"b1d3d657c21d4c2229511410eb2240c0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Academy_unselected.svg","hash":"1dd3756cbc8b5a94ddcb9057a1ddf364"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart","hash":"f20071b459b9bbb98083efedeaf02777"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_error_page.dart","hash":"6fceee0a372978fde346a852cc666727"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart","hash":"7c12bdd660d493a20f3d692be2cafe20"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart","hash":"28464c209a2293d3d4e5549539e1a751"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart","hash":"2663ff02a467c826925672bcaf6bcf66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart","hash":"01d9ad3c8c89b65f3180229081a95952"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/writer.dart","hash":"a8499171c0b67ca96b9f8b0462e1079b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/sibling.dart","hash":"6cee72f673d593b0b84628bf243727a8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/reflection/iterable.dart","hash":"bea1f59f6923a9f56c6d7b785887caab"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml.dart","hash":"fcf0dfcafac17dc3ed539b4587340320"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/initialization_settings.dart","hash":"00883d18f109cb9b8f09707e277106c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart","hash":"3bc33c65fa44a57d13430fdedef82bc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart","hash":"2fbba4502156d66db0a739144ccce9a0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart","hash":"f64029b4f4dbdc0bc61a4b8787975a94"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart","hash":"c390764eafafcc20c2e51225ce144ba8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart","hash":"0b8f9e0997c003bc97a462a2c70b91ab"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart","hash":"30d771880c8dbd68ea8e5d4a55c778c5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector4.dart","hash":"25e2aff82faa45ee7c3cb05fc8aa387d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/masking_optimizer.dart","hash":"583aae70081a96d5683cd54462840a64"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart","hash":"89dc3f84db2cd1ea37e349fdb1de09bb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart","hash":"a2ab6e0f334e5a28af29766b82f7f4b0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart","hash":"8f77cb7be1dbf41ca0fdf069ac69a215"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart","hash":"9c169d41e4740bbc21d0ce33bc753119"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart","hash":"8e0fc402506b32a335e86f7fef97f06e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/word.dart","hash":"18e902c0d484a6a2e0d68837fc5f003d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart","hash":"625e266fbab1e46e06c8d7d211a5828e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_enabled_options.dart","hash":"877295d0c356a690a3b16d271e34c543"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart","hash":"7abc7e5212374d29bfe5372de563f53c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/find.dart","hash":"17d3a0211da3d73d405d8730d46caacb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart","hash":"ef951139f9f55dc5b330d20e15d4fd0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/cupertino.dart","hash":"21e240878a582ab39a490e6ac330c645"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget_v2.dart","hash":"444af656078f102299511521fc7038d3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/numbers.dart","hash":"b30d064e9e3844eef3d2cc314139fc84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart","hash":"b0c6844b0af0cd0539060a0bfcbe3713"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart","hash":"65a04fd24f938030b7271b61a59f9a39"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_location.dart","hash":"f91bd03132e9e671e87f0b9066647164"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart","hash":"acfc0a55deec22276e085dae6197833a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart","hash":"ab7af0d1396dfa5930adaf0357fdc1cd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart","hash":"0c9897499d9ef356aa9886423cdf96e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart","hash":"a8fdf31698b305c9fdad63aa7a990766"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_success_page.dart","hash":"669fab2db1a5c93f5b0b7261a22b6b45"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/flutter_svg.dart","hash":"34cd13c59a8e623043493d748711999f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart","hash":"d195153a8c01a0392b38e3b9adc672d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart","hash":"9344bef2e519a536dfdcf9f5612671a3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart","hash":"7bbb6aab4e83fc272886a39c92157201"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/node.dart","hash":"9ec244272cb6c8da46a6dd5f104f0dfe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart","hash":"d8060c05b658b8065bc0bfdff6e4f229"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/cdata.dart","hash":"a1bc06d1d53e9b47b32fbdb4d323f44d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/utils.dart","hash":"8608f71f077e370ee14d37c711e6580e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart","hash":"0d9e952ceaa817539df84d30e876c4ee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart","hash":"f3747e025d835d0ff5cfd904d925dea2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_3.dart","hash":"9632b7c4c43e2e92f45bedc627663937"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics_compat.dart","hash":"a017616228e06275ed5610a4368f8d84"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/pattern.dart","hash":"75cd4f61b777cfcb29a03be16c612f1e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart","hash":"4d43f0629755f06d4df0b1a6ef75ef59"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart","hash":"11df661a909009a918e6eec82d13e3ff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/path.dart","hash":"6dd2142267f6ad86b6410b5eb575d784"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/vector_graphics.dart","hash":"199c06bd523145278bcd9ff9c6fe6a18"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/char.dart","hash":"e72dfdd64a9644296cdccf5ed0014b38"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart","hash":"7536ace8732469863c97185648bb15a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart","hash":"be94b8f65e9d89867287dabe5ea1dff1"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Home_unselected.svg","hash":"92f7f8888a8a844a4f1fa497cbe2decd"},{"path":"/Users/downy/flutter/packages/flutter/lib/physics.dart","hash":"6e29d5e69c5745a45214fe14da377c1a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart","hash":"7018ea64a9aab18f27a10711285d7573"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/firebase_options.dart","hash":"57c27751360c2102da5405ddc950b0e6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart","hash":"9be021a3c68f7ef171b79893e7b4fcd0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/opengl.dart","hash":"474c9e159ec8ec804957222054c877e9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/delegate.dart","hash":"5fc1a25f60cfa0a0280878377348c63c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json","hash":"2a16f501935503a19c9ffb7a0f2bf11a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart","hash":"78e53d9a4963c0d19c5ea355a0946e5d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart","hash":"0949b8197a6069783a78f4bb0a373fb0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/default.dart","hash":"7f30d05e05b047b274b1c4b45391d698"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart","hash":"7db055846295bfe7d5e376765ab0d106"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart","hash":"a1186c224201e7d203404a4270938040"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location.dart","hash":"6ed688f382406e9c782f92df9e965fac"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/enums.dart","hash":"a4b97395630dc415cc76f514d4a38869"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_plugin.dart","hash":"07db573490cf88af2c2da7b393436779"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/allocation.dart","hash":"9d62f4f58e8d63a8e106a1158eb13a02"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/lib/image_picker_linux.dart","hash":"ff17d156fe2828de1af5ccee52274163"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart","hash":"8e7e80b0f55481814454154289581855"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart","hash":"d35b72b249d19f54a4cd6f22ff3299e9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_properties.dart","hash":"953396d57b69e0e889d9dfcc4f7fdabe"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart","hash":"e9b0c1f2903ca05a29681459603679c1"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_page.dart","hash":"c16d2d577d620d569762e494d50c4abe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart","hash":"f44bbe72c4c7393277c42d5fc27b3b2b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart","hash":"5c96449c2a494ea8f3a50ecc3ba9af74"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart","hash":"fab8d6d1b0e81315a3d78131394d31e6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart","hash":"b76ebf453c4f7a78139f5c52af57fda3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart","hash":"f0d920fb2a472e43514830b20d401806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart","hash":"30ff1bba22f8f5d5442537740196fdcf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action_option.dart","hash":"be2d4c688f4ca84e68eefd04fe0ed129"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart","hash":"5893c7d3910e8924bd2dccc8837775c7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterable.dart","hash":"f0ae0acd94eb48615e14f6c4d1f5b8e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/not.dart","hash":"a7c2e189af8ef0e494c5f50550ce8500"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart","hash":"b092b123c7d8046443429a9cd72baa9a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quaternion.dart","hash":"9307caba73e148d13a0697568f0ad971"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart","hash":"87bcefcfff19652ad296ec7005799840"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart","hash":"a5d0509a39803ffb48cae2803cd4f4bd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart","hash":"14ee798b10cb318d96667b32b245f21f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid.dart","hash":"49d6d829ae481b2570a290401389d149"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart","hash":"0db5f597f1cc6570937e6c88511af3a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart","hash":"cd0db51c646e4809e09bdeb76ec931b7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid.dart","hash":"5261078afe15bcdc637478bb6d7f7e21"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterator.dart","hash":"accb24637ddbe55d7a3f76e4618bdd22"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/dbus_wrapper.dart","hash":"52e0406df2babb2958beb4b471ccbcbe"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/overdraw_optimizer.dart","hash":"b4728e8f203f8d46acae376fc7ac4225"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart","hash":"790dc5e1e0b058d13efbd42a3f46498e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart","hash":"6c6dfd5ba4546c1f32201555d6cff215"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart","hash":"a11383c33c4fdc8d2cdc091f50d17e93"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/debug.dart","hash":"d3b50e217be5e58d53f746ba267e30e9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/flatten.dart","hash":"481d21ef07dee6f82302a015f989b597"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart","hash":"5b894ae18be3e2442a34288833184ca9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_children.dart","hash":"7c666bff17f2cfae821f93f0c5e66a64"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart","hash":"2ad27cdee5e6fe69626594543bd0e7c4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.32/LICENSE","hash":"2b36ca50262dc615e560c27654badb26"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_path_ops_io.dart","hash":"518899270d23bb8654ecbc26f12702a1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/file_selector_macos.dart","hash":"2c31d235f0339d60f7cc2e1d8388deb7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart","hash":"04ad97adf4dc5676764aa8d7aad857f9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Google.png","hash":"46778e2ab517be193b725b17e63f0795"},{"path":"/Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf","hash":"e7069dfd19b331be16bed984668fe080"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast_list.dart","hash":"87751ee02d315bd2d0c615bbf2803a3d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart","hash":"e4ee21048ab83cc50d61ac3784afa9f5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart","hash":"daa0c9b859ed1959e6085188a703f387"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/uppercase.dart","hash":"c9d12a17c125e31a94ec65076a9c3ac5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/pigeon/messages.pigeon.dart","hash":"9ae23519911b78febbb5e8165ed127af"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_options.dart","hash":"4f8c5cb9fbc074ac87af61da73f925cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/src/fp16.dart","hash":"63681ec4b0641faab6e783c1c213b5d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart","hash":"3fab1c4c90dce6d5451027be460e81fc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart","hash":"de161004250e30098d14049bdf54ce38"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart","hash":"3fd33becc9141d8a690c4205c72c5d40"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/descendants.dart","hash":"ffaf08c52f141dda6e8be50b3e46ea50"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action.dart","hash":"6a3849c802c2fd63cd4d3db06470f387"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart","hash":"ed11d553b999afddfd85ca57540af7d0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/upload_images_page.dart","hash":"6c36a955a27a6c36cf747b890518d89e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart","hash":"0e2afa27a9682352d434c10d20ffdc7f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/list_converter.dart","hash":"5f5f3a1074f40b8fc37c2b3ba5ec0432"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/firebase_messaging.dart","hash":"4c539cce5d187ad2bc808303fd6d6113"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/notification_details.dart","hash":"fcb452549a7c86cdf118933be09ef427"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart","hash":"92ec3dd43504f533d1985d189ffc9562"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/ios/enums.dart","hash":"670388961b23da0ffd68cf26f5104e49"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/utils/exception.dart","hash":"8abcbb724ffa31d2cf158a95c588db62"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/failure_joiner.dart","hash":"12b975946bcb9ba1b5a6dc3309a19de9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/preceding.dart","hash":"9d5375413b37f738384990ebdd6c6285"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart","hash":"2458910beb2b4f3b177a7db027cf7d34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart","hash":"e5b4b18b359c9703926f723a1b8dd4ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart","hash":"2a374faf6587ee0a408c4097b5ed7a6e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/display_settings_page.dart","hash":"6ff50f2efd60b7917e991fb0505b154f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart","hash":"2122907e49766bb1f044ae97841c2b86"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart","hash":"61dd7991c06ba3bae351fee9a80c64e1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart","hash":"44b3c2a3d6e67a3213a49cce58fed932"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart","hash":"4a73924a7083f5e9d700ada6f2b53098"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart","hash":"110b9903c2673d2ae6f626dee25c45f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart","hash":"bbc7eccdbd8472a2180e0dffce323bb9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart","hash":"b9abba31a48a9c2caee10ef52c5c1d0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart","hash":"16d2669eba65e0d92613a0aef0a169d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/divider.dart","hash":"400da5c3ae6b8c8cf1ad20c796ce413b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart","hash":"9c23e23bd2cb8afe39b51de3545ab2ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart","hash":"98f725d06ba20a1032cb8770d00d7fca"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart","hash":"74708cb40b7b102b8e65ae54a0b644be"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart","hash":"feacc941aea1ec8b3a30601915b7d353"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/LICENSE","hash":"b776a584ba475b946d8e76f1e42585f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart","hash":"a85856ccbb262dd4c1207418f8bc7801"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart","hash":"5061e0737e2db44e82d8a8c12f328a48"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/_file_io.dart","hash":"76964a546c84af33fb4bd8b2ba2fefda"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart","hash":"a88e90675c4b55522b3e9226f0135237"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/sound.dart","hash":"58f14973ee61401b0bf79de491dd1e69"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart","hash":"7711f4b6c3574cec77169f2d2c35ee3d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix3.dart","hash":"d8b0931c64fbd4bdd435df207b303a04"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart","hash":"02139a0e85c6b42bceaf3377d2aee3de"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart","hash":"3eb1458ae1a271dbe202030d5b8f0852"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart","hash":"e556497953d1ee6cd5d7058d92d4e052"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/page.dart","hash":"c5bf16620e9021a14d7fdd8d605e611a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart","hash":"5d30df9a71208100cd9e649ec1f21f69"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart","hash":"2346472ec1cfdb77f3b27d3b7af72d4c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/utils.dart","hash":"e85b4f3cf370581b3ef11497a9a5bce3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/node_list.dart","hash":"6b9e945de99fb44b45f72925b6e862b2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/cross_file.dart","hash":"b5c8f4dba868efb80ed69fcd5a7d3f07"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart","hash":"aaace37762c25bcd679c2ab09129db12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart","hash":"6b6d593e4facdae2c82b9133fa8e69e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_decoder.dart","hash":"16eac0a8fcc5fdae0d8f38b7ea301c37"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_name.dart","hash":"749e18efee29d6925d7c55e573d3eb2f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart","hash":"597d897c972c255ade7307dfcc2e5524"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart","hash":"6566a35ff0dea9376debf257bdb08fba"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_call.dart","hash":"da6f500c03c005a207d38c1daf24b00a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/social_login/Button_Google.png","hash":"46778e2ab517be193b725b17e63f0795"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/attribute.dart","hash":"9554d9749364a5e33fc853c08b09f076"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart","hash":"2ca785b09f831ebde51eca8654fd23b2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart","hash":"6edb3eb5d6e5b289f28ce2fb68047e91"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart","hash":"325ce403b3634a9c45bd705d91ed31a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart","hash":"eabd3dc33b1a3a2966fa68f6efeb6bce"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE","hash":"3323850953be5c35d320c2035aad1a87"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/dart_plugin_registrant.dart","hash":"44b8efa69ec831d1a0ce74c20ecc27b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart","hash":"ae1f6fe977a287d316ee841eadf00c2b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart","hash":"a0816d2682f6a93a6bf602f6be7cebe1"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_unselected.svg","hash":"93a54f90a6de31d713d9a0fe53f11f8b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart","hash":"026b1fa8f1d7ff0d7c1a6e1afb2e75ca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/character.dart","hash":"ddce6034695da8c5dc36994409d26189"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_all.png","hash":"9479f3d4c7e70fc2c423c8f358e2dc92"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart","hash":"ac08cb84358e3b08fc1edebf575d7f19"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header.dart","hash":"172d44c4d881917a3f7b252fc2b9744e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2026.jpg","hash":"c1da37a2c4aa0902d24a0325e5014df5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart","hash":"5f5c07df31f7d37780708976065ac8d3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_selected.svg","hash":"f78d02a831d5135b07c39aaadc50bfca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_image_picker_options.dart","hash":"06a5bb71bbe7e618353d9c58948e3d21"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart","hash":"b0851d75151b4ad4d87a1443d2041382"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_title.dart","hash":"9d2c294d83aa23e84b94905b21194e25"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart","hash":"be0a77cf3f0463f3dacd09ec596d9002"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart","hash":"61d7b16669f075a39023fed8967fbdb9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf8.dart","hash":"329d62f7bbbfaf993dea464039ae886c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/colors.dart","hash":"a385ed3a073e36a430c51f9641564853"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart","hash":"41f7bdb7d1eb3c86c21489902221b859"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart","hash":"cdef014561140d05b803ce8d9d85e02e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase_app.dart","hash":"4f4575a514eec25990a9923547e2ac28"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart","hash":"c4806d7aa676f2573de819bcf2b1e19e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name.dart","hash":"2426dbde1829bfb9d5707ea69f21b4fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/x_type_group.dart","hash":"826066d6663c91c94cee09406ded70be"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category.dart","hash":"a94a67f325606644fee6ad6aa922752e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart","hash":"5bbe4c9f8221f331ef61519909f5cc54"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/lowercase.dart","hash":"05b3f9197904fe6acb3facfa980e097e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart","hash":"a6adbe3868e017441360895c35fd6aa2"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/account_management_page.dart","hash":"d3336f95699a96616dffa9f32e4d4250"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_selected.svg","hash":"b007fa5f063d26273adf3911feafdc5d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_error_name.dart","hash":"7398500b1824f6043f23e208cd993866"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_tessellator_ffi.dart","hash":"785a30044e959dfd84e84764a9c2a08f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/lazy.dart","hash":"c55ebccc440e68cd5b9553b5cadb9781"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_page.dart","hash":"7b6fdb08d6a6aae462d53c72d38ece9f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart","hash":"daeb052f1089d4e84d8a22acf56c1da2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/platform_interface/platform_interface_messaging.dart","hash":"6d506abd151728fbae098fe619a819a6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart","hash":"81bf43e01741bf8b9df15ec37ffbc9ea"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart","hash":"ceca25b48ef58dff53262c111c0dc9e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart","hash":"d2694042e337ac1f2d99602c25be195a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart","hash":"7050c8c94b55eb51260ca54708b460fa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart","hash":"e40877daa15509fcbd3e465d246dbc09"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/_flutterfire_internals.dart","hash":"09004088d4048afe4f54ef5c78ffe98e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart","hash":"be096140df774ec827218c6fe69b80e5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart","hash":"24d6b5d55c0b41213c9bb4b2342764f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart","hash":"210d4d542d997e93c121b4dc814b95cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE","hash":"83228a1ae32476770262d4ff2ac6f984"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/skip.dart","hash":"e0af2f414117c942cbe5e23f4f60ba3d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/matcher.dart","hash":"faa18ee55924a5c65995875c94338d98"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart","hash":"603b7b0647b2f77517d6e5cf1d073e5a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/mypage.dart","hash":"d723712119af4e11e9484b7a7f8ebdca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart","hash":"9a12cf2a3549924510006db4651a1743"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_list_page.dart","hash":"bf39a22a974cee04d2ecf4efc098cb49"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart","hash":"95545fdf17c2014df41408bad8115997"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart","hash":"3fa7a3bafbab98c305119475eb004a06"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_manager.dart","hash":"5f173a5c0de15909e95d3275051138c1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/io.dart","hash":"15f42b93489935782fd5f175832157c9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart","hash":"bbc54fca40953c4a17c12bf45c349c77"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_encoder.dart","hash":"ff402ced5472590045b91c0f30e4b089"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart","hash":"105813825251a3235085757d723ae97c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_source.dart","hash":"9989cfb5871d34d04fa38e13480d5eab"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart","hash":"b6a30b7ed48f83f446db37577b30e62e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart","hash":"7c2c3a23031810f7aa97f4d2f016330d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart","hash":"72aa3452833246a4d22c084e75fb93c3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/separated_list.dart","hash":"82acaf4c715888e486eb9d714c23b266"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart","hash":"c66e615feaae8abf62893d4eaeef0ed6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart","hash":"16f71d097900371eb87d706863a8469c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart","hash":"a053986c2d9a24d11b9b8df45049c49c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Mypage_unselected.svg","hash":"dee348e2202f671e34773695f6a38cc8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart","hash":"09973ba0a94d2d819052c0544dcdce70"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/unicode_character.dart","hash":"d0e1db4618e688ad41ba325f1a35667e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart","hash":"4ba0a4163d73b3df00db62013fb0604e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications_platform_linux.dart","hash":"145a18283aef042bba506a2190347763"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/whitespace.dart","hash":"e63d3f21c1e3534e237fefbf5d3c2579"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart","hash":"0f2a1a61119c0bef3eaf52c47a2ebcf4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart","hash":"c0da8171c63f0ab4e822dd094fc2c595"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart","hash":"27c61344ce9c31ab29dff9add7511263"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart","hash":"d3b949a1e7578291493af5fd28846314"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/format_exception.dart","hash":"2128831f60d3870d6790e019887e77ac"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/question_detail_page.dart","hash":"8ef257c50ebc90d2f4b9ba64beaf2b97"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/LICENSE","hash":"7b7fcd3f415f29a260e0d5f15c7d9565"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart","hash":"7c07d5cc739ae29abcfbf6343ae84fdf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_100to100.png","hash":"454be3ff72282ffa8fe50f8f3e44658b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb2.dart","hash":"713156bb4c3a820c34bd6587a12b9074"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_verification_page.dart","hash":"7b0ed6e158cc3b625c502964151533ec"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/types.dart","hash":"24b206328a01c6923f0c599c64088645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_buffer.dart","hash":"99760254cc7c1941d4d7d7bb0fad045d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart","hash":"69be6215ea4781ec3da1e389b321cad4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart","hash":"18223495a47aa96889552c9834042729"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart","hash":"458e80784a70a0e225366534c905b294"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf16.dart","hash":"10969c23d56bc924ded3adedeb13ecff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/accept.dart","hash":"740f17823564c3c7eca15bca5c110e17"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/clock.dart","hash":"2c91507ecca892cf65c6eaf3fbe0a7e6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lowercase.dart","hash":"e2bcdfd80ddc73e02b457e8544242028"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart","hash":"80eec0865406718828ef0dccff8154ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart","hash":"702f8b87ec7fc125312d9ff64434e7cc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/named_entities.dart","hash":"c7e489fa5d00c1717fe499f3845c2abb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE","hash":"22aea0b7487320a5aeef22c3f2dfc977"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/parser.dart","hash":"ed6e10b66c408845188f75959c15a23b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart","hash":"1099a5c5ee8ae0d01e2dd7d07c3edf90"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/text.dart","hash":"d3de5e8090ec30687a667fdb5e01f923"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart","hash":"92e6028556e74c1dc297e332b473f78e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button.dart","hash":"d7a239f8b80f844857527c2012e4fa1c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart","hash":"91e808d781743242114a756dec8f2cbf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart","hash":"9fc2a184241aaf2f8e24b5742e163636"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/vector_instructions.dart","hash":"c46976f5c36e761463ad24614d724ce0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/comment.dart","hash":"87546066dfc566126ed9357805535e97"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_bus_name.dart","hash":"9cf807e15d1e83af4f62cdeb36582a91"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart","hash":"13be7153ef162d162d922f19eb99f341"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart","hash":"3405e08e614528c3c17afc561d056964"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/platform_interface/file_selector_interface.dart","hash":"5937c2b1cbdf77126bc2dd93570d3c98"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/AssetManifest.json","hash":"6dfdd4a84db74aba6ac3de6f75385bd6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart","hash":"a7424dc75f961325d400c58f0e946ba2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart","hash":"d0911329ae74edbd7f6ad6a89e0703f8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart","hash":"a73883c523a61b1393b5e8c66de884c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart","hash":"6f6fb24055973d0370e30a78ca69db89"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart","hash":"2c582bec6fc77f68c975f84d2252ed8d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_attributes.dart","hash":"1059ea9e8a0e858f944bf05dcb7b8edd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart","hash":"a340eddbf129cfd60e2c67db33c6003e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart","hash":"06455706949396049309d1cc90b76efd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/firebase_core_platform_interface.dart","hash":"a12b9a0771829ebdd5571928f9c48e7d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart","hash":"af5377d18db2f18bd4ac0ec35ed7d308"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart","hash":"157d1983388ff7abc75e862b5231aa28"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart","hash":"35bf7179f32e4ab5b13e9d9ec2abbe86"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart","hash":"997f4b4e6bf9981e307f46f08fa90b82"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart","hash":"fa0d3415d04242864a0c411fceeaabd8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/constant.dart","hash":"54356788d5c11fa49cae271d737b0c78"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_uuid.dart","hash":"c9efc107e2b16a48d4e132bfcc679af4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart","hash":"38e17b28106d00f831c56d4e78ca7421"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/hint.dart","hash":"570573fffe43860513d5cc911da0668f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/file_system.dart","hash":"f72f7c9e3a3971fdfd58d38c94b4e005"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart","hash":"9c9f1e70fac06b3e87bb33ece047c4cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart","hash":"596fb2e55b1ff1662e4bd67461fdc89d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart","hash":"cbbb174cb00bf954fdc9e2854517dbd9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart","hash":"72804f9d34b9a247c43d6cc575527370"},{"path":"/Users/downy/flutter/packages/flutter/lib/widgets.dart","hash":"0d4b8c16e7b8e4d8baf6fca9161c7e56"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart","hash":"3ed378957409718f644078da99891428"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart","hash":"21f4467f19bac7f0fe6f0e730ab10fda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/file_selector_platform_interface.dart","hash":"eeb75628a0a17d5d8b5dbe0eafc08a29"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart","hash":"205bb888a773c736206a9f2c84c8fd92"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart","hash":"9f2eb24284aeaa1bacc5629ddb55b287"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name_matcher.dart","hash":"5c4dc37f36fc78823f785b92b944560d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/mime-2.0.0/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart","hash":"50062b12181ce59a75a26727cacaf5cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart","hash":"aef544fef0ced7679e0edaf5f8d036b7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/vector_graphics_codec.dart","hash":"1cb908a37b3d1b606ce345ce629694b9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/constants.dart","hash":"55422a6a3ed3f0829854a5bbb97d4e6f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/academy_management_page.dart","hash":"455038cbaee05ad9cfbf84d5ca1b7d0a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/utils.dart","hash":"c65a1aef14f77e85636770f08f4388d9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/node_codec.dart","hash":"a40d7d4a17e700bbb41bf31de37c6bae"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/exception.dart","hash":"7be00974229804e8ec49ca8c4fca3b5f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart","hash":"121fcbdc1af81a0fd804490f85357fa0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart","hash":"5fe5b5ed3ec92338a01f24258b6070a3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/debug.dart","hash":"0575a78fbb39a292302737868752da77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart","hash":"3dc9f56e0fb2e949ac4c68187162c0a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart","hash":"bbc9542eb5e3c4701c24bc1268b8165c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart","hash":"aff8f09b64bc316bf514d7a58be4131f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart","hash":"1e30703fc6d5663dea611a3c783b21aa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart","hash":"0073f703be7f7ddbd7f04d1b740f35c6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart","hash":"62dce337eb5905e15da1113e7ba50806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart","hash":"44d59e37041b6305018f70012fef7d52"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart","hash":"9f8b50d98e75350b41d40fee06a9d7ed"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart","hash":"d1d1398bda204825136843ad63735067"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart","hash":"866257a42b6b721549b351382b365c47"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart","hash":"a6350a577e531a76d89b24942fca3073"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart","hash":"46e577ec532e21029e9cee153d7ca434"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/stopwatch.dart","hash":"f38a99a51f4062e7861bb366f85265d5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart","hash":"2083695b7b9150b87307af446032ba45"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart","hash":"bca928191c274201a95a3b9474582b31"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel.dart","hash":"bc48ae34e58774e84a72567a86034fef"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart","hash":"12b637659bb42a669c3b60bc09a42150"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart","hash":"5843b4750179f6099d443212b76f04a2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart","hash":"c0cf85f80b79542d2b0e1a00547d7310"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart","hash":"a2c7734430a38c6f25a3e99f10aa19fa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart","hash":"ad4f49532706bd4252a8383731d0e349"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_4.dart","hash":"ba02460ed2591611ff8506bdd88f569e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/normalizer.dart","hash":"bd502c5f75cc8148d708eb3e01c02765"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart","hash":"a2eb984b374f7375264ed4b139a0eb03"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object_manager.dart","hash":"69c08243f2f74c58d6ad38b17bb5cb9a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart","hash":"3623c605586d2e37af23d6b746721bd7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart","hash":"3e4d53a860279f33b4e7c6b1d9957a51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart","hash":"b0b28dbb0d6b26d142ff99ecbd5d8187"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/element.dart","hash":"361f3bd2e6ba6710885e241d7574326b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/compute.dart","hash":"c01ffc2036120e75a95496900bb49a4f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart","hash":"f209fe925dbbe18566facbfe882fdcb0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart","hash":"135373d55120d14b786fdabe98c9c64b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Textbook_unselected.svg","hash":"93a54f90a6de31d713d9a0fe53f11f8b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/newline.dart","hash":"d6beb013c7ba06cf6076e547a7b21f1f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart","hash":"4b5d82ddeb09bc46ae0e980616ce0109"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_attachment.dart","hash":"796d0d545778c85ce27a9304092b5ed0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/vector_graphics_compiler.dart","hash":"339d4b38a75faaa45624222be37f9109"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/theme.dart","hash":"4ccdd5e6210285f9baf09909e7d4f593"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart","hash":"a79a6f9bb06c7d6dc5fb74ac53dce31b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart","hash":"1f437276972808bf4cf722440da1b231"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart","hash":"db4a14227247e2524e46f6b0dd9da267"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart","hash":"b09ffd962fcbee7d3403b54155e33047"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE","hash":"3b954371d922e30c595d3f72f54bb6e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/LICENSE","hash":"2b36ca50262dc615e560c27654badb26"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/typedefs.dart","hash":"4c00fd95f493a02179f1013a29629e43"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart","hash":"0ddbbba088a930cb7ae5b5920ce346cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/optional.dart","hash":"7d49b944ccc5ee228590126488731a95"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart","hash":"f77f6a903d346f842a7fe474e427d6a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart","hash":"ed59d68fc74e5f7be21e0d7fc1c7242a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart","hash":"24094ce9de1b9222a8d6548d3c01045a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart","hash":"9298606a388e3adb5f1bbe88ae45b1e6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_response.dart","hash":"f29d1458f73f015dabefc27f98181f05"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/node_type.dart","hash":"57e5dc91c30bff1774eaaa45a798d0df"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_reset_page.dart","hash":"b316e534e1967412c68b1a042986a798"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart","hash":"ae85856265742b6237ed0cb67c4364af"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart","hash":"e5a3ca065f292c0f0b0cca0a55df41aa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/flatten.dart","hash":"b192f8c8e04e47ae69d662e5feff7306"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/namespace.dart","hash":"d7259aeee1602df30d051e8fc0523d91"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart","hash":"e45c87e4aadaebf7ba449f4c60929928"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_member_name.dart","hash":"2ef397117616f6ff779ed0ab2dd0d61d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.10.10/LICENSE","hash":"1ac261c28033869c8bcf9caaedf74f6e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/visitor.dart","hash":"9e63190d98c0519ef00473a9451fc5db"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart","hash":"6618a55cdb528b43addda36642363d96"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart","hash":"9e8b56ffe3de97538d012849a1afa5ac"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Textbook_selected.svg","hash":"658f8ff54183bf1c1c90677a39dc7f05"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart","hash":"4250bd72ef305d1f376e96cc6b994778"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart","hash":"f54f6b61b175b0a37d51ff3ac8b8c800"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/types.dart","hash":"1187c7bfe4c5a401ffb5ad27a944c035"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart","hash":"a06bb87266e0bac30a263d7182aaf68c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/comment.dart","hash":"74fb000405fb96842a3ce15a519d8ae8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/noise.dart","hash":"996d7bdb8134338c2357699662cee703"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/default_style_information.dart","hash":"4cc8128599d4dfdcbd699b3f01d68904"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart","hash":"0f70aaa46e42cb439dcc5a21fba00f44"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart","hash":"0fa4800227413041d2699ed47918c7f7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart","hash":"d9d777d58bfe8521d1cee4c60700de58"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Alarm_unselected.svg","hash":"22f085ac90f93a6cbfea8c2c872edc30"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart","hash":"777aca422776ac8e4455ccc7958f7972"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart","hash":"154bcb3658f38871192c3955ebccb00a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/definition.dart","hash":"f0cf3060fe907fd075c49261e69b477c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart","hash":"fb2c02d4f540edce4651227e18a35d19"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/mutator.dart","hash":"e105e8d3303975f4db202ed32d9aa4c7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart","hash":"3c1bedbe57228c35f8421d813a7237ec"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/path_ops.dart","hash":"bc3896a61a99aaf962226bd29cf010f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart","hash":"1b5af29e062854d33f5e4c81c2bdf11c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/parser.dart","hash":"1905c946413915323ba969930f19d207"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any.dart","hash":"3a1d79b051bd693ad652b0f905ff1588"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_options.dart","hash":"1693d7de0d1d5b50ab8a0db8e3c08667"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart","hash":"458f3bf784829a083098291a97123e81"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget.dart","hash":"d172e05d6fc5261869d94426786031d9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_pattern.dart","hash":"79a5f25a1a9d4aa4689bf37171e1b615"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart","hash":"229f98ffbc538c9813ef41d9f707f00a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart","hash":"904ebe4c195d2036f989a5e1c3c6052d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart","hash":"6f18c18a1a5649f27b6e0c29dfba4dc9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart","hash":"4c5df57cfe2a6a2bc0d7462330344982"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart","hash":"9c053b0efcabd70996cc27e9d6c9303e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/env.dart","hash":"278242320426f869a4121f48b98c2ed9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart","hash":"a8c03fde31609e92e69be46cf798cbd7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart","hash":"55675ef4bbddffa94d962bd52b3088ca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/inbox_style_information.dart","hash":"b54d4d23f060b78a02290d93a10d3319"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart","hash":"03001d3ddae80bbf1f35c5e70e0d93e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parser.dart","hash":"7f7dd4c5d3d4ad18886a0d575ebb655e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart","hash":"7901ed0c67e85a20ff901594a4231ba3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_message.dart","hash":"eb54a5ead5cb8ea548f36e4b8780e4b8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider.dart","hash":"1962877d0f77e2d3d7ebadbb093d4997"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart","hash":"9645e1d88d63387bb98a35849f4cbe53"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_web-2.24.1/LICENSE","hash":"2abd2c9a42d4caf2b4f1640d68b02fd5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/exception.dart","hash":"9a74595c2e95795b6c96d74f2b6bcca8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart","hash":"95bedb83cd5b163e43b554086b016380"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart","hash":"2a10c15764942d10992468122feea62f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart","hash":"4a4e74da2f12d15dddf3cddd0628372f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/comparison.dart","hash":"643ca26571c2ba94477233dbb914b1ed"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart","hash":"e1648c3accd2c87d0897e5454a387c3c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart","hash":"34a4d340931147322eaddc77fdc65c22"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart","hash":"d1e0e0c2904bd9e5145d919296eeb580"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart","hash":"c7fd5a3a7f809d37cfe6af2af573d097"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/possessive.dart","hash":"485043a68e11755920abd67f229ffe9d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/about.dart","hash":"1a8cf97475fa611bd193041415e8220f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart","hash":"56a59615d1fa716ece6eff8304f7bd34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart","hash":"7592e5df71403552b6109cb4fe946eee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/code.dart","hash":"1216b7dc6f446693a3fcb9a566b94d94"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart","hash":"29befe23f841cf5dd2dc7df24c13d88d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_write_buffer.dart","hash":"63d2768cdd6ab5a282fbb6a86c237b78"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart","hash":"b29e302994b1b0ea5029734406101b8e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart","hash":"f90beedee11a434d706e3152bfb2fd15"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/src/messages.g.dart","hash":"a5362386f63b48f5c6b1099ad942b40d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart","hash":"d857a3ae7f599cc71f41689ffcf1fc5b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/processing.dart","hash":"5a7bd956aa537e95be882d4809232c39"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart","hash":"6b3b758749ea0e06a43533073febcb66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications.dart","hash":"672695b311530b8c64badc8eb93e6fd9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/default_theme.dart","hash":"92cd3ab206500a956ac5bd8c53e8286c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml_events.dart","hash":"81c2aad8ddfe7e91e913fa4c319764f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart","hash":"8dfd28d2164bbd446b480491aace196c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/LICENSE","hash":"9633ac2bb6bd16fe5066b9905b6f0d1c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/predicate.dart","hash":"c135a8cfe6154841111bd7d4f7c7e69a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object.dart","hash":"0cb51131f14d4d8df95aee83e4931780"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart","hash":"d74d8acd1490e1db907df61d756d2c71"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart","hash":"b1da6e4c330ab79eb371fb535a8fb7cd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart","hash":"4349dd08c33e677b65d9e00f13c35d2e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart","hash":"66272a6751b167051ba879724cfe5749"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart","hash":"de7fb154b9b151b81a78d43ade695365"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/file_selector_linux.dart","hash":"25c44b3908d2602e0df540ca5b17da27"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart","hash":"34485853c65233b4daedcede2ade0c69"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/obb3.dart","hash":"5ad121ce46b5c0473bbe34be6d5c0913"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart","hash":"951bd729c13e8dd03a7f4edd8b10c06d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document_fragment.dart","hash":"88acdeb4b5b5a9e5b057f7696935fc2e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart","hash":"5da121a0d3087e7cf021bfcdeb247b77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart","hash":"b266a6c412cb5bbd5355fc22a3be3f84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart","hash":"391dfdeb37052a0c52eb8adbc96bffc1"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/NOTICES.Z","hash":"cd73c76aa70c71429eeee003d0a60286"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart","hash":"f7b4c0027cecafcb6711746922663d7c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_selected.svg","hash":"658f8ff54183bf1c1c90677a39dc7f05"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart","hash":"d74cafcf507b38e3f3094c6d5ed94a9d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2025.jpg","hash":"c0c39825a7e79a0d397864528c2c8b81"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/loader.dart","hash":"14d64729800391fb58a32643b7126984"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart","hash":"9a023a5d9b2c849e9c7fd9e16db1e7e2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart","hash":"75f947f0ba87a0789a3ef91542bbc82c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart","hash":"d70df86ce471e8470438627a65b2824b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category_option.dart","hash":"f328cfe04255be8a4d740b54f2854bbe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart","hash":"fe766313e73046aa145217de64ca7760"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/typedefs.dart","hash":"3e93222dc359a938c1354ba486d44244"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/event_attribute.dart","hash":"304fc982848b57cf13da0ec511f05ed9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/messaging_style_information.dart","hash":"017129b89f3045aa21d9a8032f5dfec0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart","hash":"a056a48864751b648133bf4d0886134a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart","hash":"8a39bdc324d0ff25097784bd98333c08"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/chip.dart","hash":"926a78bbb0d20acd22028c14ca8b8071"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart","hash":"91d8303ca1ccc72eccc1ae636c7825ed"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart","hash":"bf6d84f8802d83e64fe83477c83752b4"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page_v2.dart","hash":"a475b741bdefeed0127f22fd7bd540e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart","hash":"974d0c452808a1c68d61285d0bd16b28"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart","hash":"44c1268c1ecafd3b4cd06ab573f6779a"},{"path":"/Users/downy/flutter/packages/flutter/lib/animation.dart","hash":"29a29ed9169067da757990e05a1476ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart","hash":"3167bedcdf6eb73bb3355fc778c69ab2"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/fonts/MaterialIcons-Regular.otf","hash":"e7069dfd19b331be16bed984668fe080"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/ancestors.dart","hash":"3f842dc9d82d8b21557bf598ff4ec83b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart","hash":"a6c467b3086118863463a925df22d187"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/basic_types.dart","hash":"3661d2fbcfb187977923b56f618b1103"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart","hash":"2675cdf47e408031206cc9c215200004"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart","hash":"36bb3dc8435f5085b78c2972f8efe90d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart","hash":"f9ff8d662779df64515cdb55d0c3e342"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart","hash":"8d05e0330774daca2ab93f307ded78f3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/doctype.dart","hash":"c2d76b78fb107e358b1ad967f15f1746"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart","hash":"12143f732513790cd579481704256dcd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart","hash":"c7cc72c1e40d30770550bfc16b13ef40"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart","hash":"a8f2c6aa382890a1bb34572bd2d264aa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/each_event.dart","hash":"5776e262e9291819ba2122854943ea6d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/default_mapping.dart","hash":"a2187618f84ad697f470a748b2a27f56"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/capabilities.dart","hash":"b7729342f9613bd823c71f9c12c680b1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_vector_graphic.dart","hash":"3f4bc5c1ecc7c8c1756db79f8be177b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart","hash":"6efba60755f63ff2efc82c76d3a50222"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart","hash":"1f131d7f971396d52ce5fe78ae6a8a83"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/repeating.dart","hash":"9a0bdbeb6a1452722cc91b80ee779998"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart","hash":"1268762fa54412a0d265cb57a14cba84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart","hash":"19c24981d3d862f7206e587073eaae67"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_tree.dart","hash":"eedac0b4fc9b2865aae62ba790f0e26a"},{"path":"/Users/downy/flutter/bin/cache/engine.stamp","hash":"383b255daebb4eb59cd9619930afce20"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_segment_type.dart","hash":"b46578a0f8f94ea4767f634b5235a54e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart","hash":"d33374c0857b9ee8927c22a5d269de9b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart","hash":"6486bc074c81ec57bdafc82e6a64683a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/draw_command_builder.dart","hash":"dc602dea0bc34c673d92a3e6096995c1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart","hash":"08c3fd9ed1607d3a707ffe9b3532218a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/types.dart","hash":"7e327134a49991d7ba65bbfe46bb8f4c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/tessellator.dart","hash":"5e4fca343abbf78a251574e239c0220b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location_database.dart","hash":"011e1e9f46dfe9400619c8e5103c30ef"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart","hash":"7e45468116224ee318aa9b1f210cab12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart","hash":"bd6d122c12d867a991bd2fd36a3c46a8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart","hash":"cc6cce102fab186d0e7a063d0d917504"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart","hash":"06078529e4523830f3ad70e0aab603d0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart","hash":"f487ad099842793e5deeebcc3a8048cb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart","hash":"77900a31d721da1722fe34c455a00d3f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart","hash":"73d5607bd6f5dccf91add39e25ad157d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart","hash":"bc3c12f9555c86aa11866996e60c0ec9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE","hash":"2d0c70561d7f1d35b4ccc7df9158beed"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/petitparser.dart","hash":"6cb32004f228090f1200484076254c7a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_detail_page.dart","hash":"11023d38b622c8afd4f67442d66639f9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/end.dart","hash":"d6b4c337633cf50449be67966688dc32"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart","hash":"eaf5aa7cf4fe19db30724f637b38257a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/core.dart","hash":"b969cd0066fa07b8082edb76d2af77e1"},{"path":"/Users/downy/flutter/packages/flutter/lib/semantics.dart","hash":"4b784d6e4f290bd6d5a1f38bfb5701d8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/port_mapping.dart","hash":"d1870b4415ddf7f379e6e41b520ca299"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart","hash":"c761b80666ae3a0a349cef1131f4413d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/nav_home.png","hash":"875ffbaba3b258b9a62790bbacd26472"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parent_exception.dart","hash":"2ede71f09a240decbc57417850f8feb7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart","hash":"f5b38c21bf580c89610a8b58c65aae00"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart","hash":"3d71d8940be022672282ed70f0cbb8c6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart","hash":"8ac28b43cbabd2954dafb72dc9a58f01"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/pretty_writer.dart","hash":"09214b5a4ed4e104f212ef38f676fb1f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart","hash":"6cae6900e82c94905cc2aaefd806f8eb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart","hash":"f949f49484067589ef08e13a892f3101"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_workbook.png","hash":"72c5af6bfaa9a9ae4e20a77548c4f6c4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/permute.dart","hash":"8171c3b0d66f560aad82b73d43393092"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/LICENSE","hash":"9741c346eef56131163e13b9db1241b3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/event.dart","hash":"1a7fe7a35dbd168a7f2e10065f4a3158"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart","hash":"0fbec63144acf1cb9e5d3a3d462e244b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/date_time.dart","hash":"2faf9ca0d113c0ed79c6651a9c1f76db"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart","hash":"e3127548d819af5ec9ecb10b5732b28e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart","hash":"ca959e5242b0f3616ee4b630b9866a51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart","hash":"e9a141d0ed4d585b165b7fcacc3874d1"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/login_page.dart","hash":"e16fecac4335e99bb8ca534154d6262e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart","hash":"dc667b5b278c7b8a2191913ac49e33d0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Mypage_selected.svg","hash":"4081b7b651f16b9421f4eef92cd8f69c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart","hash":"eafe83db9186e4fbb802d857e4bb42ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/binding.dart","hash":"064a460171599d3d2a4596a5d1ea2b00"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_menu_button.dart","hash":"c5e9b21796184a1bdbd5788371a913c8"},{"path":"/Users/downy/flutter/packages/flutter/lib/material.dart","hash":"79c87aaef3dd490ff1c43fad2f2f6e8e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart","hash":"ff5d66c50ec833a263625d39f0c195b9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart","hash":"184d3b79d275d28cd02745b455041ee6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart","hash":"f6d7d6477016f1f991e57b2cbeef7292"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart","hash":"8fde18d2ef5c741e3b748bbc854d6b17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart","hash":"58feb628edda8670acd9b4c4db589918"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart","hash":"f158ffadca730ab601c60307ba31a5e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart","hash":"20051c4912af535e0a8362fb1e93f423"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart","hash":"caf148b76c44a3f0f1bd6055ddbb8f5e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/parent.dart","hash":"210257ed62edd783098ed34d7cfb0204"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_match_rule.dart","hash":"0298dac3221d4c6752b6207594e4f470"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/digit.dart","hash":"e475fe11812000841b73324ccc3b3183"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart","hash":"207aa61e81c77c54342772a6367af334"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_verification_page.dart","hash":"c476cb167807940f2c6ee986934daea8"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/bottom_nav_home.png","hash":"9479f3d4c7e70fc2c423c8f358e2dc92"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/resolve.dart","hash":"cbb8e1af9f1f0decfb6fc25a0725c51f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate.dart","hash":"bd343bbe0baca1494e15a8872fe23e6f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/position.dart","hash":"faedea5895c9ddd2b2c270817c61d1f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart","hash":"5de15d7a41897996ef485c087ef4245b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/sequential.dart","hash":"b5519514c9b9570c951c0da186030e29"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/text.dart","hash":"f52860ffbd4c6858f092292d1589d556"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_video_picker_options.dart","hash":"091c22e31f88028ff0cee6f6ed581d74"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart","hash":"9ad11b4bdb179abe4ccb587eb0e2aebc"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Kakao.png","hash":"7e3eb90819c0f6ef186ee3d8835b5bb3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/nodes.dart","hash":"8608080cdfc143d462b0f9947dc0d7c1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/path_parsing.dart","hash":"498f254119e3d3c67475fe8ca026d01a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/image/image_info.dart","hash":"de8156593b2cb55c127213759bc77f58"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart","hash":"56e9b43aa79d6b888e779ad7905c1617"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart","hash":"4d6c8c8185327af9d064a1fbeab18fa1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart","hash":"fda1d4b1be4a584133638117945d3dff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/posix.dart","hash":"f19239fe10cca0cd002c22edba90eb52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart","hash":"b698617b81ba534ca60cdb6dee762fff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/notification_settings.dart","hash":"806db0fe7cc5bbedb3e8f229ed0786dc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/range.dart","hash":"5e99407d87eef382375ad62495706f32"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_notification.dart","hash":"862e144a0d18968ff9720807fc2a43a8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/character_data_parser.dart","hash":"7b4a3d153a0c2e22401073c511515325"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/group.dart","hash":"e3471fd3bfb2f9217d1cf61b1bbcb43e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag","hash":"a0e89676ccae6cf3669483d52fa61075"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart","hash":"4935fd96677780d631f23a75e7009534"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/label.dart","hash":"7de7aec8bf9b53488692403a3feb7672"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/processing.dart","hash":"0ca8410c364e97f0bd676f3c7c3c9e32"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_interface_name.dart","hash":"4f835012742ef22df8c85292594f9823"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart","hash":"0672d853d5097a03eddc7dbe558eeabd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart","hash":"43ef2382f5e86c859817da872279301e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart","hash":"d4252f423175e5c21fca23dc24154b84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart","hash":"6f02e150859b1047ec04ffa4a924f90a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE","hash":"175792518e4ac015ab6696d16c4f607e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart","hash":"f56109c40e6fe9e53f9c6ad021d25ff5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart","hash":"2aec07fe4a1cd25aa500e5e22f365800"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart","hash":"605dcc1d6bd5023fc0b651a625076ca8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart","hash":"5176206f3155513053dda23b0c32fc8c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart","hash":"986845a7043505c19753e1d499d49a4a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart","hash":"edd2f9cabffc7ea6a5a9497a1b1beccd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart","hash":"ab177cf671fb7bab974d9c08618a677c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_message.dart","hash":"f4b52208f2ac65794c0722ae22b2ed5a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart","hash":"c9cd996cea2334f644c74ebbdb41f7f5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/undefined.dart","hash":"bb00c98e50d3c71d4ab7ac7c46122f3f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart","hash":"13c8dcc201f970674db72fbbd0505581"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/FontManifest.json","hash":"dc3d03800ccca4601324923c0b1d6d57"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/learning_statistics_page.dart","hash":"a5c850065330b1ca508af48bb7920fa4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart","hash":"270de9c98f9c1284da0a6af9176ee1f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart","hash":"dc2cfe4408f094916cd5eb1d294d1f2f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart","hash":"920b63c794849c8a7a0f03f23314bbb1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart","hash":"8a7e3b181572ed50e923e5dc05a7533d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart","hash":"289e5bbf4975b43a1bc7510306854b34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart","hash":"d161560a01cd02902c87f5decd590cfa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_5.dart","hash":"1e4da3528271172cb17b59a72a37a57a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart","hash":"e79db1a382e61436ed81f9f47dc06d7a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart","hash":"1542c76e7b3e366d393fcb2c3bc601d5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart","hash":"89b2bd5c8fc199b582eb9f10973f97b4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart","hash":"e792b35686d28f5a239264b5b791c0cd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart","hash":"395f07418a28b12b0ed665f32270d702"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart","hash":"92868012710ac163590ba05c788c0816"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart","hash":"c4d13715583d2c97acba184a3e821151"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart","hash":"555fcdeebbe6517cde1cdd95133cabd7"},{"path":"/Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE","hash":"4fd63b752aa4c209c7c0bdd1ee5f8a10"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart","hash":"1205ed5e14a59c237c712b8a495b1981"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart","hash":"73189b511058625710f6e09c425c4278"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart","hash":"53d7a28895126d1b4c472405e2876fb0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_tessellator_io.dart","hash":"4aa9532707ae3709836dac6e154dd477"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart","hash":"8a60b4ed49f146296d6896973154e1d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart","hash":"3cddcab8b952545bc05a5c1475a06c9d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parser_exception.dart","hash":"a62996936bad6c27697a35bed070547d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart","hash":"85cf42bafb7c0646bd7a99379649da29"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart","hash":"9ffd4af5e11781c62ed4e40fdf15b182"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/notification_details.dart","hash":"5bc24b31455e76bc74c05a2ee528dcbe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart","hash":"269af8ca7030ccfd9c868fe9af8a6b0a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterable.dart","hash":"037df9e7342fc8b812d985c8b6e8a0c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart","hash":"ed5548873fcf5a0a5614fc52139600b8"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_page.dart","hash":"09ab94aeb507991e01e2a6a26402fe5e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/flutter_local_notifications_linux.dart","hash":"bd3131f212db4084582e634bc232b43b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart","hash":"7ebcf3ce26dea573af17627d822e9759"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart","hash":"f64837679a1abb526e942b166db5c244"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart","hash":"965c702e5f0b6ba27c6292cf3a602781"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart","hash":"d3eb6373e2fd626717b8de7cbf19cd8c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart","hash":"b3a6dd250e09b61bffbc04a767f0c920"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart","hash":"3c8d2d2b73f69d670141d376642e5252"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/failure.dart","hash":"30a4963c49e7dd57d8cec29b8f4821db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/image.dart","hash":"5d0aef3e7f7bc482577c813d6fb87f20"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart","hash":"6a612ac4de579506fd1b806fac3fe062"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart","hash":"ad139ffd36c17bbb2c069eb50b2ec5af"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart","hash":"78f6899dd22a8086e573217b5538f98c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart","hash":"b062a8e2dade00779072d1c37846d161"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart","hash":"59b6b74779849bf5b836b84bb362b99b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_result_page.dart","hash":"4e96f5ebb837b7ddf114b335c507dea4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart","hash":"cb454929d7810d3ee5aa5fc28283d3fd"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/common.dart","hash":"b9127267cdd2de6c1285a11eac48d269"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart","hash":"553c5e7dc9700c1fa053cd78c1dcd60a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart","hash":"546a4af6d99fa77922a881e2f131c1f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart","hash":"f3d29b37515ed98685cd81aa319dd254"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/uppercase.dart","hash":"997830cae101fd7a406061c7a46c5114"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_server.dart","hash":"0b4a237293e913152ca376cdcfbe752a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart","hash":"5577ef7cd41e467cc247a42b677f93c9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/color_mapper.dart","hash":"5baf64b18f36d2e7620e01237c625a19"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart","hash":"79c35fba64a91629072a76526adb9aa7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart","hash":"107c33a245427bf0f05e21c250653dc6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart","hash":"6be1e6f404dc5206ea2b4fa512c45dc3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart","hash":"de17df889317f7a54961ea540cf4b807"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/helpers.dart","hash":"20e259f655329b9bc2ecb98ae2975e72"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/image_picker_ios.dart","hash":"7b97e07dc767038c0b776897e88f1ccf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/prefix_name.dart","hash":"fbb3e43ae57262b3fc190cb173a7b5bf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_address.dart","hash":"4ecc0e7678d4ed3bf62a04b3e383e424"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/schedule_mode.dart","hash":"9979b67c6fdb803b55c4628af847ad4c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Upload_image_selected.svg","hash":"b007fa5f063d26273adf3911feafdc5d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart","hash":"8b15d222f5742b46bf55a4ef4cbfd6e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/start_element.dart","hash":"2c72add0b4beec6c29322827553e616d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time.dart","hash":"872d879ea43b6b56c6feb519cc12d5a9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/vm_snapshot_data","hash":"b8ee00883037778797bf5949230f40a6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/colors.dart","hash":"f59aed120736d81640750c612c8cfe5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart","hash":"f94061e9a635be75dd8e38eab352c344"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart","hash":"ea7c9cbd710872ba6d1b93050936bea7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart","hash":"ef5fc00d685cd2a36c4de80e1c7e3a8f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart","hash":"85b908f2e50b980d5cab7f458371f430"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/result.dart","hash":"bc503b6c5e3658a13efaee4e0638935a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/LICENSE","hash":"a02789da8b51e7b039db4810ec3a7d03"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart","hash":"1fd7c932679011d491315ff136d13822"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart","hash":"15a20afe634cea8448869b051ad52b3c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart","hash":"cc4a516908b08edff4fade47d6945e5c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/plane.dart","hash":"fe0f3503d326c72bc31945d24f76946f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart","hash":"d7a6c07c0b77c6d7e5f71ff3d28b86bd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/icon.dart","hash":"cb4cf0d998a65879bb40daf8db093eed"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/event_codec.dart","hash":"3a9a69af68cc0a35c422d0bf03873265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart","hash":"4da7ecc08c07abdd0226004f30973748"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart","hash":"9d1525a634d27c83e1637a512a198b4f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart","hash":"785eedcc96fa6a4fcc7c81a8736a7427"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart","hash":"3ee18da390e16ca65f2ef168adb8a1ef"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart","hash":"c679063104d2f24639459c8ab3eed77a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_home.png","hash":"875ffbaba3b258b9a62790bbacd26472"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart","hash":"1e2afd780c32baef8cedd0eb9c4dee6d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart","hash":"cf63ef7fb2873f43a2b2e25485734429"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart","hash":"faf4d014b3617ede3150f80eba25e3b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart","hash":"12580e996c5cb68c4e80588f6dd9f235"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart","hash":"cb49e0d1c096a600c37190f5a40cbecb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/arena.dart","hash":"04f3f5a6ad35c823aef3b3033dc66c3c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart","hash":"6d0b38802aff8cbe310e72f1a62750d6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/paint.dart","hash":"340ffd6b17fc593e08d99aece89e600d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart","hash":"9ea1746a0f17f049b99a29f2f74e62ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart","hash":"f6c6b31745eec54a45d25ffe6e5d7816"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart","hash":"36fc598c656490ab430ca1be5fb909e8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart","hash":"a93ae192d60f10b56cf1659d2123bc95"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/types.dart","hash":"4a9817f509bb8eb7192a89fa9aa015dc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/normalizer.dart","hash":"8bd96caadcaefb063cca0c83d7707a57"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/string.dart","hash":"1aaa0309ba77b0f57733e99543c455ea"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart","hash":"38fcdd2be2a4d0ecbbe01cc03cd03e96"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/and.dart","hash":"1e9ed9cdf00b9449d9b72dcd00add4d3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_path_ops_ffi.dart","hash":"41a453ca5b911d0322a4cb525f53a92a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/entity_mapping.dart","hash":"5abb58e10e8ea85ea5990a97ee20ae4e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/lib/image_picker_macos.dart","hash":"016db765422b67025aa356222c67d610"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart","hash":"a74b5a39115ffd608a19cad9309e6a31"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/platform_interface/image_picker_platform.dart","hash":"304510c80e4af2a9a60fda4d9efaa8eb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart","hash":"838c8a1a376a7c9c3fb3424927bcc75e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart","hash":"4eede9144b4c0e4b14bd426654183174"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any_of.dart","hash":"853db49f6cc034267b3dffc26052f4aa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart","hash":"c3ccb5b6cd3df44e6587a4f04dd6a4e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart","hash":"d2372e0fb5a584dcd1304d52e64d3f17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart","hash":"e4a32acbcd5da5e636d429dc167fc5f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart","hash":"e6467427260f3274e8424d691615ca5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart","hash":"b39287c180e3ac3047fc5dba3a44a524"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart","hash":"bf50f61746b9744a0e2d45a88815288f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart","hash":"9f5e8439ef3cbfa84f76922ec3580363"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart","hash":"47ccb32c843b4075a001e612853b2a31"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/string.dart","hash":"a1f47bfa90f0153386bbcd0c4b16e09c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart","hash":"632d3c730c9b6e4f46d9c0459c53ca9c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart","hash":"58678829e383937c51f539f2ad67fc17"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/social_login/Button_Kakao.png","hash":"7e3eb90819c0f6ef186ee3d8835b5bb3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart","hash":"5aa51467523e637443dec44f6c7b1e6c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart","hash":"1adcc56e3affffb23739c7c9d8a5fca0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart","hash":"a2350d9426fefa6d657868d9e59eac7b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart","hash":"9434ff8aa06e13d5981ed6ec15eceb64"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart","hash":"87f0b72f24e05d2d3f4b0f1b4709eb51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart","hash":"3ee6304161ca2993b303a8074557fe66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/method_channel/method_channel_image_picker.dart","hash":"0dd542b84d1bdffac36624b0e9207d90"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart","hash":"85814d14dae3bc1d159edd0a4bef48e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart","hash":"2d2cd1fbe11b3e587475449fa04ad4eb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material.dart","hash":"5c93305f52983c3f2be825bf54ebbd78"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/unbounded.dart","hash":"a617a91b12a3156406da1d95552aa4a0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart","hash":"89aeee125822690cbd46b2ff43c76ec1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/annotator.dart","hash":"d45b4bb922c2941476a8b797e0e275ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart","hash":"cad4582fa75bf25d887c787f8bb92d04"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart","hash":"5d8e29422039d9dcce6908b427814d80"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart","hash":"900a13c9fcd73f4e8e3d069d76af6ffa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart","hash":"b1bb8356cca8b86afca314ab4898a527"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterator.dart","hash":"dd8517aec9099740b2b5828bde8d33aa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_server.dart","hash":"8580846ee9612281791cc377a99d0581"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_selected.svg","hash":"4081b7b651f16b9421f4eef92cd8f69c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart","hash":"5692636576c4bec471fd3a1275f08525"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/declaration.dart","hash":"3cf7786074ce9f1e148fe5f4a60479d2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/parser.dart","hash":"bb70d2e76c8609b7a22250037d9185f0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/base.dart","hash":"86039b13313ad468f867bb5522411241"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_form_page.dart","hash":"bef836fed3414eb345f753bc8a109eee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart","hash":"67d16e841606c4e5355211fe15a2dbfd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart","hash":"c8f69577793923bfda707dcbb48a08b1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/helpers.dart","hash":"25feac2cd9c96cc475403e601757cdaa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_details.dart","hash":"7c5b14805d686129e90293ef086d4d68"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart","hash":"3431f50e7abf9e27af232de10193931a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart","hash":"11fc97acd20679368ae2eaa698c6f130"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart","hash":"151d12284cf607a6e984aa31fe766faa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart","hash":"74939c971de1eb61ef05a7eb5056cc20"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/labeled.dart","hash":"715bccb8e9ba9889573a60bf0e457402"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart","hash":"a3bdbf775c61477db47c508f513688e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notifications_manager.dart","hash":"ce45b60ad9b0d7c8690b9b1fae2b7f6d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart","hash":"b80f25d51570eededff370f0c2b94c38"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart","hash":"075310a7fe661b71e9a583aab7ed4869"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/type_exception.dart","hash":"d39becdaf9cc42e3efd0c9cdf0034ac4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart","hash":"c069ad8b31e18adb75c27530f218957a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart","hash":"787093e38fffbbd356129a373907124c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart","hash":"62f852a5f85345e608cdc7b62a689202"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart","hash":"b78c67723942ac5480c158576c1247e3"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Academy_selected.svg","hash":"b68b6a15add7b6220fd62524a90fee5b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart","hash":"fe2489ea57393e2508d17e99b05f9c99"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart","hash":"62d88517fa4f29f5f3bcec07ba6e1b62"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_sound.dart","hash":"c0d5d7856094b4be15b738392704b921"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart","hash":"484481ff93d08a930ecfcf6907acf691"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector.dart","hash":"e8911b74c8d90dfc01657354e57d0fb1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart","hash":"8e286948f2eaa63514196c1e4c91666c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart","hash":"d72a4ddaf6162d8b897954e02b4a2a4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart","hash":"0ae47d8943764c9c7d362c57d6227526"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart","hash":"63db75c602690371aef0f83279a929d7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/curves.dart","hash":"4aeb4635d84df42e6f220aba366af7d9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/notification/notification_page.dart","hash":"42c46888feebad74a4368c9b0b74eef6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/result.dart","hash":"6782f277d348804f26f7a748f647695a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart","hash":"db799bf48af97b7c0edc93ad96b4a6da"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart","hash":"ee36aadc3fac54d5659c94c6aadcd007"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/LICENSE","hash":"46158b74167f78e44896e35a92c7c5e0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart","hash":"34ebb85f7f2122d2e1265626cf252781"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_unselected.svg","hash":"92f7f8888a8a844a4f1fa497cbe2decd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart","hash":"dbf4f1e95289bc83e42f6b35d9f19ebe"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart","hash":"0cf4e80f9e0fbdba47f42fef07fd5499"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart","hash":"dd510cd97dc23d22aebc7b60affd6329"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart","hash":"eb9b3bf513b18ddaf0057f3877439d9b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart","hash":"dcef90946d14527736cde04a54d334db"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart","hash":"42212bb3508502e1b011bd783d51ea78"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/lib/image_picker.dart","hash":"327c288f80ee09130d794ef74a733699"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_parent.dart","hash":"7f47dda6ed10e33236d465680dc8c12b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart","hash":"6987c3474a94dd1c4ff8f8540212f16b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart","hash":"5265b4bdec5c90bfd2937f140f3ba8fc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart","hash":"8d0306ecedceab52f23b17a0694e7842"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart","hash":"a2aa815908f2e15493e374b9380e558a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/utilities.dart","hash":"9b478f27df3e7bd44722deb3c1c69ca3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart","hash":"101ff6d49da9d3040faf0722153efee7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart","hash":"78ce7527fa364df47ba0e611f4531c2c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/chapter_detail_page.dart","hash":"17d725129f3d2750746304e3534ec124"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notification_info.dart","hash":"5f02ac3087f8d081f489730eecb97f70"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart","hash":"377fef989628d5fbcb306e46a03b7a12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart","hash":"fe750f835c7dc27ef38ee2fdb486a6ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart","hash":"d390b15ecef4289db88a4545e359bc8a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart","hash":"816a5cf300a6461fe2e7e8ca8a66a709"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/mappers.dart","hash":"27bd31140f6d692c98f0cc901a7d77a1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/lost_data.dart","hash":"f63f9b37983c0ce9736806a60038a055"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/.DS_Store","hash":"f1090a7e0712544a5401a7311bfb9e6d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/end_element.dart","hash":"813218451c1d8dd310e1233bd4ca7a4a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/firebase_core.dart","hash":"e80d9a4901b1381733c442e0cc05a708"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/frustum.dart","hash":"c19a7119c5f0f19f3d0f4531c5345616"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Alarm_selected.svg","hash":"b5a02676b50172a80c155f0104471695"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_9.dart","hash":"e20355dd45521a6de91669be6cbfb3a3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/attribute_type.dart","hash":"a9d570114e5a6e733fb029f6b3cffad7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_options.dart","hash":"df28ae2c4812ff5a3e9f41ca219b92ee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart","hash":"b2015570257a2a6579f231937e7dea0e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics.dart","hash":"671b26ea03821b4c63c0fe2fd64f9e87"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2024.jpg","hash":"bac3e7ec19ff9a3512b243743484c706"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/lib/xdg_directories.dart","hash":"737107f1a98a5ff745dd4e3236c5bb7b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_delegate.dart","hash":"f92c294999d700b8a78f8b1d5cd3cc2e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart","hash":"f8275b74f8f83272b8a8d1a79d5b2253"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_selected.svg","hash":"b68b6a15add7b6220fd62524a90fee5b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/file_selector_windows.dart","hash":"0902c41eed709a7841f11130fac2a593"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart","hash":"4e04af41f89adf9231bad1579f5bb9a1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart","hash":"77e3a9ed54e0497465a4346f273bcccf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart","hash":"8dea906a9b8773920b6d1ccea59807bf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart","hash":"97c7266e528b6f706b08b4ad340006d2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/flutter_local_notifications_platform_interface.dart","hash":"64aba6b07ccfb43755f1c29955134b53"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart","hash":"200da5ba0b0cee2bca1acd1c4d772118"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/LICENSE","hash":"2b36ca50262dc615e560c27654badb26"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/enums.dart","hash":"523742c594766cc9e39179d93cb23259"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart","hash":"4c09fb1ea4651f47d1a0a67ba3b31886"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart","hash":"4c13b34211e2b17645a6a5cd8defbe0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart","hash":"04451542afc67a74282bd56d7ee454f5"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/services/fcm_service.dart","hash":"dd1dc8abdd29f9af05b64d09ec827863"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/limited.dart","hash":"aa439be89f7997c3c5949ce32d2486bf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_writer.dart","hash":"c932575d5afb22daa2456a44889b3cdb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/method_channel_mappers.dart","hash":"5d0fb3d359f4af000209c65b873ae97f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/LICENSE","hash":"038c3f869f408e1194eda71cafcca6f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/painting.dart","hash":"4bd60bd8ede4b9dad954493d26d3e586"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart","hash":"43ba7557388f413902313df64e072389"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/triangle.dart","hash":"d9eedadb461aac1eebde731afb42a2d1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/picked_file.dart","hash":"4923864c67868dd1f3a8d7be3e4ca0f8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_picture_style_information.dart","hash":"5f8bbfd23974ae2842d3d03760b98f99"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/subtree_selector.dart","hash":"ef93f78a8a380eeade385040b1d075c7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE","hash":"d53c45c14285d5ae1612c4146c90050b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart","hash":"b4ab536e0cb6945296bb962bc1e9a3f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/services.dart","hash":"29ae1507a6ec4c2ffae469a10e505bda"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart","hash":"cccaa1a390453623404ad2f98ba719c9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/initialization_settings.dart","hash":"dc69aa43b73c7a61a7d20c82ac98cc36"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/predicate.dart","hash":"5cae30214f9509b4b47641f1d38b7fef"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase.dart","hash":"5ac6d992f5cbebe5e5d4e8bc4ed5ae6a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart","hash":"32f33f52f1a1e1b0911dbbfa4dd7785a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart","hash":"168bedc5b96bb6fea46c5b5aa43addd1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart","hash":"14acfddcb9e62f0de6f82d28e22c22f0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/cache.dart","hash":"e0cbefa359309715e5101bce98eb65e2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart","hash":"2d18e0064b57f514fab5c3abc06ace0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart","hash":"cd3f0ebbc282b839928f5fe3ad12c779"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart","hash":"b16458199371a46aeb93979e747962a3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/word.dart","hash":"27756cabcc328c2f7ae9e353b339d89a"},{"path":"/Users/downy/flutter/packages/flutter/lib/scheduler.dart","hash":"95d8d1f6a859205f5203384e2d38173a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart","hash":"29439c1f30cb2958458664e1e6e40289"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart","hash":"51fa10cf30bde630913ff4c6e40723ba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart","hash":"31d8245447d51dba20c81f00b214fb36"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/none_of.dart","hash":"9f69b819f3943f691b452d84d4cdb609"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart","hash":"c6da76a71962267cab91aadde5b59426"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/bottom_navigation_widget.dart","hash":"8067f607e74fd60a539ff359b14395a3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/conversion_sink.dart","hash":"efcbc6fd4212ea81281561abddbf29f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart","hash":"f7b9c7a2d1589badb0b796029090d0d5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart","hash":"df699735e3bcd730f16ce377d562f787"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart","hash":"bfb39b98783e4013d9fe5006de40874d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart","hash":"5275d424aba5c931a30e6bd3e467027d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/sequence.dart","hash":"061e3925eb77146a83903821d09bbd58"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart","hash":"984acd55714db5ebfdcab5aeb55467fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart","hash":"81d01d8cecc6783526e350800988db74"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart","hash":"18ad2d48b68dc9b514fde418b7acb599"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart","hash":"cb0d5b80330326e301ab4d49952b2f34"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/interop_shimmer.dart","hash":"b6d804ca88cfe7ef727b6da2d7c35b30"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart","hash":"f01b78dd243cdceae98d62e7429f3d04"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart","hash":"40587a28640d3c90ad2e52fdfbcd7520"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/pick.dart","hash":"c60b204fb5e7d501c0addb330c88d2de"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/continuation.dart","hash":"95adecf7ec0db3c154665406582e0513"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart","hash":"15439eaa12b927b0e9a42b9d168e3371"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart","hash":"9eb1b00e42fadb0be56354c8bc9feb4c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart","hash":"f12f9a9b8bb504f4617bfd1c00d403f0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart","hash":"f301af2d0392296f456363085becbf47"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase.dart","hash":"1c59332e69e34c4a84aa48efd657f103"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/theme.dart","hash":"88718f823c0de3f8398075d24b150ecf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/src/messages.g.dart","hash":"e44269ac2e84082ce2d4d67a1ceae2d2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart","hash":"8fa0c1ec158277156da896110a03d968"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart","hash":"a0936682931bc884c5052e9f49bf8829"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart","hash":"aad5ba4c4076b74ded1d769dc1edbceb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/x_file.dart","hash":"d06c42e6c83be207b86412e11889266a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/badge.dart","hash":"134441e2b4b42a7b2ee012ce48910557"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/native_assets.json","hash":"f3a664e105b4f792c6c7fe4e4d22c398"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/LICENSE","hash":"b776a584ba475b946d8e76f1e42585f4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/io.dart","hash":"a45632c7d0440400b3f7a2ce615d21c0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart","hash":"f179ed2f20226c436293849c724b2c4d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_100to100.png","hash":"454be3ff72282ffa8fe50f8f3e44658b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/whitespace.dart","hash":"57a5a9f535e7c37d09bab9aca685dfd2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart","hash":"063f2360bd47faba2c178ce7da715d92"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart","hash":"e76d7da2d8f4281119d176fdcc04b991"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart","hash":"b7b71e22b53d4d100702d2ba7a7130db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/converter.dart","hash":"affb97b6cbd84919fa30ea3bcd5f12df"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart","hash":"5b04f80518a8417cb87a0aec07dacf4f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_object_selection.dart","hash":"dd006282a4ae0bc84d10206ea7441925"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart","hash":"dc196a3f1d514347c5f7da6e197b384d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart","hash":"393c6d8b9c1a038b62a418fadf8c69c9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart","hash":"5b98d0be4d89f1274c832a4c340ab315"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart","hash":"af709d56567f1923ade761542e8dd796"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart","hash":"600a92f02eb307032e6cedc6c5f104f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart","hash":"6c0e97a3b04c9819fe935659014f92e8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart","hash":"f49291d1bc73b109df4c162db10003d2"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/edit_grading_result_page.dart","hash":"cbfa4a17211b74bffa1e9924389d0111"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector3.dart","hash":"1dd695066bccfccf510bb80b2b137ad0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/exception.dart","hash":"773da8c184ab316ec6998980a1448a1c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/file.dart","hash":"cf3d93bae83850abf2c5e943a6b1ccbc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart","hash":"1fc94d5523beb1dda68dd704b8f99bd8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart","hash":"53b9028402187f878713225b48bdd5bb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/character.dart","hash":"091e29d23c58b7a4b5529953044bd344"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/html_render_vector_graphics.dart","hash":"2ac99a26ca075c8cd9f8f7ffb741f3ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart","hash":"f60846aa76dab98607aa06c9bd6cf1dd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart","hash":"43268fa3ac45f3c527c72fc3822b9cb2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio.dart","hash":"1e0f99d28825c416ceb5f264b6af7fdc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/pattern.dart","hash":"984f27f723ba52ab371439e37b31ca91"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/token.dart","hash":"710a4fd96b6281c1ab359ea6df4ceee8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart","hash":"fa2a57b3b873fb7db4b8b961735e4ca3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart","hash":"e4da90bb20b3980a03665a080c87a098"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart","hash":"21e56afda1f096f0425a34987708ed56"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart","hash":"0976264b99a1702a5d74e9acb841b775"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/util.dart","hash":"d66f7ff750a1747331f6a8eff5de618f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart","hash":"6a9dc1f0e0e14fc0ef5efb4c3c1e8a77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart","hash":"5be90cbe4bbf72b0264413e4ccb5c275"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart","hash":"a64e270c19c9e9ed0c5d9a17e0c4a5d0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/matrix.dart","hash":"d431d7f75c308e2c52c9f02a3872c677"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_selection_type.dart","hash":"edc1b7a42a3cbf8c27d6952381902b71"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart","hash":"04c960ae6d770135bb0b6acf14b134a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart","hash":"622fb5559ef551a734f0ebae8660485e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart","hash":"8986177ba204a808c603c35260601cce"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart","hash":"1d8fa1cee64f2d791002749fabe23e2e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/isolate_snapshot_data","hash":"c8760dd22936a794d8412e15baab1397"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart","hash":"547eac441130505674f44bf786aee606"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart","hash":"625b4ed63675ca8ffe8c11d0469bdd9f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE","hash":"3c68a7c20b2296875f67e431093dd99e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart","hash":"617fb0bcef7162a860ca76636507117f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lookup.dart","hash":"f2698cdf4b07ce88e4996e23f26cd0da"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/svg.dart","hash":"31f93c7db16a50136e8ce4042de7169a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_decoder.dart","hash":"3d7fed590b9d1ab99d591b04487b9287"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/LICENSE","hash":"2b36ca50262dc615e560c27654badb26"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/src/messages.g.dart","hash":"5b5f54337e36aedd16b5409efa8a5aec"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/.DS_Store","hash":"f1090a7e0712544a5401a7311bfb9e6d"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","hash":"0864ad73108959b573b007ab6025d731"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart","hash":"83fc222e671ddaa7fdb3868c0acaba0a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart","hash":"d828c4334e98a12974d90e38d48db9f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart","hash":"aaf8cbac74b7b5a3a487d5ddfc2bcdbc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart","hash":"d67712d7f3394870d88650dc0baf5855"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart","hash":"73f043194b9c158454e55b3cafbdb395"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart","hash":"a1e4de51bdb32e327bf559008433ab46"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart","hash":"2a08c219491feeb1c8e9b9d492ffce44"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/message.dart","hash":"fe4f36f2c139e1900dbda797a7e07fc9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page.dart","hash":"ce65d8fe10d5c94741dda20b41546ecb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart","hash":"cd6b036d4e6b746161846a50d182c0b5"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_LightSsen.png","hash":"5ae53d61eeb9909a8c892ca39defd1f5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart","hash":"bf365ded028510087ed69c227bda0d52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart","hash":"a36981329a77de46168efd089c4102e2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_device.dart","hash":"58c3d0c10ca3f530bab03bd5c0b43c72"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/cdata.dart","hash":"008d33cc2aea11e7921ee238469947b2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart","hash":"38570a2af41c2f9a4632e2af3b42ffe7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart","hash":"2b2a74f1e45f48fed04eab35ae3c85d7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart","hash":"7cbeab73e95bd7561ac8b9519c579ffb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart","hash":"8cff8c004f57019314d3fe8176de4043"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_terms_page.dart","hash":"f68301976a35bbbfe4ef761c339268b6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart","hash":"13c9680b76d03cbd8c23463259d8deb1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart","hash":"56a764067b45a1a7cb6b7f186f54e43a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parsers.dart","hash":"377b2ee79e4a825356b695b7b6f017dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart","hash":"dd518cb667f5a97b3456d53571512bba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart","hash":"b15a3573191a80dfb78fd6a729390c0e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart","hash":"9011b30a404dec657806a780b55d0610"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/LICENSE","hash":"96ed4c0b2ac486bba3db2c5d2a96afc4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_match.dart","hash":"d742d41268dec3da5e669142ae344928"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2025.jpg","hash":"c0c39825a7e79a0d397864528c2c8b81"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart","hash":"9d273d5a3c1851b0313cd949e7f84355"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/helpers.dart","hash":"dad9796d04d76633de091aec36be71c2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart","hash":"c83781cf0c38883486f707cddbb96773"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart","hash":"374ee130942948f52e47681818bd315e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart","hash":"5c9195780e56985cc88956aab0887ab3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/char.dart","hash":"7a6d53ccbed48dd524627ee1a945ac15"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart","hash":"25dd0d36ba8109e3199faf508b41d633"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf","hash":"b93248a553f9e8bc17f1065929d5934b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart","hash":"0d8aed1407088c73788f25ffba071cc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch.dart","hash":"721c2d087f423a3293f5314804ae66a5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object.dart","hash":"4f187fc37cb2a7eedf4681e2321792f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart","hash":"49f335e51e1a6242ba8ab55b48de9d92"}]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/app.dill b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/app.dill new file mode 100644 index 0000000..e0c3a52 Binary files /dev/null and b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/app.dill differ diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build.d b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build.d new file mode 100644 index 0000000..40f60e0 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build_result.json: \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build.stamp b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build.stamp new file mode 100644 index 0000000..34a1ca0 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build_result.json","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build_result.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build_result.json b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build_result.json new file mode 100644 index 0000000..0d218ca --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/dart_build_result.json @@ -0,0 +1 @@ +{"dependencies":[],"code_assets":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/debug_android_application.stamp b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/debug_android_application.stamp new file mode 100644 index 0000000..3cd60b1 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/debug_android_application.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/app.dill","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/.DS_Store","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_all.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_workbook.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2026.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_Blacklabel.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2024.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2025.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_100to100.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_LightSsen.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Google.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Kakao.png","/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf","/Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf","/Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/native_assets.json","/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/args-2.7.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_web-2.24.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.10.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.32/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_for_web-3.1.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/mime-2.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/LICENSE","/Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE","/Users/downy/flutter/packages/flutter/LICENSE","/Users/downy/Documents/Gradi_25Fall/frontend/DOES_NOT_EXIST_RERUN_FOR_WILDCARD84779822"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/vm_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/isolate_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/kernel_blob.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/.DS_Store","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/bottom_nav_all.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Academy_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/nav_workbook.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Upload_image_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Mypage_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Alarm_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Upload_image_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Alarm_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Textbook_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Textbook_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Mypage_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Home_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/bottom_nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Academy_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Home_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2026.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_Blacklabel.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2024.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2025.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_100to100.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_LightSsen.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/social_login/Button_Google.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/social_login/Button_Kakao.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/fonts/MaterialIcons-Regular.otf","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/AssetManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/AssetManifest.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/FontManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/NOTICES.Z","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/NativeAssetsManifest.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/flutter_assets.d b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/flutter_assets.d new file mode 100644 index 0000000..55a1418 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/flutter_assets.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/.DS_Store /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/bottom_nav_all.png /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Academy_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/nav_workbook.png /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Upload_image_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Mypage_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Alarm_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Upload_image_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Alarm_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Textbook_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Textbook_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Mypage_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Home_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/bottom_nav_home.png /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/nav_home.png /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Academy_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Home_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2026.jpg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_Blacklabel.png /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2024.jpg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2025.jpg /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_100to100.png /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_LightSsen.png /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/social_login/Button_Google.png /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/social_login/Button_Kakao.png /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/fonts/MaterialIcons-Regular.otf /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/shaders/ink_sparkle.frag /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/AssetManifest.json /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/AssetManifest.bin /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/FontManifest.json /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/NOTICES.Z /Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/NativeAssetsManifest.json: /Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/.DS_Store /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_all.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_workbook.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_home.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_home.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2026.jpg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_Blacklabel.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2024.jpg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2025.jpg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_100to100.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_LightSsen.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Google.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Kakao.png /Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf /Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf /Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/native_assets.json /Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/args-2.7.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_web-2.24.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.10.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.32/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_for_web-3.1.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/mime-2.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/LICENSE /Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE /Users/downy/flutter/packages/flutter/LICENSE /Users/downy/Documents/Gradi_25Fall/frontend/DOES_NOT_EXIST_RERUN_FOR_WILDCARD84779822 \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/gen_dart_plugin_registrant.stamp b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/gen_dart_plugin_registrant.stamp new file mode 100644 index 0000000..9b77114 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/gen_dart_plugin_registrant.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/gen_localizations.stamp b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/gen_localizations.stamp new file mode 100644 index 0000000..1b2d28c --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/gen_localizations.stamp @@ -0,0 +1 @@ +{"inputs":[],"outputs":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/install_code_assets.d b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/install_code_assets.d new file mode 100644 index 0000000..185f852 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/install_code_assets.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/native_assets.json: \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/install_code_assets.stamp b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/install_code_assets.stamp new file mode 100644 index 0000000..1ca4ec9 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/install_code_assets.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/native_assets.json","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/native_assets.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/kernel_snapshot_program.d b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/kernel_snapshot_program.d new file mode 100644 index 0000000..7f6c242 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/kernel_snapshot_program.d @@ -0,0 +1 @@ +/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/app.dill: /Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart /Users/downy/flutter/packages/flutter/lib/src/dart_plugin_registrant.dart /Users/downy/flutter/packages/flutter/lib/material.dart /Users/downy/flutter/packages/flutter/lib/services.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/firebase_core.dart /Users/downy/flutter/packages/flutter/lib/foundation.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/firebase_options.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/services/fcm_service.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/flutter_local_notifications.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/image_picker_android.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/image_picker_ios.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/file_selector_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/flutter_local_notifications_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/lib/image_picker_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/file_selector_macos.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/lib/image_picker_macos.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/file_selector_windows.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/lib/image_picker_windows.dart /Users/downy/flutter/packages/flutter/lib/src/material/about.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/app.dart /Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/arc.dart /Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart /Users/downy/flutter/packages/flutter/lib/src/material/badge.dart /Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/banner.dart /Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/button.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/card.dart /Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart /Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart /Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart /Users/downy/flutter/packages/flutter/lib/src/material/colors.dart /Users/downy/flutter/packages/flutter/lib/src/material/constants.dart /Users/downy/flutter/packages/flutter/lib/src/material/curves.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/date.dart /Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/debug.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart /Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/divider.dart /Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart /Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/material/material.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart /Users/downy/flutter/packages/flutter/lib/src/material/motion.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart /Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/page.dart /Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart /Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart /Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart /Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart /Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart /Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart /Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/search.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart /Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart /Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart /Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/material/time.dart /Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart /Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart /Users/downy/flutter/packages/flutter/lib/src/material/typography.dart /Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart /Users/downy/flutter/packages/flutter/lib/widgets.dart /Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart /Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart /Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart /Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart /Users/downy/flutter/packages/flutter/lib/src/services/binding.dart /Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/debug.dart /Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart /Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart /Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart /Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart /Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart /Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart /Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart /Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart /Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart /Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart /Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart /Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart /Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart /Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart /Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart /Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart /Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart /Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart /Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart /Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/firebase_core_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase_app.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/port_mapping.dart /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/firebase_messaging.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/login_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_terms_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_success_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/reset_password_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_form_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_success_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_error_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_verification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_result_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_error_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_verification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_reset_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/main_navigation_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_list_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_detail_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_detail_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/chapter_detail_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/question_detail_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/mypage.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/display_settings_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/homework_status_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/learning_statistics_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/account_management_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/academy_management_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/notification_settings_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/notification/notification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/upload_images_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/edit_grading_result_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/continuous_learning_detail_page.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/flutter_local_notifications_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/flutter_local_notifications_plugin.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/initialization_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/notification_details.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_flutter_local_notifications.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/bitmap.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/enums.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/icon.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/initialization_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/message.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel_group.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_details.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_sound.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/person.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/schedule_mode.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_picture_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_text_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/default_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/inbox_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/media_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/messaging_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/initialization_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/interruption_level.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action_option.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_attachment.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category_option.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_details.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_enabled_options.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/ios/enums.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/typedefs.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/types.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/image_picker_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/src/messages.g.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/src/messages.g.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/file_selector_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/src/messages.g.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/capabilities.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/enums.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/icon.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/initialization_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/location.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/notification_details.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/sound.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/timeout.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/src/messages.g.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/src/messages.g.dart /Users/downy/flutter/packages/flutter/lib/cupertino.dart /Users/downy/flutter/packages/flutter/lib/scheduler.dart /Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart /Users/downy/flutter/packages/flutter/lib/rendering.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart /Users/downy/flutter/packages/flutter/lib/animation.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart /Users/downy/flutter/packages/flutter/lib/gestures.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart /Users/downy/flutter/packages/flutter/lib/painting.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart /Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/pigeon/messages.pigeon.dart /Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/lib/plugin_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_core_exceptions.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_options.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase_app.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_app.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_plugin.dart /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/firebase_messaging_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/src/messaging.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/bottom_navigation_widget.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page_v2.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_title.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_menu_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget_v2.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/lib/image_picker.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/types.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/typedefs.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/timezone.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/clock.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/callback_dispatcher.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/method_channel_mappers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/mappers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/tz_datetime_mapper.dart /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/cross_file.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/platform_interface/image_picker_platform.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/types.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/platform_interface/file_selector_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/types.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications_platform_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notifications_manager.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/hint.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart /Users/downy/flutter/packages/flutter/lib/semantics.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart /Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart /Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart /Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart /Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart /Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart /Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart /Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart /Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart /Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart /Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart /Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart /Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart /Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart /Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart /Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart /Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart /Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart /Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart /Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart /Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart /Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart /Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart /Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart /Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart /Users/downy/flutter/packages/flutter/lib/physics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/platform_interface/platform_interface_messaging.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/notification_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/types.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_message.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_notification.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/flutter_svg.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/date_time.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/env.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/exceptions.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location_database.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/default.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/clock.dart /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/x_file.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/method_channel/method_channel_image_picker.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_delegate.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_device.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_options.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_source.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/lost_data_response.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_options.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_selection_type.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_image_picker_options.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_video_picker_options.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/picked_file.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/retrieve_type.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/method_channel/method_channel_file_selector.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_dialog_options.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_save_location.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/x_type_group.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/dbus.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/dbus_wrapper.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notification_info.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/platform_info.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/storage.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart /Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart /Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart /Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/method_channel_messaging.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/svg.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/tzdb.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/stopwatch.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/io.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/lost_data.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/io.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_address.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_client.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_client.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspect.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_call.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_response.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object_manager.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_server.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_signal.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_value.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart /Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/lib/xdg_directories.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/posix.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/file_system.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/utils/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics_compat.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/cache.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/loaders.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/file.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/default_theme.dart /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/base.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/base.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_uuid.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_bus_name.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_error_name.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_interface_name.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspectable.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_match_rule.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_member_name.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_message.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_manager.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_tree.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_peer.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_properties.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_read_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_write_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_server.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart /Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/_flutterfire_internals.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/vector_graphics.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/vector_graphics_compiler.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/compute.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/_file_io.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid_windows.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/builder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/default_mapping.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/entity_mapping.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/null_mapping.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/attribute_type.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/node_type.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/format_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parent_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parser_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/tag_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/type_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/ancestors.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/comparison.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/descendants.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/find.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/following.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/mutator.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/nodes.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/parent.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/preceding.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/sibling.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/string.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_attributes.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_children.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_name.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_parent.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_visitor.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_writer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/attribute.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/cdata.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/comment.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/declaration.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/doctype.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document_fragment.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/element.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/node.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/processing.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/text.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/token.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/normalizer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/pretty_writer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/visitor.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/writer.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/interop_shimmer.dart /Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/vector_graphics_codec.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/html_render_vector_graphics.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/listener.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/loader.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_object_selection.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_vector_graphic.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/image.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/matrix.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/path.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/vertices.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/paint.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/color_mapper.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parser.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/theme.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/vector_instructions.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_path_ops_io.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_tessellator_io.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/basic_types.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/path_ops.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/resolver.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/tessellator.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/ffi.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/dtd/external_id.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/data.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/namespace.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/named_entities.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/core.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name_matcher.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/node_list.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/predicate.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml_events.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_value.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/prefix_name.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/simple_name.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/src/fp16.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/debug.dart /Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/path_parsing.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/util.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/image/image_info.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/clipping_optimizer.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/masking_optimizer.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/node.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/numbers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/overdraw_optimizer.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parsers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/visitor.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_path_ops_ffi.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_tessellator_ffi.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/allocation.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/arena.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf16.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf8.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/context.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/parser.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/result.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/token.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/event.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/event_codec.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/node_codec.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_decoder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_encoder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_decoder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_encoder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/cdata.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/comment.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/declaration.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/doctype.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/end_element.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/processing.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/start_element.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/text.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/each_event.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/flatten.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/normalizer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/subtree_selector.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/with_parent.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/event_attribute.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/visitor.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/_debug_io.dart /Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_parsing.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/draw_command_builder.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/pragma.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/token.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/newline.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_location.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_parent.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/annotator.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterator.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/petitparser.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/parser.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/conversion_sink.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/list_converter.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/named.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math.dart /Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_segment_type.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/delegate.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/definition.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/expression.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/matcher.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/parser.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/cache.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/character_data_parser.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/error_helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/frustum.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/intersection_result.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix4.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/noise.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/obb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/opengl.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/plane.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quad.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quaternion.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/ray.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/sphere.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/triangle.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/utilities.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector4.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterator.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/grammar.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/reference.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/resolve.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/builder.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/group.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/accept.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast_list.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/continuation.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/flatten.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/map.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/permute.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/pick.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/trim.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/where.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any_of.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/char.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/digit.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/letter.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/lowercase.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/none_of.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/range.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/uppercase.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/whitespace.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/word.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/and.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/choice.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/list.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/not.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/optional.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/sequence.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/settable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/skip.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/end.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/epsilon.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/failure.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/label.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/position.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/character.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/converter.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/predicate.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/single_character.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/string.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/unicode_character.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/character.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/greedy.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/lazy.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/limited.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/possessive.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/repeating.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/separated.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/unbounded.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/failure_joiner.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/labeled.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/resolvable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/separated_list.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/reference.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/undefined.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/reflection/iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/result.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/types.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/sequential.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/constant.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/code.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/optimize.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/char.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/digit.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/letter.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lowercase.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/not.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/range.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/uppercase.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/whitespace.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/word.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_2.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_3.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_4.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_5.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_6.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_7.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_8.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_9.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_match.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lookup.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterator.dart diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/kernel_snapshot_program.stamp b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/kernel_snapshot_program.stamp new file mode 100644 index 0000000..30ae43a --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/kernel_snapshot_program.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/common.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart","/Users/downy/flutter/packages/flutter/lib/src/dart_plugin_registrant.dart","/Users/downy/flutter/packages/flutter/lib/material.dart","/Users/downy/flutter/packages/flutter/lib/services.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/firebase_core.dart","/Users/downy/flutter/packages/flutter/lib/foundation.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/firebase_options.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/services/fcm_service.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/flutter_local_notifications.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/image_picker_android.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/image_picker_ios.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/file_selector_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/flutter_local_notifications_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/lib/image_picker_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/file_selector_macos.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/lib/image_picker_macos.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/file_selector_windows.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/lib/image_picker_windows.dart","/Users/downy/flutter/packages/flutter/lib/src/material/about.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/arc.dart","/Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart","/Users/downy/flutter/packages/flutter/lib/src/material/badge.dart","/Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/banner.dart","/Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/card.dart","/Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart","/Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/material/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/material/curves.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/divider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart","/Users/downy/flutter/packages/flutter/lib/src/material/motion.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart","/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/page.dart","/Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart","/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart","/Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart","/Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart","/Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart","/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart","/Users/downy/flutter/packages/flutter/lib/src/material/typography.dart","/Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart","/Users/downy/flutter/packages/flutter/lib/widgets.dart","/Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart","/Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart","/Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart","/Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart","/Users/downy/flutter/packages/flutter/lib/src/services/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart","/Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart","/Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart","/Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart","/Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart","/Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart","/Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart","/Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart","/Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart","/Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart","/Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart","/Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart","/Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart","/Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart","/Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart","/Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart","/Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart","/Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart","/Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart","/Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/firebase_core_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase_app.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/port_mapping.dart","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/firebase_messaging.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/login_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_terms_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_success_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/reset_password_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_form_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_success_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_error_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_verification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_result_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_error_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_verification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_reset_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/main_navigation_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_list_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_detail_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_detail_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/chapter_detail_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/question_detail_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/mypage.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/display_settings_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/homework_status_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/learning_statistics_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/account_management_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/academy_management_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/notification_settings_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/notification/notification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/upload_images_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/edit_grading_result_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/continuous_learning_detail_page.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/flutter_local_notifications_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/flutter_local_notifications_plugin.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/initialization_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/notification_details.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_flutter_local_notifications.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/bitmap.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/enums.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/icon.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/initialization_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/message.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel_group.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_details.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_sound.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/person.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/schedule_mode.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_picture_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_text_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/default_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/inbox_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/media_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/messaging_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/initialization_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/interruption_level.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action_option.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_attachment.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category_option.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_details.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_enabled_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/ios/enums.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/typedefs.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/image_picker_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/src/messages.g.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/src/messages.g.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/file_selector_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/src/messages.g.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/capabilities.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/enums.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/icon.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/initialization_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/location.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/notification_details.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/sound.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/timeout.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/src/messages.g.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/src/messages.g.dart","/Users/downy/flutter/packages/flutter/lib/cupertino.dart","/Users/downy/flutter/packages/flutter/lib/scheduler.dart","/Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart","/Users/downy/flutter/packages/flutter/lib/rendering.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart","/Users/downy/flutter/packages/flutter/lib/animation.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart","/Users/downy/flutter/packages/flutter/lib/gestures.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart","/Users/downy/flutter/packages/flutter/lib/painting.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/pigeon/messages.pigeon.dart","/Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/lib/plugin_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_core_exceptions.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase_app.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_app.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_plugin.dart","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/firebase_messaging_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/src/messaging.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/bottom_navigation_widget.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page_v2.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_title.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_menu_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget_v2.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/lib/image_picker.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/typedefs.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/timezone.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/clock.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/callback_dispatcher.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/method_channel_mappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/mappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/tz_datetime_mapper.dart","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/cross_file.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/platform_interface/image_picker_platform.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/platform_interface/file_selector_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications_platform_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notifications_manager.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/hint.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart","/Users/downy/flutter/packages/flutter/lib/semantics.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart","/Users/downy/flutter/packages/flutter/lib/physics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/platform_interface/platform_interface_messaging.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/notification_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_message.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_notification.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/flutter_svg.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/date_time.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/env.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/exceptions.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location_database.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/default.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/clock.dart","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/x_file.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/method_channel/method_channel_image_picker.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_delegate.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_device.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_source.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/lost_data_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_selection_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_image_picker_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_video_picker_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/picked_file.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/retrieve_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/method_channel/method_channel_file_selector.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_dialog_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_save_location.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/x_type_group.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/dbus.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/dbus_wrapper.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notification_info.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/platform_info.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/storage.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/method_channel_messaging.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/svg.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/tzdb.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/stopwatch.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/io.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/lost_data.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/io.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_address.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspect.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_call.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object_manager.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_server.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_signal.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_value.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/lib/xdg_directories.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/posix.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/file_system.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/utils/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics_compat.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/cache.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/loaders.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/file.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/default_theme.dart","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/base.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/base.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_uuid.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_bus_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_error_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_interface_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspectable.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_match_rule.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_member_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_message.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_manager.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_tree.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_peer.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_properties.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_read_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_write_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_server.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart","/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/_flutterfire_internals.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/vector_graphics.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/vector_graphics_compiler.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/compute.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/_file_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid_windows.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/builder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/default_mapping.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/entity_mapping.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/null_mapping.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/attribute_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/node_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/format_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parent_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parser_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/tag_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/type_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/ancestors.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/comparison.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/descendants.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/find.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/following.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/mutator.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/nodes.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/parent.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/preceding.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/sibling.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/string.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_attributes.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_children.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_parent.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_visitor.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_writer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/attribute.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/cdata.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/comment.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/declaration.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/doctype.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document_fragment.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/element.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/node.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/processing.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/text.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/token.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/normalizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/pretty_writer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/visitor.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/writer.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/interop_shimmer.dart","/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/vector_graphics_codec.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/html_render_vector_graphics.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/listener.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/loader.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_object_selection.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_vector_graphic.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/image.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/matrix.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/path.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/vertices.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/paint.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/color_mapper.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/theme.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/vector_instructions.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_path_ops_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_tessellator_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/basic_types.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/path_ops.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/resolver.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/tessellator.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/ffi.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/dtd/external_id.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/data.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/namespace.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/named_entities.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/core.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name_matcher.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/node_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/predicate.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml_events.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_value.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/prefix_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/simple_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/src/fp16.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/debug.dart","/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/path_parsing.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/util.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/image/image_info.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/clipping_optimizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/masking_optimizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/node.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/numbers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/overdraw_optimizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parsers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/visitor.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_path_ops_ffi.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_tessellator_ffi.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/allocation.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/arena.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf16.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf8.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/context.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/result.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/token.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/event.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/event_codec.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/node_codec.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_decoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_encoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_decoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_encoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/cdata.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/comment.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/declaration.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/doctype.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/end_element.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/processing.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/start_element.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/text.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/each_event.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/flatten.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/normalizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/subtree_selector.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/with_parent.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/event_attribute.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/visitor.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/_debug_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_parsing.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/draw_command_builder.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/pragma.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/token.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/newline.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_location.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_parent.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/annotator.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterator.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/petitparser.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/conversion_sink.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/list_converter.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/named.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math.dart","/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_segment_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/delegate.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/definition.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/expression.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/matcher.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/cache.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/character_data_parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/error_helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/frustum.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/intersection_result.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix4.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/noise.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/obb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/opengl.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/plane.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quad.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quaternion.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/ray.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/sphere.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/triangle.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/utilities.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector4.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterator.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/grammar.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/reference.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/resolve.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/builder.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/group.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/accept.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/continuation.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/flatten.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/map.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/permute.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/pick.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/trim.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/where.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any_of.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/char.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/digit.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/letter.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/lowercase.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/none_of.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/range.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/uppercase.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/whitespace.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/word.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/and.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/choice.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/list.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/not.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/optional.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/sequence.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/settable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/skip.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/end.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/epsilon.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/failure.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/label.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/position.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/character.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/converter.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/predicate.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/single_character.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/string.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/unicode_character.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/character.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/greedy.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/lazy.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/limited.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/possessive.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/repeating.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/separated.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/unbounded.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/failure_joiner.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/labeled.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/resolvable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/separated_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/reference.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/undefined.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/reflection/iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/result.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/sequential.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/constant.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/code.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/optimize.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/char.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/digit.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/letter.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lowercase.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/not.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/range.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/uppercase.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/whitespace.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/word.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_2.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_3.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_4.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_5.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_6.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_7.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_8.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_9.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_match.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lookup.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterator.dart"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/app.dill","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/app.dill"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/native_assets.json b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/native_assets.json new file mode 100644 index 0000000..523bfc7 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/native_assets.json @@ -0,0 +1 @@ +{"format-version":[1,0,0],"native-assets":{}} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/outputs.json b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/outputs.json new file mode 100644 index 0000000..e34e550 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/710320b22e58a5324de93e9097bc1895/outputs.json @@ -0,0 +1 @@ +["/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/vm_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/isolate_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/kernel_blob.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/.DS_Store","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/bottom_nav_all.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Academy_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/nav_workbook.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Upload_image_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Mypage_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Alarm_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Upload_image_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Alarm_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Textbook_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Textbook_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Mypage_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Home_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/bottom_nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Academy_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/icons/Home_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2026.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_Blacklabel.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2024.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/workbook_2025.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_100to100.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/bookcovers/BookCover_LightSsen.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/social_login/Button_Google.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/assets/images/social_login/Button_Kakao.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/fonts/MaterialIcons-Regular.otf","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/AssetManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/AssetManifest.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/FontManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/NOTICES.Z","/Users/downy/Documents/Gradi_25Fall/frontend/build/app/intermediates/flutter/debug/flutter_assets/NativeAssetsManifest.json"] \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart b/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart new file mode 100644 index 0000000..94db4dc --- /dev/null +++ b/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart @@ -0,0 +1,142 @@ +// +// Generated file. Do not edit. +// This file is generated from template in file `flutter_tools/lib/src/flutter_plugins.dart`. +// + +// @dart = 3.9 + +import 'dart:io'; // flutter_ignore: dart_io_import. +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:image_picker_android/image_picker_android.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:image_picker_ios/image_picker_ios.dart'; +import 'package:file_selector_linux/file_selector_linux.dart'; +import 'package:flutter_local_notifications_linux/flutter_local_notifications_linux.dart'; +import 'package:image_picker_linux/image_picker_linux.dart'; +import 'package:file_selector_macos/file_selector_macos.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:image_picker_macos/image_picker_macos.dart'; +import 'package:file_selector_windows/file_selector_windows.dart'; +import 'package:image_picker_windows/image_picker_windows.dart'; + +@pragma('vm:entry-point') +class _PluginRegistrant { + + @pragma('vm:entry-point') + static void register() { + if (Platform.isAndroid) { + try { + AndroidFlutterLocalNotificationsPlugin.registerWith(); + } catch (err) { + print( + '`flutter_local_notifications` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + ImagePickerAndroid.registerWith(); + } catch (err) { + print( + '`image_picker_android` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } else if (Platform.isIOS) { + try { + IOSFlutterLocalNotificationsPlugin.registerWith(); + } catch (err) { + print( + '`flutter_local_notifications` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + ImagePickerIOS.registerWith(); + } catch (err) { + print( + '`image_picker_ios` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } else if (Platform.isLinux) { + try { + FileSelectorLinux.registerWith(); + } catch (err) { + print( + '`file_selector_linux` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + LinuxFlutterLocalNotificationsPlugin.registerWith(); + } catch (err) { + print( + '`flutter_local_notifications_linux` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + ImagePickerLinux.registerWith(); + } catch (err) { + print( + '`image_picker_linux` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } else if (Platform.isMacOS) { + try { + FileSelectorMacOS.registerWith(); + } catch (err) { + print( + '`file_selector_macos` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + MacOSFlutterLocalNotificationsPlugin.registerWith(); + } catch (err) { + print( + '`flutter_local_notifications` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + ImagePickerMacOS.registerWith(); + } catch (err) { + print( + '`image_picker_macos` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } else if (Platform.isWindows) { + try { + FileSelectorWindows.registerWith(); + } catch (err) { + print( + '`file_selector_windows` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + ImagePickerWindows.registerWith(); + } catch (err) { + print( + '`image_picker_windows` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } + } +} diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/.filecache b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/.filecache new file mode 100644 index 0000000..70d30b9 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/.filecache @@ -0,0 +1 @@ +{"version":2,"files":[{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/cache.dart","hash":"27e508023821ad3aadd30156d20a229c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/typography.dart","hash":"d4335eeb3dd8ee5df4498661b368ebea"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/types.dart","hash":"f4d93b039bc86c4a156848d06fbc2917"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart","hash":"c93eab1631a5606c8ba301346fa8e483"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart","hash":"72b6519b69dfbf0f2959b7e590bea0bf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart","hash":"32a40215ba4c55ed5bb5e9795e404937"},{"path":"/Users/downy/flutter/packages/flutter/lib/rendering.dart","hash":"4bd3950a0bf4a9f9b09f97594e363d36"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/digit.dart","hash":"fc5bd8041afab0229dff18f2011a51a5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart","hash":"648a6cdab2fd44688152ab1b016e5e9c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart","hash":"d6f045db9bd5b72180157d44fee9fbfc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/builder.dart","hash":"edd1157c0a6badd18824781de14280e6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart","hash":"ea5bbc17f187d311ef6dcfa764927c9d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_read_buffer.dart","hash":"fd517e61edeaf09f9e4cf9e9ba8af13c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/LICENSE","hash":"e8b32b6d7c1328dfb1968caef8249452"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_page.dart","hash":"40bd83521b764e8bc5f3a8acf5e60f9e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE","hash":"d2e1c26363672670d1aa5cc58334a83b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart","hash":"54c7f23362a7e78be04b113d00022090"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart","hash":"38861aee0e2ba92ec8005a64746c0d10"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/timeout.dart","hash":"6665bae4ddca65609834735a7f24c95f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart","hash":"3d925b9cf0a12dd519256aa23a4e3512"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/resolvable.dart","hash":"f7329cc0811af555900320e49bd9686f"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/tools/shader_compiler.dart","hash":"57b58eaf8484f5be3274077f5af029f8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart","hash":"61137458bbcab0dfb643d5d50a5ae80f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/App.framework/App","hash":"1cd3604d8ff6e3f6caf4c32361dd63f9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/intersection_result.dart","hash":"0cd5a938f3a3bf96aa0d7353906eace6"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/Info.plist","hash":"9e82e9ff68feb959a5eb6cd5efab9b66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb3.dart","hash":"ec3a274c8e6537ec92c8d5f877a670ae"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/exceptions.dart","hash":"ad84ac2c0607f2ca46d74eb0facbca3f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart","hash":"732535ba697d95c80d1215c0879477f1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/debug.dart","hash":"17fec0de01669e6234ccb93fc1d171f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart","hash":"ed28f6ca17f72062078193cc8053f1bb"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/darwin.dart","hash":"8e0517e25fde2e092795b066ba2b7310"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart","hash":"954effbd324f486a6948427c605454e8"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/main_navigation_page.dart","hash":"8f154668e618c75d3821a005aba27a4e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart","hash":"aed826e965e4aa2fdb3466d39e33d824"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid_windows.dart","hash":"659cff14f1665a31dec63407d7839624"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/sphere.dart","hash":"8b2f2f630b059eae09aa7e46fc3137b2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/map.dart","hash":"822f0a79dfd6a3c997d2b898ec420b97"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart","hash":"4a7b03b0c037b260c1a321f7aaa8b6ff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart","hash":"7504c44d1fa6150901dd65ec78877be0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/method_channel/method_channel_file_selector.dart","hash":"331caab132b93f55efc7e79e6849c229"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart","hash":"608be960e670661114e97b498d6a6473"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/loaders.dart","hash":"69d071a3792f36aaf595067b248c5952"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart","hash":"9b61320422b3f577a77f50badebd040f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart","hash":"d69cd05d9de1731242d357de56893a6f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspect.dart","hash":"1d43aa18b7cd09879287a4e8ba5ea5ef"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart","hash":"6a8aecb412af6e981bc3d4817b82f7d2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart","hash":"38c93c95cb266619fd6cf7de928884db"},{"path":"/Users/downy/flutter/packages/flutter/lib/foundation.dart","hash":"84939e70d6b7b36e8098dd0cda8cbb2a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart","hash":"eca4f0ff81b2d3a801b6c61d80bc211c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart","hash":"5ee4b9f196c81041c45d27e3b2d33d88"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/location.dart","hash":"17db713e9a12494613ca23ad84def9c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart","hash":"ce4bfd9659d667457cc3ada513fae71e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_app.dart","hash":"209399f0e6f16675c3f087b8eb17087b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/optimize.dart","hash":"ebd9dcbeebab7ad717e6f7efb6a47f0f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quad.dart","hash":"375711cedfc8dfb78018a282ba880296"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart","hash":"008b3ea4691331636bbea9e057357ceb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/retrieve_type.dart","hash":"299d2603043fd7b764e47fb1829b6175"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart","hash":"ef1ff22066328de1e83b8180592a470f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/initialization_settings.dart","hash":"84dbd0aa38844da5b7a683c754582df9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart","hash":"d98495bcbc301290a10e6d1dfc255d69"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_2.dart","hash":"312e69b666cc1e860274006e86688bf9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart","hash":"fb2be6f27b32bb1ab12dd6aea8c5ecda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart","hash":"c02d47d7f7e95654d3eb9b795e416dda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/firebase_messaging_platform_interface.dart","hash":"feb2a618792357be2682e61fdab02d6a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart","hash":"f5e7b04452b0066dff82aec6597afdc5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart","hash":"83bb40406ac73bcd194c621137ed0349"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart","hash":"92901585628d81f7bb3d578fd6d6657d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document.dart","hash":"8fd257a17e57f8c7a9e9c3c5d77df78b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/colors.dart","hash":"07fa95aca6c82e2f15c0007388cef3a6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart","hash":"f45f530a8be1596d7ffd25719c66c87e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/named.dart","hash":"7d9a75e0bd8e5c9b49ad6c0816666b4a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/LICENSE","hash":"d2e1c26363672670d1aa5cc58334a83b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/list.dart","hash":"69c4980a512a91477aa1a6289583342b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart","hash":"6cf1ca324535366e2ea214049ffc9918"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/LICENSE","hash":"619f69d64af6f097877e92ac5f67f329"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspectable.dart","hash":"a8d03ee07caa5c7bca8609694786bbf0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart","hash":"3d892f04e5e34b591f8afa5dcbcee96d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_unselected.svg","hash":"dee348e2202f671e34773695f6a38cc8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart","hash":"f7bbc690baa3db88e9a15522b9c2f139"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart","hash":"62e0b7dc1550fd71644c5cc94797eee1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart","hash":"056355e344c26558a3591f2f8574e4e5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart","hash":"0938e0447f447ceb7d16477a0213ce2c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_visitor.dart","hash":"61e938fe770ed7331e39f1dda1b64dd4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart","hash":"094b2c03ad4e0ef5bc1144e281142b2e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_core_exceptions.dart","hash":"bc949707cfd60ff573b48a27b02f6756"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_success_page.dart","hash":"d1d30b68037cbdc2e7f022540303e5ef"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart","hash":"7692ca5e3a50523edceb59e80a6205a1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart","hash":"1dab3723527db6a19410ed34b6acaeed"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart","hash":"2ff3d9ddebd8dd6545b4ef0dfaf76184"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart","hash":"10cb76c02997cab59c925fe8bfbfd8f1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart","hash":"ebafc07567edebe5e176f39360b09f52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart","hash":"481e435dd11c202a9d2293db5b58b179"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_buffer.dart","hash":"22acb270c1bb267ee16b3d64a3faa825"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart","hash":"fb76e9ed5173ac1ae6a6f43288581808"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart","hash":"63ea4f418d2305e0cf2c18a773821f9b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart","hash":"1b20a6e406ca8e79675b2ebd9b362d10"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart","hash":"e88b0574946e5926fde7dd4de1ef3b0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart","hash":"eaef2926557480e27a3ce92f89de68b7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart","hash":"52f779d8f66642da5db6810754b0ba5c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_LightSsen.png","hash":"5ae53d61eeb9909a8c892ca39defd1f5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/null_mapping.dart","hash":"4bc463f9c4b5496d8918b58070c10515"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart","hash":"a47062dc6143c80c485bcfc7a06b9490"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/LICENSE","hash":"46158b74167f78e44896e35a92c7c5e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart","hash":"bdc22e9e77382045196b5aafd42b5e55"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart","hash":"dbb0bb20c79bcea9397c34e3620c56c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart","hash":"0ee043f9e3f8fc817bc6bb354731879d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart","hash":"e05529d31a09e4c86cde70483824fa10"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart","hash":"c8564aa311746f4047cd02e26ff4df75"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart","hash":"b5b9320ef8cd47d81a68063558c1ed4d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/pattern.dart","hash":"d881c458d06573eb887bdf0f3ce9f586"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/src/messaging.dart","hash":"d0210310f0eb42949d15a2995dac586f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/single_character.dart","hash":"8db9443001d816c1f89abdf5bc0e7c7e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart","hash":"d891dabfc112fbaa77f11a249d547179"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_value.dart","hash":"2aef91d8cd008f57a605919dba2b095b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart","hash":"7ffb6e525c28a185f737e3e6f198f694"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/token.dart","hash":"89176d8be6120f2900340b369ce80cd8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart","hash":"21496c39aba7bb1435e82558fc3dc9f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart","hash":"efad3646c2aadca0c462ae31919205ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart","hash":"727e4f662a828d4611c731f330a3d79a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_unselected.svg","hash":"1dd3756cbc8b5a94ddcb9057a1ddf364"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart","hash":"c8a14f8ecb364849dcdd8c67e1299fb3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart","hash":"290ff7e27e670467d4f520e320ed9660"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart","hash":"efbedb75be354b65520bce3f0855b8db"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart","hash":"e1396042533b733f081ced0923a94cdf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart","hash":"24cd1bed27dc8cfdc2d00045c1b85b53"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_home.png","hash":"9479f3d4c7e70fc2c423c8f358e2dc92"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/motion.dart","hash":"505f6c9750f9390c9e9e4d881092cef4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart","hash":"ecc072620f2a72e685360292690c8a68"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart","hash":"3bcc95d3183f101e656079052017f57d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/dtd/external_id.dart","hash":"3598a401936c6a9e0a645251fba246f9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/ffi.dart","hash":"ae66b0cbdfe2e2a5a99c5dfa48fd5399"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart","hash":"4b50828d394e7fe1a1198468175270d9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart","hash":"280be2dbc10de2dd1913281d29e1b29f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart","hash":"7821d01f98c559fcbec46a41b4df7ebf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart","hash":"af4bf4aa827f5ac651aed6fb7b9a038e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart","hash":"1506ba940aec506086f3093420336467"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart","hash":"fc5d931b0e52f2fbd5ba118ca7f34467"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_7.dart","hash":"e7f41e9640a11f484fe97a34fd0c6fe4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_value.dart","hash":"21beb4ff2c06d1edc806270e0bfac51f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart","hash":"ca2e098cce59851623bf60c022a3bad1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/lost_data_response.dart","hash":"08f9da8824c26449b9df1c0e674ef2cb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE","hash":"5bd4f0c87c75d94b51576389aeaef297"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix4.dart","hash":"48ec0166ccbd3f834b89d19fcf8bf2e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart","hash":"b815d11a718e0a4d6dec5341e2af4c02"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart","hash":"21494fec4563fdcefa3d28fad8ffd12b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart","hash":"46826fe180ac83f5855d6126ad250b81"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/ray.dart","hash":"81926da83d9ea41cd5ad389174aa96dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart","hash":"e4eb87da41119742a2dcbcdbc39c7a96"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Home_unselected.svg","hash":"92f7f8888a8a844a4f1fa497cbe2decd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart","hash":"bd3f0349089d88d3cd79ffed23e9163b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/platform_info.dart","hash":"81e7d988ce6f8a20230e61cdac83f21f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart","hash":"c7627484ec7f4005dae2321f6de6768e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_peer.dart","hash":"681b70272ec68e757f2394c9e7fa9398"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/timezone.dart","hash":"f8c5df6155feb71c22fdca5ea2d10a53"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart","hash":"c4b5de17270534014eb846299d500eb5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart","hash":"94235ba74c3f3ad26e22c4b40538ce07"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart","hash":"61d3c1705094ee0ea6c465e47b457198"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterable.dart","hash":"f0db904cb4051a93b08f326f9f4ded00"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/clipping_optimizer.dart","hash":"6a0f3ad096e056352806cf44a29f4dd3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart","hash":"ae53c1bc8f95419bee08ba4fde0e173e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart","hash":"1357b049a06aa8a7413982e814b87ab5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart","hash":"985cf5499dc6e521191985f55245a22c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart","hash":"c5e44030289c2c25b26c5b3aa843b3cc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/storage.dart","hash":"3032f1c2edfd44ab46f3b4673c5c8deb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/clock.dart","hash":"84ad21db5ba97deb809b65697546e39c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/args-2.7.0/LICENSE","hash":"d26b134ce6925adbbb07c08b02583fb8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart","hash":"4b495ff6681b3a7dda3f098bf9ecc77d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart","hash":"5486e2ea9b0b005e5d5295e6c41ad3c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart","hash":"05ab01a88b45fe10a762dc3068e7e1dd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart","hash":"90a1a95cfd75677cfe6295f0bad3a3e9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/bitmap.dart","hash":"30207bb624460e743b557f58e7b39479"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart","hash":"b3eacd047eaec8b4b214d8d35f471f06"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/error_helpers.dart","hash":"ef40ba86423f614b2b841a3a11478937"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_signal.dart","hash":"8596b58c127792783625b4b22a4d023c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart","hash":"0c520a6b1ab38e0f294c3ddbc2ec9737"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/pragma.dart","hash":"6fc8c606a9db58715ea15f5ee1e062fb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart","hash":"77d5759abfee21d18803f19b603da875"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart","hash":"123520ee3a48eebf4ba444e93436bb1a"},{"path":"/Users/downy/flutter/packages/flutter/LICENSE","hash":"1d84cf16c48e571923f837136633a265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart","hash":"90f70ffdd26c85d735fbedd47d5ad80b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/image_picker_platform_interface.dart","hash":"340bfb4c1c748a6b1b9bc91b523d0237"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_6.dart","hash":"3c158ce6f79d219073cbe23a7fe48595"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern.dart","hash":"2108c716fd8198fa3a319a1ec6cadc9d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/declaration.dart","hash":"79198336b26da3116eb3cf2258e9f72b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart","hash":"7c8b701267e773fa9293eb10736e0ca7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart","hash":"a004396fa64ff2163b438ad88d1003f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart","hash":"62cbf59e5c816c224ef5eaf803fc877b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart","hash":"2aacf74fb08ed144ee859c99233588ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart","hash":"11b4d96c7383b017773d65cb2843d887"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart","hash":"fa8eb6909c6c4c0ced2ac0ec5a69f640"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart","hash":"b6bcae6974bafba60ad95f20c12c72b9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Textbook_unselected.svg","hash":"93a54f90a6de31d713d9a0fe53f11f8b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/vertices.dart","hash":"5db8a9ae89b9f40979a35f8c0eb56638"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE","hash":"4cb782b79f6fc5792728e331e81a3558"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/following.dart","hash":"7f4a5458515781cb38e39651bfdd2f04"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/letter.dart","hash":"3b849eb1eb50df2663eeecd3801e3193"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/LICENSE","hash":"6eb17212266d6f143295fbec385617aa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart","hash":"be66f00d2c9bb816f4236dd0f92bff55"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart","hash":"964f3ee4853c34a4695db0c7e063eaa3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE","hash":"901fb8012bd0bea60fea67092c26b918"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart","hash":"0b3ae865c8e82bcd0c94aa60cdd8237f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/LICENSE","hash":"fcc4d991b068e4103c4ef152baf65fb3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart","hash":"5a41dbb4425fcc9ce228f1db68360c1e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/where.dart","hash":"30325626c486da5b0b5e6ca9d6a6d337"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/notification_settings_page.dart","hash":"4aaf1341462afc8acd645202c945b79f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_detail_page.dart","hash":"87e1d4f79f197cb95a25c56b0ef920bf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/initialization_settings.dart","hash":"150f91352c1070fd5f15a65ba10e9cda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/trim.dart","hash":"37b4a8b2d509ad6dd3f486053edecb3c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/listener.dart","hash":"a84e929eb69f77beaea9aaa61a1623ed"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart","hash":"c517fb54b3d66b22988ad7c8d07c6f53"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart","hash":"db4d348cc51cfecc2c86a34122b48806"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/visitor.dart","hash":"87e0c94a0dd945f819a8bd24a9ac5e67"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/tz_datetime_mapper.dart","hash":"2f6d6663f131dd0e24f37f58530342c6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart","hash":"83df4f6e4084a06a4f98c27a524cc505"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_parent.dart","hash":"a7ac3293430577fa9c028b0df6607fa4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart","hash":"edbd68eb36df4f06299204439c771edd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/src/messages.g.dart","hash":"d631809a6f4e20b7aa9ea7e17a6581de"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/arc.dart","hash":"511ff5c6f0e454b22943906697db172f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart","hash":"eca5aa939aa9722ead4b6c347fb4d11a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart","hash":"2b76d589cc052dc9ef928ddba5382a4b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart","hash":"1303bc77ad63625069f2d23afc73f523"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart","hash":"6326660aedecbaed7a342070ba74de13"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/flutter_local_notifications.dart","hash":"6911901b1e6f800a6d433577dd9b93a6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart","hash":"cdb411d670a094822c46ead81fc1c4f7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/method_channel_messaging.dart","hash":"32607e48ff8d5b1dca4d9aaed5c65cab"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart","hash":"c9111e47389ee4b70aab720435a2a2df"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_client.dart","hash":"6b3c8cd4c0677edeb4fb8c22d923657c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","hash":"dac22fca3e7d3a8dea390391c26464dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/gestures.dart","hash":"ac772288a52f82606f20d68636327e34"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/lib/plugin_platform_interface.dart","hash":"8e49d86f5f9c801960f1d579ca210eab"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart","hash":"6297da5be01fb7c0d5c4aaffe7a27a50"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/image_picker_android.dart","hash":"70e88a3e2ff97b5acfa273e5964271ae"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart","hash":"7bd8137185bc07516a1869d2065efe0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart","hash":"028eb8497ffa66b6d051c09361dc19f3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/epsilon.dart","hash":"b9283cabc57ae94b3c75f147903751fa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart","hash":"89b2eba11b385c32cad8745bfba9798b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/resolver.dart","hash":"129621686dbf25bd8492f93ee01aede9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart","hash":"e6069a6342a49cdb410fbccfbe4e8557"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icons.dart","hash":"32b222420709e8e40d12f6ea9fc0041e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/_debug_io.dart","hash":"118b6a62408f796e238c61d271e5146f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart","hash":"ec48414c6983150c30241ba7128634fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/tag_exception.dart","hash":"65fe1b7c956a57db85d24838ab970d2d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart","hash":"530c4f96f1475cc4e4128ffedd705028"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart","hash":"0ff55be19444856c892e701c475b20f6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart","hash":"9f069b0f65439fc693626369d779c95e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_dialog_options.dart","hash":"c7a750b73798e6fbab221eff051e22c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart","hash":"57d74766f36a3d72789bc7466ae44dba"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/visitor.dart","hash":"27780bbb98adce3f00386fc6223bf2c9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/token.dart","hash":"007b05bbaaa5af831aed126b4db596e5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches.dart","hash":"5ba6e004392bbc498c40ccb026b0a845"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_encoder.dart","hash":"af7b5d8de0c9d9df88cdffcae9d7c959"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart","hash":"dd109d67b92b9fbe6e0051f0c890c903"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE","hash":"175792518e4ac015ab6696d16c4f607e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart","hash":"2936a409e1029ec52f7c0003f4db18c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart","hash":"ac172606bd706d958c4fe83218c60125"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart","hash":"eb115c2e8f0ff170bf26a44efd1b5c05"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/range.dart","hash":"8319b5c0133f9badc667b37194fa492d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/base.dart","hash":"45de232761192d4a3d0ad379ca89ebfc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/node.dart","hash":"2da1c79b8281803ba4c3b68c61e7cbc2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE","hash":"83228a1ae32476770262d4ff2ac6f984"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_error_page.dart","hash":"706ef200d552a72ad468ccb74518d0fe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart","hash":"e7b2de136a99cf5253477d4fb4138394"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart","hash":"7da554c3a69a1c2d019202e3f63331c5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart","hash":"73089c9737db54a05691e09bc9fc1bcd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart","hash":"d3ac4a3d093bab7e3c97e51db9e4218f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart","hash":"74c42b320d58fca1c02c22c577c5fdf7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart","hash":"c39101179f8bdf0b2116c1f40a3acc25"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_unselected.svg","hash":"276234b99389b2bcc7bdc79c22df0e55"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart","hash":"b45f6f4ad67efa5c374cabc278ede26a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart","hash":"ddf1bde8f4b9706d5769690b7819e5d4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/reference.dart","hash":"1253a1a49f9d6789e547fbb5a9301d3d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/banner.dart","hash":"576f65e88d664b3c39aa0e07825b29a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart","hash":"0b630cc8a66d79c161a58858593ae1ae"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart","hash":"8830333c78de58ad9df05d396b651ef7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart","hash":"6c54f90e0db5f42a13be6b3efeb4a04d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart","hash":"ae36c7cc9b21f98bedf401f2d67a0fd4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart","hash":"ae42d99121b00899d038edc753e0b23c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart","hash":"68c724edcc385ae2764308632abb76b4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/lib/image_picker_windows.dart","hash":"fbe2834efbf133b1b0b0ad8be7ea499d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/choice.dart","hash":"404ec528c031ebc7486f12477b06de28"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart","hash":"3ce88fe27ca35ed2f5b7a333d43676e1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/LICENSE","hash":"038c3f869f408e1194eda71cafcca6f0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/separated.dart","hash":"70a35c4e76561a207bce18013ed087c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart","hash":"a6d730f196620dffe89ac987b96ef6c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart","hash":"37f181e3096dc69dc408bf7d07fcd39a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_flutter_local_notifications.dart","hash":"610a95b3eab95b5d9ccb03edc03818b5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/dbus.dart","hash":"59ba4a85ea18ab7b3030f370a0e93450"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart","hash":"3188cef277d7af7b79cfeb3286289551"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart","hash":"7088cc45b21c93be6b42dc748fc3a29a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart","hash":"0cf5ebf6593fabf6bb7dfb9d82db735b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart","hash":"153fd637fe660527ff42e1be068d99ac"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/reference.dart","hash":"f25bbc73708cc35ac55836cbea772849"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart","hash":"a29f0df228136549b7364fcae4093031"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_text_style_information.dart","hash":"e1c112a7342a7ee3110a1c2df175b89d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart","hash":"5d8d6684175fbdcb66d313aa7c93f5e0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart","hash":"3fce8e0c4d9b3cb4e3dbc168f41a132e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart","hash":"b7525dbbd1c51211c6edc9ea544a62e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_exception.dart","hash":"7cb7fe22378ec39b40d4b519d0928d80"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart","hash":"b9c13cdd078c3b28c3392f0d6d5d647b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/homework_status_page.dart","hash":"a79358bd23738f5ba5cf1498b393df27"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel_group.dart","hash":"9a2704474807a196e3a72883d73b5be2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart","hash":"998487b87817cbb87019455d4abfaed8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/types.dart","hash":"98947dc53131e00bf0eb82564931fabf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart","hash":"2f426329cad3640d8a125303c3509018"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart","hash":"57f09243c4e3f4099a10951225c6d1ec"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/style_information.dart","hash":"9787d9b12ea9461874ea0faa9cccf9db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/flutter_local_notifications_plugin.dart","hash":"c9b70f4004e9ec7f0856ecc0e45430bc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart","hash":"9bc30281f42d8003b7f9d636ebc8bfc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart","hash":"e3d917994e875601c2dadaf62de546f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart","hash":"3e0eaeb97804d1bc93e6c6088aa351b7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid_linux.dart","hash":"cc4abe2eecf823ea14c55f9c5c09e203"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/bottom_nav_home.png","hash":"9479f3d4c7e70fc2c423c8f358e2dc92"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart","hash":"99b4d15f76889687c07a41b43911cc39"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart","hash":"700328ab0177ddfd9a003a8c15619c1a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/interruption_level.dart","hash":"3667c2cba3e0537e66b40353a1482487"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector2.dart","hash":"6860d784322e97b761960551131a565d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart","hash":"204fb623e2b782051e9bcb6e320e97c0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart","hash":"0c9bd1af5747fd55e7488c731ad32dee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart","hash":"d44c6aa2c95d66ec45eeb0bd0df79cee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart","hash":"2150550461fec00b57e9b9110f8fde94"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_selected.svg","hash":"b5a02676b50172a80c155f0104471695"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart","hash":"00ec0dfac52c24607bbdffd84060d019"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart","hash":"34c5e6ba4664d331c977bdc010aad709"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search.dart","hash":"3798784648f57e129514c1cb6f534612"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_page.dart","hash":"f28a774baf869ad89f779c824c00c245"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart","hash":"e324dd19cc02a1bf47bf7cc545dcca79"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart","hash":"40dec7d9dd1c5150bf10ef4b46cc36c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart","hash":"82604e7dbb83dc8f66f5ec9d0962378b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart","hash":"7146d1c18ac515c3fd3465cd4a7f7a34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart","hash":"734e496890e84ac4195229409538f700"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart","hash":"0bc80db5885f9d8ecc0f80ddab6fe8b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart","hash":"98772211ffa69a8340f8088cd7193398"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart","hash":"f35a027c2538224fe2e64e2eb36a71c5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/with_parent.dart","hash":"5e97dbe19781055ba2585ce570bc4643"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/expression.dart","hash":"79503c7448238b77502c169788e26dbf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart","hash":"940daf4491e3ab2e15d7eac5d6ce6b23"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart","hash":"30c8c6264748aba97477a1c81c8fb9d1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart","hash":"0d86d4ba2e01e5e62f80fcf3e872f561"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart","hash":"b5bd9d15c10929b4a63ea0df649e2d52"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Alarm_selected.svg","hash":"b5a02676b50172a80c155f0104471695"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app.dart","hash":"5b539c57fb0cbea66a99efbc8239e590"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart","hash":"4a4b67b573e2338cf03cb704b2c18f04"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_save_location.dart","hash":"3c21d269eae774b7e06b8adbe73aa18e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart","hash":"c7fe678fd3ad24ff5928e24dff4367b5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart","hash":"fb23ec509c4792802accd10fa7c8a6b0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_details.dart","hash":"f61c50d40c00ac96c595ea0b2682937c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart","hash":"853b1406f2756bef671f6d57135606f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart","hash":"a6ce313fc162c7c4402e1979454559a8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart","hash":"21a43efc5058f6132660bba47766b26b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart","hash":"5c3b7996bd913451665c9b1634098d83"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart","hash":"8b525140e1bf7268e1681a62c7640eea"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/reset_password_page.dart","hash":"fb2e6cdb72e5a96214cdfffad347c369"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/LICENSE","hash":"387ff7f9f31f23c3cf5b17f261a091bc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/LICENSE","hash":"46158b74167f78e44896e35a92c7c5e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/doctype.dart","hash":"a0ff9321b483226cdbe4773e33779715"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_Blacklabel.png","hash":"2a1292ee675efd8f5b3b072a648a0aeb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/tzdb.dart","hash":"01c25b2dabe912c532a94956c2e40c8f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date.dart","hash":"f36568b4288388242cb6f7775cb60c42"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart","hash":"7514fc34af698a2ef36a68486f7340d8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/context.dart","hash":"6f1cce384d53a00c3d6e036e78554066"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/person.dart","hash":"a0f12d72bbc64d6edba6d1174d5603e9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart","hash":"3e8df17480fcb123b3cdc775ca88dd89"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart","hash":"58b9bc8a40fd3e2f7d9d380d0c2d420f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart","hash":"b972c32590c642256132827def0b9923"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart","hash":"2cb2b1aac78bff7cc9be5f0a45aaa94b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_unselected.svg","hash":"22f085ac90f93a6cbfea8c2c872edc30"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart","hash":"e14417c43b6cb787f11bebd1c39280cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/card.dart","hash":"90d9d45eef80ac53b194a71da4e10975"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/data.dart","hash":"d7fab9eeba6ce2b3fae0a93d5622ac93"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart","hash":"00c9e1f53ab22efcb34cca55fc46b4cf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart","hash":"5979a1b66500c09f65550fab874ee847"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/callback_dispatcher.dart","hash":"5239ca253366a3b71796f8e9d2baf065"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json","hash":"f3a664e105b4f792c6c7fe4e4d22c398"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Academy_selected.svg","hash":"b68b6a15add7b6220fd62524a90fee5b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart","hash":"d7eb1678ec74acd9857a4193fd62ed5b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart","hash":"0b55082ca3ffb2bec57cbd8c61db5977"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart","hash":"66df4fe41752a6a990878623e36a3ad2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart","hash":"b7c2cc8260bb9ff9a961390b92e93294"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase.dart","hash":"81402c8eea37df800d379c88bdcf6f44"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/simple_name.dart","hash":"208d1ef7a6cc2445551b3138139613bd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart","hash":"527d9250e523e442bc07faadf2cb1741"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart","hash":"c06267b6c315a5e40f28feb6019de223"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_8.dart","hash":"5f0138a157edf46a36bd960b7eaa9885"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/src/messages.g.dart","hash":"f381ed91de52f40a7dff4d2f0f3f6d4c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/continuous_learning_detail_page.dart","hash":"0aff4cfd6dc7a7698a63b2bec1cffeab"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart","hash":"93d025adfc0409629c51036cb0fdc085"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart","hash":"2af013984ccce4c43e3024da472560d7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/not.dart","hash":"6bb47d3d823202b76bef61c1ccce067c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart","hash":"5b92fc2fdb9b39ca8d3072d08f9f2356"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart","hash":"991024814d51967a20be5851be93a8e3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/greedy.dart","hash":"01b051da3c61c872efd639af5fa0f4f7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart","hash":"8bb5842ab79616954e268adb624dc6fb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart","hash":"206ef1a664f500f173416d5634d95c8b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math.dart","hash":"4181db4115c5cbbf774171b3cde1542e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/letter.dart","hash":"4165baac3466972c71160f4aa15cd185"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart","hash":"9d437a8fcd0a5c0ad90aa6e31d66834c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart","hash":"945227f3863339e388d92c2b3bfbf673"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/settable.dart","hash":"442a233329c158bcfbb129ccea0fe8ca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/grammar.dart","hash":"9467e21c572f79ad7a41afb250e26905"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart","hash":"5c3150272dcfc4b6d488ba16b0b21594"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart","hash":"166147b7bee5919995e69f8ca3e69d17"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_client.dart","hash":"3bc24109049f63bedd0393f75bc23503"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/builder.dart","hash":"9e5f67e1d8edbcd97531a8377e706d71"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_parsing.dart","hash":"ce49b6015a5f5b5bb716420efbef22c9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase_app.dart","hash":"fc8837c1b0c22211799e9412e64b08a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart","hash":"75abcdfe5d010a07b1833f1a2c48fa73"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart","hash":"8b4d7c15da02f61ba78cdade9d3e7374"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast.dart","hash":"dc379ed249557649f50b9c27d0033be6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterator.dart","hash":"4c92351d347c52a00797317aa487600f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart","hash":"07664903d8026f2514b29b786a27f318"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/constants.dart","hash":"2c6facdb1b63e687304c4b2852f6ef4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart","hash":"ccd754ed5584fb2b22056464dbfc9b37"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart","hash":"ea7754f2c684266799d36538300b6ffa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_for_web-3.1.0/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix2.dart","hash":"5a770014b927807d1ef52e7b6e287897"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/media_style_information.dart","hash":"4fe97d87eee37e8a1dddc5230ebbf9ce"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart","hash":"64c347128324802ec3aa6618f5723cc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart","hash":"7dc8dec32ceed4732299990cedf383dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart","hash":"035b8d3642fa73c21eafbee7851cc85d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart","hash":"5e054086533f32f7181757a17890ae56"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart","hash":"d2386b256656121d501a16234b008e2b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/icon.dart","hash":"b1d3d657c21d4c2229511410eb2240c0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart","hash":"f20071b459b9bbb98083efedeaf02777"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_error_page.dart","hash":"6fceee0a372978fde346a852cc666727"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart","hash":"7c12bdd660d493a20f3d692be2cafe20"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart","hash":"28464c209a2293d3d4e5549539e1a751"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart","hash":"2663ff02a467c826925672bcaf6bcf66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart","hash":"01d9ad3c8c89b65f3180229081a95952"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/writer.dart","hash":"a8499171c0b67ca96b9f8b0462e1079b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/sibling.dart","hash":"6cee72f673d593b0b84628bf243727a8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml.dart","hash":"fcf0dfcafac17dc3ed539b4587340320"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/reflection/iterable.dart","hash":"bea1f59f6923a9f56c6d7b785887caab"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/initialization_settings.dart","hash":"00883d18f109cb9b8f09707e277106c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart","hash":"3bc33c65fa44a57d13430fdedef82bc2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart","hash":"2fbba4502156d66db0a739144ccce9a0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart","hash":"f64029b4f4dbdc0bc61a4b8787975a94"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart","hash":"c390764eafafcc20c2e51225ce144ba8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart","hash":"0b8f9e0997c003bc97a462a2c70b91ab"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart","hash":"30d771880c8dbd68ea8e5d4a55c778c5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector4.dart","hash":"25e2aff82faa45ee7c3cb05fc8aa387d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/masking_optimizer.dart","hash":"583aae70081a96d5683cd54462840a64"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart","hash":"89dc3f84db2cd1ea37e349fdb1de09bb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart","hash":"a2ab6e0f334e5a28af29766b82f7f4b0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart","hash":"8f77cb7be1dbf41ca0fdf069ac69a215"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart","hash":"9c169d41e4740bbc21d0ce33bc753119"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart","hash":"8e0fc402506b32a335e86f7fef97f06e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/word.dart","hash":"18e902c0d484a6a2e0d68837fc5f003d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart","hash":"625e266fbab1e46e06c8d7d211a5828e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_enabled_options.dart","hash":"877295d0c356a690a3b16d271e34c543"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.json","hash":"6dfdd4a84db74aba6ac3de6f75385bd6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart","hash":"7abc7e5212374d29bfe5372de563f53c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/find.dart","hash":"17d3a0211da3d73d405d8730d46caacb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart","hash":"ef951139f9f55dc5b330d20e15d4fd0e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget_v2.dart","hash":"444af656078f102299511521fc7038d3"},{"path":"/Users/downy/flutter/packages/flutter/lib/cupertino.dart","hash":"21e240878a582ab39a490e6ac330c645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/numbers.dart","hash":"b30d064e9e3844eef3d2cc314139fc84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart","hash":"b0c6844b0af0cd0539060a0bfcbe3713"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart","hash":"65a04fd24f938030b7271b61a59f9a39"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_location.dart","hash":"f91bd03132e9e671e87f0b9066647164"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart","hash":"acfc0a55deec22276e085dae6197833a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart","hash":"ab7af0d1396dfa5930adaf0357fdc1cd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart","hash":"0c9897499d9ef356aa9886423cdf96e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart","hash":"a8fdf31698b305c9fdad63aa7a990766"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_success_page.dart","hash":"669fab2db1a5c93f5b0b7261a22b6b45"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/flutter_svg.dart","hash":"34cd13c59a8e623043493d748711999f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart","hash":"d195153a8c01a0392b38e3b9adc672d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart","hash":"9344bef2e519a536dfdcf9f5612671a3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart","hash":"7bbb6aab4e83fc272886a39c92157201"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/node.dart","hash":"9ec244272cb6c8da46a6dd5f104f0dfe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart","hash":"d8060c05b658b8065bc0bfdff6e4f229"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/cdata.dart","hash":"a1bc06d1d53e9b47b32fbdb4d323f44d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/utils.dart","hash":"8608f71f077e370ee14d37c711e6580e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart","hash":"0d9e952ceaa817539df84d30e876c4ee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart","hash":"f3747e025d835d0ff5cfd904d925dea2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_3.dart","hash":"9632b7c4c43e2e92f45bedc627663937"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics_compat.dart","hash":"a017616228e06275ed5610a4368f8d84"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/pattern.dart","hash":"75cd4f61b777cfcb29a03be16c612f1e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart","hash":"11df661a909009a918e6eec82d13e3ff"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart","hash":"4d43f0629755f06d4df0b1a6ef75ef59"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/path.dart","hash":"6dd2142267f6ad86b6410b5eb575d784"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/vector_graphics.dart","hash":"199c06bd523145278bcd9ff9c6fe6a18"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/char.dart","hash":"e72dfdd64a9644296cdccf5ed0014b38"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart","hash":"7536ace8732469863c97185648bb15a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart","hash":"be94b8f65e9d89867287dabe5ea1dff1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart","hash":"7018ea64a9aab18f27a10711285d7573"},{"path":"/Users/downy/flutter/packages/flutter/lib/physics.dart","hash":"6e29d5e69c5745a45214fe14da377c1a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/firebase_options.dart","hash":"57c27751360c2102da5405ddc950b0e6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart","hash":"9be021a3c68f7ef171b79893e7b4fcd0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/kernel_blob.bin","hash":"208cbfd2b2a79758506cb2fd02e9e481"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/opengl.dart","hash":"474c9e159ec8ec804957222054c877e9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/delegate.dart","hash":"5fc1a25f60cfa0a0280878377348c63c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_100to100.png","hash":"454be3ff72282ffa8fe50f8f3e44658b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json","hash":"2a16f501935503a19c9ffb7a0f2bf11a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2025.jpg","hash":"c0c39825a7e79a0d397864528c2c8b81"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart","hash":"78e53d9a4963c0d19c5ea355a0946e5d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/default.dart","hash":"7f30d05e05b047b274b1c4b45391d698"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart","hash":"0949b8197a6069783a78f4bb0a373fb0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart","hash":"7db055846295bfe7d5e376765ab0d106"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart","hash":"a1186c224201e7d203404a4270938040"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location.dart","hash":"6ed688f382406e9c782f92df9e965fac"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/enums.dart","hash":"a4b97395630dc415cc76f514d4a38869"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_plugin.dart","hash":"07db573490cf88af2c2da7b393436779"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/lib/image_picker_linux.dart","hash":"ff17d156fe2828de1af5ccee52274163"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/allocation.dart","hash":"9d62f4f58e8d63a8e106a1158eb13a02"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart","hash":"8e7e80b0f55481814454154289581855"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart","hash":"d35b72b249d19f54a4cd6f22ff3299e9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_properties.dart","hash":"953396d57b69e0e889d9dfcc4f7fdabe"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart","hash":"e9b0c1f2903ca05a29681459603679c1"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_page.dart","hash":"c16d2d577d620d569762e494d50c4abe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart","hash":"5c96449c2a494ea8f3a50ecc3ba9af74"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart","hash":"f44bbe72c4c7393277c42d5fc27b3b2b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart","hash":"fab8d6d1b0e81315a3d78131394d31e6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart","hash":"b76ebf453c4f7a78139f5c52af57fda3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart","hash":"f0d920fb2a472e43514830b20d401806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart","hash":"30ff1bba22f8f5d5442537740196fdcf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action_option.dart","hash":"be2d4c688f4ca84e68eefd04fe0ed129"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart","hash":"5893c7d3910e8924bd2dccc8837775c7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterable.dart","hash":"f0ae0acd94eb48615e14f6c4d1f5b8e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/not.dart","hash":"a7c2e189af8ef0e494c5f50550ce8500"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart","hash":"b092b123c7d8046443429a9cd72baa9a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quaternion.dart","hash":"9307caba73e148d13a0697568f0ad971"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart","hash":"87bcefcfff19652ad296ec7005799840"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart","hash":"a5d0509a39803ffb48cae2803cd4f4bd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart","hash":"14ee798b10cb318d96667b32b245f21f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid.dart","hash":"49d6d829ae481b2570a290401389d149"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart","hash":"cd0db51c646e4809e09bdeb76ec931b7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart","hash":"0db5f597f1cc6570937e6c88511af3a9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid.dart","hash":"5261078afe15bcdc637478bb6d7f7e21"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterator.dart","hash":"accb24637ddbe55d7a3f76e4618bdd22"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/dbus_wrapper.dart","hash":"52e0406df2babb2958beb4b471ccbcbe"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/overdraw_optimizer.dart","hash":"b4728e8f203f8d46acae376fc7ac4225"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart","hash":"790dc5e1e0b058d13efbd42a3f46498e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart","hash":"6c6dfd5ba4546c1f32201555d6cff215"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart","hash":"a11383c33c4fdc8d2cdc091f50d17e93"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/debug.dart","hash":"d3b50e217be5e58d53f746ba267e30e9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/flatten.dart","hash":"481d21ef07dee6f82302a015f989b597"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/ephemeral/flutter_lldbinit","hash":"4c0c8550624ce117572c484ae3e7d9ce"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart","hash":"5b894ae18be3e2442a34288833184ca9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_children.dart","hash":"7c666bff17f2cfae821f93f0c5e66a64"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/nav_workbook.png","hash":"72c5af6bfaa9a9ae4e20a77548c4f6c4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart","hash":"2ad27cdee5e6fe69626594543bd0e7c4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.32/LICENSE","hash":"2b36ca50262dc615e560c27654badb26"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_path_ops_io.dart","hash":"518899270d23bb8654ecbc26f12702a1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/file_selector_macos.dart","hash":"2c31d235f0339d60f7cc2e1d8388deb7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart","hash":"04ad97adf4dc5676764aa8d7aad857f9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Google.png","hash":"46778e2ab517be193b725b17e63f0795"},{"path":"/Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf","hash":"e7069dfd19b331be16bed984668fe080"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast_list.dart","hash":"87751ee02d315bd2d0c615bbf2803a3d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart","hash":"e4ee21048ab83cc50d61ac3784afa9f5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart","hash":"daa0c9b859ed1959e6085188a703f387"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/uppercase.dart","hash":"c9d12a17c125e31a94ec65076a9c3ac5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/pigeon/messages.pigeon.dart","hash":"9ae23519911b78febbb5e8165ed127af"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_options.dart","hash":"4f8c5cb9fbc074ac87af61da73f925cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/src/fp16.dart","hash":"63681ec4b0641faab6e783c1c213b5d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart","hash":"3fab1c4c90dce6d5451027be460e81fc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart","hash":"de161004250e30098d14049bdf54ce38"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart","hash":"3fd33becc9141d8a690c4205c72c5d40"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/descendants.dart","hash":"ffaf08c52f141dda6e8be50b3e46ea50"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action.dart","hash":"6a3849c802c2fd63cd4d3db06470f387"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart","hash":"ed11d553b999afddfd85ca57540af7d0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/upload_images_page.dart","hash":"6c36a955a27a6c36cf747b890518d89e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart","hash":"0e2afa27a9682352d434c10d20ffdc7f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/list_converter.dart","hash":"5f5f3a1074f40b8fc37c2b3ba5ec0432"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/firebase_messaging.dart","hash":"4c539cce5d187ad2bc808303fd6d6113"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart","hash":"92ec3dd43504f533d1985d189ffc9562"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/notification_details.dart","hash":"fcb452549a7c86cdf118933be09ef427"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/ios/enums.dart","hash":"670388961b23da0ffd68cf26f5104e49"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/utils/exception.dart","hash":"8abcbb724ffa31d2cf158a95c588db62"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/failure_joiner.dart","hash":"12b975946bcb9ba1b5a6dc3309a19de9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/preceding.dart","hash":"9d5375413b37f738384990ebdd6c6285"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart","hash":"2458910beb2b4f3b177a7db027cf7d34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart","hash":"e5b4b18b359c9703926f723a1b8dd4ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart","hash":"2a374faf6587ee0a408c4097b5ed7a6e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/display_settings_page.dart","hash":"6ff50f2efd60b7917e991fb0505b154f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart","hash":"2122907e49766bb1f044ae97841c2b86"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart","hash":"61dd7991c06ba3bae351fee9a80c64e1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart","hash":"44b3c2a3d6e67a3213a49cce58fed932"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart","hash":"110b9903c2673d2ae6f626dee25c45f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart","hash":"4a73924a7083f5e9d700ada6f2b53098"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart","hash":"bbc7eccdbd8472a2180e0dffce323bb9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart","hash":"b9abba31a48a9c2caee10ef52c5c1d0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/divider.dart","hash":"400da5c3ae6b8c8cf1ad20c796ce413b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart","hash":"9c23e23bd2cb8afe39b51de3545ab2ec"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart","hash":"16d2669eba65e0d92613a0aef0a169d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart","hash":"74708cb40b7b102b8e65ae54a0b644be"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart","hash":"98f725d06ba20a1032cb8770d00d7fca"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart","hash":"feacc941aea1ec8b3a30601915b7d353"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/LICENSE","hash":"b776a584ba475b946d8e76f1e42585f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart","hash":"a85856ccbb262dd4c1207418f8bc7801"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart","hash":"5061e0737e2db44e82d8a8c12f328a48"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/_file_io.dart","hash":"76964a546c84af33fb4bd8b2ba2fefda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart","hash":"7711f4b6c3574cec77169f2d2c35ee3d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/sound.dart","hash":"58f14973ee61401b0bf79de491dd1e69"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart","hash":"a88e90675c4b55522b3e9226f0135237"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix3.dart","hash":"d8b0931c64fbd4bdd435df207b303a04"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart","hash":"02139a0e85c6b42bceaf3377d2aee3de"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart","hash":"e556497953d1ee6cd5d7058d92d4e052"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart","hash":"3eb1458ae1a271dbe202030d5b8f0852"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart","hash":"5d30df9a71208100cd9e649ec1f21f69"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/page.dart","hash":"c5bf16620e9021a14d7fdd8d605e611a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart","hash":"2346472ec1cfdb77f3b27d3b7af72d4c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/utils.dart","hash":"e85b4f3cf370581b3ef11497a9a5bce3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/node_list.dart","hash":"6b9e945de99fb44b45f72925b6e862b2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/cross_file.dart","hash":"b5c8f4dba868efb80ed69fcd5a7d3f07"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart","hash":"aaace37762c25bcd679c2ab09129db12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart","hash":"6b6d593e4facdae2c82b9133fa8e69e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_decoder.dart","hash":"16eac0a8fcc5fdae0d8f38b7ea301c37"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_name.dart","hash":"749e18efee29d6925d7c55e573d3eb2f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart","hash":"597d897c972c255ade7307dfcc2e5524"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart","hash":"6566a35ff0dea9376debf257bdb08fba"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_call.dart","hash":"da6f500c03c005a207d38c1daf24b00a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/attribute.dart","hash":"9554d9749364a5e33fc853c08b09f076"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart","hash":"2ca785b09f831ebde51eca8654fd23b2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart","hash":"eabd3dc33b1a3a2966fa68f6efeb6bce"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart","hash":"6edb3eb5d6e5b289f28ce2fb68047e91"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart","hash":"325ce403b3634a9c45bd705d91ed31a9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE","hash":"3323850953be5c35d320c2035aad1a87"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/dart_plugin_registrant.dart","hash":"44b8efa69ec831d1a0ce74c20ecc27b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart","hash":"ae1f6fe977a287d316ee841eadf00c2b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart","hash":"a0816d2682f6a93a6bf602f6be7cebe1"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_unselected.svg","hash":"93a54f90a6de31d713d9a0fe53f11f8b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart","hash":"026b1fa8f1d7ff0d7c1a6e1afb2e75ca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/character.dart","hash":"ddce6034695da8c5dc36994409d26189"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_all.png","hash":"9479f3d4c7e70fc2c423c8f358e2dc92"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header.dart","hash":"172d44c4d881917a3f7b252fc2b9744e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart","hash":"ac08cb84358e3b08fc1edebf575d7f19"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2026.jpg","hash":"c1da37a2c4aa0902d24a0325e5014df5"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/social_login/Button_Google.png","hash":"46778e2ab517be193b725b17e63f0795"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart","hash":"5f5c07df31f7d37780708976065ac8d3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_selected.svg","hash":"f78d02a831d5135b07c39aaadc50bfca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_image_picker_options.dart","hash":"06a5bb71bbe7e618353d9c58948e3d21"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart","hash":"b0851d75151b4ad4d87a1443d2041382"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_title.dart","hash":"9d2c294d83aa23e84b94905b21194e25"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart","hash":"be0a77cf3f0463f3dacd09ec596d9002"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart","hash":"61d7b16669f075a39023fed8967fbdb9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf8.dart","hash":"329d62f7bbbfaf993dea464039ae886c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/colors.dart","hash":"a385ed3a073e36a430c51f9641564853"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart","hash":"41f7bdb7d1eb3c86c21489902221b859"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart","hash":"cdef014561140d05b803ce8d9d85e02e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart","hash":"c4806d7aa676f2573de819bcf2b1e19e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase_app.dart","hash":"4f4575a514eec25990a9923547e2ac28"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name.dart","hash":"2426dbde1829bfb9d5707ea69f21b4fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/x_type_group.dart","hash":"826066d6663c91c94cee09406ded70be"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category.dart","hash":"a94a67f325606644fee6ad6aa922752e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart","hash":"5bbe4c9f8221f331ef61519909f5cc54"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/lowercase.dart","hash":"05b3f9197904fe6acb3facfa980e097e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart","hash":"a6adbe3868e017441360895c35fd6aa2"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/account_management_page.dart","hash":"d3336f95699a96616dffa9f32e4d4250"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_selected.svg","hash":"b007fa5f063d26273adf3911feafdc5d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_error_name.dart","hash":"7398500b1824f6043f23e208cd993866"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_tessellator_ffi.dart","hash":"785a30044e959dfd84e84764a9c2a08f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/lazy.dart","hash":"c55ebccc440e68cd5b9553b5cadb9781"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_page.dart","hash":"7b6fdb08d6a6aae462d53c72d38ece9f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart","hash":"daeb052f1089d4e84d8a22acf56c1da2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart","hash":"81bf43e01741bf8b9df15ec37ffbc9ea"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/platform_interface/platform_interface_messaging.dart","hash":"6d506abd151728fbae098fe619a819a6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart","hash":"ceca25b48ef58dff53262c111c0dc9e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart","hash":"d2694042e337ac1f2d99602c25be195a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin","hash":"98c24403bb02b04545f78b7c2ca41c25"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart","hash":"7050c8c94b55eb51260ca54708b460fa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart","hash":"e40877daa15509fcbd3e465d246dbc09"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/_flutterfire_internals.dart","hash":"09004088d4048afe4f54ef5c78ffe98e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart","hash":"be096140df774ec827218c6fe69b80e5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart","hash":"24d6b5d55c0b41213c9bb4b2342764f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart","hash":"210d4d542d997e93c121b4dc814b95cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE","hash":"83228a1ae32476770262d4ff2ac6f984"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/skip.dart","hash":"e0af2f414117c942cbe5e23f4f60ba3d"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart","hash":"77f6ca8fc03e4edc47032b2817f4f41b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/matcher.dart","hash":"faa18ee55924a5c65995875c94338d98"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart","hash":"603b7b0647b2f77517d6e5cf1d073e5a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/mypage.dart","hash":"d723712119af4e11e9484b7a7f8ebdca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart","hash":"9a12cf2a3549924510006db4651a1743"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_list_page.dart","hash":"bf39a22a974cee04d2ecf4efc098cb49"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart","hash":"3fa7a3bafbab98c305119475eb004a06"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart","hash":"95545fdf17c2014df41408bad8115997"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_manager.dart","hash":"5f173a5c0de15909e95d3275051138c1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/io.dart","hash":"15f42b93489935782fd5f175832157c9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart","hash":"bbc54fca40953c4a17c12bf45c349c77"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_encoder.dart","hash":"ff402ced5472590045b91c0f30e4b089"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart","hash":"105813825251a3235085757d723ae97c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_source.dart","hash":"9989cfb5871d34d04fa38e13480d5eab"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart","hash":"b6a30b7ed48f83f446db37577b30e62e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart","hash":"7c2c3a23031810f7aa97f4d2f016330d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart","hash":"72aa3452833246a4d22c084e75fb93c3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/separated_list.dart","hash":"82acaf4c715888e486eb9d714c23b266"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart","hash":"c66e615feaae8abf62893d4eaeef0ed6"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart","hash":"a053986c2d9a24d11b9b8df45049c49c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart","hash":"16f71d097900371eb87d706863a8469c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart","hash":"09973ba0a94d2d819052c0544dcdce70"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/unicode_character.dart","hash":"d0e1db4618e688ad41ba325f1a35667e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications_platform_linux.dart","hash":"145a18283aef042bba506a2190347763"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart","hash":"4ba0a4163d73b3df00db62013fb0604e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/whitespace.dart","hash":"e63d3f21c1e3534e237fefbf5d3c2579"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart","hash":"0f2a1a61119c0bef3eaf52c47a2ebcf4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart","hash":"c0da8171c63f0ab4e822dd094fc2c595"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart","hash":"27c61344ce9c31ab29dff9add7511263"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart","hash":"d3b949a1e7578291493af5fd28846314"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/format_exception.dart","hash":"2128831f60d3870d6790e019887e77ac"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/question_detail_page.dart","hash":"8ef257c50ebc90d2f4b9ba64beaf2b97"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/LICENSE","hash":"7b7fcd3f415f29a260e0d5f15c7d9565"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart","hash":"7c07d5cc739ae29abcfbf6343ae84fdf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/bottom_nav_all.png","hash":"9479f3d4c7e70fc2c423c8f358e2dc92"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb2.dart","hash":"713156bb4c3a820c34bd6587a12b9074"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_verification_page.dart","hash":"7b0ed6e158cc3b625c502964151533ec"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/types.dart","hash":"24b206328a01c6923f0c599c64088645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_buffer.dart","hash":"99760254cc7c1941d4d7d7bb0fad045d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart","hash":"69be6215ea4781ec3da1e389b321cad4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart","hash":"18223495a47aa96889552c9834042729"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart","hash":"458e80784a70a0e225366534c905b294"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter","hash":"34de21e180d7144f166b7ab48d85d88b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf16.dart","hash":"10969c23d56bc924ded3adedeb13ecff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/accept.dart","hash":"740f17823564c3c7eca15bca5c110e17"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/clock.dart","hash":"2c91507ecca892cf65c6eaf3fbe0a7e6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lowercase.dart","hash":"e2bcdfd80ddc73e02b457e8544242028"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart","hash":"80eec0865406718828ef0dccff8154ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart","hash":"702f8b87ec7fc125312d9ff64434e7cc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/named_entities.dart","hash":"c7e489fa5d00c1717fe499f3845c2abb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE","hash":"22aea0b7487320a5aeef22c3f2dfc977"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/parser.dart","hash":"ed6e10b66c408845188f75959c15a23b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart","hash":"1099a5c5ee8ae0d01e2dd7d07c3edf90"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/text.dart","hash":"d3de5e8090ec30687a667fdb5e01f923"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart","hash":"92e6028556e74c1dc297e332b473f78e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button.dart","hash":"d7a239f8b80f844857527c2012e4fa1c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart","hash":"91e808d781743242114a756dec8f2cbf"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart","hash":"9fc2a184241aaf2f8e24b5742e163636"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/comment.dart","hash":"87546066dfc566126ed9357805535e97"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/vector_instructions.dart","hash":"c46976f5c36e761463ad24614d724ce0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_bus_name.dart","hash":"9cf807e15d1e83af4f62cdeb36582a91"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart","hash":"13be7153ef162d162d922f19eb99f341"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/platform_interface/file_selector_interface.dart","hash":"5937c2b1cbdf77126bc2dd93570d3c98"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart","hash":"3405e08e614528c3c17afc561d056964"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/isolate_snapshot_data","hash":"c8760dd22936a794d8412e15baab1397"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart","hash":"a7424dc75f961325d400c58f0e946ba2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart","hash":"a73883c523a61b1393b5e8c66de884c2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart","hash":"6f6fb24055973d0370e30a78ca69db89"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart","hash":"d0911329ae74edbd7f6ad6a89e0703f8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart","hash":"2c582bec6fc77f68c975f84d2252ed8d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_attributes.dart","hash":"1059ea9e8a0e858f944bf05dcb7b8edd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart","hash":"a340eddbf129cfd60e2c67db33c6003e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart","hash":"06455706949396049309d1cc90b76efd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/firebase_core_platform_interface.dart","hash":"a12b9a0771829ebdd5571928f9c48e7d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart","hash":"af5377d18db2f18bd4ac0ec35ed7d308"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart","hash":"157d1983388ff7abc75e862b5231aa28"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart","hash":"35bf7179f32e4ab5b13e9d9ec2abbe86"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart","hash":"fa0d3415d04242864a0c411fceeaabd8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart","hash":"997f4b4e6bf9981e307f46f08fa90b82"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/constant.dart","hash":"54356788d5c11fa49cae271d737b0c78"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_uuid.dart","hash":"c9efc107e2b16a48d4e132bfcc679af4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart","hash":"38e17b28106d00f831c56d4e78ca7421"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/hint.dart","hash":"570573fffe43860513d5cc911da0668f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/file_system.dart","hash":"f72f7c9e3a3971fdfd58d38c94b4e005"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart","hash":"9c9f1e70fac06b3e87bb33ece047c4cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart","hash":"596fb2e55b1ff1662e4bd67461fdc89d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart","hash":"cbbb174cb00bf954fdc9e2854517dbd9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart","hash":"72804f9d34b9a247c43d6cc575527370"},{"path":"/Users/downy/flutter/packages/flutter/lib/widgets.dart","hash":"0d4b8c16e7b8e4d8baf6fca9161c7e56"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart","hash":"3ed378957409718f644078da99891428"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/nav_home.png","hash":"875ffbaba3b258b9a62790bbacd26472"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart","hash":"21f4467f19bac7f0fe6f0e730ab10fda"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/file_selector_platform_interface.dart","hash":"eeb75628a0a17d5d8b5dbe0eafc08a29"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart","hash":"205bb888a773c736206a9f2c84c8fd92"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart","hash":"9f2eb24284aeaa1bacc5629ddb55b287"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name_matcher.dart","hash":"5c4dc37f36fc78823f785b92b944560d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/mime-2.0.0/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart","hash":"50062b12181ce59a75a26727cacaf5cc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart","hash":"aef544fef0ced7679e0edaf5f8d036b7"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json","hash":"dc3d03800ccca4601324923c0b1d6d57"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/vector_graphics_codec.dart","hash":"1cb908a37b3d1b606ce345ce629694b9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/constants.dart","hash":"55422a6a3ed3f0829854a5bbb97d4e6f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/academy_management_page.dart","hash":"455038cbaee05ad9cfbf84d5ca1b7d0a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/utils.dart","hash":"c65a1aef14f77e85636770f08f4388d9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/node_codec.dart","hash":"a40d7d4a17e700bbb41bf31de37c6bae"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart","hash":"121fcbdc1af81a0fd804490f85357fa0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/exception.dart","hash":"7be00974229804e8ec49ca8c4fca3b5f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/debug.dart","hash":"0575a78fbb39a292302737868752da77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart","hash":"5fe5b5ed3ec92338a01f24258b6070a3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart","hash":"3dc9f56e0fb2e949ac4c68187162c0a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart","hash":"bbc9542eb5e3c4701c24bc1268b8165c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart","hash":"aff8f09b64bc316bf514d7a58be4131f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart","hash":"1e30703fc6d5663dea611a3c783b21aa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart","hash":"0073f703be7f7ddbd7f04d1b740f35c6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart","hash":"62dce337eb5905e15da1113e7ba50806"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart","hash":"44d59e37041b6305018f70012fef7d52"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart","hash":"866257a42b6b721549b351382b365c47"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart","hash":"9f8b50d98e75350b41d40fee06a9d7ed"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart","hash":"d1d1398bda204825136843ad63735067"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart","hash":"a6350a577e531a76d89b24942fca3073"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart","hash":"46e577ec532e21029e9cee153d7ca434"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart","hash":"2083695b7b9150b87307af446032ba45"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/stopwatch.dart","hash":"f38a99a51f4062e7861bb366f85265d5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart","hash":"bca928191c274201a95a3b9474582b31"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel.dart","hash":"bc48ae34e58774e84a72567a86034fef"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart","hash":"12b637659bb42a669c3b60bc09a42150"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart","hash":"5843b4750179f6099d443212b76f04a2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart","hash":"c0cf85f80b79542d2b0e1a00547d7310"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart","hash":"a2c7734430a38c6f25a3e99f10aa19fa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart","hash":"ad4f49532706bd4252a8383731d0e349"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_4.dart","hash":"ba02460ed2591611ff8506bdd88f569e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/normalizer.dart","hash":"bd502c5f75cc8148d708eb3e01c02765"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart","hash":"a2eb984b374f7375264ed4b139a0eb03"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object_manager.dart","hash":"69c08243f2f74c58d6ad38b17bb5cb9a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart","hash":"3e4d53a860279f33b4e7c6b1d9957a51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart","hash":"3623c605586d2e37af23d6b746721bd7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart","hash":"b0b28dbb0d6b26d142ff99ecbd5d8187"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/element.dart","hash":"361f3bd2e6ba6710885e241d7574326b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/compute.dart","hash":"c01ffc2036120e75a95496900bb49a4f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart","hash":"f209fe925dbbe18566facbfe882fdcb0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart","hash":"135373d55120d14b786fdabe98c9c64b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/newline.dart","hash":"d6beb013c7ba06cf6076e547a7b21f1f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart","hash":"4b5d82ddeb09bc46ae0e980616ce0109"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_attachment.dart","hash":"796d0d545778c85ce27a9304092b5ed0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/vector_graphics_compiler.dart","hash":"339d4b38a75faaa45624222be37f9109"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/theme.dart","hash":"4ccdd5e6210285f9baf09909e7d4f593"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart","hash":"a79a6f9bb06c7d6dc5fb74ac53dce31b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart","hash":"1f437276972808bf4cf722440da1b231"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart","hash":"db4a14227247e2524e46f6b0dd9da267"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart","hash":"b09ffd962fcbee7d3403b54155e33047"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE","hash":"3b954371d922e30c595d3f72f54bb6e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/LICENSE","hash":"2b36ca50262dc615e560c27654badb26"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/typedefs.dart","hash":"4c00fd95f493a02179f1013a29629e43"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/.DS_Store","hash":"f1090a7e0712544a5401a7311bfb9e6d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart","hash":"0ddbbba088a930cb7ae5b5920ce346cf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/optional.dart","hash":"7d49b944ccc5ee228590126488731a95"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart","hash":"f77f6a903d346f842a7fe474e427d6a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart","hash":"ed59d68fc74e5f7be21e0d7fc1c7242a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart","hash":"24094ce9de1b9222a8d6548d3c01045a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart","hash":"9298606a388e3adb5f1bbe88ae45b1e6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_response.dart","hash":"f29d1458f73f015dabefc27f98181f05"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/node_type.dart","hash":"57e5dc91c30bff1774eaaa45a798d0df"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_reset_page.dart","hash":"b316e534e1967412c68b1a042986a798"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart","hash":"ae85856265742b6237ed0cb67c4364af"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart","hash":"e5a3ca065f292c0f0b0cca0a55df41aa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/flatten.dart","hash":"b192f8c8e04e47ae69d662e5feff7306"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/namespace.dart","hash":"d7259aeee1602df30d051e8fc0523d91"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart","hash":"e45c87e4aadaebf7ba449f4c60929928"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_member_name.dart","hash":"2ef397117616f6ff779ed0ab2dd0d61d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.10.10/LICENSE","hash":"1ac261c28033869c8bcf9caaedf74f6e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/vm_snapshot_data","hash":"b8ee00883037778797bf5949230f40a6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/visitor.dart","hash":"9e63190d98c0519ef00473a9451fc5db"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart","hash":"6618a55cdb528b43addda36642363d96"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart","hash":"9e8b56ffe3de97538d012849a1afa5ac"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart","hash":"4250bd72ef305d1f376e96cc6b994778"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart","hash":"f54f6b61b175b0a37d51ff3ac8b8c800"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/types.dart","hash":"1187c7bfe4c5a401ffb5ad27a944c035"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart","hash":"a06bb87266e0bac30a263d7182aaf68c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/comment.dart","hash":"74fb000405fb96842a3ce15a519d8ae8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/noise.dart","hash":"996d7bdb8134338c2357699662cee703"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/default_style_information.dart","hash":"4cc8128599d4dfdcbd699b3f01d68904"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart","hash":"0f70aaa46e42cb439dcc5a21fba00f44"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart","hash":"0fa4800227413041d2699ed47918c7f7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart","hash":"d9d777d58bfe8521d1cee4c60700de58"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart","hash":"777aca422776ac8e4455ccc7958f7972"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart","hash":"154bcb3658f38871192c3955ebccb00a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/definition.dart","hash":"f0cf3060fe907fd075c49261e69b477c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/mutator.dart","hash":"e105e8d3303975f4db202ed32d9aa4c7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart","hash":"fb2c02d4f540edce4651227e18a35d19"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart","hash":"3c1bedbe57228c35f8421d813a7237ec"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/path_ops.dart","hash":"bc3896a61a99aaf962226bd29cf010f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart","hash":"1b5af29e062854d33f5e4c81c2bdf11c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/parser.dart","hash":"1905c946413915323ba969930f19d207"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any.dart","hash":"3a1d79b051bd693ad652b0f905ff1588"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Mypage_unselected.svg","hash":"dee348e2202f671e34773695f6a38cc8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_options.dart","hash":"1693d7de0d1d5b50ab8a0db8e3c08667"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget.dart","hash":"d172e05d6fc5261869d94426786031d9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart","hash":"458f3bf784829a083098291a97123e81"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_pattern.dart","hash":"79a5f25a1a9d4aa4689bf37171e1b615"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart","hash":"904ebe4c195d2036f989a5e1c3c6052d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart","hash":"229f98ffbc538c9813ef41d9f707f00a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart","hash":"6f18c18a1a5649f27b6e0c29dfba4dc9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart","hash":"4c5df57cfe2a6a2bc0d7462330344982"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart","hash":"9c053b0efcabd70996cc27e9d6c9303e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart","hash":"55675ef4bbddffa94d962bd52b3088ca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/env.dart","hash":"278242320426f869a4121f48b98c2ed9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart","hash":"a8c03fde31609e92e69be46cf798cbd7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/inbox_style_information.dart","hash":"b54d4d23f060b78a02290d93a10d3319"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart","hash":"03001d3ddae80bbf1f35c5e70e0d93e4"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/app.dill","hash":"208cbfd2b2a79758506cb2fd02e9e481"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parser.dart","hash":"7f7dd4c5d3d4ad18886a0d575ebb655e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart","hash":"7901ed0c67e85a20ff901594a4231ba3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_message.dart","hash":"eb54a5ead5cb8ea548f36e4b8780e4b8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/slider.dart","hash":"1962877d0f77e2d3d7ebadbb093d4997"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart","hash":"9645e1d88d63387bb98a35849f4cbe53"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_web-2.24.1/LICENSE","hash":"2abd2c9a42d4caf2b4f1640d68b02fd5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart","hash":"95bedb83cd5b163e43b554086b016380"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/exception.dart","hash":"9a74595c2e95795b6c96d74f2b6bcca8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart","hash":"2a10c15764942d10992468122feea62f"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Alarm_unselected.svg","hash":"22f085ac90f93a6cbfea8c2c872edc30"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart","hash":"4a4e74da2f12d15dddf3cddd0628372f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/comparison.dart","hash":"643ca26571c2ba94477233dbb914b1ed"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart","hash":"34a4d340931147322eaddc77fdc65c22"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart","hash":"e1648c3accd2c87d0897e5454a387c3c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart","hash":"d1e0e0c2904bd9e5145d919296eeb580"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart","hash":"c7fd5a3a7f809d37cfe6af2af573d097"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/possessive.dart","hash":"485043a68e11755920abd67f229ffe9d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/about.dart","hash":"1a8cf97475fa611bd193041415e8220f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart","hash":"56a59615d1fa716ece6eff8304f7bd34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart","hash":"7592e5df71403552b6109cb4fe946eee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/code.dart","hash":"1216b7dc6f446693a3fcb9a566b94d94"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart","hash":"29befe23f841cf5dd2dc7df24c13d88d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/AppDelegate.swift","hash":"303ca46dbd58544be7b816861d70a27c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_write_buffer.dart","hash":"63d2768cdd6ab5a282fbb6a86c237b78"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart","hash":"b29e302994b1b0ea5029734406101b8e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart","hash":"f90beedee11a434d706e3152bfb2fd15"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/src/messages.g.dart","hash":"a5362386f63b48f5c6b1099ad942b40d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart","hash":"d857a3ae7f599cc71f41689ffcf1fc5b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/processing.dart","hash":"5a7bd956aa537e95be882d4809232c39"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart","hash":"6b3b758749ea0e06a43533073febcb66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications.dart","hash":"672695b311530b8c64badc8eb93e6fd9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/default_theme.dart","hash":"92cd3ab206500a956ac5bd8c53e8286c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml_events.dart","hash":"81c2aad8ddfe7e91e913fa4c319764f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart","hash":"8dfd28d2164bbd446b480491aace196c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/LICENSE","hash":"9633ac2bb6bd16fe5066b9905b6f0d1c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/predicate.dart","hash":"c135a8cfe6154841111bd7d4f7c7e69a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart","hash":"b1da6e4c330ab79eb371fb535a8fb7cd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart","hash":"d74d8acd1490e1db907df61d756d2c71"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object.dart","hash":"0cb51131f14d4d8df95aee83e4931780"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart","hash":"4349dd08c33e677b65d9e00f13c35d2e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart","hash":"de7fb154b9b151b81a78d43ade695365"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart","hash":"66272a6751b167051ba879724cfe5749"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/file_selector_linux.dart","hash":"25c44b3908d2602e0df540ca5b17da27"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart","hash":"34485853c65233b4daedcede2ade0c69"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/obb3.dart","hash":"5ad121ce46b5c0473bbe34be6d5c0913"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart","hash":"951bd729c13e8dd03a7f4edd8b10c06d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document_fragment.dart","hash":"88acdeb4b5b5a9e5b057f7696935fc2e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart","hash":"b266a6c412cb5bbd5355fc22a3be3f84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart","hash":"5da121a0d3087e7cf021bfcdeb247b77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart","hash":"391dfdeb37052a0c52eb8adbc96bffc1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart","hash":"f7b4c0027cecafcb6711746922663d7c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_selected.svg","hash":"658f8ff54183bf1c1c90677a39dc7f05"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart","hash":"d74cafcf507b38e3f3094c6d5ed94a9d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2025.jpg","hash":"c0c39825a7e79a0d397864528c2c8b81"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/loader.dart","hash":"14d64729800391fb58a32643b7126984"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart","hash":"9a023a5d9b2c849e9c7fd9e16db1e7e2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart","hash":"75f947f0ba87a0789a3ef91542bbc82c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart","hash":"d70df86ce471e8470438627a65b2824b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category_option.dart","hash":"f328cfe04255be8a4d740b54f2854bbe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart","hash":"fe766313e73046aa145217de64ca7760"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/typedefs.dart","hash":"3e93222dc359a938c1354ba486d44244"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/event_attribute.dart","hash":"304fc982848b57cf13da0ec511f05ed9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/messaging_style_information.dart","hash":"017129b89f3045aa21d9a8032f5dfec0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart","hash":"a056a48864751b648133bf4d0886134a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart","hash":"8a39bdc324d0ff25097784bd98333c08"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/chip.dart","hash":"926a78bbb0d20acd22028c14ca8b8071"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart","hash":"91d8303ca1ccc72eccc1ae636c7825ed"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart","hash":"bf6d84f8802d83e64fe83477c83752b4"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page_v2.dart","hash":"a475b741bdefeed0127f22fd7bd540e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart","hash":"974d0c452808a1c68d61285d0bd16b28"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart","hash":"44c1268c1ecafd3b4cd06ab573f6779a"},{"path":"/Users/downy/flutter/packages/flutter/lib/animation.dart","hash":"29a29ed9169067da757990e05a1476ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart","hash":"3167bedcdf6eb73bb3355fc778c69ab2"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build_result.json","hash":"1f8e8e6dbc6166b50ef81df96e58f812"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/ancestors.dart","hash":"3f842dc9d82d8b21557bf598ff4ec83b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart","hash":"a6c467b3086118863463a925df22d187"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/basic_types.dart","hash":"3661d2fbcfb187977923b56f618b1103"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart","hash":"2675cdf47e408031206cc9c215200004"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart","hash":"36bb3dc8435f5085b78c2972f8efe90d"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart","hash":"f9ff8d662779df64515cdb55d0c3e342"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart","hash":"8d05e0330774daca2ab93f307ded78f3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/doctype.dart","hash":"c2d76b78fb107e358b1ad967f15f1746"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart","hash":"12143f732513790cd579481704256dcd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart","hash":"c7cc72c1e40d30770550bfc16b13ef40"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart","hash":"a8f2c6aa382890a1bb34572bd2d264aa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/each_event.dart","hash":"5776e262e9291819ba2122854943ea6d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/default_mapping.dart","hash":"a2187618f84ad697f470a748b2a27f56"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/capabilities.dart","hash":"b7729342f9613bd823c71f9c12c680b1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_vector_graphic.dart","hash":"3f4bc5c1ecc7c8c1756db79f8be177b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart","hash":"6efba60755f63ff2efc82c76d3a50222"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart","hash":"1f131d7f971396d52ce5fe78ae6a8a83"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/repeating.dart","hash":"9a0bdbeb6a1452722cc91b80ee779998"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart","hash":"1268762fa54412a0d265cb57a14cba84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart","hash":"19c24981d3d862f7206e587073eaae67"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_tree.dart","hash":"eedac0b4fc9b2865aae62ba790f0e26a"},{"path":"/Users/downy/flutter/bin/cache/engine.stamp","hash":"383b255daebb4eb59cd9619930afce20"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_segment_type.dart","hash":"b46578a0f8f94ea4767f634b5235a54e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart","hash":"d33374c0857b9ee8927c22a5d269de9b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart","hash":"6486bc074c81ec57bdafc82e6a64683a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/draw_command_builder.dart","hash":"dc602dea0bc34c673d92a3e6096995c1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart","hash":"08c3fd9ed1607d3a707ffe9b3532218a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/types.dart","hash":"7e327134a49991d7ba65bbfe46bb8f4c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/tessellator.dart","hash":"5e4fca343abbf78a251574e239c0220b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location_database.dart","hash":"011e1e9f46dfe9400619c8e5103c30ef"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart","hash":"7e45468116224ee318aa9b1f210cab12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart","hash":"bd6d122c12d867a991bd2fd36a3c46a8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart","hash":"cc6cce102fab186d0e7a063d0d917504"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart","hash":"06078529e4523830f3ad70e0aab603d0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Upload_image_selected.svg","hash":"b007fa5f063d26273adf3911feafdc5d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart","hash":"77900a31d721da1722fe34c455a00d3f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart","hash":"f487ad099842793e5deeebcc3a8048cb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart","hash":"73d5607bd6f5dccf91add39e25ad157d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart","hash":"bc3c12f9555c86aa11866996e60c0ec9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE","hash":"2d0c70561d7f1d35b4ccc7df9158beed"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/petitparser.dart","hash":"6cb32004f228090f1200484076254c7a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_detail_page.dart","hash":"11023d38b622c8afd4f67442d66639f9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/end.dart","hash":"d6b4c337633cf50449be67966688dc32"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart","hash":"eaf5aa7cf4fe19db30724f637b38257a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/App","hash":"a6af943f8fd5bf215c58d625c7aa5d5c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/core.dart","hash":"b969cd0066fa07b8082edb76d2af77e1"},{"path":"/Users/downy/flutter/packages/flutter/lib/semantics.dart","hash":"4b784d6e4f290bd6d5a1f38bfb5701d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart","hash":"c761b80666ae3a0a349cef1131f4413d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/port_mapping.dart","hash":"d1870b4415ddf7f379e6e41b520ca299"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parent_exception.dart","hash":"2ede71f09a240decbc57417850f8feb7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart","hash":"f5b38c21bf580c89610a8b58c65aae00"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart","hash":"3d71d8940be022672282ed70f0cbb8c6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart","hash":"8ac28b43cbabd2954dafb72dc9a58f01"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/pretty_writer.dart","hash":"09214b5a4ed4e104f212ef38f676fb1f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart","hash":"6cae6900e82c94905cc2aaefd806f8eb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart","hash":"f949f49484067589ef08e13a892f3101"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_workbook.png","hash":"72c5af6bfaa9a9ae4e20a77548c4f6c4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/permute.dart","hash":"8171c3b0d66f560aad82b73d43393092"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/LICENSE","hash":"9741c346eef56131163e13b9db1241b3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/event.dart","hash":"1a7fe7a35dbd168a7f2e10065f4a3158"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart","hash":"0fbec63144acf1cb9e5d3a3d462e244b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/date_time.dart","hash":"2faf9ca0d113c0ed79c6651a9c1f76db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart","hash":"ca959e5242b0f3616ee4b630b9866a51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart","hash":"e3127548d819af5ec9ecb10b5732b28e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart","hash":"e9a141d0ed4d585b165b7fcacc3874d1"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/login_page.dart","hash":"e16fecac4335e99bb8ca534154d6262e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart","hash":"dc667b5b278c7b8a2191913ac49e33d0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart","hash":"eafe83db9186e4fbb802d857e4bb42ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/binding.dart","hash":"064a460171599d3d2a4596a5d1ea2b00"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Upload_image_unselected.svg","hash":"276234b99389b2bcc7bdc79c22df0e55"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_menu_button.dart","hash":"c5e9b21796184a1bdbd5788371a913c8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart","hash":"ff5d66c50ec833a263625d39f0c195b9"},{"path":"/Users/downy/flutter/packages/flutter/lib/material.dart","hash":"79c87aaef3dd490ff1c43fad2f2f6e8e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart","hash":"184d3b79d275d28cd02745b455041ee6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart","hash":"8fde18d2ef5c741e3b748bbc854d6b17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart","hash":"f6d7d6477016f1f991e57b2cbeef7292"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart","hash":"58feb628edda8670acd9b4c4db589918"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart","hash":"f158ffadca730ab601c60307ba31a5e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart","hash":"20051c4912af535e0a8362fb1e93f423"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/parent.dart","hash":"210257ed62edd783098ed34d7cfb0204"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart","hash":"caf148b76c44a3f0f1bd6055ddbb8f5e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_match_rule.dart","hash":"0298dac3221d4c6752b6207594e4f470"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/Info.plist","hash":"3e84ffd77b8e1d46de0dec59f05dfec4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/digit.dart","hash":"e475fe11812000841b73324ccc3b3183"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart","hash":"207aa61e81c77c54342772a6367af334"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_verification_page.dart","hash":"c476cb167807940f2c6ee986934daea8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/resolve.dart","hash":"cbb8e1af9f1f0decfb6fc25a0725c51f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate.dart","hash":"bd343bbe0baca1494e15a8872fe23e6f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/position.dart","hash":"faedea5895c9ddd2b2c270817c61d1f4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart","hash":"5de15d7a41897996ef485c087ef4245b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/sequential.dart","hash":"b5519514c9b9570c951c0da186030e29"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/text.dart","hash":"f52860ffbd4c6858f092292d1589d556"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_video_picker_options.dart","hash":"091c22e31f88028ff0cee6f6ed581d74"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart","hash":"9ad11b4bdb179abe4ccb587eb0e2aebc"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Kakao.png","hash":"7e3eb90819c0f6ef186ee3d8835b5bb3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/nodes.dart","hash":"8608080cdfc143d462b0f9947dc0d7c1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/path_parsing.dart","hash":"498f254119e3d3c67475fe8ca026d01a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/image/image_info.dart","hash":"de8156593b2cb55c127213759bc77f58"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE","hash":"e9f463669bd6dfea2166dcdcbf392645"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart","hash":"56e9b43aa79d6b888e779ad7905c1617"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart","hash":"fda1d4b1be4a584133638117945d3dff"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart","hash":"4d6c8c8185327af9d064a1fbeab18fa1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/posix.dart","hash":"f19239fe10cca0cd002c22edba90eb52"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart","hash":"b698617b81ba534ca60cdb6dee762fff"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/notification_settings.dart","hash":"806db0fe7cc5bbedb3e8f229ed0786dc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/range.dart","hash":"5e99407d87eef382375ad62495706f32"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_notification.dart","hash":"862e144a0d18968ff9720807fc2a43a8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/character_data_parser.dart","hash":"7b4a3d153a0c2e22401073c511515325"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/group.dart","hash":"e3471fd3bfb2f9217d1cf61b1bbcb43e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag","hash":"a0e89676ccae6cf3669483d52fa61075"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart","hash":"4935fd96677780d631f23a75e7009534"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/processing.dart","hash":"0ca8410c364e97f0bd676f3c7c3c9e32"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/label.dart","hash":"7de7aec8bf9b53488692403a3feb7672"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_interface_name.dart","hash":"4f835012742ef22df8c85292594f9823"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart","hash":"0672d853d5097a03eddc7dbe558eeabd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart","hash":"43ef2382f5e86c859817da872279301e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart","hash":"d4252f423175e5c21fca23dc24154b84"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart","hash":"6f02e150859b1047ec04ffa4a924f90a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE","hash":"175792518e4ac015ab6696d16c4f607e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart","hash":"f56109c40e6fe9e53f9c6ad021d25ff5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart","hash":"2aec07fe4a1cd25aa500e5e22f365800"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart","hash":"5176206f3155513053dda23b0c32fc8c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart","hash":"605dcc1d6bd5023fc0b651a625076ca8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart","hash":"986845a7043505c19753e1d499d49a4a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart","hash":"edd2f9cabffc7ea6a5a9497a1b1beccd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart","hash":"ab177cf671fb7bab974d9c08618a677c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_message.dart","hash":"f4b52208f2ac65794c0722ae22b2ed5a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart","hash":"c9cd996cea2334f644c74ebbdb41f7f5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/undefined.dart","hash":"bb00c98e50d3c71d4ab7ac7c46122f3f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart","hash":"13c8dcc201f970674db72fbbd0505581"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/learning_statistics_page.dart","hash":"a5c850065330b1ca508af48bb7920fa4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart","hash":"270de9c98f9c1284da0a6af9176ee1f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart","hash":"920b63c794849c8a7a0f03f23314bbb1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart","hash":"dc2cfe4408f094916cd5eb1d294d1f2f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart","hash":"8a7e3b181572ed50e923e5dc05a7533d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart","hash":"289e5bbf4975b43a1bc7510306854b34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart","hash":"d161560a01cd02902c87f5decd590cfa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_5.dart","hash":"1e4da3528271172cb17b59a72a37a57a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart","hash":"e79db1a382e61436ed81f9f47dc06d7a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart","hash":"1542c76e7b3e366d393fcb2c3bc601d5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart","hash":"89b2bd5c8fc199b582eb9f10973f97b4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart","hash":"e792b35686d28f5a239264b5b791c0cd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart","hash":"395f07418a28b12b0ed665f32270d702"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart","hash":"92868012710ac163590ba05c788c0816"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Textbook_selected.svg","hash":"658f8ff54183bf1c1c90677a39dc7f05"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart","hash":"555fcdeebbe6517cde1cdd95133cabd7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart","hash":"c4d13715583d2c97acba184a3e821151"},{"path":"/Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE","hash":"4fd63b752aa4c209c7c0bdd1ee5f8a10"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart","hash":"1205ed5e14a59c237c712b8a495b1981"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2024.jpg","hash":"bac3e7ec19ff9a3512b243743484c706"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart","hash":"73189b511058625710f6e09c425c4278"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart","hash":"53d7a28895126d1b4c472405e2876fb0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_tessellator_io.dart","hash":"4aa9532707ae3709836dac6e154dd477"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart","hash":"8a60b4ed49f146296d6896973154e1d8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart","hash":"3cddcab8b952545bc05a5c1475a06c9d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parser_exception.dart","hash":"a62996936bad6c27697a35bed070547d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart","hash":"85cf42bafb7c0646bd7a99379649da29"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart","hash":"9ffd4af5e11781c62ed4e40fdf15b182"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/notification_details.dart","hash":"5bc24b31455e76bc74c05a2ee528dcbe"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart","hash":"269af8ca7030ccfd9c868fe9af8a6b0a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterable.dart","hash":"037df9e7342fc8b812d985c8b6e8a0c3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart","hash":"ed5548873fcf5a0a5614fc52139600b8"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_page.dart","hash":"09ab94aeb507991e01e2a6a26402fe5e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/flutter_local_notifications_linux.dart","hash":"bd3131f212db4084582e634bc232b43b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart","hash":"7ebcf3ce26dea573af17627d822e9759"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart","hash":"f64837679a1abb526e942b166db5c244"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart","hash":"965c702e5f0b6ba27c6292cf3a602781"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart","hash":"d3eb6373e2fd626717b8de7cbf19cd8c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart","hash":"b3a6dd250e09b61bffbc04a767f0c920"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart","hash":"3c8d2d2b73f69d670141d376642e5252"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/failure.dart","hash":"30a4963c49e7dd57d8cec29b8f4821db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/image.dart","hash":"5d0aef3e7f7bc482577c813d6fb87f20"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart","hash":"6a612ac4de579506fd1b806fac3fe062"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart","hash":"ad139ffd36c17bbb2c069eb50b2ec5af"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart","hash":"78f6899dd22a8086e573217b5538f98c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart","hash":"b062a8e2dade00779072d1c37846d161"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart","hash":"59b6b74779849bf5b836b84bb362b99b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_result_page.dart","hash":"4e96f5ebb837b7ddf114b335c507dea4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart","hash":"cb454929d7810d3ee5aa5fc28283d3fd"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/common.dart","hash":"b9127267cdd2de6c1285a11eac48d269"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart","hash":"553c5e7dc9700c1fa053cd78c1dcd60a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart","hash":"546a4af6d99fa77922a881e2f131c1f3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart","hash":"f3d29b37515ed98685cd81aa319dd254"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/uppercase.dart","hash":"997830cae101fd7a406061c7a46c5114"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_server.dart","hash":"0b4a237293e913152ca376cdcfbe752a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_Blacklabel.png","hash":"2a1292ee675efd8f5b3b072a648a0aeb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart","hash":"5577ef7cd41e467cc247a42b677f93c9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/color_mapper.dart","hash":"5baf64b18f36d2e7620e01237c625a19"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart","hash":"79c35fba64a91629072a76526adb9aa7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart","hash":"107c33a245427bf0f05e21c250653dc6"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart","hash":"de17df889317f7a54961ea540cf4b807"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart","hash":"6be1e6f404dc5206ea2b4fa512c45dc3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/image_picker_ios.dart","hash":"7b97e07dc767038c0b776897e88f1ccf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/helpers.dart","hash":"20e259f655329b9bc2ecb98ae2975e72"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/prefix_name.dart","hash":"fbb3e43ae57262b3fc190cb173a7b5bf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_address.dart","hash":"4ecc0e7678d4ed3bf62a04b3e383e424"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/schedule_mode.dart","hash":"9979b67c6fdb803b55c4628af847ad4c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE","hash":"f721b495d225cd93026aaeb2f6e41bcc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart","hash":"8b15d222f5742b46bf55a4ef4cbfd6e0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/start_element.dart","hash":"2c72add0b4beec6c29322827553e616d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time.dart","hash":"872d879ea43b6b56c6feb519cc12d5a9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/colors.dart","hash":"f59aed120736d81640750c612c8cfe5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart","hash":"f94061e9a635be75dd8e38eab352c344"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart","hash":"ef5fc00d685cd2a36c4de80e1c7e3a8f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart","hash":"ea7c9cbd710872ba6d1b93050936bea7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart","hash":"85b908f2e50b980d5cab7f458371f430"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/result.dart","hash":"bc503b6c5e3658a13efaee4e0638935a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/LICENSE","hash":"a02789da8b51e7b039db4810ec3a7d03"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart","hash":"1fd7c932679011d491315ff136d13822"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart","hash":"15a20afe634cea8448869b051ad52b3c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart","hash":"cc4a516908b08edff4fade47d6945e5c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/plane.dart","hash":"fe0f3503d326c72bc31945d24f76946f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart","hash":"d7a6c07c0b77c6d7e5f71ff3d28b86bd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/icon.dart","hash":"cb4cf0d998a65879bb40daf8db093eed"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/event_codec.dart","hash":"3a9a69af68cc0a35c422d0bf03873265"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart","hash":"4da7ecc08c07abdd0226004f30973748"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart","hash":"9d1525a634d27c83e1637a512a198b4f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart","hash":"785eedcc96fa6a4fcc7c81a8736a7427"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart","hash":"3ee18da390e16ca65f2ef168adb8a1ef"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart","hash":"c679063104d2f24639459c8ab3eed77a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_home.png","hash":"875ffbaba3b258b9a62790bbacd26472"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart","hash":"1e2afd780c32baef8cedd0eb9c4dee6d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart","hash":"cf63ef7fb2873f43a2b2e25485734429"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart","hash":"faf4d014b3617ede3150f80eba25e3b4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart","hash":"12580e996c5cb68c4e80588f6dd9f235"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart","hash":"cb49e0d1c096a600c37190f5a40cbecb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/arena.dart","hash":"04f3f5a6ad35c823aef3b3033dc66c3c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Academy_unselected.svg","hash":"1dd3756cbc8b5a94ddcb9057a1ddf364"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart","hash":"6d0b38802aff8cbe310e72f1a62750d6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/paint.dart","hash":"340ffd6b17fc593e08d99aece89e600d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart","hash":"9ea1746a0f17f049b99a29f2f74e62ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart","hash":"f6c6b31745eec54a45d25ffe6e5d7816"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart","hash":"36fc598c656490ab430ca1be5fb909e8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart","hash":"a93ae192d60f10b56cf1659d2123bc95"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/types.dart","hash":"4a9817f509bb8eb7192a89fa9aa015dc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/normalizer.dart","hash":"8bd96caadcaefb063cca0c83d7707a57"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/string.dart","hash":"1aaa0309ba77b0f57733e99543c455ea"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart","hash":"38fcdd2be2a4d0ecbbe01cc03cd03e96"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/and.dart","hash":"1e9ed9cdf00b9449d9b72dcd00add4d3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/entity_mapping.dart","hash":"5abb58e10e8ea85ea5990a97ee20ae4e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_path_ops_ffi.dart","hash":"41a453ca5b911d0322a4cb525f53a92a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/platform_interface/image_picker_platform.dart","hash":"304510c80e4af2a9a60fda4d9efaa8eb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/lib/image_picker_macos.dart","hash":"016db765422b67025aa356222c67d610"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart","hash":"a74b5a39115ffd608a19cad9309e6a31"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart","hash":"838c8a1a376a7c9c3fb3424927bcc75e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart","hash":"4eede9144b4c0e4b14bd426654183174"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any_of.dart","hash":"853db49f6cc034267b3dffc26052f4aa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart","hash":"c3ccb5b6cd3df44e6587a4f04dd6a4e7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart","hash":"d2372e0fb5a584dcd1304d52e64d3f17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart","hash":"e4a32acbcd5da5e636d429dc167fc5f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart","hash":"e6467427260f3274e8424d691615ca5c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart","hash":"b39287c180e3ac3047fc5dba3a44a524"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart","hash":"47ccb32c843b4075a001e612853b2a31"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart","hash":"bf50f61746b9744a0e2d45a88815288f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart","hash":"9f5e8439ef3cbfa84f76922ec3580363"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/string.dart","hash":"a1f47bfa90f0153386bbcd0c4b16e09c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart","hash":"632d3c730c9b6e4f46d9c0459c53ca9c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart","hash":"58678829e383937c51f539f2ad67fc17"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart","hash":"5aa51467523e637443dec44f6c7b1e6c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart","hash":"1adcc56e3affffb23739c7c9d8a5fca0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart","hash":"a2350d9426fefa6d657868d9e59eac7b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart","hash":"9434ff8aa06e13d5981ed6ec15eceb64"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart","hash":"87f0b72f24e05d2d3f4b0f1b4709eb51"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart","hash":"3ee6304161ca2993b303a8074557fe66"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE","hash":"39062f759b587cf2d49199959513204a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/method_channel/method_channel_image_picker.dart","hash":"0dd542b84d1bdffac36624b0e9207d90"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart","hash":"2d2cd1fbe11b3e587475449fa04ad4eb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart","hash":"85814d14dae3bc1d159edd0a4bef48e4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material.dart","hash":"5c93305f52983c3f2be825bf54ebbd78"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/unbounded.dart","hash":"a617a91b12a3156406da1d95552aa4a0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart","hash":"89aeee125822690cbd46b2ff43c76ec1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/annotator.dart","hash":"d45b4bb922c2941476a8b797e0e275ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart","hash":"5d8e29422039d9dcce6908b427814d80"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart","hash":"cad4582fa75bf25d887c787f8bb92d04"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2026.jpg","hash":"c1da37a2c4aa0902d24a0325e5014df5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart","hash":"900a13c9fcd73f4e8e3d069d76af6ffa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart","hash":"b1bb8356cca8b86afca314ab4898a527"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterator.dart","hash":"dd8517aec9099740b2b5828bde8d33aa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_server.dart","hash":"8580846ee9612281791cc377a99d0581"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Mypage_selected.svg","hash":"4081b7b651f16b9421f4eef92cd8f69c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_selected.svg","hash":"4081b7b651f16b9421f4eef92cd8f69c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart","hash":"5692636576c4bec471fd3a1275f08525"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/declaration.dart","hash":"3cf7786074ce9f1e148fe5f4a60479d2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/parser.dart","hash":"bb70d2e76c8609b7a22250037d9185f0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_form_page.dart","hash":"bef836fed3414eb345f753bc8a109eee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/base.dart","hash":"86039b13313ad468f867bb5522411241"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart","hash":"67d16e841606c4e5355211fe15a2dbfd"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart","hash":"c8f69577793923bfda707dcbb48a08b1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/helpers.dart","hash":"25feac2cd9c96cc475403e601757cdaa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_details.dart","hash":"7c5b14805d686129e90293ef086d4d68"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart","hash":"3431f50e7abf9e27af232de10193931a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart","hash":"11fc97acd20679368ae2eaa698c6f130"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart","hash":"151d12284cf607a6e984aa31fe766faa"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart","hash":"74939c971de1eb61ef05a7eb5056cc20"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/labeled.dart","hash":"715bccb8e9ba9889573a60bf0e457402"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notifications_manager.dart","hash":"ce45b60ad9b0d7c8690b9b1fae2b7f6d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart","hash":"a3bdbf775c61477db47c508f513688e4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart","hash":"b80f25d51570eededff370f0c2b94c38"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart","hash":"075310a7fe661b71e9a583aab7ed4869"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/type_exception.dart","hash":"d39becdaf9cc42e3efd0c9cdf0034ac4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart","hash":"c069ad8b31e18adb75c27530f218957a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart","hash":"787093e38fffbbd356129a373907124c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart","hash":"b78c67723942ac5480c158576c1247e3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart","hash":"62f852a5f85345e608cdc7b62a689202"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart","hash":"fe2489ea57393e2508d17e99b05f9c99"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart","hash":"62d88517fa4f29f5f3bcec07ba6e1b62"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_sound.dart","hash":"c0d5d7856094b4be15b738392704b921"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart","hash":"484481ff93d08a930ecfcf6907acf691"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector.dart","hash":"e8911b74c8d90dfc01657354e57d0fb1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart","hash":"8e286948f2eaa63514196c1e4c91666c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart","hash":"d72a4ddaf6162d8b897954e02b4a2a4c"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart","hash":"0ae47d8943764c9c7d362c57d6227526"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart","hash":"63db75c602690371aef0f83279a929d7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/curves.dart","hash":"4aeb4635d84df42e6f220aba366af7d9"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/notification/notification_page.dart","hash":"42c46888feebad74a4368c9b0b74eef6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/result.dart","hash":"6782f277d348804f26f7a748f647695a"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z","hash":"cd73c76aa70c71429eeee003d0a60286"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart","hash":"db799bf48af97b7c0edc93ad96b4a6da"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart","hash":"ee36aadc3fac54d5659c94c6aadcd007"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/LICENSE","hash":"46158b74167f78e44896e35a92c7c5e0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart","hash":"34ebb85f7f2122d2e1265626cf252781"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_unselected.svg","hash":"92f7f8888a8a844a4f1fa497cbe2decd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart","hash":"dbf4f1e95289bc83e42f6b35d9f19ebe"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart","hash":"0cf4e80f9e0fbdba47f42fef07fd5499"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart","hash":"dd510cd97dc23d22aebc7b60affd6329"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart","hash":"eb9b3bf513b18ddaf0057f3877439d9b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart","hash":"dcef90946d14527736cde04a54d334db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/lib/image_picker.dart","hash":"327c288f80ee09130d794ef74a733699"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart","hash":"42212bb3508502e1b011bd783d51ea78"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_parent.dart","hash":"7f47dda6ed10e33236d465680dc8c12b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart","hash":"6987c3474a94dd1c4ff8f8540212f16b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart","hash":"5265b4bdec5c90bfd2937f140f3ba8fc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart","hash":"8d0306ecedceab52f23b17a0694e7842"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart","hash":"a2aa815908f2e15493e374b9380e558a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/utilities.dart","hash":"9b478f27df3e7bd44722deb3c1c69ca3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart","hash":"101ff6d49da9d3040faf0722153efee7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart","hash":"78ce7527fa364df47ba0e611f4531c2c"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/chapter_detail_page.dart","hash":"17d725129f3d2750746304e3534ec124"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notification_info.dart","hash":"5f02ac3087f8d081f489730eecb97f70"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart","hash":"377fef989628d5fbcb306e46a03b7a12"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart","hash":"fe750f835c7dc27ef38ee2fdb486a6ee"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart","hash":"d390b15ecef4289db88a4545e359bc8a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart","hash":"816a5cf300a6461fe2e7e8ca8a66a709"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/mappers.dart","hash":"27bd31140f6d692c98f0cc901a7d77a1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/lost_data.dart","hash":"f63f9b37983c0ce9736806a60038a055"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/.DS_Store","hash":"f1090a7e0712544a5401a7311bfb9e6d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/end_element.dart","hash":"813218451c1d8dd310e1233bd4ca7a4a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/firebase_core.dart","hash":"e80d9a4901b1381733c442e0cc05a708"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/frustum.dart","hash":"c19a7119c5f0f19f3d0f4531c5345616"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/attribute_type.dart","hash":"a9d570114e5a6e733fb029f6b3cffad7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_9.dart","hash":"e20355dd45521a6de91669be6cbfb3a3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_options.dart","hash":"df28ae2c4812ff5a3e9f41ca219b92ee"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics.dart","hash":"671b26ea03821b4c63c0fe2fd64f9e87"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart","hash":"b2015570257a2a6579f231937e7dea0e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2024.jpg","hash":"bac3e7ec19ff9a3512b243743484c706"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/lib/xdg_directories.dart","hash":"737107f1a98a5ff745dd4e3236c5bb7b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_delegate.dart","hash":"f92c294999d700b8a78f8b1d5cd3cc2e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart","hash":"f8275b74f8f83272b8a8d1a79d5b2253"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_selected.svg","hash":"b68b6a15add7b6220fd62524a90fee5b"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/file_selector_windows.dart","hash":"0902c41eed709a7841f11130fac2a593"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart","hash":"4e04af41f89adf9231bad1579f5bb9a1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart","hash":"77e3a9ed54e0497465a4346f273bcccf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart","hash":"8dea906a9b8773920b6d1ccea59807bf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart","hash":"97c7266e528b6f706b08b4ad340006d2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/flutter_local_notifications_platform_interface.dart","hash":"64aba6b07ccfb43755f1c29955134b53"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart","hash":"200da5ba0b0cee2bca1acd1c4d772118"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/LICENSE","hash":"2b36ca50262dc615e560c27654badb26"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/enums.dart","hash":"523742c594766cc9e39179d93cb23259"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart","hash":"4c09fb1ea4651f47d1a0a67ba3b31886"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart","hash":"4c13b34211e2b17645a6a5cd8defbe0d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart","hash":"04451542afc67a74282bd56d7ee454f5"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/services/fcm_service.dart","hash":"dd1dc8abdd29f9af05b64d09ec827863"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_writer.dart","hash":"c932575d5afb22daa2456a44889b3cdb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/limited.dart","hash":"aa439be89f7997c3c5949ce32d2486bf"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/method_channel_mappers.dart","hash":"5d0fb3d359f4af000209c65b873ae97f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/LICENSE","hash":"038c3f869f408e1194eda71cafcca6f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/painting.dart","hash":"4bd60bd8ede4b9dad954493d26d3e586"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart","hash":"43ba7557388f413902313df64e072389"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/triangle.dart","hash":"d9eedadb461aac1eebde731afb42a2d1"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/picked_file.dart","hash":"4923864c67868dd1f3a8d7be3e4ca0f8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_picture_style_information.dart","hash":"5f8bbfd23974ae2842d3d03760b98f99"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/subtree_selector.dart","hash":"ef93f78a8a380eeade385040b1d075c7"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE","hash":"d53c45c14285d5ae1612c4146c90050b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","hash":"b93248a553f9e8bc17f1065929d5934b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart","hash":"b4ab536e0cb6945296bb962bc1e9a3f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/services.dart","hash":"29ae1507a6ec4c2ffae469a10e505bda"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart","hash":"cccaa1a390453623404ad2f98ba719c9"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/LICENSE","hash":"a60894397335535eb10b54e2fff9f265"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/initialization_settings.dart","hash":"dc69aa43b73c7a61a7d20c82ac98cc36"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/predicate.dart","hash":"5cae30214f9509b4b47641f1d38b7fef"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase.dart","hash":"5ac6d992f5cbebe5e5d4e8bc4ed5ae6a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart","hash":"32f33f52f1a1e1b0911dbbfa4dd7785a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart","hash":"168bedc5b96bb6fea46c5b5aa43addd1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart","hash":"14acfddcb9e62f0de6f82d28e22c22f0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/cache.dart","hash":"e0cbefa359309715e5101bce98eb65e2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart","hash":"2d18e0064b57f514fab5c3abc06ace0e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart","hash":"cd3f0ebbc282b839928f5fe3ad12c779"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart","hash":"b16458199371a46aeb93979e747962a3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/word.dart","hash":"27756cabcc328c2f7ae9e353b339d89a"},{"path":"/Users/downy/flutter/packages/flutter/lib/scheduler.dart","hash":"95d8d1f6a859205f5203384e2d38173a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart","hash":"29439c1f30cb2958458664e1e6e40289"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart","hash":"51fa10cf30bde630913ff4c6e40723ba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart","hash":"31d8245447d51dba20c81f00b214fb36"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/none_of.dart","hash":"9f69b819f3943f691b452d84d4cdb609"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart","hash":"c6da76a71962267cab91aadde5b59426"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag","hash":"6cd606d3e368485de4ee213b4887f8a0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/bottom_navigation_widget.dart","hash":"8067f607e74fd60a539ff359b14395a3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/conversion_sink.dart","hash":"efcbc6fd4212ea81281561abddbf29f9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart","hash":"f7b9c7a2d1589badb0b796029090d0d5"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart","hash":"df699735e3bcd730f16ce377d562f787"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Home_selected.svg","hash":"f78d02a831d5135b07c39aaadc50bfca"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart","hash":"bfb39b98783e4013d9fe5006de40874d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart","hash":"5275d424aba5c931a30e6bd3e467027d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/sequence.dart","hash":"061e3925eb77146a83903821d09bbd58"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart","hash":"984acd55714db5ebfdcab5aeb55467fa"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart","hash":"81d01d8cecc6783526e350800988db74"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart","hash":"18ad2d48b68dc9b514fde418b7acb599"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart","hash":"cb0d5b80330326e301ab4d49952b2f34"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart","hash":"f01b78dd243cdceae98d62e7429f3d04"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/interop_shimmer.dart","hash":"b6d804ca88cfe7ef727b6da2d7c35b30"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart","hash":"40587a28640d3c90ad2e52fdfbcd7520"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/pick.dart","hash":"c60b204fb5e7d501c0addb330c88d2de"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/continuation.dart","hash":"95adecf7ec0db3c154665406582e0513"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart","hash":"15439eaa12b927b0e9a42b9d168e3371"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart","hash":"9eb1b00e42fadb0be56354c8bc9feb4c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart","hash":"f12f9a9b8bb504f4617bfd1c00d403f0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart","hash":"f301af2d0392296f456363085becbf47"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase.dart","hash":"1c59332e69e34c4a84aa48efd657f103"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/theme.dart","hash":"88718f823c0de3f8398075d24b150ecf"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart","hash":"8fa0c1ec158277156da896110a03d968"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/src/messages.g.dart","hash":"e44269ac2e84082ce2d4d67a1ceae2d2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart","hash":"a0936682931bc884c5052e9f49bf8829"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart","hash":"aad5ba4c4076b74ded1d769dc1edbceb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/x_file.dart","hash":"d06c42e6c83be207b86412e11889266a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/badge.dart","hash":"134441e2b4b42a7b2ee012ce48910557"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/LICENSE","hash":"b776a584ba475b946d8e76f1e42585f4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart","hash":"f179ed2f20226c436293849c724b2c4d"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/io.dart","hash":"a45632c7d0440400b3f7a2ce615d21c0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_100to100.png","hash":"454be3ff72282ffa8fe50f8f3e44658b"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/AppFrameworkInfo.plist","hash":"3e84ffd77b8e1d46de0dec59f05dfec4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/whitespace.dart","hash":"57a5a9f535e7c37d09bab9aca685dfd2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart","hash":"063f2360bd47faba2c178ce7da715d92"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart","hash":"e76d7da2d8f4281119d176fdcc04b991"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart","hash":"b7b71e22b53d4d100702d2ba7a7130db"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/converter.dart","hash":"affb97b6cbd84919fa30ea3bcd5f12df"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart","hash":"5b04f80518a8417cb87a0aec07dacf4f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_object_selection.dart","hash":"dd006282a4ae0bc84d10206ea7441925"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart","hash":"dc196a3f1d514347c5f7da6e197b384d"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart","hash":"393c6d8b9c1a038b62a418fadf8c69c9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart","hash":"5b98d0be4d89f1274c832a4c340ab315"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart","hash":"af709d56567f1923ade761542e8dd796"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart","hash":"600a92f02eb307032e6cedc6c5f104f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart","hash":"f49291d1bc73b109df4c162db10003d2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart","hash":"6c0e97a3b04c9819fe935659014f92e8"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/edit_grading_result_page.dart","hash":"cbfa4a17211b74bffa1e9924389d0111"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/exception.dart","hash":"773da8c184ab316ec6998980a1448a1c"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector3.dart","hash":"1dd695066bccfccf510bb80b2b137ad0"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/file.dart","hash":"cf3d93bae83850abf2c5e943a6b1ccbc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart","hash":"1fc94d5523beb1dda68dd704b8f99bd8"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart","hash":"53b9028402187f878713225b48bdd5bb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/character.dart","hash":"091e29d23c58b7a4b5529953044bd344"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/html_render_vector_graphics.dart","hash":"2ac99a26ca075c8cd9f8f7ffb741f3ad"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart","hash":"f60846aa76dab98607aa06c9bd6cf1dd"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart","hash":"43268fa3ac45f3c527c72fc3822b9cb2"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/native_assets.json","hash":"f3a664e105b4f792c6c7fe4e4d22c398"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/radio.dart","hash":"1e0f99d28825c416ceb5f264b6af7fdc"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/pattern.dart","hash":"984f27f723ba52ab371439e37b31ca91"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/token.dart","hash":"710a4fd96b6281c1ab359ea6df4ceee8"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart","hash":"fa2a57b3b873fb7db4b8b961735e4ca3"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart","hash":"e4da90bb20b3980a03665a080c87a098"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart","hash":"21e56afda1f096f0425a34987708ed56"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart","hash":"0976264b99a1702a5d74e9acb841b775"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/util.dart","hash":"d66f7ff750a1747331f6a8eff5de618f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart","hash":"6a9dc1f0e0e14fc0ef5efb4c3c1e8a77"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart","hash":"5be90cbe4bbf72b0264413e4ccb5c275"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart","hash":"a64e270c19c9e9ed0c5d9a17e0c4a5d0"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/social_login/Button_Kakao.png","hash":"7e3eb90819c0f6ef186ee3d8835b5bb3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/matrix.dart","hash":"d431d7f75c308e2c52c9f02a3872c677"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_selection_type.dart","hash":"edc1b7a42a3cbf8c27d6952381902b71"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart","hash":"04c960ae6d770135bb0b6acf14b134a4"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart","hash":"622fb5559ef551a734f0ebae8660485e"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart","hash":"8986177ba204a808c603c35260601cce"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart","hash":"1d8fa1cee64f2d791002749fabe23e2e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart","hash":"625b4ed63675ca8ffe8c11d0469bdd9f"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart","hash":"547eac441130505674f44bf786aee606"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE","hash":"3c68a7c20b2296875f67e431093dd99e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart","hash":"617fb0bcef7162a860ca76636507117f"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lookup.dart","hash":"f2698cdf4b07ce88e4996e23f26cd0da"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/svg.dart","hash":"31f93c7db16a50136e8ce4042de7169a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_decoder.dart","hash":"3d7fed590b9d1ab99d591b04487b9287"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/LICENSE","hash":"2b36ca50262dc615e560c27654badb26"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/src/messages.g.dart","hash":"5b5f54337e36aedd16b5409efa8a5aec"},{"path":"/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","hash":"0864ad73108959b573b007ab6025d731"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart","hash":"83fc222e671ddaa7fdb3868c0acaba0a"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart","hash":"d828c4334e98a12974d90e38d48db9f2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart","hash":"aaf8cbac74b7b5a3a487d5ddfc2bcdbc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart","hash":"d67712d7f3394870d88650dc0baf5855"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart","hash":"73f043194b9c158454e55b3cafbdb395"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart","hash":"a1e4de51bdb32e327bf559008433ab46"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart","hash":"2a08c219491feeb1c8e9b9d492ffce44"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page.dart","hash":"ce65d8fe10d5c94741dda20b41546ecb"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/message.dart","hash":"fe4f36f2c139e1900dbda797a7e07fc9"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart","hash":"cd6b036d4e6b746161846a50d182c0b5"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_LightSsen.png","hash":"5ae53d61eeb9909a8c892ca39defd1f5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart","hash":"a36981329a77de46168efd089c4102e2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart","hash":"bf365ded028510087ed69c227bda0d52"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_device.dart","hash":"58c3d0c10ca3f530bab03bd5c0b43c72"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/cdata.dart","hash":"008d33cc2aea11e7921ee238469947b2"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart","hash":"38570a2af41c2f9a4632e2af3b42ffe7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart","hash":"2b2a74f1e45f48fed04eab35ae3c85d7"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart","hash":"7cbeab73e95bd7561ac8b9519c579ffb"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart","hash":"8cff8c004f57019314d3fe8176de4043"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_terms_page.dart","hash":"f68301976a35bbbfe4ef761c339268b6"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart","hash":"13c9680b76d03cbd8c23463259d8deb1"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart","hash":"56a764067b45a1a7cb6b7f186f54e43a"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parsers.dart","hash":"377b2ee79e4a825356b695b7b6f017dc"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart","hash":"dd518cb667f5a97b3456d53571512bba"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart","hash":"b15a3573191a80dfb78fd6a729390c0e"},{"path":"/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf","hash":"e7069dfd19b331be16bed984668fe080"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart","hash":"9011b30a404dec657806a780b55d0610"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/LICENSE","hash":"96ed4c0b2ac486bba3db2c5d2a96afc4"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_match.dart","hash":"d742d41268dec3da5e669142ae344928"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart","hash":"9d273d5a3c1851b0313cd949e7f84355"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/helpers.dart","hash":"dad9796d04d76633de091aec36be71c2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart","hash":"c83781cf0c38883486f707cddbb96773"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart","hash":"374ee130942948f52e47681818bd315e"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart","hash":"5c9195780e56985cc88956aab0887ab3"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart","hash":"25dd0d36ba8109e3199faf508b41d633"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/char.dart","hash":"7a6d53ccbed48dd524627ee1a945ac15"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf","hash":"b93248a553f9e8bc17f1065929d5934b"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/switch.dart","hash":"721c2d087f423a3293f5314804ae66a5"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart","hash":"0d8aed1407088c73788f25ffba071cc2"},{"path":"/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object.dart","hash":"4f187fc37cb2a7eedf4681e2321792f0"},{"path":"/Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart","hash":"49f335e51e1a6242ba8ab55b48de9d92"}]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/App.framework/App b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/App.framework/App new file mode 100755 index 0000000..697eaf1 Binary files /dev/null and b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/App.framework/App differ diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/IssueLaunchRootViewControllerAccess.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/IssueLaunchRootViewControllerAccess.stamp new file mode 100644 index 0000000..5cba3c0 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/IssueLaunchRootViewControllerAccess.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart","/Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/AppDelegate.swift"],"outputs":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/app.dill b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/app.dill new file mode 100644 index 0000000..72bb8d8 Binary files /dev/null and b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/app.dill differ diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build.d b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build.d new file mode 100644 index 0000000..1b4ff05 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build_result.json: \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build.stamp new file mode 100644 index 0000000..b19c332 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build_result.json","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build_result.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build_result.json b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build_result.json new file mode 100644 index 0000000..0d218ca --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/dart_build_result.json @@ -0,0 +1 @@ +{"dependencies":[],"code_assets":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_ios_bundle_flutter_assets.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_ios_bundle_flutter_assets.stamp new file mode 100644 index 0000000..ae042fe --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_ios_bundle_flutter_assets.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/app.dill","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/App.framework/App","/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/tools/shader_compiler.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml","/Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/Info.plist","/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/AppFrameworkInfo.plist","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/.DS_Store","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_all.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_workbook.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2026.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_Blacklabel.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2024.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2025.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_100to100.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_LightSsen.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Google.png","/Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Kakao.png","/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf","/Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf","/Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/native_assets.json","/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/args-2.7.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_web-2.24.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.10.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.32/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_for_web-3.1.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/mime-2.0.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/LICENSE","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/LICENSE","/Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE","/Users/downy/flutter/packages/flutter/LICENSE","/Users/downy/Documents/Gradi_25Fall/frontend/DOES_NOT_EXIST_RERUN_FOR_WILDCARD47272210"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/vm_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/isolate_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/kernel_blob.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/App","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/Info.plist","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/.DS_Store","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/bottom_nav_all.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Academy_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/nav_workbook.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Upload_image_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Mypage_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Alarm_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Upload_image_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Alarm_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Textbook_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Textbook_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Mypage_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Home_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/bottom_nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Academy_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Home_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2026.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_Blacklabel.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2024.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2025.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_100to100.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_LightSsen.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/social_login/Button_Google.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/social_login/Button_Kakao.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_ios_lldb_init.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_ios_lldb_init.stamp new file mode 100644 index 0000000..5100359 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_ios_lldb_init.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/darwin.dart"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/ephemeral/flutter_lldbinit"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_universal_framework.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_universal_framework.stamp new file mode 100644 index 0000000..78a7c89 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_universal_framework.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/App.framework/App"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_unpack_ios.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_unpack_ios.stamp new file mode 100644 index 0000000..a6e77ca --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/debug_unpack_ios.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/ios.dart","/Users/downy/flutter/bin/cache/engine.stamp"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/flutter_assets.d b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/flutter_assets.d new file mode 100644 index 0000000..b859bf3 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/flutter_assets.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/.DS_Store /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/bottom_nav_all.png /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Academy_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/nav_workbook.png /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Upload_image_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Mypage_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Alarm_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Upload_image_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Alarm_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Textbook_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Textbook_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Mypage_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Home_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/bottom_nav_home.png /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/nav_home.png /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Academy_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Home_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2026.jpg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_Blacklabel.png /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2024.jpg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2025.jpg /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_100to100.png /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_LightSsen.png /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/social_login/Button_Google.png /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/social_login/Button_Kakao.png /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.json /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z /Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json: /Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml /Users/downy/Documents/Gradi_25Fall/frontend/ios/Runner/Info.plist /Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/AppFrameworkInfo.plist /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/.DS_Store /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_all.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_workbook.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Upload_image_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Alarm_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Textbook_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Mypage_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/bottom_nav_home.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/nav_home.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Academy_selected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/icons/Home_unselected.svg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2026.jpg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_Blacklabel.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2024.jpg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/workbook_2025.jpg /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_100to100.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/bookcovers/BookCover_LightSsen.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Google.png /Users/downy/Documents/Gradi_25Fall/frontend/assets/images/social_login/Button_Kakao.png /Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf /Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf /Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/native_assets.json /Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/args-2.7.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_web-2.24.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.10.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.32/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_for_web-3.1.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/mime-2.0.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/LICENSE /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/LICENSE /Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE /Users/downy/flutter/packages/flutter/LICENSE /Users/downy/Documents/Gradi_25Fall/frontend/DOES_NOT_EXIST_RERUN_FOR_WILDCARD47272210 \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/gen_dart_plugin_registrant.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/gen_dart_plugin_registrant.stamp new file mode 100644 index 0000000..9b77114 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/gen_dart_plugin_registrant.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/gen_localizations.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/gen_localizations.stamp new file mode 100644 index 0000000..1b2d28c --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/gen_localizations.stamp @@ -0,0 +1 @@ +{"inputs":[],"outputs":[]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/install_code_assets.d b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/install_code_assets.d new file mode 100644 index 0000000..6c9cf0f --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/install_code_assets.d @@ -0,0 +1 @@ + /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/native_assets.json: \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/install_code_assets.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/install_code_assets.stamp new file mode 100644 index 0000000..c38a632 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/install_code_assets.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/native_assets.json","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/native_assets.json"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/kernel_snapshot_program.d b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/kernel_snapshot_program.d new file mode 100644 index 0000000..43a1ad2 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/kernel_snapshot_program.d @@ -0,0 +1 @@ +/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/app.dill: /Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/_flutterfire_internals.dart /Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/interop_shimmer.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/clock.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/clock.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/default.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/stopwatch.dart /Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/cross_file.dart /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/base.dart /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/io.dart /Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/x_file.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/dbus.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_address.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_client.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_server.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_bus_name.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_client.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_error_name.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_interface_name.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspect.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspectable.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_match_rule.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_member_name.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_message.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_call.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_response.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_manager.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_tree.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_peer.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_properties.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_read_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object_manager.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_server.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_signal.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_uuid.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_value.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_write_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid_windows.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid.dart /Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/ffi.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/allocation.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/arena.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf16.dart /Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf8.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/file_selector_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/src/messages.g.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/file_selector_macos.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/src/messages.g.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/file_selector_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/method_channel/method_channel_file_selector.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/platform_interface/file_selector_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_dialog_options.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_save_location.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/types.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/x_type_group.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/file_selector_windows.dart /Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/src/messages.g.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/firebase_core.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase_app.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/port_mapping.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/firebase_core_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_options.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase_app.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_app.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_plugin.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_core_exceptions.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/pigeon/messages.pigeon.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/firebase_messaging.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/src/messaging.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/firebase_messaging_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/method_channel_messaging.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/utils/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/notification_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/platform_interface/platform_interface_messaging.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_message.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_notification.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/types.dart /Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/utils.dart /Users/downy/flutter/packages/flutter/lib/animation.dart /Users/downy/flutter/packages/flutter/lib/cupertino.dart /Users/downy/flutter/packages/flutter/lib/foundation.dart /Users/downy/flutter/packages/flutter/lib/gestures.dart /Users/downy/flutter/packages/flutter/lib/material.dart /Users/downy/flutter/packages/flutter/lib/painting.dart /Users/downy/flutter/packages/flutter/lib/physics.dart /Users/downy/flutter/packages/flutter/lib/rendering.dart /Users/downy/flutter/packages/flutter/lib/scheduler.dart /Users/downy/flutter/packages/flutter/lib/semantics.dart /Users/downy/flutter/packages/flutter/lib/services.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart /Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart /Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart /Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart /Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart /Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart /Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart /Users/downy/flutter/packages/flutter/lib/src/dart_plugin_registrant.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart /Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart /Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart /Users/downy/flutter/packages/flutter/lib/src/material/about.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart /Users/downy/flutter/packages/flutter/lib/src/material/app.dart /Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/arc.dart /Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart /Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/badge.dart /Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/banner.dart /Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart /Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/button.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/card.dart /Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart /Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart /Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart /Users/downy/flutter/packages/flutter/lib/src/material/colors.dart /Users/downy/flutter/packages/flutter/lib/src/material/constants.dart /Users/downy/flutter/packages/flutter/lib/src/material/curves.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart /Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/date.dart /Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/debug.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart /Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/divider.dart /Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart /Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart /Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/icons.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart /Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart /Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/material/material.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart /Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart /Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart /Users/downy/flutter/packages/flutter/lib/src/material/motion.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart /Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart /Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/page.dart /Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart /Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart /Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart /Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart /Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart /Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart /Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart /Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart /Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/search.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart /Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart /Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart /Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart /Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart /Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart /Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart /Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/material/time.dart /Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart /Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart /Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart /Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart /Users/downy/flutter/packages/flutter/lib/src/material/typography.dart /Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart /Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart /Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart /Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart /Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart /Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart /Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart /Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart /Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart /Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart /Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart /Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart /Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart /Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart /Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart /Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart /Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart /Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart /Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart /Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart /Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart /Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart /Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart /Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart /Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart /Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart /Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart /Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart /Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart /Users/downy/flutter/packages/flutter/lib/src/services/binding.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart /Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart /Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart /Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart /Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart /Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart /Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart /Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart /Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/debug.dart /Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart /Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart /Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart /Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart /Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart /Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart /Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart /Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart /Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart /Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart /Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart /Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart /Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart /Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart /Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart /Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart /Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart /Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart /Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart /Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart /Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart /Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart /Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart /Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart /Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart /Users/downy/flutter/packages/flutter/lib/widgets.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/flutter_local_notifications.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/callback_dispatcher.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/flutter_local_notifications_plugin.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/initialization_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/notification_details.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_flutter_local_notifications.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/bitmap.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/enums.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/icon.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/initialization_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/message.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/method_channel_mappers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel_group.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_details.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_sound.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/person.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/schedule_mode.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_picture_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_text_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/default_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/inbox_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/media_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/messaging_style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/style_information.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/initialization_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/interruption_level.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/mappers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action_option.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_attachment.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category_option.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_details.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_enabled_options.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/ios/enums.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/typedefs.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/types.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/tz_datetime_mapper.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/flutter_local_notifications_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/dbus_wrapper.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/file_system.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications_platform_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/capabilities.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/enums.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/hint.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/icon.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/initialization_settings.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/location.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/notification_details.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/sound.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/timeout.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notification_info.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notifications_manager.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/platform_info.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/posix.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/storage.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/flutter_local_notifications_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/typedefs.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/types.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/flutter_svg.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/cache.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/default_theme.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/loaders.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/_file_io.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/compute.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/file.dart /Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/svg.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart /Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart /Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/lib/image_picker.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/image_picker_android.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/src/messages.g.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/image_picker_ios.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/src/messages.g.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/lib/image_picker_linux.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/lib/image_picker_macos.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/image_picker_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/method_channel/method_channel_image_picker.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/platform_interface/image_picker_platform.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_delegate.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_device.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_options.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_source.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/lost_data_response.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_options.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_selection_type.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_image_picker_options.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_video_picker_options.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/base.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/io.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/lost_data.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/picked_file.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/retrieve_type.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/types.dart /Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/lib/image_picker_windows.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart /Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart /Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/path_parsing.dart /Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_parsing.dart /Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_segment_type.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/core.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/definition.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/expression.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/matcher.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/parser.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/petitparser.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/context.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/parser.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/result.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/token.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/grammar.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/reference.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/undefined.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/reference.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/resolve.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/builder.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/group.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/result.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/accept.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterator.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_match.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterator.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast_list.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/continuation.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/flatten.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/map.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/permute.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/pick.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/token.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/trim.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/where.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any_of.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/char.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/digit.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/letter.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/lowercase.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/none_of.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/char.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/constant.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/digit.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/letter.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lookup.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lowercase.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/not.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/range.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/uppercase.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/whitespace.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/word.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/range.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/uppercase.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/code.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/optimize.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/whitespace.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/word.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/and.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/choice.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/delegate.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_2.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_3.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_4.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_5.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_6.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_7.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_8.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_9.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/list.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/not.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/optional.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/sequence.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/settable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/skip.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/end.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/epsilon.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/failure.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/label.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/newline.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/position.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/character.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/converter.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/predicate.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/single_character.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/string.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/unicode_character.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/character.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/greedy.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/lazy.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/limited.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/possessive.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/repeating.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/separated.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/unbounded.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/failure_joiner.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/labeled.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/resolvable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/separated_list.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/sequential.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/reflection/iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/pragma.dart /Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/types.dart /Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/lib/plugin_platform_interface.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart /Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart /Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart /Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/date_time.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/env.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/exceptions.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location_database.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/tzdb.dart /Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/timezone.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart /Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/_debug_io.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/debug.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/html_render_vector_graphics.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/listener.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/loader.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_object_selection.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_vector_graphic.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/vector_graphics.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics_compat.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/src/fp16.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/vector_graphics_codec.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_path_ops_io.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_tessellator_io.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/draw_command_builder.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/basic_types.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/image.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/matrix.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/path.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/pattern.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/vertices.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/image/image_info.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/paint.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_path_ops_ffi.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_tessellator_ffi.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/visitor.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/clipping_optimizer.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/color_mapper.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/masking_optimizer.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/node.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/numbers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/overdraw_optimizer.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parser.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parsers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/path_ops.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/resolver.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/tessellator.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/theme.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/util.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/vector_instructions.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/vector_graphics_compiler.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/frustum.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/intersection_result.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix4.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/noise.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/obb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/plane.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quad.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quaternion.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/ray.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/sphere.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/triangle.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector4.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/error_helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/opengl.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/utilities.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart /Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart /Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/lib/xdg_directories.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/builder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/dtd/external_id.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/default_mapping.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/entity_mapping.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/named_entities.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/null_mapping.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/attribute_type.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/node_type.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/format_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parent_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parser_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/tag_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/type_exception.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/ancestors.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/comparison.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/descendants.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/find.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/following.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/mutator.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/nodes.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/parent.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/preceding.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/sibling.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/string.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_attributes.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_children.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_name.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_parent.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_value.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_visitor.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_writer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/attribute.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/cdata.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/comment.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/data.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/declaration.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/doctype.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document_fragment.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/element.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/node.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/processing.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/text.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/cache.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/character_data_parser.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name_matcher.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/namespace.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/node_list.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/predicate.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/prefix_name.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/simple_name.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/token.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/normalizer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/visitor.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/pretty_writer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/writer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/annotator.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_buffer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_location.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_parent.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/event_codec.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/node_codec.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_decoder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_encoder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/visitor.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_decoder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_encoder.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/event.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/cdata.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/comment.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/declaration.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/doctype.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/end_element.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/named.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/processing.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/start_element.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/text.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterable.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterator.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/parser.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/each_event.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/flatten.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/normalizer.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/subtree_selector.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/with_parent.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/conversion_sink.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/event_attribute.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/list_converter.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml.dart /Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml_events.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/firebase_options.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_detail_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_list_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_error_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_result_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_verification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_error_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_reset_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_verification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/login_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_form_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_success_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/reset_password_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_success_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_terms_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/continuous_learning_detail_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page_v2.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/main_navigation_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/academy_management_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/account_management_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/display_settings_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/homework_status_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/learning_statistics_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/mypage.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/notification_settings_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/notification/notification_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/edit_grading_result_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/upload_images_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/chapter_detail_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/question_detail_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_detail_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_page.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_menu_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_title.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/bottom_navigation_widget.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget_v2.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart /Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart /Users/downy/Documents/Gradi_25Fall/frontend/lib/services/fcm_service.dart diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/kernel_snapshot_program.stamp b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/kernel_snapshot_program.stamp new file mode 100644 index 0000000..326234d --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/kernel_snapshot_program.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json","/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/common.dart","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/flutter/bin/cache/engine.stamp","/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/_flutterfire_internals.dart","/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/_flutterfire_internals-1.3.59/lib/src/interop_shimmer.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/clock.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/clock.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/default.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/stopwatch.dart","/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/cross_file.dart","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/base.dart","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/types/io.dart","/Users/downy/.pub-cache/hosted/pub.dev/cross_file-0.3.4+2/lib/src/x_file.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/dbus.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_address.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_auth_server.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_bus_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_error_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_interface_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspect.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_introspectable.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_match_rule.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_member_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_message.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_call.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_method_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_manager.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_object_tree.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_peer.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_properties.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_read_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_remote_object_manager.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_server.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_signal.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_uuid.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_value.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/dbus_write_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getsid_windows.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid.dart","/Users/downy/.pub-cache/hosted/pub.dev/dbus-0.7.11/lib/src/getuid_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/ffi.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/allocation.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/arena.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf16.dart","/Users/downy/.pub-cache/hosted/pub.dev/ffi-2.1.4/lib/src/utf8.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/file_selector_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/lib/src/messages.g.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/file_selector_macos.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/lib/src/messages.g.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/file_selector_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/method_channel/method_channel_file_selector.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/platform_interface/file_selector_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_dialog_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/file_save_location.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_platform_interface-2.6.2/lib/src/types/x_type_group.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/file_selector_windows.dart","/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/lib/src/messages.g.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/firebase_core.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/firebase_app.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/lib/src/port_mapping.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/firebase_core_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/method_channel/method_channel_firebase_app.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_app.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/platform_interface/platform_interface_firebase_plugin.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/firebase_core_exceptions.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_platform_interface-6.0.2/lib/src/pigeon/messages.pigeon.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/firebase_messaging.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/lib/src/messaging.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/firebase_messaging_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/method_channel_messaging.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/method_channel/utils/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/notification_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/platform_interface/platform_interface_messaging.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_message.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/remote_notification.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_platform_interface-4.6.10/lib/src/utils.dart","/Users/downy/flutter/packages/flutter/lib/animation.dart","/Users/downy/flutter/packages/flutter/lib/cupertino.dart","/Users/downy/flutter/packages/flutter/lib/foundation.dart","/Users/downy/flutter/packages/flutter/lib/gestures.dart","/Users/downy/flutter/packages/flutter/lib/material.dart","/Users/downy/flutter/packages/flutter/lib/painting.dart","/Users/downy/flutter/packages/flutter/lib/physics.dart","/Users/downy/flutter/packages/flutter/lib/rendering.dart","/Users/downy/flutter/packages/flutter/lib/scheduler.dart","/Users/downy/flutter/packages/flutter/lib/semantics.dart","/Users/downy/flutter/packages/flutter/lib/services.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart","/Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart","/Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart","/Users/downy/flutter/packages/flutter/lib/src/dart_plugin_registrant.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart","/Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart","/Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/about.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/arc.dart","/Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart","/Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/badge.dart","/Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/banner.dart","/Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/card.dart","/Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart","/Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/material/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/material/curves.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart","/Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/divider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart","/Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart","/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/icons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart","/Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart","/Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart","/Users/downy/flutter/packages/flutter/lib/src/material/motion.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart","/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart","/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/page.dart","/Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart","/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart","/Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart","/Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart","/Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart","/Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart","/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart","/Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart","/Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart","/Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart","/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart","/Users/downy/flutter/packages/flutter/lib/src/material/typography.dart","/Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart","/Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart","/Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/services/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart","/Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart","/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart","/Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart","/Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart","/Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart","/Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart","/Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart","/Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart","/Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart","/Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart","/Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart","/Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart","/Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart","/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart","/Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart","/Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart","/Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart","/Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart","/Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart","/Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart","/Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart","/Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart","/Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart","/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart","/Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart","/Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart","/Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart","/Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart","/Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart","/Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart","/Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart","/Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart","/Users/downy/flutter/packages/flutter/lib/widgets.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/flutter_local_notifications.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/callback_dispatcher.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/flutter_local_notifications_plugin.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/initialization_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/notification_details.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_flutter_local_notifications.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/bitmap.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/enums.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/icon.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/initialization_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/message.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/method_channel_mappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_channel_group.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_details.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/notification_sound.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/person.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/schedule_mode.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_picture_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/big_text_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/default_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/inbox_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/media_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/messaging_style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/android/styles/style_information.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/initialization_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/interruption_level.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/mappers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_action_option.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_attachment.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_category_option.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_details.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/darwin/notification_enabled_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/platform_specifics/ios/enums.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/typedefs.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/lib/src/tz_datetime_mapper.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/flutter_local_notifications_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/dbus_wrapper.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/file_system.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/flutter_local_notifications_platform_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/capabilities.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/enums.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/hint.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/icon.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/initialization_settings.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/location.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/notification_details.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/sound.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/model/timeout.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notification_info.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/notifications_manager.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/platform_info.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/posix.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/lib/src/storage.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/flutter_local_notifications_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/typedefs.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_platform_interface-8.0.0/lib/src/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/flutter_svg.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/cache.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/default_theme.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/loaders.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/_file_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/compute.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/src/utilities/file.dart","/Users/downy/.pub-cache/hosted/pub.dev/flutter_svg-2.2.1/lib/svg.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart","/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker-1.2.0/lib/image_picker.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/image_picker_android.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/lib/src/messages.g.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/image_picker_ios.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/lib/src/messages.g.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/lib/image_picker_linux.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/lib/image_picker_macos.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/image_picker_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/method_channel/method_channel_image_picker.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/platform_interface/image_picker_platform.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_delegate.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/camera_device.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/image_source.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/lost_data_response.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/media_selection_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_image_picker_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/multi_video_picker_options.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/base.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/io.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/lost_data.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/picked_file/picked_file.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/retrieve_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_platform_interface-2.11.1/lib/src/types/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/lib/image_picker_windows.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart","/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart","/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/path_parsing.dart","/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_parsing.dart","/Users/downy/.pub-cache/hosted/pub.dev/path_parsing-1.1.0/lib/src/path_segment_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/core.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/definition.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/expression.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/matcher.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/petitparser.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/context.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/result.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/core/token.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/grammar.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/reference.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/internal/undefined.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/reference.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/definition/resolve.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/builder.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/group.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/result.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/expression/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/accept.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/matches/matches_iterator.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_match.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/parser_pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/matcher/pattern/pattern_iterator.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/cast_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/continuation.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/flatten.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/map.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/permute.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/pick.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/token.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/trim.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/action/where.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/any_of.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/char.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/digit.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/letter.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/lowercase.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/none_of.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/char.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/constant.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/digit.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/letter.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lookup.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/lowercase.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/not.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/range.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/uppercase.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/whitespace.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/predicate/word.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/range.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/uppercase.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/code.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/utils/optimize.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/whitespace.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/character/word.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/and.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/choice.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/delegate.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_2.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_3.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_4.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_5.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_6.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_7.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_8.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/generated/sequence_9.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/list.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/not.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/optional.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/sequence.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/settable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/combinator/skip.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/end.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/epsilon.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/failure.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/label.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/newline.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/misc/position.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/character.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/converter.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/predicate.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/single_character.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/string.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/predicate/unicode_character.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/character.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/greedy.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/lazy.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/limited.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/possessive.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/repeating.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/separated.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/repeater/unbounded.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/failure_joiner.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/labeled.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/resolvable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/separated_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/parser/utils/sequential.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/reflection/iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/pragma.dart","/Users/downy/.pub-cache/hosted/pub.dev/petitparser-7.0.1/lib/src/shared/types.dart","/Users/downy/.pub-cache/hosted/pub.dev/plugin_platform_interface-2.1.8/lib/plugin_platform_interface.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart","/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart","/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart","/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/date_time.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/env.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/exceptions.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/location_database.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/src/tzdb.dart","/Users/downy/.pub-cache/hosted/pub.dev/timezone-0.10.1/lib/timezone.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart","/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/_debug_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/debug.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/html_render_vector_graphics.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/listener.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/loader.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_object_selection.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/render_vector_graphic.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/src/vector_graphics.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics-1.1.19/lib/vector_graphics_compat.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/src/fp16.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_codec-1.1.13/lib/vector_graphics_codec.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_path_ops_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/_initialize_tessellator_io.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/draw_command_builder.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/basic_types.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/image.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/matrix.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/path.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/pattern.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/geometry/vertices.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/image/image_info.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/paint.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_path_ops_ffi.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/_tessellator_ffi.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/visitor.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/clipping_optimizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/color_mapper.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/masking_optimizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/node.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/numbers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/overdraw_optimizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/parsers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/path_ops.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/resolver.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/tessellator.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/svg/theme.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/util.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/src/vector_instructions.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_graphics_compiler-1.1.19/lib/vector_graphics_compiler.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/aabb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/frustum.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/intersection_result.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/matrix4.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/noise.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/obb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/plane.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quad.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/quaternion.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/ray.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/sphere.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/triangle.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/vector4.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/error_helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/opengl.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math/utilities.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart","/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart","/Users/downy/.pub-cache/hosted/pub.dev/xdg_directories-1.1.0/lib/xdg_directories.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/builder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/dtd/external_id.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/default_mapping.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/entity_mapping.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/named_entities.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/entities/null_mapping.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/attribute_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/enums/node_type.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/format_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parent_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/parser_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/tag_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/exceptions/type_exception.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/ancestors.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/comparison.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/descendants.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/find.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/following.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/mutator.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/nodes.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/parent.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/preceding.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/sibling.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/extensions/string.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_attributes.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_children.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_parent.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_value.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_visitor.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/mixins/has_writer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/attribute.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/cdata.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/comment.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/data.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/declaration.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/doctype.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/document_fragment.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/element.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/node.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/processing.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/nodes/text.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/cache.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/character_data_parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/name_matcher.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/namespace.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/node_list.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/predicate.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/prefix_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/simple_name.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/utils/token.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/normalizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/visitor.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/pretty_writer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml/visitors/writer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/annotator.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_buffer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_location.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/annotations/has_parent.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/event_codec.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/codec/node_codec.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_decoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/event_encoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/visitor.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_decoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/converters/node_encoder.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/event.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/cdata.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/comment.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/declaration.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/doctype.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/end_element.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/named.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/processing.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/start_element.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/events/text.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterable.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/iterator.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/parser.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/each_event.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/flatten.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/normalizer.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/subtree_selector.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/streams/with_parent.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/conversion_sink.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/event_attribute.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/src/xml_events/utils/list_converter.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml.dart","/Users/downy/.pub-cache/hosted/pub.dev/xml-6.6.1/lib/xml_events.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/firebase_options.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_detail_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_list_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/academy/academy_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_error_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_result_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_id_verification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_error_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_reset_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/account/find_password_verification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/login_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_form_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/password_reset_success_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/reset_password_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_success_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/auth/signup_terms_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/continuous_learning_detail_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/home_page_v2.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/main_navigation_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/academy_management_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/account_management_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/display_settings_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/homework_status_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/learning_statistics_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/mypage.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/mypage/notification_settings_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/notification/notification_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/edit_grading_result_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/upload/upload_images_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/chapter_detail_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/question_detail_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_detail_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/workbook/workbook_page.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_menu_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_header_title.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/bottom_navigation_widget.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/continuous_learning_widget_v2.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/dart_plugin_registrant.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart","/Users/downy/Documents/Gradi_25Fall/frontend/lib/services/fcm_service.dart"],"outputs":["/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/app.dill","/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/app.dill"]} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/native_assets.json b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/native_assets.json new file mode 100644 index 0000000..523bfc7 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/native_assets.json @@ -0,0 +1 @@ +{"format-version":[1,0,0],"native-assets":{}} \ No newline at end of file diff --git a/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/outputs.json b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/outputs.json new file mode 100644 index 0000000..eaa2543 --- /dev/null +++ b/frontend/.dart_tool/flutter_build/e425483cde2513462d063a33d7ea03c2/outputs.json @@ -0,0 +1 @@ +["/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter","/Users/downy/Documents/Gradi_25Fall/frontend/ios/Flutter/ephemeral/flutter_lldbinit","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/vm_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/isolate_snapshot_data","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/kernel_blob.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/App","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/Info.plist","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/.DS_Store","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/bottom_nav_all.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Academy_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/nav_workbook.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Upload_image_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Mypage_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Alarm_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Upload_image_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Alarm_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Textbook_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Textbook_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Mypage_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Home_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/bottom_nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/nav_home.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Academy_selected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/icons/Home_unselected.svg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2026.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_Blacklabel.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2024.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/workbook_2025.jpg","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_100to100.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/bookcovers/BookCover_LightSsen.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/social_login/Button_Google.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/assets/images/social_login/Button_Kakao.png","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z","/Users/downy/Documents/Gradi_25Fall/frontend/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json"] \ No newline at end of file diff --git a/frontend/.dart_tool/package_config.json b/frontend/.dart_tool/package_config.json new file mode 100644 index 0000000..ecc59b2 --- /dev/null +++ b/frontend/.dart_tool/package_config.json @@ -0,0 +1,178 @@ +{ + "configVersion": 2, + "packages": [ + { + "name": "async", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "boolean_selector", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "characters", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "clock", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "collection", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "cupertino_icons", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "fake_async", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "flutter", + "rootUri": "file:///Users/downy/flutter/packages/flutter", + "packageUri": "lib/", + "languageVersion": "3.8" + }, + { + "name": "flutter_lints", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "flutter_test", + "rootUri": "file:///Users/downy/flutter/packages/flutter_test", + "packageUri": "lib/", + "languageVersion": "3.8" + }, + { + "name": "leak_tracker", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2", + "packageUri": "lib/", + "languageVersion": "3.2" + }, + { + "name": "leak_tracker_flutter_testing", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10", + "packageUri": "lib/", + "languageVersion": "3.2" + }, + { + "name": "leak_tracker_testing", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2", + "packageUri": "lib/", + "languageVersion": "3.2" + }, + { + "name": "lints", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1", + "packageUri": "lib/", + "languageVersion": "3.6" + }, + { + "name": "matcher", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "material_color_utilities", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "meta", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "path", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "sky_engine", + "rootUri": "file:///Users/downy/flutter/bin/cache/pkg/sky_engine", + "packageUri": "lib/", + "languageVersion": "3.8" + }, + { + "name": "source_span", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "stack_trace", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "stream_channel", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "string_scanner", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "term_glyph", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "test_api", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "vector_math", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "vm_service", + "rootUri": "file:///Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "gradi_frontend", + "rootUri": "../", + "packageUri": "lib/", + "languageVersion": "3.9" + } + ], + "generator": "pub", + "generatorVersion": "3.9.2", + "flutterRoot": "file:///Users/downy/flutter", + "flutterVersion": "3.35.4", + "pubCache": "file:///Users/downy/.pub-cache" +} diff --git a/frontend/.dart_tool/package_graph.json b/frontend/.dart_tool/package_graph.json new file mode 100644 index 0000000..e08c4dd --- /dev/null +++ b/frontend/.dart_tool/package_graph.json @@ -0,0 +1,230 @@ +{ + "roots": [ + "gradi_frontend" + ], + "packages": [ + { + "name": "gradi_frontend", + "version": "1.0.0+1", + "dependencies": [ + "cupertino_icons", + "flutter" + ], + "devDependencies": [ + "flutter_lints", + "flutter_test" + ] + }, + { + "name": "flutter_lints", + "version": "5.0.0", + "dependencies": [ + "lints" + ] + }, + { + "name": "flutter_test", + "version": "0.0.0", + "dependencies": [ + "clock", + "collection", + "fake_async", + "flutter", + "leak_tracker_flutter_testing", + "matcher", + "meta", + "path", + "stack_trace", + "stream_channel", + "test_api", + "vector_math" + ] + }, + { + "name": "cupertino_icons", + "version": "1.0.8", + "dependencies": [] + }, + { + "name": "flutter", + "version": "0.0.0", + "dependencies": [ + "characters", + "collection", + "material_color_utilities", + "meta", + "sky_engine", + "vector_math" + ] + }, + { + "name": "lints", + "version": "5.1.1", + "dependencies": [] + }, + { + "name": "stream_channel", + "version": "2.1.4", + "dependencies": [ + "async" + ] + }, + { + "name": "meta", + "version": "1.16.0", + "dependencies": [] + }, + { + "name": "collection", + "version": "1.19.1", + "dependencies": [] + }, + { + "name": "leak_tracker_flutter_testing", + "version": "3.0.10", + "dependencies": [ + "flutter", + "leak_tracker", + "leak_tracker_testing", + "matcher", + "meta" + ] + }, + { + "name": "vector_math", + "version": "2.2.0", + "dependencies": [] + }, + { + "name": "stack_trace", + "version": "1.12.1", + "dependencies": [ + "path" + ] + }, + { + "name": "clock", + "version": "1.1.2", + "dependencies": [] + }, + { + "name": "fake_async", + "version": "1.3.3", + "dependencies": [ + "clock", + "collection" + ] + }, + { + "name": "path", + "version": "1.9.1", + "dependencies": [] + }, + { + "name": "matcher", + "version": "0.12.17", + "dependencies": [ + "async", + "meta", + "stack_trace", + "term_glyph", + "test_api" + ] + }, + { + "name": "test_api", + "version": "0.7.6", + "dependencies": [ + "async", + "boolean_selector", + "collection", + "meta", + "source_span", + "stack_trace", + "stream_channel", + "string_scanner", + "term_glyph" + ] + }, + { + "name": "sky_engine", + "version": "0.0.0", + "dependencies": [] + }, + { + "name": "material_color_utilities", + "version": "0.11.1", + "dependencies": [ + "collection" + ] + }, + { + "name": "characters", + "version": "1.4.0", + "dependencies": [] + }, + { + "name": "async", + "version": "2.13.0", + "dependencies": [ + "collection", + "meta" + ] + }, + { + "name": "leak_tracker_testing", + "version": "3.0.2", + "dependencies": [ + "leak_tracker", + "matcher", + "meta" + ] + }, + { + "name": "leak_tracker", + "version": "11.0.2", + "dependencies": [ + "clock", + "collection", + "meta", + "path", + "vm_service" + ] + }, + { + "name": "term_glyph", + "version": "1.2.2", + "dependencies": [] + }, + { + "name": "string_scanner", + "version": "1.4.1", + "dependencies": [ + "source_span" + ] + }, + { + "name": "source_span", + "version": "1.10.1", + "dependencies": [ + "collection", + "path", + "term_glyph" + ] + }, + { + "name": "boolean_selector", + "version": "2.1.2", + "dependencies": [ + "source_span", + "string_scanner" + ] + }, + { + "name": "vm_service", + "version": "15.0.2", + "dependencies": [] + } + ], + "configVersion": 1 +} \ No newline at end of file diff --git a/frontend/.dart_tool/version b/frontend/.dart_tool/version new file mode 100644 index 0000000..7b1bd83 --- /dev/null +++ b/frontend/.dart_tool/version @@ -0,0 +1 @@ +3.35.4 \ No newline at end of file diff --git a/frontend/.flutter-plugins-dependencies b/frontend/.flutter-plugins-dependencies new file mode 100644 index 0000000..ad8ccb4 --- /dev/null +++ b/frontend/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"firebase_core","path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_local_notifications","path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_ios","path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/","native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"firebase_core","path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_local_notifications","path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_plugin_android_lifecycle","path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.32/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_android","path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_android-0.8.13+5/","native_build":true,"dependencies":["flutter_plugin_android_lifecycle"],"dev_dependency":false}],"macos":[{"name":"file_selector_macos","path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_messaging","path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/","native_build":true,"dependencies":["firebase_core"],"dev_dependency":false},{"name":"flutter_local_notifications","path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_macos","path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_macos-0.2.2+1/","native_build":false,"dependencies":["file_selector_macos"],"dev_dependency":false}],"linux":[{"name":"file_selector_linux","path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"flutter_local_notifications_linux","path":"/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/","native_build":false,"dependencies":[],"dev_dependency":false},{"name":"image_picker_linux","path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/","native_build":false,"dependencies":["file_selector_linux"],"dev_dependency":false}],"windows":[{"name":"file_selector_windows","path":"/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"firebase_core","path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"image_picker_windows","path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/","native_build":false,"dependencies":["file_selector_windows"],"dev_dependency":false}],"web":[{"name":"firebase_core_web","path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_core_web-2.24.1/","dependencies":[],"dev_dependency":false},{"name":"firebase_messaging_web","path":"/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging_web-3.10.10/","dependencies":["firebase_core_web"],"dev_dependency":false},{"name":"image_picker_for_web","path":"/Users/downy/.pub-cache/hosted/pub.dev/image_picker_for_web-3.1.0/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"file_selector_linux","dependencies":[]},{"name":"file_selector_macos","dependencies":[]},{"name":"file_selector_windows","dependencies":[]},{"name":"firebase_core","dependencies":["firebase_core_web"]},{"name":"firebase_core_web","dependencies":[]},{"name":"firebase_messaging","dependencies":["firebase_core","firebase_messaging_web"]},{"name":"firebase_messaging_web","dependencies":["firebase_core","firebase_core_web"]},{"name":"flutter_local_notifications","dependencies":["flutter_local_notifications_linux"]},{"name":"flutter_local_notifications_linux","dependencies":[]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"image_picker","dependencies":["image_picker_android","image_picker_for_web","image_picker_ios","image_picker_linux","image_picker_macos","image_picker_windows"]},{"name":"image_picker_android","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker_for_web","dependencies":[]},{"name":"image_picker_ios","dependencies":[]},{"name":"image_picker_linux","dependencies":["file_selector_linux"]},{"name":"image_picker_macos","dependencies":["file_selector_macos"]},{"name":"image_picker_windows","dependencies":["file_selector_windows"]}],"date_created":"2025-11-05 12:42:42.795007","version":"3.35.7","swift_package_manager_enabled":{"ios":false,"macos":false}} \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..3820a95 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/coverage/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/frontend/.metadata b/frontend/.metadata new file mode 100644 index 0000000..84f56b1 --- /dev/null +++ b/frontend/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "d693b4b9dbac2acd4477aea4555ca6dcbea44ba2" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + - platform: android + create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + - platform: ios + create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + - platform: linux + create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + - platform: macos + create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + - platform: web + create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + - platform: windows + create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..26be299 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,16 @@ +# gradi_frontend + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/frontend/analysis_options.yaml b/frontend/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/frontend/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/frontend/android/.gitignore b/frontend/android/.gitignore new file mode 100644 index 0000000..be3943c --- /dev/null +++ b/frontend/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/frontend/android/.gradle/8.12/checksums/checksums.lock b/frontend/android/.gradle/8.12/checksums/checksums.lock new file mode 100644 index 0000000..9d17719 Binary files /dev/null and b/frontend/android/.gradle/8.12/checksums/checksums.lock differ diff --git a/frontend/android/.gradle/8.12/checksums/md5-checksums.bin b/frontend/android/.gradle/8.12/checksums/md5-checksums.bin new file mode 100644 index 0000000..2686ef8 Binary files /dev/null and b/frontend/android/.gradle/8.12/checksums/md5-checksums.bin differ diff --git a/frontend/android/.gradle/8.12/checksums/sha1-checksums.bin b/frontend/android/.gradle/8.12/checksums/sha1-checksums.bin new file mode 100644 index 0000000..46692a2 Binary files /dev/null and b/frontend/android/.gradle/8.12/checksums/sha1-checksums.bin differ diff --git a/frontend/android/.gradle/8.12/executionHistory/executionHistory.bin b/frontend/android/.gradle/8.12/executionHistory/executionHistory.bin new file mode 100644 index 0000000..aaefcc9 Binary files /dev/null and b/frontend/android/.gradle/8.12/executionHistory/executionHistory.bin differ diff --git a/frontend/android/.gradle/8.12/executionHistory/executionHistory.lock b/frontend/android/.gradle/8.12/executionHistory/executionHistory.lock new file mode 100644 index 0000000..3dfe7cb Binary files /dev/null and b/frontend/android/.gradle/8.12/executionHistory/executionHistory.lock differ diff --git a/frontend/android/.gradle/8.12/fileChanges/last-build.bin b/frontend/android/.gradle/8.12/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/frontend/android/.gradle/8.12/fileChanges/last-build.bin differ diff --git a/frontend/android/.gradle/8.12/fileHashes/fileHashes.bin b/frontend/android/.gradle/8.12/fileHashes/fileHashes.bin new file mode 100644 index 0000000..37dc8f9 Binary files /dev/null and b/frontend/android/.gradle/8.12/fileHashes/fileHashes.bin differ diff --git a/frontend/android/.gradle/8.12/fileHashes/fileHashes.lock b/frontend/android/.gradle/8.12/fileHashes/fileHashes.lock new file mode 100644 index 0000000..ea5ae3b Binary files /dev/null and b/frontend/android/.gradle/8.12/fileHashes/fileHashes.lock differ diff --git a/frontend/android/.gradle/8.12/fileHashes/resourceHashesCache.bin b/frontend/android/.gradle/8.12/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..1d588b6 Binary files /dev/null and b/frontend/android/.gradle/8.12/fileHashes/resourceHashesCache.bin differ diff --git a/frontend/android/.gradle/8.12/gc.properties b/frontend/android/.gradle/8.12/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/frontend/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/frontend/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000..5c9976d Binary files /dev/null and b/frontend/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/frontend/android/.gradle/buildOutputCleanup/cache.properties b/frontend/android/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..987f21c --- /dev/null +++ b/frontend/android/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Wed Nov 05 13:09:01 KST 2025 +gradle.version=8.12 diff --git a/frontend/android/.gradle/buildOutputCleanup/outputFiles.bin b/frontend/android/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000..3a49fe4 Binary files /dev/null and b/frontend/android/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/frontend/android/.gradle/file-system.probe b/frontend/android/.gradle/file-system.probe new file mode 100644 index 0000000..08fe13e Binary files /dev/null and b/frontend/android/.gradle/file-system.probe differ diff --git a/frontend/android/.gradle/noVersion/buildLogic.lock b/frontend/android/.gradle/noVersion/buildLogic.lock new file mode 100644 index 0000000..81627a8 Binary files /dev/null and b/frontend/android/.gradle/noVersion/buildLogic.lock differ diff --git a/frontend/android/.gradle/vcs-1/gc.properties b/frontend/android/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/frontend/android/app/build.gradle.kts b/frontend/android/app/build.gradle.kts new file mode 100644 index 0000000..84895a6 --- /dev/null +++ b/frontend/android/app/build.gradle.kts @@ -0,0 +1,58 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") + // Firebase ์ถ”๊ฐ€ + id("com.google.gms.google-services") +} + +android { + namespace = "com.gradi.gradi_frontend" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + // Core library desugaring ํ™œ์„ฑํ™” (flutter_local_notifications ํ•„์š”) + isCoreLibraryDesugaringEnabled = true + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.gradi.gradi_frontend" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} + +dependencies { + // Firebase ์ถ”๊ฐ€ + implementation(platform("com.google.firebase:firebase-bom:33.7.0")) + implementation("com.google.firebase:firebase-messaging") + implementation("com.google.firebase:firebase-analytics") + + // Core library desugaring (flutter_local_notifications ํ•„์š”) + coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4") +} diff --git a/frontend/android/app/google-services.json b/frontend/android/app/google-services.json new file mode 100644 index 0000000..dbe31b0 --- /dev/null +++ b/frontend/android/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "120799260544", + "project_id": "gradi-bd52c", + "storage_bucket": "gradi-bd52c.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:120799260544:android:a8e550dc78b59824b19b65", + "android_client_info": { + "package_name": "com.gradi.gradi_frontend" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyDoT9s6gZZQ6dCznYqVK3_aMDJCXVIHcRk" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/frontend/android/app/src/debug/AndroidManifest.xml b/frontend/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/frontend/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/frontend/android/app/src/main/AndroidManifest.xml b/frontend/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d2e88a0 --- /dev/null +++ b/frontend/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/frontend/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java new file mode 100644 index 0000000..539ab02 --- /dev/null +++ b/frontend/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java @@ -0,0 +1,19 @@ +package io.flutter.plugins; + +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import io.flutter.Log; + +import io.flutter.embedding.engine.FlutterEngine; + +/** + * Generated file. Do not edit. + * This file is generated by the Flutter tool based on the + * plugins that support the Android platform. + */ +@Keep +public final class GeneratedPluginRegistrant { + private static final String TAG = "GeneratedPluginRegistrant"; + public static void registerWith(@NonNull FlutterEngine flutterEngine) { + } +} diff --git a/frontend/android/app/src/main/kotlin/com/gradi/gradi_frontend/MainActivity.kt b/frontend/android/app/src/main/kotlin/com/gradi/gradi_frontend/MainActivity.kt new file mode 100644 index 0000000..080afd3 --- /dev/null +++ b/frontend/android/app/src/main/kotlin/com/gradi/gradi_frontend/MainActivity.kt @@ -0,0 +1,5 @@ +package com.gradi.gradi_frontend + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/frontend/android/app/src/main/res/drawable-v21/launch_background.xml b/frontend/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/frontend/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/frontend/android/app/src/main/res/drawable/launch_background.xml b/frontend/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/frontend/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/frontend/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/frontend/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/frontend/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/frontend/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/frontend/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/frontend/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/frontend/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/frontend/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/frontend/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/frontend/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/frontend/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/frontend/android/app/src/main/res/values-night/styles.xml b/frontend/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/frontend/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/frontend/android/app/src/main/res/values/styles.xml b/frontend/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/frontend/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/frontend/android/app/src/profile/AndroidManifest.xml b/frontend/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/frontend/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/frontend/android/build.gradle.kts b/frontend/android/build.gradle.kts new file mode 100644 index 0000000..85ed027 --- /dev/null +++ b/frontend/android/build.gradle.kts @@ -0,0 +1,35 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + // Firebase ์ถ”๊ฐ€ + classpath("com.google.gms:google-services:4.4.2") + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/frontend/android/gradi_frontend_android.iml b/frontend/android/gradi_frontend_android.iml new file mode 100644 index 0000000..1899969 --- /dev/null +++ b/frontend/android/gradi_frontend_android.iml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/android/gradle.properties b/frontend/android/gradle.properties new file mode 100644 index 0000000..f018a61 --- /dev/null +++ b/frontend/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/frontend/android/gradle/wrapper/gradle-wrapper.jar b/frontend/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/frontend/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/frontend/android/gradle/wrapper/gradle-wrapper.properties b/frontend/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ac3b479 --- /dev/null +++ b/frontend/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/frontend/android/gradlew b/frontend/android/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/frontend/android/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/frontend/android/gradlew.bat b/frontend/android/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/frontend/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/frontend/android/local.properties b/frontend/android/local.properties new file mode 100644 index 0000000..b066178 --- /dev/null +++ b/frontend/android/local.properties @@ -0,0 +1,2 @@ +sdk.dir=/Users/downy/Library/Android/sdk +flutter.sdk=/Users/downy/flutter \ No newline at end of file diff --git a/frontend/android/settings.gradle.kts b/frontend/android/settings.gradle.kts new file mode 100644 index 0000000..fb605bc --- /dev/null +++ b/frontend/android/settings.gradle.kts @@ -0,0 +1,26 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/frontend/assets/images/bookcovers/BookCover_100to100.png b/frontend/assets/images/bookcovers/BookCover_100to100.png new file mode 100644 index 0000000..b189475 Binary files /dev/null and b/frontend/assets/images/bookcovers/BookCover_100to100.png differ diff --git a/frontend/assets/images/bookcovers/BookCover_Blacklabel.png b/frontend/assets/images/bookcovers/BookCover_Blacklabel.png new file mode 100644 index 0000000..78db49f Binary files /dev/null and b/frontend/assets/images/bookcovers/BookCover_Blacklabel.png differ diff --git a/frontend/assets/images/bookcovers/BookCover_LightSsen.png b/frontend/assets/images/bookcovers/BookCover_LightSsen.png new file mode 100644 index 0000000..5efbb3b Binary files /dev/null and b/frontend/assets/images/bookcovers/BookCover_LightSsen.png differ diff --git a/frontend/assets/images/bookcovers/workbook_2024.jpg b/frontend/assets/images/bookcovers/workbook_2024.jpg new file mode 100644 index 0000000..427795a Binary files /dev/null and b/frontend/assets/images/bookcovers/workbook_2024.jpg differ diff --git a/frontend/assets/images/bookcovers/workbook_2025.jpg b/frontend/assets/images/bookcovers/workbook_2025.jpg new file mode 100644 index 0000000..829559e Binary files /dev/null and b/frontend/assets/images/bookcovers/workbook_2025.jpg differ diff --git a/frontend/assets/images/bookcovers/workbook_2026.jpg b/frontend/assets/images/bookcovers/workbook_2026.jpg new file mode 100644 index 0000000..16fb1e1 Binary files /dev/null and b/frontend/assets/images/bookcovers/workbook_2026.jpg differ diff --git a/frontend/assets/images/icons/Academy_selected.svg b/frontend/assets/images/icons/Academy_selected.svg new file mode 100644 index 0000000..20e4b8c --- /dev/null +++ b/frontend/assets/images/icons/Academy_selected.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/assets/images/icons/Academy_unselected.svg b/frontend/assets/images/icons/Academy_unselected.svg new file mode 100644 index 0000000..7ff9b66 --- /dev/null +++ b/frontend/assets/images/icons/Academy_unselected.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/assets/images/icons/Alarm_selected.svg b/frontend/assets/images/icons/Alarm_selected.svg new file mode 100644 index 0000000..345bf9d --- /dev/null +++ b/frontend/assets/images/icons/Alarm_selected.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/assets/images/icons/Alarm_unselected.svg b/frontend/assets/images/icons/Alarm_unselected.svg new file mode 100644 index 0000000..46d20c8 --- /dev/null +++ b/frontend/assets/images/icons/Alarm_unselected.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/assets/images/icons/Home_selected.svg b/frontend/assets/images/icons/Home_selected.svg new file mode 100644 index 0000000..6307829 --- /dev/null +++ b/frontend/assets/images/icons/Home_selected.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/assets/images/icons/Home_unselected.svg b/frontend/assets/images/icons/Home_unselected.svg new file mode 100644 index 0000000..ac58144 --- /dev/null +++ b/frontend/assets/images/icons/Home_unselected.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/assets/images/icons/Mypage_selected.svg b/frontend/assets/images/icons/Mypage_selected.svg new file mode 100644 index 0000000..2ece542 --- /dev/null +++ b/frontend/assets/images/icons/Mypage_selected.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/assets/images/icons/Mypage_unselected.svg b/frontend/assets/images/icons/Mypage_unselected.svg new file mode 100644 index 0000000..e020516 --- /dev/null +++ b/frontend/assets/images/icons/Mypage_unselected.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/assets/images/icons/Textbook_selected.svg b/frontend/assets/images/icons/Textbook_selected.svg new file mode 100644 index 0000000..c703dc0 --- /dev/null +++ b/frontend/assets/images/icons/Textbook_selected.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/assets/images/icons/Textbook_unselected.svg b/frontend/assets/images/icons/Textbook_unselected.svg new file mode 100644 index 0000000..6b8e8d2 --- /dev/null +++ b/frontend/assets/images/icons/Textbook_unselected.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/assets/images/icons/Upload_image_selected.svg b/frontend/assets/images/icons/Upload_image_selected.svg new file mode 100644 index 0000000..4c5e0b9 --- /dev/null +++ b/frontend/assets/images/icons/Upload_image_selected.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/assets/images/icons/Upload_image_unselected.svg b/frontend/assets/images/icons/Upload_image_unselected.svg new file mode 100644 index 0000000..b681424 --- /dev/null +++ b/frontend/assets/images/icons/Upload_image_unselected.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/assets/images/icons/bottom_nav_all.png b/frontend/assets/images/icons/bottom_nav_all.png new file mode 100644 index 0000000..990548a Binary files /dev/null and b/frontend/assets/images/icons/bottom_nav_all.png differ diff --git a/frontend/assets/images/icons/bottom_nav_home.png b/frontend/assets/images/icons/bottom_nav_home.png new file mode 100644 index 0000000..990548a Binary files /dev/null and b/frontend/assets/images/icons/bottom_nav_home.png differ diff --git a/frontend/assets/images/icons/nav_home.png b/frontend/assets/images/icons/nav_home.png new file mode 100644 index 0000000..d303893 Binary files /dev/null and b/frontend/assets/images/icons/nav_home.png differ diff --git a/frontend/assets/images/icons/nav_workbook.png b/frontend/assets/images/icons/nav_workbook.png new file mode 100644 index 0000000..7e5a39f Binary files /dev/null and b/frontend/assets/images/icons/nav_workbook.png differ diff --git a/frontend/assets/images/social_login/Button_Google.png b/frontend/assets/images/social_login/Button_Google.png new file mode 100644 index 0000000..57b731b Binary files /dev/null and b/frontend/assets/images/social_login/Button_Google.png differ diff --git a/frontend/assets/images/social_login/Button_Kakao.png b/frontend/assets/images/social_login/Button_Kakao.png new file mode 100644 index 0000000..3e15a1f Binary files /dev/null and b/frontend/assets/images/social_login/Button_Kakao.png differ diff --git a/frontend/gradi_frontend.iml b/frontend/gradi_frontend.iml new file mode 100644 index 0000000..f66303d --- /dev/null +++ b/frontend/gradi_frontend.iml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/.gitignore b/frontend/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/frontend/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/frontend/ios/.symlinks/plugins/firebase_core b/frontend/ios/.symlinks/plugins/firebase_core new file mode 120000 index 0000000..9493d36 --- /dev/null +++ b/frontend/ios/.symlinks/plugins/firebase_core @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ \ No newline at end of file diff --git a/frontend/ios/.symlinks/plugins/firebase_messaging b/frontend/ios/.symlinks/plugins/firebase_messaging new file mode 120000 index 0000000..81e1084 --- /dev/null +++ b/frontend/ios/.symlinks/plugins/firebase_messaging @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/ \ No newline at end of file diff --git a/frontend/ios/.symlinks/plugins/flutter_local_notifications b/frontend/ios/.symlinks/plugins/flutter_local_notifications new file mode 120000 index 0000000..52470ee --- /dev/null +++ b/frontend/ios/.symlinks/plugins/flutter_local_notifications @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ \ No newline at end of file diff --git a/frontend/ios/.symlinks/plugins/image_picker_ios b/frontend/ios/.symlinks/plugins/image_picker_ios new file mode 120000 index 0000000..8b51f35 --- /dev/null +++ b/frontend/ios/.symlinks/plugins/image_picker_ios @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ \ No newline at end of file diff --git a/frontend/ios/Flutter/AppFrameworkInfo.plist b/frontend/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..1dc6cf7 --- /dev/null +++ b/frontend/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 13.0 + + diff --git a/frontend/ios/Flutter/Debug.xcconfig b/frontend/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/frontend/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/frontend/ios/Flutter/Flutter.podspec b/frontend/ios/Flutter/Flutter.podspec new file mode 100644 index 0000000..3aed58d --- /dev/null +++ b/frontend/ios/Flutter/Flutter.podspec @@ -0,0 +1,18 @@ +# +# This podspec is NOT to be published. It is only used as a local source! +# This is a generated file; do not edit or check into version control. +# + +Pod::Spec.new do |s| + s.name = 'Flutter' + s.version = '1.0.0' + s.summary = 'A UI toolkit for beautiful and fast apps.' + s.homepage = 'https://flutter.dev' + s.license = { :type => 'BSD' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } + s.ios.deployment_target = '13.0' + # Framework linking is handled by Flutter tooling, not CocoaPods. + # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs. + s.vendored_frameworks = 'path/to/nothing' +end diff --git a/frontend/ios/Flutter/Generated.xcconfig b/frontend/ios/Flutter/Generated.xcconfig new file mode 100644 index 0000000..a63d096 --- /dev/null +++ b/frontend/ios/Flutter/Generated.xcconfig @@ -0,0 +1,15 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=/Users/downy/flutter +FLUTTER_APPLICATION_PATH=/Users/downy/Documents/Gradi_25Fall/frontend +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_TARGET=/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 +EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 +EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 +DART_DEFINES=RkxVVFRFUl9WRVJTSU9OPTMuMzUuNA==,RkxVVFRFUl9DSEFOTkVMPXN0YWJsZQ==,RkxVVFRFUl9HSVRfVVJMPWh0dHBzOi8vZ2l0aHViLmNvbS9mbHV0dGVyL2ZsdXR0ZXIuZ2l0,RkxVVFRFUl9GUkFNRVdPUktfUkVWSVNJT049ZDY5M2I0YjlkYg==,RkxVVFRFUl9FTkdJTkVfUkVWSVNJT049YzI5ODA5MTM1MQ==,RkxVVFRFUl9EQVJUX1ZFUlNJT049My45LjI= +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json diff --git a/frontend/ios/Flutter/Release.xcconfig b/frontend/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/frontend/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/frontend/ios/Flutter/ephemeral/flutter_lldb_helper.py b/frontend/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 0000000..a88caf9 --- /dev/null +++ b/frontend/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/frontend/ios/Flutter/ephemeral/flutter_lldbinit b/frontend/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 0000000..e3ba6fb --- /dev/null +++ b/frontend/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/frontend/ios/Flutter/flutter_export_environment.sh b/frontend/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 0000000..f98b857 --- /dev/null +++ b/frontend/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Users/downy/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/downy/Documents/Gradi_25Fall/frontend" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_TARGET=/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_DEFINES=RkxVVFRFUl9WRVJTSU9OPTMuMzUuNA==,RkxVVFRFUl9DSEFOTkVMPXN0YWJsZQ==,RkxVVFRFUl9HSVRfVVJMPWh0dHBzOi8vZ2l0aHViLmNvbS9mbHV0dGVyL2ZsdXR0ZXIuZ2l0,RkxVVFRFUl9GUkFNRVdPUktfUkVWSVNJT049ZDY5M2I0YjlkYg==,RkxVVFRFUl9FTkdJTkVfUkVWSVNJT049YzI5ODA5MTM1MQ==,RkxVVFRFUl9EQVJUX1ZFUlNJT049My45LjI=" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=/Users/downy/Documents/Gradi_25Fall/frontend/.dart_tool/package_config.json" diff --git a/frontend/ios/Podfile b/frontend/ios/Podfile new file mode 100644 index 0000000..620e46e --- /dev/null +++ b/frontend/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/frontend/ios/Podfile.lock b/frontend/ios/Podfile.lock new file mode 100644 index 0000000..efe541e --- /dev/null +++ b/frontend/ios/Podfile.lock @@ -0,0 +1,136 @@ +PODS: + - Firebase/CoreOnly (11.15.0): + - FirebaseCore (~> 11.15.0) + - Firebase/Messaging (11.15.0): + - Firebase/CoreOnly + - FirebaseMessaging (~> 11.15.0) + - firebase_core (3.15.2): + - Firebase/CoreOnly (= 11.15.0) + - Flutter + - firebase_messaging (15.2.10): + - Firebase/Messaging (= 11.15.0) + - firebase_core + - Flutter + - FirebaseCore (11.15.0): + - FirebaseCoreInternal (~> 11.15.0) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/Logger (~> 8.1) + - FirebaseCoreInternal (11.15.0): + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - FirebaseInstallations (11.15.0): + - FirebaseCore (~> 11.15.0) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/UserDefaults (~> 8.1) + - PromisesObjC (~> 2.4) + - FirebaseMessaging (11.15.0): + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleDataTransport (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/Reachability (~> 8.1) + - GoogleUtilities/UserDefaults (~> 8.1) + - nanopb (~> 3.30910.0) + - Flutter (1.0.0) + - flutter_local_notifications (0.0.1): + - Flutter + - geolocator_apple (1.2.0): + - Flutter + - FlutterMacOS + - GoogleDataTransport (10.1.0): + - nanopb (~> 3.30910.0) + - PromisesObjC (~> 2.4) + - GoogleUtilities/AppDelegateSwizzler (8.1.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Privacy + - GoogleUtilities/Environment (8.1.0): + - GoogleUtilities/Privacy + - GoogleUtilities/Logger (8.1.0): + - GoogleUtilities/Environment + - GoogleUtilities/Privacy + - GoogleUtilities/Network (8.1.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Privacy + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (8.1.0)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (8.1.0) + - GoogleUtilities/Reachability (8.1.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GoogleUtilities/UserDefaults (8.1.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - image_picker_ios (0.0.1): + - Flutter + - nanopb (3.30910.0): + - nanopb/decode (= 3.30910.0) + - nanopb/encode (= 3.30910.0) + - nanopb/decode (3.30910.0) + - nanopb/encode (3.30910.0) + - PromisesObjC (2.4.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) + - Flutter (from `Flutter`) + - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + +SPEC REPOS: + trunk: + - Firebase + - FirebaseCore + - FirebaseCoreInternal + - FirebaseInstallations + - FirebaseMessaging + - GoogleDataTransport + - GoogleUtilities + - nanopb + - PromisesObjC + +EXTERNAL SOURCES: + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_messaging: + :path: ".symlinks/plugins/firebase_messaging/ios" + Flutter: + :path: Flutter + flutter_local_notifications: + :path: ".symlinks/plugins/flutter_local_notifications/ios" + geolocator_apple: + :path: ".symlinks/plugins/geolocator_apple/darwin" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + +SPEC CHECKSUMS: + Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e + firebase_core: 995454a784ff288be5689b796deb9e9fa3601818 + firebase_messaging: f4a41dd102ac18b840eba3f39d67e77922d3f707 + FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e + FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 + FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 + FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + flutter_local_notifications: 395056b3175ba4f08480a7c5de30cd36d69827e4 + geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e + GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 + GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 + image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 + nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb + +PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e + +COCOAPODS: 1.16.2 diff --git a/frontend/ios/Pods/Firebase/CoreOnly/Sources/Firebase.h b/frontend/ios/Pods/Firebase/CoreOnly/Sources/Firebase.h new file mode 100755 index 0000000..37d5f9e --- /dev/null +++ b/frontend/ios/Pods/Firebase/CoreOnly/Sources/Firebase.h @@ -0,0 +1,88 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#if !defined(__has_include) + #error "Firebase.h won't import anything if your compiler doesn't support __has_include. Please \ + import the headers individually." +#else + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #if __has_include("FirebaseAuth-umbrella.h") + #if __has_include() + #import + #endif + #import + #import + #endif + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include("FirebaseFunctions-umbrella.h") + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include("FirebaseStorage-umbrella.h") + #import + #endif + +#endif // defined(__has_include) diff --git a/frontend/ios/Pods/Firebase/CoreOnly/Sources/module.modulemap b/frontend/ios/Pods/Firebase/CoreOnly/Sources/module.modulemap new file mode 100755 index 0000000..3685b54 --- /dev/null +++ b/frontend/ios/Pods/Firebase/CoreOnly/Sources/module.modulemap @@ -0,0 +1,4 @@ +module Firebase { + export * + header "Firebase.h" +} \ No newline at end of file diff --git a/frontend/ios/Pods/Firebase/LICENSE b/frontend/ios/Pods/Firebase/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/frontend/ios/Pods/Firebase/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/ios/Pods/Firebase/README.md b/frontend/ios/Pods/Firebase/README.md new file mode 100644 index 0000000..8c98212 --- /dev/null +++ b/frontend/ios/Pods/Firebase/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 16.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](docs/AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@20 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRAppInternal.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..96d42ef --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,182 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRAPPINTERNAL_H +#define FIREBASECORE_FIRAPPINTERNAL_H + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRAPPINTERNAL_H diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponent.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..98c7a89 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,89 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRCOMPONENT_H +#define FIREBASECORE_FIRCOMPONENT_H + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRCOMPONENT_H diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentContainer.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6864087 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRCOMPONENTCONTAINER_H +#define FIREBASECORE_FIRCOMPONENTCONTAINER_H + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRCOMPONENTCONTAINER_H diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentType.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..92a5aab --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,40 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRCOMPONENTTYPE_H +#define FIREBASECORE_FIRCOMPONENTTYPE_H + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRCOMPONENTTYPE_H diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRHeartbeatLogger.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..95497d2 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,110 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIREBASECORE_FIRHEARTBEATLOGGER_H +#define FIREBASECORE_FIRHEARTBEATLOGGER_H + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +NS_SWIFT_SENDABLE +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns the header value for the heartbeat logger via the given completion handler.. +- (void)asyncHeaderValueWithCompletionHandler:(void (^)(NSString *_Nullable))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)); + +/// Return the header value for the heartbeat logger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Synchronously flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; + +/// Asynchronously flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @param completionHandler A completion handler to process the flushed payload of heartbeats. +- (void)flushHeartbeatsIntoPayloadWithCompletionHandler: + (void (^)(FIRHeartbeatsPayload *))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)); +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRHEARTBEATLOGGER_H diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRLibrary.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..fe256ad --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRLIBRARY_H +#define FIREBASECORE_FIRLIBRARY_H + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ + +#endif // FIREBASECORE_FIRLIBRARY_H diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRLogger.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..8117189 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,198 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRLOGGER_H +#define FIREBASECORE_FIRLOGGER_H + +#import + +typedef NS_ENUM(NSInteger, FIRLoggerLevel); + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +void FIRSetLoggerLevelNotice(void); +void FIRSetLoggerLevelWarning(void); +void FIRSetLoggerLevelError(void); +void FIRSetLoggerLevelDebug(void); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +BOOL FIRIsLoggableLevelNotice(void); +BOOL FIRIsLoggableLevelWarning(void); +BOOL FIRIsLoggableLevelError(void); +BOOL FIRIsLoggableLevelDebug(void); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +/** + * This function is similar to the one above, except it takes a `va_list` instead of the listed + * variables. + * + * The following functions accept the following parameters in order: (required) service + * name of type FirebaseLoggerService. + * + * (required) message code starting from "I-" which means iOS, + * followed by a capitalized three-character service identifier and a six digit integer message + * ID that is unique within the service. An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) A va_list + */ +extern void FIRLogBasicError(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicWarning(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicNotice(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicInfo(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicDebug(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - category: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRLOGGER_H diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FirebaseCoreInternal.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..2561008 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,28 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIREBASECORE_FIREBASECOREINTERNAL_H +#define FIREBASECORE_FIREBASECOREINTERNAL_H + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" + +#endif // FIREBASECORE_FIREBASECOREINTERNAL_H diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h new file mode 100644 index 0000000..6429ac7 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/// Values stored in analyticsEnabledState. Never alter these constants since they must match with +/// values persisted to disk. +typedef NS_ENUM(int64_t, FIRAnalyticsEnabledState) { + // 0 is the default value for keys not found stored in persisted config, so it cannot represent + // kFIRAnalyticsEnabledStateSetNo. It must represent kFIRAnalyticsEnabledStateNotSet. + kFIRAnalyticsEnabledStateNotSet = 0, + kFIRAnalyticsEnabledStateSetYes = 1, + kFIRAnalyticsEnabledStateSetNo = 2, +}; + +/// The user defaults key for the persisted measurementEnabledState value. FIRAPersistedConfig reads +/// measurementEnabledState using this same key. +static NSString *const kFIRAPersistedConfigMeasurementEnabledStateKey = + @"/google/measurement/measurement_enabled_state"; + +static NSString *const kFIRAnalyticsConfigurationSetEnabledNotification = + @"FIRAnalyticsConfigurationSetEnabledNotification"; +static NSString *const kFIRAnalyticsConfigurationSetMinimumSessionIntervalNotification = + @"FIRAnalyticsConfigurationSetMinimumSessionIntervalNotification"; +static NSString *const kFIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification = + @"FIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification"; + +@interface FIRAnalyticsConfiguration : NSObject + +/// Returns the shared instance of FIRAnalyticsConfiguration. ++ (FIRAnalyticsConfiguration *)sharedInstance; + +// Sets whether analytics collection is enabled for this app on this device. This setting is +// persisted across app sessions. By default it is enabled. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets whether analytics collection is enabled for this app on this device, and a flag to persist +/// the value or not. The setting should not be persisted if being set by the global data collection +/// flag. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled + persistSetting:(BOOL)shouldPersist; + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m new file mode 100644 index 0000000..07c786c --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m @@ -0,0 +1,62 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +@implementation FIRAnalyticsConfiguration +#pragma clang diagnostic pop + ++ (FIRAnalyticsConfiguration *)sharedInstance { + static FIRAnalyticsConfiguration *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRAnalyticsConfiguration alloc] init]; + }); + return sharedInstance; +} + +- (void)postNotificationName:(NSString *)name value:(id)value { + if (!name.length || !value) { + return; + } + [[NSNotificationCenter defaultCenter] postNotificationName:name + object:self + userInfo:@{name : value}]; +} + +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled { + [self setAnalyticsCollectionEnabled:analyticsCollectionEnabled persistSetting:YES]; +} + +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled + persistSetting:(BOOL)shouldPersist { + // Persist the measurementEnabledState. Use FIRAnalyticsEnabledState values instead of YES/NO. + FIRAnalyticsEnabledState analyticsEnabledState = + analyticsCollectionEnabled ? kFIRAnalyticsEnabledStateSetYes : kFIRAnalyticsEnabledStateSetNo; + if (shouldPersist) { + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + [userDefaults setObject:@(analyticsEnabledState) + forKey:kFIRAPersistedConfigMeasurementEnabledStateKey]; + [userDefaults synchronize]; + } + + [self postNotificationName:kFIRAnalyticsConfigurationSetEnabledNotification + value:@(analyticsCollectionEnabled)]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m new file mode 100644 index 0000000..702799c --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m @@ -0,0 +1,910 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#if __has_include() +#import +#endif + +#if __has_include() +#import +#endif + +#if __has_include() +#import +#endif + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h" + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" +#import "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/FIRComponentContainerInternal.h" +#import "FirebaseCore/Sources/FIRConfigurationInternal.h" +#import "FirebaseCore/Sources/FIRFirebaseUserAgent.h" + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRHeartbeatLogger.h" +#import "FirebaseCore/Extension/FIRLibrary.h" +#import "FirebaseCore/Extension/FIRLogger.h" +#import "FirebaseCore/Sources/FIROptionsInternal.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +#import + +#import + +NSString *const kFIRDefaultAppName = @"__FIRAPP_DEFAULT"; +NSString *const kFIRAppReadyToConfigureSDKNotification = @"FIRAppReadyToConfigureSDKNotification"; +NSString *const kFIRAppDeleteNotification = @"FIRAppDeleteNotification"; +NSString *const kFIRAppIsDefaultAppKey = @"FIRAppIsDefaultAppKey"; +NSString *const kFIRAppNameKey = @"FIRAppNameKey"; +NSString *const kFIRGoogleAppIDKey = @"FIRGoogleAppIDKey"; + +NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat = + @"/google/firebase/global_data_collection_enabled:%@"; +NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey = + @"FirebaseDataCollectionDefaultEnabled"; + +NSString *const kFIRAppDiagnosticsConfigurationTypeKey = @"ConfigType"; +NSString *const kFIRAppDiagnosticsErrorKey = @"Error"; +NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRApp"; +NSString *const kFIRAppDiagnosticsSDKNameKey = @"SDKName"; +NSString *const kFIRAppDiagnosticsSDKVersionKey = @"SDKVersion"; +NSString *const kFIRAppDiagnosticsApplePlatformPrefix = @"apple-platform"; + +// Auth internal notification notification and key. +NSString *const FIRAuthStateDidChangeInternalNotification = + @"FIRAuthStateDidChangeInternalNotification"; +NSString *const FIRAuthStateDidChangeInternalNotificationAppKey = + @"FIRAuthStateDidChangeInternalNotificationAppKey"; +NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey = + @"FIRAuthStateDidChangeInternalNotificationTokenKey"; +NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey = + @"FIRAuthStateDidChangeInternalNotificationUIDKey"; + +/** + * Error domain for exceptions and NSError construction. + */ +NSString *const kFirebaseCoreErrorDomain = @"com.firebase.core"; + +/** + * The URL to download plist files. + */ +static NSString *const kPlistURL = @"https://console.firebase.google.com/"; + +@interface FIRApp () + +#ifdef DEBUG +@property(nonatomic) BOOL alreadyOutputDataCollectionFlag; +#endif // DEBUG + +@end + +@implementation FIRApp + +// This is necessary since our custom getter prevents `_options` from being created. +@synthesize options = _options; + +static NSMutableDictionary *sAllApps; +static FIRApp *sDefaultApp; + ++ (void)configure { + FIROptions *options = [FIROptions defaultOptions]; + if (!options) { +#if DEBUG + [self findMisnamedGoogleServiceInfoPlist]; +#endif // DEBUG + [NSException raise:kFirebaseCoreErrorDomain + format:@"`FirebaseApp.configure()` could not find " + @"a valid GoogleService-Info.plist in your project. Please download one " + @"from %@.", + kPlistURL]; + } + [FIRApp configureWithOptions:options]; +} + ++ (void)configureWithOptions:(FIROptions *)options { + if (!options) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Options is nil. Please pass a valid options."]; + } + [FIRApp configureWithName:kFIRDefaultAppName options:options]; +} + ++ (NSCharacterSet *)applicationNameAllowedCharacters { + static NSCharacterSet *applicationNameAllowedCharacters; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSMutableCharacterSet *allowedNameCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedNameCharacters addCharactersInString:@"-_"]; + applicationNameAllowedCharacters = [allowedNameCharacters copy]; + }); + return applicationNameAllowedCharacters; +} + ++ (void)configureWithName:(NSString *)name options:(FIROptions *)options { + if (!name || !options) { + [NSException raise:kFirebaseCoreErrorDomain format:@"Neither name nor options can be nil."]; + } + if (name.length == 0) { + [NSException raise:kFirebaseCoreErrorDomain format:@"Name cannot be empty."]; + } + + if ([name isEqualToString:kFIRDefaultAppName]) { + if (sDefaultApp) { + // The default app already exists. Handle duplicate `configure` calls and return. + [self appWasConfiguredTwice:sDefaultApp usingOptions:options]; + return; + } + + FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configuring the default app."); + } else { + // Validate the app name and ensure it hasn't been configured already. + NSCharacterSet *nameCharacters = [NSCharacterSet characterSetWithCharactersInString:name]; + + if (![[self applicationNameAllowedCharacters] isSupersetOfSet:nameCharacters]) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App name can only contain alphanumeric, " + @"hyphen (-), and underscore (_) characters"]; + } + + @synchronized(self) { + if (sAllApps && sAllApps[name]) { + // The app already exists. Handle a duplicate `configure` call and return. + [self appWasConfiguredTwice:sAllApps[name] usingOptions:options]; + return; + } + } + + FIRLogDebug(kFIRLoggerCore, @"I-COR000002", @"Configuring app named %@", name); + } + + // Default instantiation, make sure we populate with Swift SDKs that can't register in time. + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [self registerSwiftComponents]; + }); + + @synchronized(self) { + FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; + if (app.isDefaultApp) { + sDefaultApp = app; + } + + [FIRApp addAppToAppDictionary:app]; + + // The FIRApp instance is ready to go, `sDefaultApp` is assigned, other SDKs are now ready to be + // instantiated. + [app.container instantiateEagerComponents]; + [FIRApp sendNotificationsToSDKs:app]; + } +} + +/// Called when `configure` has been called multiple times for the same app. This can either throw +/// an exception (most cases) or ignore the duplicate configuration in situations where it's allowed +/// like an extension. ++ (void)appWasConfiguredTwice:(FIRApp *)app usingOptions:(FIROptions *)options { + // Only extensions should potentially be able to call `configure` more than once. + if (![GULAppEnvironmentUtil isAppExtension]) { + // Throw an exception since this is now an invalid state. + if (app.isDefaultApp) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Default app has already been configured."]; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } + } + + // In an extension, the entry point could be called multiple times. As long as the options are + // identical we should allow multiple `configure` calls. + if ([options isEqual:app.options]) { + // Everything is identical but the extension's lifecycle triggered `configure` twice. + // Ignore duplicate calls and return since everything should still be in a valid state. + FIRLogDebug(kFIRLoggerCore, @"I-COR000035", + @"Ignoring second `configure` call in an extension."); + return; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } +} + ++ (FIRApp *)defaultApp { + if (sDefaultApp) { + return sDefaultApp; + } + FIRLogError(kFIRLoggerCore, @"I-COR000003", + @"The default Firebase app has not yet been " + @"configured. Add `FirebaseApp.configure()` to your " + @"application initialization. This can be done in " + @"in the App Delegate's application(_:didFinishLaunchingWithOptions:)` " + @"(or the `@main` struct's initializer in SwiftUI). " + @"Read more: " + @"https://firebase.google.com/docs/ios/setup#initialize_firebase_in_your_app"); + return nil; +} + ++ (FIRApp *)appNamed:(NSString *)name { + @synchronized(self) { + if (sAllApps) { + FIRApp *app = sAllApps[name]; + if (app) { + return app; + } + } + FIRLogError(kFIRLoggerCore, @"I-COR000004", @"App with name %@ does not exist.", name); + return nil; + } +} + ++ (NSDictionary *)allApps { + @synchronized(self) { + if (!sAllApps) { + FIRLogError(kFIRLoggerCore, @"I-COR000005", @"No app has been configured yet."); + } + return [sAllApps copy]; + } +} + +// Public only for tests ++ (void)resetApps { + @synchronized(self) { + sDefaultApp = nil; + [sAllApps removeAllObjects]; + sAllApps = nil; + [[self userAgent] reset]; + } +} + +- (void)deleteApp:(FIRAppVoidBoolCallback)completion { + @synchronized([self class]) { + if (sAllApps && sAllApps[self.name]) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000006", @"Deleting app named %@", self.name); + + // Remove all registered libraries from the container to avoid creating new instances. + [self.container removeAllComponents]; + // Remove all cached instances from the container before deleting the app. + [self.container removeAllCachedInstances]; + + [sAllApps removeObjectForKey:self.name]; + [self clearDataCollectionSwitchFromUserDefaults]; + if ([self.name isEqualToString:kFIRDefaultAppName]) { + sDefaultApp = nil; + } + NSDictionary *appInfoDict = @{kFIRAppNameKey : self.name}; + [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppDeleteNotification + object:[self class] + userInfo:appInfoDict]; + completion(YES); + } else { + FIRLogError(kFIRLoggerCore, @"I-COR000007", @"App does not exist."); + completion(NO); + } + } +} + ++ (void)addAppToAppDictionary:(FIRApp *)app { + if (!sAllApps) { + sAllApps = [NSMutableDictionary dictionary]; + } + if ([app configureCore]) { + sAllApps[app.name] = app; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Configuration fails. It may be caused by an invalid GOOGLE_APP_ID in " + @"GoogleService-Info.plist or set in the customized options."]; + } +} + +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options { + self = [super init]; + if (self) { + _name = [name copy]; + _options = [options copy]; + _options.editingLocked = YES; + _isDefaultApp = [name isEqualToString:kFIRDefaultAppName]; + _container = [[FIRComponentContainer alloc] initWithApp:self]; + _heartbeatLogger = [[FIRHeartbeatLogger alloc] initWithAppID:self.options.googleAppID]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (BOOL)configureCore { + [self checkExpectedBundleID]; + if (![self isAppIDValid]) { + return NO; + } + + // Initialize the Analytics once there is a valid options under default app. Analytics should + // always initialize first by itself before the other SDKs. + if ([self.name isEqualToString:kFIRDefaultAppName]) { + Class firAnalyticsClass = NSClassFromString(@"FIRAnalytics"); + if (firAnalyticsClass) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" + SEL startWithConfigurationSelector = @selector(startWithConfiguration:options:); +#pragma clang diagnostic pop + if ([firAnalyticsClass respondsToSelector:startWithConfigurationSelector]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [firAnalyticsClass performSelector:startWithConfigurationSelector + withObject:[FIRConfiguration sharedInstance].analyticsConfiguration + withObject:_options]; +#pragma clang diagnostic pop + } + } + } + + [self subscribeForAppDidBecomeActiveNotifications]; + + return YES; +} + +- (FIROptions *)options { + return [_options copy]; +} + +- (void)setDataCollectionDefaultEnabled:(BOOL)dataCollectionDefaultEnabled { +#ifdef DEBUG + FIRLogDebug(kFIRLoggerCore, @"I-COR000034", @"Explicitly %@ data collection flag.", + dataCollectionDefaultEnabled ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; +#endif // DEBUG + + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; + [[NSUserDefaults standardUserDefaults] setBool:dataCollectionDefaultEnabled forKey:key]; + + // Core also controls the FirebaseAnalytics flag, so check if the Analytics flags are set + // within FIROptions and change the Analytics value if necessary. Analytics only works with the + // default app, so return if this isn't the default app. + if (!self.isDefaultApp) { + return; + } + + // Check if the Analytics flag is explicitly set. If so, no further actions are necessary. + if ([self.options isAnalyticsCollectionExplicitlySet]) { + return; + } + + // The Analytics flag has not been explicitly set, so update with the value being set. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[FIRAnalyticsConfiguration sharedInstance] + setAnalyticsCollectionEnabled:dataCollectionDefaultEnabled + persistSetting:NO]; +#pragma clang diagnostic pop +} + +- (BOOL)isDataCollectionDefaultEnabled { + // Check if it's been manually set before in code, and use that as the higher priority value. + NSNumber *defaultsObject = [[self class] readDataCollectionSwitchFromUserDefaultsForApp:self]; + if (defaultsObject != nil) { +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000031", @"Data Collection flag is %@ in user defaults.", + [defaultsObject boolValue] ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return [defaultsObject boolValue]; + } + + // Read the Info.plist to see if the flag is set. If it's not set, it should default to `YES`. + // As per the implementation of `readDataCollectionSwitchFromPlist`, it's a cached value and has + // no performance impact calling multiple times. + NSNumber *collectionEnabledPlistValue = [[self class] readDataCollectionSwitchFromPlist]; + if (collectionEnabledPlistValue != nil) { +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000032", @"Data Collection flag is %@ in plist.", + [collectionEnabledPlistValue boolValue] ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return [collectionEnabledPlistValue boolValue]; + } + +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000033", @"Data Collection flag is not set."); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return YES; +} + +#pragma mark - private + ++ (void)sendNotificationsToSDKs:(FIRApp *)app { + // TODO: Remove this notification once all SDKs are registered with `FIRCoreConfigurable`. + NSNumber *isDefaultApp = [NSNumber numberWithBool:app.isDefaultApp]; + NSDictionary *appInfoDict = @{ + kFIRAppNameKey : app.name, + kFIRAppIsDefaultAppKey : isDefaultApp, + kFIRGoogleAppIDKey : app.options.googleAppID + }; + [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppReadyToConfigureSDKNotification + object:self + userInfo:appInfoDict]; +} + ++ (NSError *)errorForMissingOptions { + NSDictionary *errorDict = @{ + NSLocalizedDescriptionKey : + @"Unable to parse GoogleService-Info.plist in order to configure services.", + NSLocalizedRecoverySuggestionErrorKey : + @"Check formatting and location of GoogleService-Info.plist." + }; + return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-100 userInfo:errorDict]; +} + ++ (NSError *)errorForInvalidAppID { + NSDictionary *errorDict = @{ + NSLocalizedDescriptionKey : @"Unable to validate Google App ID", + NSLocalizedRecoverySuggestionErrorKey : + @"Check formatting and location of GoogleService-Info.plist or GoogleAppID set in the " + @"customized options." + }; + return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-101 userInfo:errorDict]; +} + ++ (BOOL)isDefaultAppConfigured { + return (sDefaultApp != nil); +} + ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version { + // Create the set of characters which aren't allowed, only if this feature is used. + NSMutableCharacterSet *allowedSet = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedSet addCharactersInString:@"-_."]; + NSCharacterSet *disallowedSet = [allowedSet invertedSet]; + // Make sure the library name and version strings do not contain unexpected characters, and + // add the name/version pair to the dictionary. + if ([name rangeOfCharacterFromSet:disallowedSet].location == NSNotFound && + [version rangeOfCharacterFromSet:disallowedSet].location == NSNotFound) { + [[self userAgent] setValue:version forComponent:name]; + } else { + FIRLogError(kFIRLoggerCore, @"I-COR000027", + @"The library name (%@) or version number (%@) contain invalid characters. " + @"Only alphanumeric, dash, underscore and period characters are allowed.", + name, version); + } +} + ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name { + [self registerInternalLibrary:library withName:name withVersion:FIRFirebaseVersion()]; +} + ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version { + // This is called at +load time, keep the work to a minimum. + + // Ensure the class given conforms to the proper protocol. + if (![(Class)library conformsToProtocol:@protocol(FIRLibrary)] || + ![(Class)library respondsToSelector:@selector(componentsToRegister)]) { + [NSException raise:NSInvalidArgumentException + format:@"Class %@ attempted to register components, but it does not conform to " + @"`FIRLibrary or provide a `componentsToRegister:` method.", + library]; + } + + [FIRComponentContainer registerAsComponentRegistrant:library]; + [self registerLibrary:name withVersion:version]; +} + ++ (FIRFirebaseUserAgent *)userAgent { + static dispatch_once_t onceToken; + static FIRFirebaseUserAgent *_userAgent; + dispatch_once(&onceToken, ^{ + _userAgent = [[FIRFirebaseUserAgent alloc] init]; + [_userAgent setValue:FIRFirebaseVersion() forComponent:@"fire-ios"]; + }); + return _userAgent; +} + ++ (NSString *)firebaseUserAgent { + return [[self userAgent] firebaseUserAgent]; +} + +- (void)checkExpectedBundleID { + NSArray *bundles = [FIRBundleUtil relevantBundles]; + NSString *expectedBundleID = [self expectedBundleID]; + // The checking is only done when the bundle ID is provided in the serviceInfo dictionary for + // backward compatibility. + if (expectedBundleID != nil && ![FIRBundleUtil hasBundleIdentifierPrefix:expectedBundleID + inBundles:bundles]) { + FIRLogError(kFIRLoggerCore, @"I-COR000008", + @"The project's Bundle ID is inconsistent with " + @"either the Bundle ID in '%@.%@', or the Bundle ID in the options if you are " + @"using a customized options. To ensure that everything can be configured " + @"correctly, you may need to make the Bundle IDs consistent. To continue with this " + @"plist file, you may change your app's bundle identifier to '%@'. Or you can " + @"download a new configuration file that matches your bundle identifier from %@ " + @"and replace the current one.", + kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + } +} + +#pragma mark - private - App ID Validation + +/** + * Validates the format of app ID and its included bundle ID hash contained in GOOGLE_APP_ID in the + * plist file. This is the main method for validating app ID. + * + * @return YES if the app ID fulfills the expected format and contains a hashed bundle ID, NO + * otherwise. + */ +- (BOOL)isAppIDValid { + NSString *appID = _options.googleAppID; + BOOL isValid = [FIRApp validateAppID:appID]; + if (!isValid) { + NSString *expectedBundleID = [self expectedBundleID]; + FIRLogError(kFIRLoggerCore, @"I-COR000009", + @"The GOOGLE_APP_ID either in the plist file " + @"'%@.%@' or the one set in the customized options is invalid. If you are using " + @"the plist file, use the iOS version of bundle identifier to download the file, " + @"and do not manually edit the GOOGLE_APP_ID. You may change your app's bundle " + @"identifier to '%@'. Or you can download a new configuration file that matches " + @"your bundle identifier from %@ and replace the current one.", + kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + }; + return isValid; +} + ++ (BOOL)validateAppID:(NSString *)appID { + // Failing validation only occurs when we are sure we are looking at a V2 app ID and it does not + // have a valid hashed bundle ID, otherwise we just warn about the potential issue. + if (!appID.length) { + return NO; + } + + NSScanner *stringScanner = [NSScanner scannerWithString:appID]; + stringScanner.charactersToBeSkipped = nil; + + NSString *appIDVersion; + if (![stringScanner scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] + intoString:&appIDVersion]) { + return NO; + } + + if (![stringScanner scanString:@":" intoString:NULL]) { + // appIDVersion must be separated by ":" + return NO; + } + + NSArray *knownVersions = @[ @"1" ]; + if (![knownVersions containsObject:appIDVersion]) { + // Permit unknown yet properly formatted app ID versions. + FIRLogInfo(kFIRLoggerCore, @"I-COR000010", @"Unknown GOOGLE_APP_ID version: %@", appIDVersion); + return YES; + } + + if (![self validateAppIDFormat:appID withVersion:appIDVersion]) { + return NO; + } + + if (![self validateBundleIDHashWithinAppID:appID forVersion:appIDVersion]) { + return NO; + } + + return YES; +} + ++ (NSString *)actualBundleID { + return [[NSBundle mainBundle] bundleIdentifier]; +} + +/** + * Validates that the format of the app ID string is what is expected based on the supplied version. + * The version must end in ":". + * + * For v1 app ids the format is expected to be + * '::ios:'. + * + * This method does not verify that the contents of the app id are correct, just that they fulfill + * the expected format. + * + * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param version Indicates what version of the app id format this string should be. + * @return YES if provided string fulfills the expected format, NO otherwise. + */ ++ (BOOL)validateAppIDFormat:(NSString *)appID withVersion:(NSString *)version { + if (!appID.length || !version.length) { + return NO; + } + + NSScanner *stringScanner = [NSScanner scannerWithString:appID]; + stringScanner.charactersToBeSkipped = nil; + + // Skip version part + // '**::ios:' + if (![stringScanner scanString:version intoString:NULL]) { + // The version part is missing or mismatched + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '*:*:ios:' + if (![stringScanner scanString:@":" intoString:NULL]) { + // appIDVersion must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // ':**:ios:'. + NSInteger projectNumber = NSNotFound; + if (![stringScanner scanInteger:&projectNumber]) { + // NO project number found. + return NO; + } + + // Validate version part (see part between '*' symbols below) + // ':*:*ios:'. + if (![stringScanner scanString:@":" intoString:NULL]) { + // The project number must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::*ios*:'. + NSString *platform; + if (![stringScanner scanUpToString:@":" intoString:&platform]) { + return NO; + } + + if (![platform isEqualToString:@"ios"]) { + // The platform must be @"ios" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::ios*:*'. + if (![stringScanner scanString:@":" intoString:NULL]) { + // The platform must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::ios:**'. + unsigned long long bundleIDHash = NSNotFound; + if (![stringScanner scanHexLongLong:&bundleIDHash]) { + // Hashed bundleID part is missing + return NO; + } + + if (!stringScanner.isAtEnd) { + // There are not allowed characters in the hashed bundle ID part + return NO; + } + + return YES; +} + +/** + * Validates that the hashed bundle ID included in the app ID string is what is expected based on + * the supplied version. + * + * Note that the v1 hash algorithm is not permitted on the client and cannot be fully validated. + * + * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param version Indicates what version of the app id format this string should be. + * @return YES if provided string fulfills the expected hashed bundle ID and the version is known, + * NO otherwise. + */ ++ (BOOL)validateBundleIDHashWithinAppID:(NSString *)appID forVersion:(NSString *)version { + // Extract the hashed bundle ID from the given app ID. + // This assumes the app ID format is the same for all known versions below. + // If the app ID format changes in future versions, the tokenizing of the app + // ID format will need to take into account the version of the app ID. + NSArray *components = [appID componentsSeparatedByString:@":"]; + if (components.count != 4) { + return NO; + } + + NSString *suppliedBundleIDHashString = components[3]; + if (!suppliedBundleIDHashString.length) { + return NO; + } + + uint64_t suppliedBundleIDHash; + NSScanner *scanner = [NSScanner scannerWithString:suppliedBundleIDHashString]; + if (![scanner scanHexLongLong:&suppliedBundleIDHash]) { + return NO; + } + + if ([version isEqual:@"1"]) { + // The v1 hash algorithm is not permitted on the client so the actual hash cannot be validated. + return YES; + } + + // Unknown version. + return NO; +} + +- (NSString *)expectedBundleID { + return _options.bundleID; +} + +// end App ID validation + +#pragma mark - Reading From Plist & User Defaults + +/** + * Clears the data collection switch from the standard NSUserDefaults for easier testing and + * readability. + */ +- (void)clearDataCollectionSwitchFromUserDefaults { + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:key]; +} + +/** + * Reads the data collection switch from the standard NSUserDefaults for easier testing and + * readability. + */ ++ (nullable NSNumber *)readDataCollectionSwitchFromUserDefaultsForApp:(FIRApp *)app { + // Read the object in user defaults, and only return if it's an NSNumber. + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, app.name]; + id collectionEnabledDefaultsObject = [[NSUserDefaults standardUserDefaults] objectForKey:key]; + if ([collectionEnabledDefaultsObject isKindOfClass:[NSNumber class]]) { + return collectionEnabledDefaultsObject; + } + + return nil; +} + +/** + * Reads the data collection switch from the Info.plist for easier testing and readability. Will + * only read once from the plist and return the cached value. + */ ++ (nullable NSNumber *)readDataCollectionSwitchFromPlist { + static NSNumber *collectionEnabledPlistObject; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Read the data from the `Info.plist`, only assign it if it's there and an NSNumber. + id plistValue = [[NSBundle mainBundle] + objectForInfoDictionaryKey:kFIRGlobalAppDataCollectionEnabledPlistKey]; + if (plistValue && [plistValue isKindOfClass:[NSNumber class]]) { + collectionEnabledPlistObject = (NSNumber *)plistValue; + } + }); + + return collectionEnabledPlistObject; +} + +#pragma mark - Swift Components. + ++ (void)registerSwiftComponents { + SEL componentsToRegisterSEL = @selector(componentsToRegister); + // Dictionary of class names that conform to `FIRLibrary` and their user agents. These should only + // be SDKs that are written in Swift but still visible to ObjC. + // This is only necessary for products that need to do work at launch during configuration. + NSDictionary *swiftComponents = @{ + @"FIRSessions" : @"fire-ses", + @"FIRAuthComponent" : @"fire-auth", + }; + for (NSString *className in swiftComponents.allKeys) { + Class klass = NSClassFromString(className); + if (klass && [klass respondsToSelector:componentsToRegisterSEL]) { + [FIRApp registerInternalLibrary:klass withName:swiftComponents[className]]; + } + } + + // Swift libraries that don't need component behaviour + NSDictionary *swiftLibraries = @{ + @"FIRCombineAuthLibrary" : @"comb-auth", + @"FIRCombineFirestoreLibrary" : @"comb-firestore", + @"FIRCombineFunctionsLibrary" : @"comb-functions", + @"FIRCombineStorageLibrary" : @"comb-storage", + @"FIRFunctions" : @"fire-fun", + @"FIRStorage" : @"fire-str", + @"FIRVertexAIComponent" : @"fire-vertex", + @"FIRDataConnectComponent" : @"fire-dc", + }; + for (NSString *className in swiftLibraries.allKeys) { + Class klass = NSClassFromString(className); + if (klass) { + NSString *version = FIRFirebaseVersion(); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" + SEL sdkVersionSelector = @selector(sdkVersion); +#pragma clang diagnostic pop + if ([klass respondsToSelector:sdkVersionSelector]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + NSString *sdkVersion = (NSString *)[klass performSelector:sdkVersionSelector]; + if (sdkVersion) version = sdkVersion; +#pragma clang diagnostic pop + } + [FIRApp registerLibrary:swiftLibraries[className] withVersion:version]; + } + } +} + +#pragma mark - App Life Cycle + +- (void)subscribeForAppDidBecomeActiveNotifications { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + NSNotificationName notificationName = UIApplicationDidBecomeActiveNotification; +#elif TARGET_OS_OSX + NSNotificationName notificationName = NSApplicationDidBecomeActiveNotification; +#elif TARGET_OS_WATCH + // TODO(ncooke3): Remove when minimum supported watchOS version is watchOS 7.0. + // On watchOS 7.0+, heartbeats are logged when the watch app becomes active. + // On watchOS 6.0, heartbeats are logged when the Firebase app is configuring. + // While it does not cover all use cases, logging when the Firebase app is + // configuring is done because watchOS lifecycle notifications are a + // watchOS 7.0+ feature. + NSNotificationName notificationName = kFIRAppReadyToConfigureSDKNotification; + if (@available(watchOS 7.0, *)) { + notificationName = WKApplicationDidBecomeActiveNotification; + } +#endif + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appDidBecomeActive:) + name:notificationName + object:nil]; +} + +- (void)appDidBecomeActive:(NSNotification *)notification { + if ([self isDataCollectionDefaultEnabled]) { + // If changing the below line, consult with the Games team to ensure they + // are not negatively impacted. For more details, see + // go/firebase-game-sdk-user-agent-register-timing. + [self.heartbeatLogger log]; + } +} + +#if DEBUG ++ (void)findMisnamedGoogleServiceInfoPlist { + for (NSBundle *bundle in [NSBundle allBundles]) { + // Not recursive, but we're looking for misnames, not people accidentally + // hiding their config file in a subdirectory of their bundle. + NSArray *plistPaths = [bundle pathsForResourcesOfType:@"plist" inDirectory:nil]; + for (NSString *path in plistPaths) { + @autoreleasepool { + NSDictionary *contents = [NSDictionary dictionaryWithContentsOfFile:path]; + if (contents == nil) { + continue; + } + + NSString *projectID = contents[@"PROJECT_ID"]; + if (projectID != nil) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"`FirebaseApp.configure()` could not find the default " + @"configuration plist in your project, but did find one at " + @"%@. Please rename this file to GoogleService-Info.plist to " + @"use it as the default configuration.", + path]; + } + } + } + } +} +#endif // DEBUG + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h new file mode 100644 index 0000000..d9475dd --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h @@ -0,0 +1,53 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * This class provides utilities for accessing resources in bundles. + */ +@interface FIRBundleUtil : NSObject + +/** + * Finds all relevant bundles, starting with [NSBundle mainBundle]. + */ ++ (NSArray *)relevantBundles; + +/** + * Reads the options dictionary from one of the provided bundles. + * + * @param resourceName The resource name, e.g. @"GoogleService-Info". + * @param fileType The file type (extension), e.g. @"plist". + * @param bundles The bundles to expect, in priority order. See also + * +[FIRBundleUtil relevantBundles]. + */ ++ (NSString *)optionsDictionaryPathWithResourceName:(NSString *)resourceName + andFileType:(NSString *)fileType + inBundles:(NSArray *)bundles; + +/** + * Finds URL schemes defined in all relevant bundles, starting with those from + * [NSBundle mainBundle]. + */ ++ (NSArray *)relevantURLSchemes; + +/** + * Checks if any of the given bundles have a matching bundle identifier prefix (removing extension + * suffixes). + */ ++ (BOOL)hasBundleIdentifierPrefix:(NSString *)bundleIdentifier inBundles:(NSArray *)bundles; + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m new file mode 100644 index 0000000..de2c295 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m @@ -0,0 +1,79 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Sources/FIRBundleUtil.h" + +#import + +@implementation FIRBundleUtil + ++ (NSArray *)relevantBundles { + return @[ [NSBundle mainBundle], [NSBundle bundleForClass:[self class]] ]; +} + ++ (NSString *)optionsDictionaryPathWithResourceName:(NSString *)resourceName + andFileType:(NSString *)fileType + inBundles:(NSArray *)bundles { + // Loop through all bundles to find the config dict. + for (NSBundle *bundle in bundles) { + NSString *path = [bundle pathForResource:resourceName ofType:fileType]; + // Use the first one we find. + if (path) { + return path; + } + } + return nil; +} + ++ (NSArray *)relevantURLSchemes { + NSMutableArray *result = [[NSMutableArray alloc] init]; + for (NSBundle *bundle in [[self class] relevantBundles]) { + NSArray *urlTypes = [bundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]; + for (NSDictionary *urlType in urlTypes) { + [result addObjectsFromArray:urlType[@"CFBundleURLSchemes"]]; + } + } + return result; +} + ++ (BOOL)hasBundleIdentifierPrefix:(NSString *)bundleIdentifier inBundles:(NSArray *)bundles { + for (NSBundle *bundle in bundles) { + if ([bundle.bundleIdentifier isEqualToString:bundleIdentifier]) { + return YES; + } + + if ([GULAppEnvironmentUtil isAppExtension]) { + // A developer could be using the same `FIROptions` for both their app and extension. Since + // extensions have a suffix added to the bundleID, we consider a matching prefix as valid. + NSString *appBundleIDFromExtension = + [self bundleIdentifierByRemovingLastPartFrom:bundle.bundleIdentifier]; + if ([appBundleIDFromExtension isEqualToString:bundleIdentifier]) { + return YES; + } + } + } + return NO; +} + ++ (NSString *)bundleIdentifierByRemovingLastPartFrom:(NSString *)bundleIdentifier { + NSString *bundleIDComponentsSeparator = @"."; + + NSMutableArray *bundleIDComponents = + [[bundleIdentifier componentsSeparatedByString:bundleIDComponentsSeparator] mutableCopy]; + [bundleIDComponents removeLastObject]; + + return [bundleIDComponents componentsJoinedByString:bundleIDComponentsSeparator]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m new file mode 100644 index 0000000..78c06ff --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m @@ -0,0 +1,58 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Extension/FIRComponent.h" + +#import "FirebaseCore/Extension/FIRComponentContainer.h" + +@interface FIRComponent () + +- (instancetype)initWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock; + +@end + +@implementation FIRComponent + ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock { + return [[FIRComponent alloc] initWithProtocol:protocol + instantiationTiming:FIRInstantiationTimingLazy + creationBlock:creationBlock]; +} + ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock { + return [[FIRComponent alloc] initWithProtocol:protocol + instantiationTiming:instantiationTiming + creationBlock:creationBlock]; +} + +- (instancetype)initWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock { + self = [super init]; + if (self) { + _protocol = protocol; + _instantiationTiming = instantiationTiming; + _creationBlock = creationBlock; + } + return self; +} + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m new file mode 100644 index 0000000..d4e4c7c --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m @@ -0,0 +1,252 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Extension/FIRComponentContainer.h" + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRComponent.h" +#import "FirebaseCore/Extension/FIRLibrary.h" +#import "FirebaseCore/Extension/FIRLogger.h" +#import "FirebaseCore/Sources/FIROptionsInternal.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRComponentContainer () + +/// The dictionary of components that are registered for a particular app. The key is an `NSString` +/// of the protocol. +@property(nonatomic, strong) NSMutableDictionary *components; + +/// Cached instances of components that requested to be cached. +@property(nonatomic, strong) NSMutableDictionary *cachedInstances; + +/// Protocols of components that have requested to be eagerly instantiated. +@property(nonatomic, strong, nullable) NSMutableArray *eagerProtocolsToInstantiate; + +@end + +@implementation FIRComponentContainer + +// Collection of all classes that register to provide components. +static NSMutableSet *sFIRComponentRegistrants; + +#pragma mark - Public Registration + ++ (void)registerAsComponentRegistrant:(Class)klass { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sFIRComponentRegistrants = [[NSMutableSet alloc] init]; + }); + + [self registerAsComponentRegistrant:klass inSet:sFIRComponentRegistrants]; +} + ++ (void)registerAsComponentRegistrant:(Class)klass + inSet:(NSMutableSet *)allRegistrants { + [allRegistrants addObject:klass]; +} + +#pragma mark - Internal Initialization + +- (instancetype)initWithApp:(FIRApp *)app { + NSMutableSet *componentRegistrants = sFIRComponentRegistrants; + // If the app being created is for the ARCore SDK, remove the App Check + // component (if it exists) since it does not support App Check. + if ([self isAppForARCore:app]) { + Class klass = NSClassFromString(@"FIRAppCheckComponent"); + if (klass && [sFIRComponentRegistrants containsObject:klass]) { + componentRegistrants = [componentRegistrants mutableCopy]; + [componentRegistrants removeObject:klass]; + } + } + + return [self initWithApp:app registrants:componentRegistrants]; +} + +- (instancetype)initWithApp:(FIRApp *)app registrants:(NSMutableSet *)allRegistrants { + self = [super init]; + if (self) { + _app = app; + _cachedInstances = [NSMutableDictionary dictionary]; + _components = [NSMutableDictionary dictionary]; + + [self populateComponentsFromRegisteredClasses:allRegistrants forApp:app]; + } + return self; +} + +- (void)populateComponentsFromRegisteredClasses:(NSSet *)classes forApp:(FIRApp *)app { + // Keep track of any components that need to eagerly instantiate after all components are added. + self.eagerProtocolsToInstantiate = [[NSMutableArray alloc] init]; + + // Loop through the verified component registrants and populate the components array. + for (Class klass in classes) { + // Loop through all the components being registered and store them as appropriate. + // Classes which do not provide functionality should use a dummy FIRComponentRegistrant + // protocol. + for (FIRComponent *component in [klass componentsToRegister]) { + // Check if the component has been registered before, and error out if so. + NSString *protocolName = NSStringFromProtocol(component.protocol); + if (self.components[protocolName]) { + FIRLogError(kFIRLoggerCore, @"I-COR000029", + @"Attempted to register protocol %@, but it already has an implementation.", + protocolName); + continue; + } + + // Store the creation block for later usage. + self.components[protocolName] = component.creationBlock; + + // Queue any protocols that should be eagerly instantiated. Don't instantiate them yet + // because they could depend on other components that haven't been added to the components + // array yet. + BOOL shouldInstantiateEager = + (component.instantiationTiming == FIRInstantiationTimingAlwaysEager); + BOOL shouldInstantiateDefaultEager = + (component.instantiationTiming == FIRInstantiationTimingEagerInDefaultApp && + [app isDefaultApp]); + if (shouldInstantiateEager || shouldInstantiateDefaultEager) { + [self.eagerProtocolsToInstantiate addObject:component.protocol]; + } + } + } +} + +#pragma mark - Instance Creation + +- (void)instantiateEagerComponents { + // After all components are registered, instantiate the ones that are requesting eager + // instantiation. + @synchronized(self) { + for (Protocol *protocol in self.eagerProtocolsToInstantiate) { + // Get an instance for the protocol, which will instantiate it since it couldn't have been + // cached yet. Ignore the instance coming back since we don't need it. + __unused id unusedInstance = [self instanceForProtocol:protocol]; + } + + // All eager instantiation is complete, clear the stored property now. + self.eagerProtocolsToInstantiate = nil; + } +} + +/// Instantiate an instance of a class that conforms to the specified protocol. +/// This will: +/// - Call the block to create an instance if possible, +/// - Validate that the instance returned conforms to the protocol it claims to, +/// - Cache the instance if the block requests it +/// +/// Note that this method assumes the caller already has @synchronized on self. +- (nullable id)instantiateInstanceForProtocol:(Protocol *)protocol + withBlock:(FIRComponentCreationBlock)creationBlock { + if (!creationBlock) { + return nil; + } + + // Create an instance using the creation block. + BOOL shouldCache = NO; + id instance = creationBlock(self, &shouldCache); + if (!instance) { + return nil; + } + + // An instance was created, validate that it conforms to the protocol it claims to. + NSString *protocolName = NSStringFromProtocol(protocol); + if (![instance conformsToProtocol:protocol]) { + FIRLogError(kFIRLoggerCore, @"I-COR000030", + @"An instance conforming to %@ was requested, but the instance provided does not " + @"conform to the protocol", + protocolName); + } + + // The instance is ready to be returned, but check if it should be cached first before returning. + if (shouldCache) { + self.cachedInstances[protocolName] = instance; + } + + return instance; +} + +#pragma mark - Internal Retrieval + +// Redirected for Swift users. +- (nullable id)__instanceForProtocol:(Protocol *)protocol { + return [self instanceForProtocol:protocol]; +} + +- (nullable id)instanceForProtocol:(Protocol *)protocol { + // Check if there is a cached instance, and return it if so. + NSString *protocolName = NSStringFromProtocol(protocol); + + id cachedInstance; + @synchronized(self) { + cachedInstance = self.cachedInstances[protocolName]; + if (!cachedInstance) { + // Use the creation block to instantiate an instance and return it. + FIRComponentCreationBlock creationBlock = self.components[protocolName]; + cachedInstance = [self instantiateInstanceForProtocol:protocol withBlock:creationBlock]; + } + } + return cachedInstance; +} + +#pragma mark - Lifecycle + +- (void)removeAllCachedInstances { + @synchronized(self) { + // Loop through the cache and notify each instance that is a maintainer to clean up after + // itself. + for (id instance in self.cachedInstances.allValues) { + if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] && + [instance respondsToSelector:@selector(appWillBeDeleted:)]) { + [instance appWillBeDeleted:self.app]; + } + } + + // Empty the cache. + [self.cachedInstances removeAllObjects]; + } +} + +- (void)removeAllComponents { + @synchronized(self) { + [self.components removeAllObjects]; + } +} + +#pragma mark - Helpers + +- (BOOL)isAppForARCore:(FIRApp *)app { + // First, check if the app name matches that of the one used by ARCore. + if ([app.name isEqualToString:@"ARCoreFIRApp"]) { + // Second, check if the app's gcmSenderID matches that of ARCore. This + // prevents false positives in the unlikely event a 3P Firebase app is + // named `ARCoreFIRApp`. + const char *p1 = "406756"; + const char *p2 = "893798"; + const char gcmSenderIDKey[27] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], + p2[3], p1[4], p2[4], p1[5], p2[5], p1[6], p2[6], + p1[7], p2[7], p1[8], p2[8], p1[9], p2[9], p1[10], + p2[10], p1[11], p2[11], p1[12], p2[12], '\0'}; + NSString *gcmSenderID = [NSString stringWithUTF8String:gcmSenderIDKey]; + return [app.options.GCMSenderID isEqualToString:gcmSenderID]; + } + return NO; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h new file mode 100644 index 0000000..169e181 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h @@ -0,0 +1,50 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +#import "FirebaseCore/Extension/FIRComponentContainer.h" +#import "FirebaseCore/Extension/FIRLibrary.h" + +@class FIRApp; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRComponentContainer (Private) + +/// Initializes a container for a given app. This should only be called by the app itself. +- (instancetype)initWithApp:(FIRApp *)app; + +/// Retrieves an instance that conforms to the specified protocol. This will return `nil` if the +/// protocol wasn't registered, or if the instance couldn't be instantiated for the provided app. +- (nullable id)instanceForProtocol:(Protocol *)protocol + NS_SWIFT_UNAVAILABLE("Use `instance(for:)` from the FirebaseCoreExtension module instead."); + +/// Instantiates all the components that have registered as "eager" after initialization. +- (void)instantiateEagerComponents; + +/// Remove all of the cached instances stored and allow them to clean up after themselves. +- (void)removeAllCachedInstances; + +/// Removes all the components. After calling this method no new instances will be created. +- (void)removeAllComponents; + +/// Register a class to provide components for the interoperability system. The class should conform +/// to `FIRComponentRegistrant` and provide an array of `FIRComponent` objects. ++ (void)registerAsComponentRegistrant:(Class)klass; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m new file mode 100644 index 0000000..2204fd6 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m @@ -0,0 +1,29 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Extension/FIRComponentType.h" + +#import "FirebaseCore/Sources/FIRComponentContainerInternal.h" + +@implementation FIRComponentType + ++ (nullable id)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container { + // Forward the call to the container. + return [container instanceForProtocol:protocol]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m new file mode 100644 index 0000000..8a646bd --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m @@ -0,0 +1,55 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Sources/FIRConfigurationInternal.h" + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" + +extern void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); +extern FIRLoggerLevel FIRGetLoggerLevel(void); + +@implementation FIRConfiguration + ++ (instancetype)sharedInstance { + static FIRConfiguration *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRConfiguration alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _analyticsConfiguration = [FIRAnalyticsConfiguration sharedInstance]; + } + return self; +} + +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel { + NSAssert(loggerLevel <= FIRLoggerLevelMax && loggerLevel >= FIRLoggerLevelMin, + @"Invalid logger level, %ld", (long)loggerLevel); + @synchronized(self) { + FIRSetLoggerLevel(loggerLevel); + } +} + +- (FIRLoggerLevel)loggerLevel { + @synchronized(self) { + return FIRGetLoggerLevel(); + } +} + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h new file mode 100644 index 0000000..9361e73 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h" + +@class FIRAnalyticsConfiguration; + +@interface FIRConfiguration () + +/** + * The configuration class for Firebase Analytics. This should be removed once the logic for + * enabling and disabling Analytics is moved to Analytics. + */ +@property(nonatomic, readwrite) FIRAnalyticsConfiguration *analyticsConfiguration; + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h new file mode 100644 index 0000000..ffb11fb --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFirebaseUserAgent : NSObject + +/** Returns the firebase user agent which consists of environment part and the components added via + * `setValue:forComponent` method. */ +- (NSString *)firebaseUserAgent; + +/** Sets value associated with the specified component. If value is `nil` then the component is + * removed. */ +- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName; + +/** Resets manually added components. */ +- (void)reset; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m new file mode 100644 index 0000000..04e7566 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m @@ -0,0 +1,107 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/FIRFirebaseUserAgent.h" + +#import + +@interface FIRFirebaseUserAgent () + +@property(nonatomic, readonly) NSMutableDictionary *valuesByComponent; +@property(nonatomic, readonly) NSDictionary *environmentComponents; +@property(nonatomic, readonly) NSString *firebaseUserAgent; + +@end + +@implementation FIRFirebaseUserAgent + +@synthesize firebaseUserAgent = _firebaseUserAgent; +@synthesize environmentComponents = _environmentComponents; + +- (instancetype)init { + self = [super init]; + if (self) { + _valuesByComponent = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSString *)firebaseUserAgent { + @synchronized(self) { + if (_firebaseUserAgent == nil) { + NSMutableDictionary *allComponents = + [self.valuesByComponent mutableCopy]; + [allComponents setValuesForKeysWithDictionary:self.environmentComponents]; + + __block NSMutableArray *components = + [[NSMutableArray alloc] initWithCapacity:self.valuesByComponent.count]; + [allComponents enumerateKeysAndObjectsUsingBlock:^( + NSString *_Nonnull name, NSString *_Nonnull value, BOOL *_Nonnull stop) { + [components addObject:[NSString stringWithFormat:@"%@/%@", name, value]]; + }]; + [components sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + _firebaseUserAgent = [components componentsJoinedByString:@" "]; + } + return _firebaseUserAgent; + } +} + +- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName { + @synchronized(self) { + self.valuesByComponent[componentName] = value; + // Reset cached user agent string. + _firebaseUserAgent = nil; + } +} + +- (void)reset { + @synchronized(self) { + // Reset components. + _valuesByComponent = [[[self class] environmentComponents] mutableCopy]; + // Reset cached user agent string. + _firebaseUserAgent = nil; + } +} + +#pragma mark - Environment components + +- (NSDictionary *)environmentComponents { + if (_environmentComponents == nil) { + _environmentComponents = [[self class] environmentComponents]; + } + return _environmentComponents; +} + ++ (NSDictionary *)environmentComponents { + NSMutableDictionary *components = [NSMutableDictionary dictionary]; + + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + NSString *xcodeVersion = info[@"DTXcodeBuild"]; + NSString *appleSdkVersion = info[@"DTSDKBuild"]; + NSString *isFromAppstoreFlagValue = [GULAppEnvironmentUtil isFromAppStore] ? @"true" : @"false"; + + components[@"apple-platform"] = [GULAppEnvironmentUtil applePlatform]; + components[@"apple-sdk"] = appleSdkVersion; + components[@"appstore"] = isFromAppstoreFlagValue; + components[@"deploy"] = [GULAppEnvironmentUtil deploymentType]; + components[@"device"] = [GULAppEnvironmentUtil deviceModel]; + components[@"os-version"] = [GULAppEnvironmentUtil systemVersion]; + components[@"xcode"] = xcodeVersion; + + return [components copy]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatLogger.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatLogger.m new file mode 100644 index 0000000..4becd08 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatLogger.m @@ -0,0 +1,112 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#ifndef FIREBASE_BUILD_CMAKE +@import FirebaseCoreInternal; +#endif // FIREBASE_BUILD_CMAKE + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRHeartbeatLogger.h" + +#ifndef FIREBASE_BUILD_CMAKE +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload) { + if ([heartbeatsPayload isEmpty]) { + return nil; + } + + return [heartbeatsPayload headerValue]; +} +#endif // FIREBASE_BUILD_CMAKE + +@interface FIRHeartbeatLogger () +#ifndef FIREBASE_BUILD_CMAKE +@property(nonatomic, readonly) FIRHeartbeatController *heartbeatController; +#endif // FIREBASE_BUILD_CMAKE +@property(copy, readonly) NSString * (^userAgentProvider)(void); +@end + +@implementation FIRHeartbeatLogger + +- (instancetype)initWithAppID:(NSString *)appID { + return [self initWithAppID:appID userAgentProvider:[[self class] currentUserAgentProvider]]; +} + +- (instancetype)initWithAppID:(NSString *)appID + userAgentProvider:(NSString * (^)(void))userAgentProvider { + self = [super init]; + if (self) { +#ifndef FIREBASE_BUILD_CMAKE + _heartbeatController = [[FIRHeartbeatController alloc] initWithId:[appID copy]]; +#endif // FIREBASE_BUILD_CMAKE + _userAgentProvider = [userAgentProvider copy]; + } + return self; +} + ++ (NSString * (^)(void))currentUserAgentProvider { + return ^NSString * { + return [FIRApp firebaseUserAgent]; + }; +} + +- (void)log { + NSString *userAgent = _userAgentProvider(); +#ifndef FIREBASE_BUILD_CMAKE + [_heartbeatController log:userAgent]; +#endif // FIREBASE_BUILD_CMAKE +} + +#ifndef FIREBASE_BUILD_CMAKE +- (NSString *_Nullable)headerValue { + return FIRHeaderValueFromHeartbeatsPayload([self flushHeartbeatsIntoPayload]); +} + +- (void)asyncHeaderValueWithCompletionHandler:(void (^)(NSString *_Nullable))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)) { + [self flushHeartbeatsIntoPayloadWithCompletionHandler:^(FIRHeartbeatsPayload *payload) { + completionHandler(FIRHeaderValueFromHeartbeatsPayload(payload)); + }]; +} + +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload { + FIRHeartbeatsPayload *payload = [_heartbeatController flush]; + return payload; +} + +- (void)flushHeartbeatsIntoPayloadWithCompletionHandler: + (void (^)(FIRHeartbeatsPayload *))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)) { + [_heartbeatController flushAsyncWithCompletionHandler:^(FIRHeartbeatsPayload *payload) { + completionHandler(payload); + }]; +} +#endif // FIREBASE_BUILD_CMAKE + +- (FIRDailyHeartbeatCode)heartbeatCodeForToday { +#ifndef FIREBASE_BUILD_CMAKE + FIRHeartbeatsPayload *todaysHeartbeatPayload = [_heartbeatController flushHeartbeatFromToday]; + + if ([todaysHeartbeatPayload isEmpty]) { + return FIRDailyHeartbeatCodeNone; + } else { + return FIRDailyHeartbeatCodeSome; + } +#else + return FIRDailyHeartbeatCodeNone; +#endif // FIREBASE_BUILD_CMAKE +} + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m new file mode 100644 index 0000000..9ec8999 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m @@ -0,0 +1,222 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Extension/FIRLogger.h" + +#import +#import +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h" + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +NSString *const kFIRLoggerSubsystem = @"com.google.firebase"; + +NSString *const kFIRLoggerCore = @"[FirebaseCore]"; + +// All the FIRLoggerService definitions should be migrated to clients. Do not add new ones! +NSString *const kFIRLoggerAnalytics = @"[FirebaseAnalytics]"; +NSString *const kFIRLoggerCrash = @"[FirebaseCrash]"; +NSString *const kFIRLoggerRemoteConfig = @"[FirebaseRemoteConfig]"; + +/// Arguments passed on launch. +NSString *const kFIRDisableDebugModeApplicationArgument = @"-FIRDebugDisabled"; +NSString *const kFIREnableDebugModeApplicationArgument = @"-FIRDebugEnabled"; + +/// Key for the debug mode bit in NSUserDefaults. +NSString *const kFIRPersistedDebugModeKey = @"/google/firebase/debug_mode"; + +/// NSUserDefaults that should be used to store and read variables. If nil, `standardUserDefaults` +/// will be used. +static NSUserDefaults *sFIRLoggerUserDefaults; + +static dispatch_once_t sFIRLoggerOnceToken; + +// The sFIRAnalyticsDebugMode flag is here to support the -FIRDebugEnabled/-FIRDebugDisabled +// flags used by Analytics. Users who use those flags expect Analytics to log verbosely, +// while the rest of Firebase logs at the default level. This flag is introduced to support +// that behavior. +static BOOL sFIRAnalyticsDebugMode; + +#ifdef DEBUG +/// The regex pattern for the message code. +static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$"; +static NSRegularExpression *sMessageCodeRegex; +#endif + +void FIRLoggerInitialize(void) { + dispatch_once(&sFIRLoggerOnceToken, ^{ + // Register Firebase Version with GULLogger. + GULLoggerRegisterVersion(FIRFirebaseVersion()); + + NSArray *arguments = [NSProcessInfo processInfo].arguments; + + // Use the standard NSUserDefaults if it hasn't been explicitly set. + if (sFIRLoggerUserDefaults == nil) { + sFIRLoggerUserDefaults = [NSUserDefaults standardUserDefaults]; + } + + BOOL forceDebugMode = NO; + BOOL debugMode = [sFIRLoggerUserDefaults boolForKey:kFIRPersistedDebugModeKey]; + if ([arguments containsObject:kFIRDisableDebugModeApplicationArgument]) { // Default mode + [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; + } else if ([arguments containsObject:kFIREnableDebugModeApplicationArgument] || + debugMode) { // Debug mode + [sFIRLoggerUserDefaults setBool:YES forKey:kFIRPersistedDebugModeKey]; + forceDebugMode = YES; + } + GULLoggerInitialize(); + if (forceDebugMode) { + GULLoggerForceDebug(); + } + }); +} + +__attribute__((no_sanitize("thread"))) void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode) { + sFIRAnalyticsDebugMode = analyticsDebugMode; +} + +FIRLoggerLevel FIRGetLoggerLevel(void) { + FIRLoggerInitialize(); + return (FIRLoggerLevel)GULGetLoggerLevel(); +} + +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel) { + FIRLoggerInitialize(); + GULSetLoggerLevel((GULLoggerLevel)loggerLevel); +} + +void FIRSetLoggerLevelNotice(void) { + FIRLoggerInitialize(); + GULSetLoggerLevel(GULLoggerLevelNotice); +} + +void FIRSetLoggerLevelWarning(void) { + FIRLoggerInitialize(); + GULSetLoggerLevel(GULLoggerLevelWarning); +} + +void FIRSetLoggerLevelError(void) { + FIRLoggerInitialize(); + GULSetLoggerLevel(GULLoggerLevelError); +} + +void FIRSetLoggerLevelDebug(void) { + FIRLoggerInitialize(); + GULSetLoggerLevel(GULLoggerLevelDebug); +} + +#ifdef DEBUG +void FIRResetLogger(void) { + extern void GULResetLogger(void); + sFIRLoggerOnceToken = 0; + [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; + sFIRLoggerUserDefaults = nil; + GULResetLogger(); +} + +void FIRSetLoggerUserDefaults(NSUserDefaults *defaults) { + sFIRLoggerUserDefaults = defaults; +} +#endif + +/** + * Check if the level is high enough to be loggable. + * + * Analytics can override the log level with an intentional race condition. + * Add the attribute to get a clean thread sanitizer run. + */ +__attribute__((no_sanitize("thread"))) BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, + BOOL analyticsComponent) { + FIRLoggerInitialize(); + if (sFIRAnalyticsDebugMode && analyticsComponent) { + return YES; + } + return GULIsLoggableLevel((GULLoggerLevel)loggerLevel); +} + +BOOL FIRIsLoggableLevelNotice(void) { + return FIRIsLoggableLevel(FIRLoggerLevelNotice, NO); +} + +BOOL FIRIsLoggableLevelWarning(void) { + return FIRIsLoggableLevel(FIRLoggerLevelWarning, NO); +} + +BOOL FIRIsLoggableLevelError(void) { + return FIRIsLoggableLevel(FIRLoggerLevelError, NO); +} + +BOOL FIRIsLoggableLevelDebug(void) { + return FIRIsLoggableLevel(FIRLoggerLevelDebug, NO); +} + +void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr) { + FIRLoggerInitialize(); + GULOSLogBasic((GULLoggerLevel)level, kFIRLoggerSubsystem, category, + sFIRAnalyticsDebugMode && [kFIRLoggerAnalytics isEqualToString:category], + messageCode, message, args_ptr); +} + +#define FIR_LOGGING_FUNCTION_BASIC(level) \ + void FIRLogBasic##level(NSString *category, NSString *messageCode, NSString *message, \ + va_list args_ptr) { \ + FIRLogBasic(FIRLoggerLevel##level, category, messageCode, message, args_ptr); \ + } + +FIR_LOGGING_FUNCTION_BASIC(Error) +FIR_LOGGING_FUNCTION_BASIC(Warning) +FIR_LOGGING_FUNCTION_BASIC(Notice) +FIR_LOGGING_FUNCTION_BASIC(Info) +FIR_LOGGING_FUNCTION_BASIC(Debug) + +/** + * Generates the logging functions using macros. + * + * Calling FIRLogError(kFIRLoggerCore, @"I-COR000001", @"Configure %@ failed.", @"blah") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [Firebase/Core][I-COR000001] Configure blah failed. + * Calling FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configure succeed.") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [Firebase/Core][I-COR000001] Configure succeed. + */ +#define FIR_LOGGING_FUNCTION(level) \ + void FIRLog##level(NSString *category, NSString *messageCode, NSString *message, ...) { \ + va_list args_ptr; \ + va_start(args_ptr, message); \ + FIRLogBasic(FIRLoggerLevel##level, category, messageCode, message, args_ptr); \ + va_end(args_ptr); \ + } + +FIR_LOGGING_FUNCTION(Error) +FIR_LOGGING_FUNCTION(Warning) +FIR_LOGGING_FUNCTION(Notice) +FIR_LOGGING_FUNCTION(Info) +FIR_LOGGING_FUNCTION(Debug) + +#undef FIR_LOGGING_FUNCTION + +#pragma mark - FIRLoggerWrapper + +@implementation FIRLoggerWrapper + ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)service + code:(NSString *)code + message:(NSString *)message { + FIRLogBasic(level, service, code, message, NULL); +} + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m new file mode 100644 index 0000000..16fdb6f --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m @@ -0,0 +1,487 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRLogger.h" +#import "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/FIROptionsInternal.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +// Keys for the strings in the plist file. +NSString *const kFIRAPIKey = @"API_KEY"; +NSString *const kFIRTrackingID = @"TRACKING_ID"; +NSString *const kFIRGoogleAppID = @"GOOGLE_APP_ID"; +NSString *const kFIRClientID = @"CLIENT_ID"; +NSString *const kFIRGCMSenderID = @"GCM_SENDER_ID"; +NSString *const kFIRAndroidClientID = @"ANDROID_CLIENT_ID"; +NSString *const kFIRDatabaseURL = @"DATABASE_URL"; +NSString *const kFIRStorageBucket = @"STORAGE_BUCKET"; +// The key to locate the expected bundle identifier in the plist file. +NSString *const kFIRBundleID = @"BUNDLE_ID"; +// The key to locate the project identifier in the plist file. +NSString *const kFIRProjectID = @"PROJECT_ID"; + +NSString *const kFIRIsMeasurementEnabled = @"IS_MEASUREMENT_ENABLED"; +NSString *const kFIRIsAnalyticsCollectionEnabled = @"FIREBASE_ANALYTICS_COLLECTION_ENABLED"; +NSString *const kFIRIsAnalyticsCollectionDeactivated = @"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED"; + +// Library version ID formatted like: +// @"5" // Major version (one or more digits) +// @"04" // Minor version (exactly 2 digits) +// @"01" // Build number (exactly 2 digits) +// @"000"; // Fixed "000" +NSString *kFIRLibraryVersionID; + +// Plist file name. +NSString *const kServiceInfoFileName = @"GoogleService-Info"; +// Plist file type. +NSString *const kServiceInfoFileType = @"plist"; + +// Exception raised from attempting to modify a FIROptions after it's been copied to a FIRApp. +NSString *const kFIRExceptionBadModification = + @"Attempted to modify options after it's set on FIRApp. Please modify all properties before " + @"initializing FIRApp."; + +@interface FIROptions () + +/** + * This property maintains the actual configuration key-value pairs. + */ +@property(nonatomic, readwrite) NSMutableDictionary *optionsDictionary; + +/** + * Calls `analyticsOptionsDictionaryWithInfoDictionary:` using [NSBundle mainBundle].infoDictionary. + * It combines analytics options from both the infoDictionary and the GoogleService-Info.plist. + * Values which are present in the main plist override values from the GoogleService-Info.plist. + */ +@property(nonatomic, readonly) NSDictionary *analyticsOptionsDictionary; + +/** + * Combination of analytics options from both the infoDictionary and the GoogleService-Info.plist. + * Values which are present in the infoDictionary override values from the GoogleService-Info.plist. + */ +- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary; + +/** + * Throw exception if editing is locked when attempting to modify an option. + */ +- (void)checkEditingLocked; + +@end + +@implementation FIROptions { + /// Backing variable for self.analyticsOptionsDictionary. + NSDictionary *_analyticsOptionsDictionary; +} + +static FIROptions *sDefaultOptions = nil; +static NSDictionary *sDefaultOptionsDictionary = nil; +static dispatch_once_t sDefaultOptionsOnceToken; +static dispatch_once_t sDefaultOptionsDictionaryOnceToken; + +#pragma mark - Public only for internal class methods + ++ (FIROptions *)defaultOptions { + dispatch_once(&sDefaultOptionsOnceToken, ^{ + NSDictionary *defaultOptionsDictionary = [self defaultOptionsDictionary]; + if (defaultOptionsDictionary != nil) { + sDefaultOptions = + [[FIROptions alloc] initInternalWithOptionsDictionary:defaultOptionsDictionary]; + } + }); + + return sDefaultOptions; +} + +#pragma mark - Private class methods + ++ (NSDictionary *)defaultOptionsDictionary { + dispatch_once(&sDefaultOptionsDictionaryOnceToken, ^{ + NSString *plistFilePath = [FIROptions plistFilePathWithName:kServiceInfoFileName]; + if (plistFilePath == nil) { + return; + } + sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath]; + if (sDefaultOptionsDictionary == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000011", + @"The configuration file is not a dictionary: " + @"'%@.%@'.", + kServiceInfoFileName, kServiceInfoFileType); + } + }); + + return sDefaultOptionsDictionary; +} + +// Returns the path of the plist file with a given file name. ++ (NSString *)plistFilePathWithName:(NSString *)fileName { + NSArray *bundles = [FIRBundleUtil relevantBundles]; + NSString *plistFilePath = + [FIRBundleUtil optionsDictionaryPathWithResourceName:fileName + andFileType:kServiceInfoFileType + inBundles:bundles]; + if (plistFilePath == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000012", @"Could not locate configuration file: '%@.%@'.", + fileName, kServiceInfoFileType); + } + return plistFilePath; +} + ++ (void)resetDefaultOptions { + sDefaultOptions = nil; + sDefaultOptionsDictionary = nil; + sDefaultOptionsOnceToken = 0; + sDefaultOptionsDictionaryOnceToken = 0; +} + +#pragma mark - Private instance methods + +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)optionsDictionary { + self = [super init]; + if (self) { + _optionsDictionary = [optionsDictionary mutableCopy]; + _usingOptionsFromDefaultPlist = YES; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + FIROptions *newOptions = [(FIROptions *)[[self class] allocWithZone:zone] + initInternalWithOptionsDictionary:self.optionsDictionary]; + if (newOptions) { + newOptions->_deepLinkURLScheme = self->_deepLinkURLScheme; + newOptions.appGroupID = self.appGroupID; + newOptions.editingLocked = self.isEditingLocked; + newOptions.usingOptionsFromDefaultPlist = self.usingOptionsFromDefaultPlist; + } + return newOptions; +} + +#pragma mark - Public instance methods + +- (instancetype)init { + // Unavailable. + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (instancetype)initWithContentsOfFile:(NSString *)plistPath { + self = [super init]; + if (self) { + if (plistPath == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000013", @"The plist file path is nil."); + return nil; + } + _optionsDictionary = [[NSDictionary dictionaryWithContentsOfFile:plistPath] mutableCopy]; + if (_optionsDictionary == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000014", + @"The configuration file at %@ does not exist or " + @"is not a well-formed plist file.", + plistPath); + return nil; + } + // TODO: Do we want to validate the dictionary here? It says we do that already in + // the public header. + } + return self; +} + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID GCMSenderID:(NSString *)GCMSenderID { + self = [super init]; + if (self) { + NSMutableDictionary *mutableOptionsDict = [NSMutableDictionary dictionary]; + [mutableOptionsDict setValue:googleAppID forKey:kFIRGoogleAppID]; + [mutableOptionsDict setValue:GCMSenderID forKey:kFIRGCMSenderID]; + [mutableOptionsDict setValue:[[NSBundle mainBundle] bundleIdentifier] forKey:kFIRBundleID]; + self.optionsDictionary = mutableOptionsDict; + } + return self; +} + +- (NSString *)APIKey { + return self.optionsDictionary[kFIRAPIKey]; +} + +- (void)checkEditingLocked { + if (self.isEditingLocked) { + [NSException raise:kFirebaseCoreErrorDomain format:kFIRExceptionBadModification]; + } +} + +- (void)setAPIKey:(NSString *)APIKey { + [self checkEditingLocked]; + _optionsDictionary[kFIRAPIKey] = [APIKey copy]; +} + +- (NSString *)clientID { + return self.optionsDictionary[kFIRClientID]; +} + +- (void)setClientID:(NSString *)clientID { + [self checkEditingLocked]; + _optionsDictionary[kFIRClientID] = [clientID copy]; +} + +- (NSString *)trackingID { + return self.optionsDictionary[kFIRTrackingID]; +} + +- (void)setTrackingID:(NSString *)trackingID { + [self checkEditingLocked]; + _optionsDictionary[kFIRTrackingID] = [trackingID copy]; +} + +- (NSString *)GCMSenderID { + return self.optionsDictionary[kFIRGCMSenderID]; +} + +- (void)setGCMSenderID:(NSString *)GCMSenderID { + [self checkEditingLocked]; + _optionsDictionary[kFIRGCMSenderID] = [GCMSenderID copy]; +} + +- (NSString *)projectID { + return self.optionsDictionary[kFIRProjectID]; +} + +- (void)setProjectID:(NSString *)projectID { + [self checkEditingLocked]; + _optionsDictionary[kFIRProjectID] = [projectID copy]; +} + +- (NSString *)androidClientID { + return self.optionsDictionary[kFIRAndroidClientID]; +} + +- (void)setAndroidClientID:(NSString *)androidClientID { + [self checkEditingLocked]; + _optionsDictionary[kFIRAndroidClientID] = [androidClientID copy]; +} + +- (NSString *)googleAppID { + return self.optionsDictionary[kFIRGoogleAppID]; +} + +- (void)setGoogleAppID:(NSString *)googleAppID { + [self checkEditingLocked]; + _optionsDictionary[kFIRGoogleAppID] = [googleAppID copy]; +} + +- (NSString *)libraryVersionID { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // The unit tests are set up to catch anything that does not properly convert. + NSString *version = FIRFirebaseVersion(); + NSArray *components = [version componentsSeparatedByString:@"."]; + NSString *major = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:0] intValue]]; + NSString *minor = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:1] intValue]]; + NSString *patch = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:2] intValue]]; + kFIRLibraryVersionID = [NSString stringWithFormat:@"%@%@%@000", major, minor, patch]; + }); + return kFIRLibraryVersionID; +} + +- (void)setLibraryVersionID:(NSString *)libraryVersionID { + _optionsDictionary[kFIRLibraryVersionID] = [libraryVersionID copy]; +} + +- (NSString *)databaseURL { + return self.optionsDictionary[kFIRDatabaseURL]; +} + +- (void)setDatabaseURL:(NSString *)databaseURL { + [self checkEditingLocked]; + + _optionsDictionary[kFIRDatabaseURL] = [databaseURL copy]; +} + +- (NSString *)storageBucket { + return self.optionsDictionary[kFIRStorageBucket]; +} + +- (void)setStorageBucket:(NSString *)storageBucket { + [self checkEditingLocked]; + _optionsDictionary[kFIRStorageBucket] = [storageBucket copy]; +} + +- (void)setDeepLinkURLScheme:(NSString *)deepLinkURLScheme { + [self checkEditingLocked]; + _deepLinkURLScheme = [deepLinkURLScheme copy]; +} + +- (NSString *)bundleID { + return self.optionsDictionary[kFIRBundleID]; +} + +- (void)setBundleID:(NSString *)bundleID { + [self checkEditingLocked]; + _optionsDictionary[kFIRBundleID] = [bundleID copy]; +} + +- (void)setAppGroupID:(NSString *)appGroupID { + [self checkEditingLocked]; + _appGroupID = [appGroupID copy]; +} + +#pragma mark - Equality + +- (BOOL)isEqual:(id)object { + if (!object || ![object isKindOfClass:[FIROptions class]]) { + return NO; + } + + return [self isEqualToOptions:(FIROptions *)object]; +} + +- (BOOL)isEqualToOptions:(FIROptions *)options { + // Skip any non-FIROptions classes. + if (![options isKindOfClass:[FIROptions class]]) { + return NO; + } + + // Check the internal dictionary and custom properties for differences. + if (![options.optionsDictionary isEqualToDictionary:self.optionsDictionary]) { + return NO; + } + + // Validate extra properties not contained in the dictionary. Only validate it if one of the + // objects has the property set. + if ((options->_deepLinkURLScheme != nil || self->_deepLinkURLScheme != nil) && + ![options->_deepLinkURLScheme isEqualToString:self->_deepLinkURLScheme]) { + return NO; + } + + if ((options.appGroupID != nil || self.appGroupID != nil) && + ![options.appGroupID isEqualToString:self.appGroupID]) { + return NO; + } + + // Validate the Analytics options haven't changed with the Info.plist. + if (![options.analyticsOptionsDictionary isEqualToDictionary:self.analyticsOptionsDictionary]) { + return NO; + } + + // We don't care about the `editingLocked` or `usingOptionsFromDefaultPlist` properties since + // those relate to lifecycle and construction, we only care if the contents of the options + // themselves are equal. + return YES; +} + +- (NSUInteger)hash { + // This is strongly recommended for any object that implements a custom `isEqual:` method to + // ensure that dictionary and set behavior matches other `isEqual:` checks. + // Note: `self.analyticsOptionsDictionary` was left out here since it solely relies on the + // contents of the main bundle's `Info.plist`. We should avoid reading that file and the contents + // should be identical. + return self.optionsDictionary.hash ^ self->_deepLinkURLScheme.hash ^ self.appGroupID.hash; +} + +#pragma mark - Internal instance methods + +- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary { + if (_analyticsOptionsDictionary == nil) { + NSMutableDictionary *tempAnalyticsOptions = [[NSMutableDictionary alloc] init]; + NSArray *measurementKeys = @[ + kFIRIsMeasurementEnabled, kFIRIsAnalyticsCollectionEnabled, + kFIRIsAnalyticsCollectionDeactivated + ]; + for (NSString *key in measurementKeys) { + id value = infoDictionary[key] ?: self.optionsDictionary[key] ?: nil; + if (!value) { + continue; + } + tempAnalyticsOptions[key] = value; + } + _analyticsOptionsDictionary = tempAnalyticsOptions; + } + return _analyticsOptionsDictionary; +} + +- (NSDictionary *)analyticsOptionsDictionary { + return [self analyticsOptionsDictionaryWithInfoDictionary:[NSBundle mainBundle].infoDictionary]; +} + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. This uses the old plist flag IS_MEASUREMENT_ENABLED, which should still + * be supported. + */ +- (BOOL)isMeasurementEnabled { + if (self.isAnalyticsCollectionDeactivated) { + return NO; + } + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsMeasurementEnabled]; + if (value == nil) { + // TODO: This could probably be cleaned up since FIROptions shouldn't know about FIRApp or have + // to check if it's the default app. The FIROptions instance can't be modified after + // `+configure` is called, so it's not a good place to copy it either in case the flag is + // changed at runtime. + + // If no values are set for Analytics, fall back to the global collection switch in FIRApp. + // Analytics only supports the default FIRApp, so check that first. + if (![FIRApp isDefaultAppConfigured]) { + return NO; + } + + // Fall back to the default app's collection switch when the key is not in the dictionary. + return [FIRApp defaultApp].isDataCollectionDefaultEnabled; + } + return [value boolValue]; +} + +- (BOOL)isAnalyticsCollectionExplicitlySet { + // If it's de-activated, it classifies as explicitly set. If not, it's not a good enough + // indication that the developer wants FirebaseAnalytics enabled so continue checking. + if (self.isAnalyticsCollectionDeactivated) { + return YES; + } + + // Check if the current Analytics flag is set. + id collectionEnabledObject = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionEnabled]; + if (collectionEnabledObject && [collectionEnabledObject isKindOfClass:[NSNumber class]]) { + // It doesn't matter what the value is, it's explicitly set. + return YES; + } + + // Check if the old measurement flag is set. + id measurementEnabledObject = self.analyticsOptionsDictionary[kFIRIsMeasurementEnabled]; + if (measurementEnabledObject && [measurementEnabledObject isKindOfClass:[NSNumber class]]) { + // It doesn't matter what the value is, it's explicitly set. + return YES; + } + + // No flags are set to explicitly enable or disable FirebaseAnalytics. + return NO; +} + +- (BOOL)isAnalyticsCollectionEnabled { + if (self.isAnalyticsCollectionDeactivated) { + return NO; + } + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionEnabled]; + if (value == nil) { + return self.isMeasurementEnabled; // Fall back to older plist flag. + } + return [value boolValue]; +} + +- (BOOL)isAnalyticsCollectionDeactivated { + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionDeactivated]; + if (value == nil) { + return NO; // Analytics Collection is not deactivated when the key is not in the dictionary. + } + return [value boolValue]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIROptionsInternal.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIROptionsInternal.h new file mode 100644 index 0000000..8765614 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIROptionsInternal.h @@ -0,0 +1,85 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestamp.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestamp.m new file mode 100644 index 0000000..8db07ce --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestamp.m @@ -0,0 +1,152 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/FIRTimestampInternal.h" + +NS_ASSUME_NONNULL_BEGIN + +static const int kNanosPerSecond = 1000000000; + +@implementation FIRTimestamp (Internal) + +#pragma mark - Internal public methods + +- (NSString *)ISO8601String { + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss"; + formatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; + NSDate *secondsDate = [NSDate dateWithTimeIntervalSince1970:self.seconds]; + NSString *secondsString = [formatter stringFromDate:secondsDate]; + if (secondsString.length != 19) { + [NSException raise:@"Invalid ISO string" format:@"Invalid ISO string: %@", secondsString]; + } + + NSString *nanosString = [NSString stringWithFormat:@"%09d", self.nanoseconds]; + return [NSString stringWithFormat:@"%@.%@Z", secondsString, nanosString]; +} + +@end + +@implementation FIRTimestamp + +#pragma mark - Constructors + ++ (instancetype)timestampWithDate:(NSDate *)date { + double secondsDouble; + double fraction = modf(date.timeIntervalSince1970, &secondsDouble); + // GCP Timestamps always have non-negative nanos. + if (fraction < 0) { + fraction += 1.0; + secondsDouble -= 1.0; + } + int64_t seconds = (int64_t)secondsDouble; + int32_t nanos = (int32_t)(fraction * kNanosPerSecond); + return [[FIRTimestamp alloc] initWithSeconds:seconds nanoseconds:nanos]; +} + ++ (instancetype)timestampWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds { + return [[FIRTimestamp alloc] initWithSeconds:seconds nanoseconds:nanoseconds]; +} + ++ (instancetype)timestamp { + return [FIRTimestamp timestampWithDate:[NSDate date]]; +} + +- (instancetype)initWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds { + self = [super init]; + if (self) { + if (nanoseconds < 0) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp nanoseconds out of range: %d", nanoseconds]; + } + if (nanoseconds >= 1e9) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp nanoseconds out of range: %d", nanoseconds]; + } + // Midnight at the beginning of 1/1/1 is the earliest timestamp supported. + if (seconds < -62135596800L) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp seconds out of range: %lld", seconds]; + } + // This will break in the year 10,000. + if (seconds >= 253402300800L) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp seconds out of range: %lld", seconds]; + } + + _seconds = seconds; + _nanoseconds = nanoseconds; + } + return self; +} + +#pragma mark - NSObject methods + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FIRTimestamp class]]) { + return NO; + } + return [self isEqualToTimestamp:(FIRTimestamp *)object]; +} + +- (NSUInteger)hash { + return (NSUInteger)((self.seconds >> 32) ^ self.seconds ^ self.nanoseconds); +} + +- (NSString *)description { + return [NSString stringWithFormat:@"", self.seconds, + self.nanoseconds]; +} + +/** Implements NSCopying without actually copying because timestamps are immutable. */ +- (id)copyWithZone:(__unused NSZone *_Nullable)zone { + return self; +} + +#pragma mark - Public methods + +- (NSDate *)dateValue { + NSTimeInterval interval = (NSTimeInterval)self.seconds + ((NSTimeInterval)self.nanoseconds) / 1e9; + return [NSDate dateWithTimeIntervalSince1970:interval]; +} + +- (NSComparisonResult)compare:(FIRTimestamp *)other { + if (self.seconds < other.seconds) { + return NSOrderedAscending; + } else if (self.seconds > other.seconds) { + return NSOrderedDescending; + } + + if (self.nanoseconds < other.nanoseconds) { + return NSOrderedAscending; + } else if (self.nanoseconds > other.nanoseconds) { + return NSOrderedDescending; + } + return NSOrderedSame; +} + +#pragma mark - Private methods + +- (BOOL)isEqualToTimestamp:(FIRTimestamp *)other { + return [self compare:other] == NSOrderedSame; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestampInternal.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestampInternal.h new file mode 100644 index 0000000..6261c63 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestampInternal.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Internal FIRTimestamp API we don't want exposed in our public header files. */ +@interface FIRTimestamp (Internal) + +/** + * Converts the given date to an ISO 8601 timestamp string, useful for rendering in JSON. + * + * ISO 8601 dates times in UTC look like this: "1912-04-14T23:40:00.000000000Z". + * + * @see http://www.ecma-international.org/ecma-262/6.0/#sec-date-time-string-format + */ +- (NSString *)ISO8601String; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m new file mode 100644 index 0000000..f458a3a --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +#ifndef Firebase_VERSION +#error "Firebase_VERSION is not defined: add -DFirebase_VERSION=... to the build invocation" +#endif + +// The following two macros supply the incantation so that the C +// preprocessor does not try to parse the version as a floating +// point number. See +// https://www.guyrutenberg.com/2008/12/20/expanding-macros-into-string-constants-in-c/ +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x + +NSString* FIRFirebaseVersion(void) { + return @STR(Firebase_VERSION); +} diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h new file mode 100644 index 0000000..58ef2a6 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h @@ -0,0 +1,129 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIROptions; + +NS_ASSUME_NONNULL_BEGIN + +/** A block that takes a BOOL and has no return value. */ +typedef void (^FIRAppVoidBoolCallback)(BOOL success) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * The entry point of Firebase SDKs. + * + * Initialize and configure `FirebaseApp` using `FirebaseApp.configure()` + * or other customized ways as shown below. + * + * The logging system has two modes: default mode and debug mode. In default mode, only logs with + * log level Notice, Warning and Error will be sent to device. In debug mode, all logs will be sent + * to device. The log levels that Firebase uses are consistent with the ASL log levels. + * + * Enable debug mode by passing the `-FIRDebugEnabled` argument to the application. You can add this + * argument in the application's Xcode scheme. When debug mode is enabled via `-FIRDebugEnabled`, + * further executions of the application will also be in debug mode. In order to return to default + * mode, you must explicitly disable the debug mode with the application argument + * `-FIRDebugDisabled`. + * + * It is also possible to change the default logging level in code by calling + * `FirebaseConfiguration.shared.setLoggerLevel(_:)` with the desired level. + */ +NS_SWIFT_NAME(FirebaseApp) +@interface FIRApp : NSObject + +/** + * Configures a default Firebase app. Raises an exception if any configuration step fails. The + * default app is named "__FIRAPP_DEFAULT". This method should be called after the app is launched + * and before using Firebase services. This method should be called from the main thread and + * contains synchronous file I/O (reading GoogleService-Info.plist from disk). + */ ++ (void)configure; + +/** + * Configures the default Firebase app with the provided options. The default app is named + * "__FIRAPP_DEFAULT". Raises an exception if any configuration step fails. This method should be + * called from the main thread. + * + * @param options The Firebase application options used to configure the service. + */ ++ (void)configureWithOptions:(FIROptions *)options NS_SWIFT_NAME(configure(options:)); + +/** + * Configures a Firebase app with the given name and options. Raises an exception if any + * configuration step fails. This method should be called from the main thread. + * + * @param name The application's name given by the developer. The name should should only contain + Letters, Numbers and Underscore. + * @param options The Firebase application options used to configure the services. + */ +// clang-format off ++ (void)configureWithName:(NSString *)name + options:(FIROptions *)options NS_SWIFT_NAME(configure(name:options:)); +// clang-format on + +/** + * Returns the default app, or `nil` if the default app does not exist. + */ ++ (nullable FIRApp *)defaultApp NS_SWIFT_NAME(app()); + +/** + * Returns a previously created `FirebaseApp` instance with the given name, or `nil` if no such app + * exists. This method is thread safe. + */ ++ (nullable FIRApp *)appNamed:(NSString *)name NS_SWIFT_NAME(app(name:)); + +/** + * Returns the set of all extant `FirebaseApp` instances, or `nil` if there are no `FirebaseApp` + * instances. This method is thread safe. + */ +@property(class, readonly, nullable) NSDictionary *allApps; + +/** + * Cleans up the current `FirebaseApp`, freeing associated data and returning its name to the pool + * for future use. This method is thread safe. + */ +- (void)deleteApp:(void (^)(BOOL success))completion; + +/** + * `FirebaseApp` instances should not be initialized directly. Call `FirebaseApp.configure()`, + * `FirebaseApp.configure(options:)`, or `FirebaseApp.configure(name:options:)` directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Gets the name of this app. + */ +@property(nonatomic, copy, readonly) NSString *name; + +/** + * Gets a copy of the options for this app. These are non-modifiable. + */ +@property(nonatomic, copy, readonly) FIROptions *options; + +/** + * Gets or sets whether automatic data collection is enabled for all products. Defaults to `true` + * unless `FirebaseDataCollectionDefaultEnabled` is set to `NO` in your app's Info.plist. This value + * is persisted across runs of the app so that it can be set once when users have consented to + * collection. + */ +@property(nonatomic, readwrite, getter=isDataCollectionDefaultEnabled) + BOOL dataCollectionDefaultEnabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h new file mode 100644 index 0000000..e6c1f1d --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRLoggerLevel.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * This interface provides global level properties that the developer can tweak. + */ +NS_SWIFT_NAME(FirebaseConfiguration) +@interface FIRConfiguration : NSObject + +/** Returns the shared configuration object. */ +@property(class, nonatomic, readonly) FIRConfiguration *sharedInstance NS_SWIFT_NAME(shared); + +/** + * Sets the logging level for internal Firebase logging. Firebase will only log messages + * that are logged at or below `loggerLevel`. The messages are logged both to the Xcode + * console and to the device's log. Note that if an app is running from AppStore, it will + * never log above `.notice` even if `loggerLevel` is set to a higher (more verbose) + * setting. + * + * @param loggerLevel The maximum logging level. The default level is set to FIRLoggerLevelNotice. + */ +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel; + +/// Returns the logging level for internal Firebase logging. +- (FIRLoggerLevel)loggerLevel; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h new file mode 100644 index 0000000..dca3aa0 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Note that importing GULLoggerLevel.h will lead to a non-modular header +// import error. + +/** + * The log levels used by internal logging. + */ +typedef NS_ENUM(NSInteger, FIRLoggerLevel) { + /** Error level, matches ASL_LEVEL_ERR. */ + FIRLoggerLevelError = 3, + /** Warning level, matches ASL_LEVEL_WARNING. */ + FIRLoggerLevelWarning = 4, + /** Notice level, matches ASL_LEVEL_NOTICE. */ + FIRLoggerLevelNotice = 5, + /** Info level, matches ASL_LEVEL_INFO. */ + FIRLoggerLevelInfo = 6, + /** Debug level, matches ASL_LEVEL_DEBUG. */ + FIRLoggerLevelDebug = 7, + /** Minimum log level. */ + FIRLoggerLevelMin = FIRLoggerLevelError, + /** Maximum log level. */ + FIRLoggerLevelMax = FIRLoggerLevelDebug +} NS_SWIFT_NAME(FirebaseLoggerLevel); diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h new file mode 100644 index 0000000..db1570a --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h @@ -0,0 +1,131 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class provides constant fields of Google APIs. + */ +NS_SWIFT_NAME(FirebaseOptions) +@interface FIROptions : NSObject + +/** + * Returns the default options. The first time this is called it synchronously reads + * GoogleService-Info.plist from disk. + */ ++ (nullable FIROptions *)defaultOptions NS_SWIFT_NAME(defaultOptions()); + +/** + * An API key used for authenticating requests from your Apple app, e.g. + * The key must begin with "A" and contain exactly 39 alphanumeric characters, used to identify your + * app to Google servers. + */ +@property(nonatomic, copy, nullable) NSString *APIKey NS_SWIFT_NAME(apiKey); + +/** + * The bundle ID for the application. Defaults to `Bundle.main.bundleIdentifier` when not set + * manually or in a plist. + */ +@property(nonatomic, copy) NSString *bundleID; + +/** + * The OAuth2 client ID for Apple applications used to authenticate Google users, for example + * @"12345.apps.googleusercontent.com", used for signing in with Google. + */ +@property(nonatomic, copy, nullable) NSString *clientID; + +/** + * Unused. + */ +@property(nonatomic, copy, nullable) NSString *trackingID DEPRECATED_ATTRIBUTE; + +/** + * The Project Number from the Google Developer's console, for example @"012345678901", used to + * configure Firebase Cloud Messaging. + */ +@property(nonatomic, copy) NSString *GCMSenderID NS_SWIFT_NAME(gcmSenderID); + +/** + * The Project ID from the Firebase console, for example @"abc-xyz-123". + */ +@property(nonatomic, copy, nullable) NSString *projectID; + +/** + * Unused. + */ +@property(nonatomic, copy, nullable) NSString *androidClientID DEPRECATED_ATTRIBUTE; + +/** + * The Google App ID that is used to uniquely identify an instance of an app. + */ +@property(nonatomic, copy) NSString *googleAppID; + +/** + * The database root URL, e.g. @"http://abc-xyz-123.firebaseio.com". + */ +@property(nonatomic, copy, nullable) NSString *databaseURL; + +/** + * The URL scheme used to set up Durable Deep Link service. + */ +@property(nonatomic, copy, nullable) NSString *deepLinkURLScheme DEPRECATED_ATTRIBUTE; + +/** + * The Google Cloud Storage bucket name, e.g. @"abc-xyz-123.storage.firebase.com". + */ +@property(nonatomic, copy, nullable) NSString *storageBucket; + +/** + * The App Group identifier to share data between the application and the application extensions. + * The App Group must be configured in the application and on the Apple Developer Portal. Default + * value `nil`. + */ +@property(nonatomic, copy, nullable) NSString *appGroupID; + +/** + * Initializes a customized instance of FirebaseOptions from the file at the given plist file path. + * This will read the file synchronously from disk. + * For example: + * ```swift + * if let path = Bundle.main.path(forResource:"GoogleService-Info", ofType:"plist") { + * let options = FirebaseOptions(contentsOfFile: path) + * } + * ``` + * Note that it is not possible to customize `FirebaseOptions` for Firebase Analytics which expects + * a static file named `GoogleService-Info.plist` - + * https://github.com/firebase/firebase-ios-sdk/issues/230. + * Returns `nil` if the plist file does not exist or is invalid. + */ +- (nullable instancetype)initWithContentsOfFile:(NSString *)plistPath NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a customized instance of `FirebaseOptions` with required fields. Use the mutable + * properties to modify fields for configuring specific services. Note that it is not possible to + * customize `FirebaseOptions` for Firebase Analytics which expects a static file named + * `GoogleServices-Info.plist` - https://github.com/firebase/firebase-ios-sdk/issues/230. + */ +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + GCMSenderID:(NSString *)GCMSenderID + NS_SWIFT_NAME(init(googleAppID:gcmSenderID:))NS_DESIGNATED_INITIALIZER; + +/** Unavailable. Please use `init(contentsOfFile:)` or `init(googleAppID:gcmSenderID:)` instead. */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h new file mode 100644 index 0000000..0420d40 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h @@ -0,0 +1,90 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A Timestamp represents a point in time independent of any time zone or calendar, represented as + * seconds and fractions of seconds at nanosecond resolution in UTC Epoch time. It is encoded using + * the Proleptic Gregorian Calendar which extends the Gregorian calendar backwards to year one. It + * is encoded assuming all minutes are 60 seconds long, i.e. leap seconds are "smeared" so that no + * leap second table is needed for interpretation. Range is from 0001-01-01T00:00:00Z to + * 9999-12-31T23:59:59.999999999Z. By restricting to that range, we ensure that we can convert to + * and from RFC 3339 date strings. + * + * @see https://github.com/google/protobuf/blob/main/src/google/protobuf/timestamp.proto for the + * reference timestamp definition. + */ +NS_SWIFT_SENDABLE +NS_SWIFT_NAME(Timestamp) +@interface FIRTimestamp : NSObject + +/** :nodoc: */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates a new timestamp. + * + * @param seconds the number of seconds since epoch. + * @param nanoseconds the number of nanoseconds after the seconds. + */ +- (instancetype)initWithSeconds:(int64_t)seconds + nanoseconds:(int32_t)nanoseconds NS_DESIGNATED_INITIALIZER; + +/** + * Creates a new timestamp. + * + * @param seconds the number of seconds since epoch. + * @param nanoseconds the number of nanoseconds after the seconds. + */ ++ (instancetype)timestampWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds; + +/** Creates a new timestamp from the given date. */ ++ (instancetype)timestampWithDate:(NSDate *)date; + +/** Creates a new timestamp with the current date / time. */ ++ (instancetype)timestamp; + +/** Returns a new `Date` corresponding to this timestamp. This may lose precision. */ +- (NSDate *)dateValue; + +/** + * Returns the result of comparing the receiver with another timestamp. + * @param other the other timestamp to compare. + * @return `orderedAscending` if `other` is chronologically following self, + * `orderedDescending` if `other` is chronologically preceding self, + * `orderedSame` otherwise. + */ +- (NSComparisonResult)compare:(FIRTimestamp *)other; + +/** + * Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. + * Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive. + */ +@property(nonatomic, assign, readonly) int64_t seconds; + +/** + * Non-negative fractions of a second at nanosecond resolution. Negative second values with + * fractions must still have non-negative nanos values that count forward in time. + * Must be from 0 to 999,999,999 inclusive. + */ +@property(nonatomic, assign, readonly) int32_t nanoseconds; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h new file mode 100644 index 0000000..651edaf --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h @@ -0,0 +1,25 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Returns the current version of Firebase. */ +NS_SWIFT_NAME(FirebaseVersion()) +NSString* FIRFirebaseVersion(void); + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h new file mode 100644 index 0000000..fff8631 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h @@ -0,0 +1,22 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRApp.h" +#import "FIRConfiguration.h" +#import "FIRLoggerLevel.h" +#import "FIROptions.h" +#import "FIRTimestamp.h" +#import "FIRVersion.h" diff --git a/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Resources/PrivacyInfo.xcprivacy b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..0244f2f --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/FirebaseCore/Sources/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,26 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + + + diff --git a/frontend/ios/Pods/FirebaseCore/LICENSE b/frontend/ios/Pods/FirebaseCore/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/ios/Pods/FirebaseCore/README.md b/frontend/ios/Pods/FirebaseCore/README.md new file mode 100644 index 0000000..8c98212 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCore/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 16.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](docs/AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@20 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift new file mode 100644 index 0000000..aa265ed --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift @@ -0,0 +1,76 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// An enumeration of time periods. +enum TimePeriod: Int, CaseIterable, Codable { + /// The raw value is the number of calendar days within each time period. + /// More types can be enabled in future iterations (i.e. `weekly = 7, monthly = 28`). + case daily = 1 + + /// The number of seconds in a given time period. + var timeInterval: TimeInterval { + Double(rawValue) * 86400 /* seconds in day */ + } +} + +/// A structure representing SDK usage. +struct Heartbeat: Codable, Equatable { + /// The version of the heartbeat. + private static let version: Int = 0 + + /// An anonymous string of information (i.e. user agent) to associate the heartbeat with. + let agent: String + + /// The date when the heartbeat was recorded. + let date: Date + + /// The heartbeat's model version. + let version: Int + + /// An array of `TimePeriod`s that the heartbeat is tagged with. See `TimePeriod`. + /// + /// Heartbeats represent anonymous data points that measure SDK usage in moving averages for + /// various time periods. Because a single heartbeat can help calculate moving averages for + /// multiple + /// time periods, this property serves to capture all the time periods that the heartbeat can + /// represent in + /// a moving average. + let timePeriods: [TimePeriod] + + /// Designated initializer. + /// - Parameters: + /// - agent: An anonymous string of information to associate the heartbeat with. + /// - date: The date when the heartbeat was recorded. + /// - version: The heartbeat's version. Defaults to the current version. + init(agent: String, + date: Date, + timePeriods: [TimePeriod] = [], + version: Int = version) { + self.agent = agent + self.date = date + self.timePeriods = timePeriods + self.version = version + } +} + +extension Heartbeat: HeartbeatsPayloadConvertible { + func makeHeartbeatsPayload() -> HeartbeatsPayload { + let userAgentPayloads = [ + HeartbeatsPayload.UserAgentPayload(agent: agent, dates: [date]), + ] + return HeartbeatsPayload(userAgentPayloads: userAgentPayloads) + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift new file mode 100644 index 0000000..cbc0184 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift @@ -0,0 +1,185 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// An object that provides API to log and flush heartbeats from a synchronized storage container. +public final class HeartbeatController: Sendable { + /// Used for standardizing dates for calendar-day comparison. + private enum DateStandardizer { + private static let calendar: Calendar = { + var calendar = Calendar(identifier: .iso8601) + calendar.locale = Locale(identifier: "en_US_POSIX") + calendar.timeZone = TimeZone(secondsFromGMT: 0)! + return calendar + }() + + static func standardize(_ date: Date) -> (Date) { + return calendar.startOfDay(for: date) + } + } + + /// The thread-safe storage object to log and flush heartbeats from. + private let storage: any HeartbeatStorageProtocol + /// The max capacity of heartbeats to store in storage. + private static let heartbeatsStorageCapacity: Int = 30 + /// Current date provider. It is used for testability. + private let dateProvider: @Sendable () -> Date + /// Used for standardizing dates for calendar-day comparison. + private static let dateStandardizer = DateStandardizer.self + + /// Public initializer. + /// - Parameter id: The `id` to associate this controller's heartbeat storage with. + public convenience init(id: String) { + self.init(id: id, dateProvider: { Date() }) + } + + /// Convenience initializer. Mirrors the semantics of the public initializer with the added + /// benefit of + /// injecting a custom date provider for improved testability. + /// - Parameters: + /// - id: The id to associate this controller's heartbeat storage with. + /// - dateProvider: A date provider. + convenience init(id: String, dateProvider: @escaping @Sendable () -> Date) { + let storage = HeartbeatStorage.getInstance(id: id) + self.init(storage: storage, dateProvider: dateProvider) + } + + /// Designated initializer. + /// - Parameters: + /// - storage: A heartbeat storage container. + /// - dateProvider: A date provider. Defaults to providing the current date. + init(storage: HeartbeatStorageProtocol, + dateProvider: @escaping @Sendable () -> Date = { Date() }) { + self.storage = storage + self.dateProvider = { Self.dateStandardizer.standardize(dateProvider()) } + } + + /// Asynchronously logs a new heartbeat, if needed. + /// + /// - Note: This API is thread-safe. + /// - Parameter agent: The string agent (i.e. Firebase User Agent) to associate the logged + /// heartbeat with. + public func log(_ agent: String) { + let date = dateProvider() + + storage.readAndWriteAsync { heartbeatsBundle in + var heartbeatsBundle = heartbeatsBundle ?? + HeartbeatsBundle(capacity: Self.heartbeatsStorageCapacity) + + // Filter for the time periods where the last heartbeat to be logged for + // that time period was logged more than one time period (i.e. day) ago. + let timePeriods = heartbeatsBundle.lastAddedHeartbeatDates.filter { timePeriod, lastDate in + date.timeIntervalSince(lastDate) >= timePeriod.timeInterval + } + .map { timePeriod, _ in timePeriod } + + if !timePeriods.isEmpty { + // A heartbeat should only be logged if there is a time period(s) to + // associate it with. + let heartbeat = Heartbeat(agent: agent, date: date, timePeriods: timePeriods) + heartbeatsBundle.append(heartbeat) + } + + return heartbeatsBundle + } + } + + /// Synchronously flushes heartbeats from storage into a heartbeats payload. + /// + /// - Note: This API is thread-safe. + /// - Returns: The flushed heartbeats in the form of `HeartbeatsPayload`. + @discardableResult + public func flush() -> HeartbeatsPayload { + let resetTransform = { (heartbeatsBundle: HeartbeatsBundle?) -> HeartbeatsBundle? in + guard let oldHeartbeatsBundle = heartbeatsBundle else { + return nil // Storage was empty. + } + // The new value that's stored will use the old's cache to prevent the + // logging of duplicates after flushing. + return HeartbeatsBundle( + capacity: Self.heartbeatsStorageCapacity, + cache: oldHeartbeatsBundle.lastAddedHeartbeatDates + ) + } + + do { + // Synchronously gets and returns the stored heartbeats, resetting storage + // using the given transform. + let heartbeatsBundle = try storage.getAndSet(using: resetTransform) + // If no heartbeats bundle was stored, return an empty payload. + return heartbeatsBundle?.makeHeartbeatsPayload() ?? HeartbeatsPayload.emptyPayload + } catch { + // If the operation throws, assume no heartbeat(s) were retrieved or set. + return HeartbeatsPayload.emptyPayload + } + } + + public func flushAsync(completionHandler: @escaping @Sendable (HeartbeatsPayload) -> Void) { + let resetTransform = { @Sendable (heartbeatsBundle: HeartbeatsBundle?) -> HeartbeatsBundle? in + guard let oldHeartbeatsBundle = heartbeatsBundle else { + return nil // Storage was empty. + } + // The new value that's stored will use the old's cache to prevent the + // logging of duplicates after flushing. + return HeartbeatsBundle( + capacity: Self.heartbeatsStorageCapacity, + cache: oldHeartbeatsBundle.lastAddedHeartbeatDates + ) + } + + // Asynchronously gets and returns the stored heartbeats, resetting storage + // using the given transform. + storage.getAndSetAsync(using: resetTransform) { result in + switch result { + case let .success(heartbeatsBundle): + // If no heartbeats bundle was stored, return an empty payload. + completionHandler(heartbeatsBundle?.makeHeartbeatsPayload() ?? HeartbeatsPayload + .emptyPayload) + case .failure: + // If the operation throws, assume no heartbeat(s) were retrieved or set. + completionHandler(HeartbeatsPayload.emptyPayload) + } + } + } + + /// Synchronously flushes the heartbeat for today. + /// + /// If no heartbeat was logged today, the returned payload is empty. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat. + @discardableResult + public func flushHeartbeatFromToday() -> HeartbeatsPayload { + let todaysDate = dateProvider() + var todaysHeartbeat: Heartbeat? + + storage.readAndWriteSync { heartbeatsBundle in + guard var heartbeatsBundle = heartbeatsBundle else { + return nil // Storage was empty. + } + + todaysHeartbeat = heartbeatsBundle.removeHeartbeat(from: todaysDate) + + return heartbeatsBundle + } + + // Note that `todaysHeartbeat` is updated in the above read/write block. + if todaysHeartbeat != nil { + return todaysHeartbeat!.makeHeartbeatsPayload() + } else { + return HeartbeatsPayload.emptyPayload + } + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift new file mode 100644 index 0000000..96dbcf8 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift @@ -0,0 +1,140 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if DEBUG + + import Foundation + + /// A utility class intended to be used only in testing contexts. + @objc(FIRHeartbeatLoggingTestUtils) + @objcMembers + public class HeartbeatLoggingTestUtils: NSObject { + /// This should mirror the `Constants` enum in the `HeartbeatLogging` module. + /// See `HeartbeatLogging/Sources/StorageFactory.swift`. + public enum Constants { + /// The name of the file system directory where heartbeat data is stored. + public static let heartbeatFileStorageDirectoryPath = "google-heartbeat-storage" + /// The name of the user defaults suite where heartbeat data is stored. + public static let heartbeatUserDefaultsSuiteName = "com.google.heartbeat.storage" + } + + public static var dateFormatter: DateFormatter { + HeartbeatsPayload.dateFormatter + } + + public static var emptyHeartbeatsPayload: _ObjC_HeartbeatsPayload { + let literalData = """ + { + "version": 2, + "heartbeats": [] + } + """ + .data(using: .utf8)! + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + + let heartbeatsPayload = try! decoder.decode(HeartbeatsPayload.self, from: literalData) + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } + + public static var nonEmptyHeartbeatsPayload: _ObjC_HeartbeatsPayload { + let literalData = """ + { + "version": 2, + "heartbeats": [ + { + "agent": "dummy_agent_1", + "dates": ["2021-11-01", "2021-11-02"] + }, + { + "agent": "dummy_agent_2", + "dates": ["2021-11-03"] + } + ] + } + """ + .data(using: .utf8)! + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + + let heartbeatsPayload = try! decoder.decode(HeartbeatsPayload.self, from: literalData) + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } + + @objc(assertEncodedPayloadString:isEqualToLiteralString:withError:) + public static func assertEqualPayloadStrings(_ encoded: String, _ literal: String) throws { + var encodedData = Data(base64URLEncoded: encoded)! + if encodedData.count > 0 { + encodedData = try! encodedData.unzipped() + } + + let literalData = literal.data(using: .utf8)! + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + + let payloadFromEncoded = try? decoder.decode(HeartbeatsPayload.self, from: encodedData) + + let payloadFromLiteral = try? decoder.decode(HeartbeatsPayload.self, from: literalData) + + let encoder = JSONEncoder() + encoder.dateEncodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + encoder.outputFormatting = .prettyPrinted + + let payloadDataFromEncoded = try! encoder.encode(payloadFromEncoded) + let payloadDataFromLiteral = try! encoder.encode(payloadFromLiteral) + + assert( + payloadFromEncoded == payloadFromLiteral, + """ + Mismatched payloads! + + Payload 1: + \(String(data: payloadDataFromEncoded, encoding: .utf8) ?? "") + + Payload 2: + \(String(data: payloadDataFromLiteral, encoding: .utf8) ?? "") + + """ + ) + } + + /// Removes all underlying storage containers used by the module. + /// - Throws: An error if the storage container could not be removed. + public static func removeUnderlyingHeartbeatStorageContainers() throws { + #if os(tvOS) + UserDefaults().removePersistentDomain(forName: Constants.heartbeatUserDefaultsSuiteName) + #else + + let applicationSupportDirectory = FileManager.default + .urls(for: .applicationSupportDirectory, in: .userDomainMask).first! + + let heartbeatsDirectoryURL = applicationSupportDirectory + .appendingPathComponent( + Constants.heartbeatFileStorageDirectoryPath, isDirectory: true + ) + do { + try FileManager.default.removeItem(at: heartbeatsDirectoryURL) + } catch CocoaError.fileNoSuchFile { + // Do nothing. + } catch { + throw error + } + #endif // os(tvOS) + } + } + +#endif // ENABLE_FIREBASE_CORE_INTERNAL_TESTING_UTILS diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift new file mode 100644 index 0000000..224426e --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift @@ -0,0 +1,211 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A type that can perform atomic operations using block-based transformations. +protocol HeartbeatStorageProtocol: Sendable { + func readAndWriteSync(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) + func readAndWriteAsync(using transform: @escaping @Sendable (HeartbeatsBundle?) + -> HeartbeatsBundle?) + func getAndSet(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) throws + -> HeartbeatsBundle? + func getAndSetAsync(using transform: @escaping @Sendable (HeartbeatsBundle?) -> HeartbeatsBundle?, + completion: @escaping @Sendable (Result) -> Void) +} + +/// Thread-safe storage object designed for transforming heartbeat data that is persisted to disk. +final class HeartbeatStorage: Sendable, HeartbeatStorageProtocol { + /// The identifier used to differentiate instances. + private let id: String + /// The underlying storage container to read from and write to. + private let storage: any Storage + /// The encoder used for encoding heartbeat data. + private let encoder: JSONEncoder = .init() + /// The decoder used for decoding heartbeat data. + private let decoder: JSONDecoder = .init() + /// The queue for synchronizing storage operations. + private let queue: DispatchQueue + + /// Designated initializer. + /// - Parameters: + /// - id: A string identifier. + /// - storage: The underlying storage container where heartbeat data is stored. + init(id: String, + storage: Storage) { + self.id = id + self.storage = storage + queue = DispatchQueue(label: "com.heartbeat.storage.\(id)") + } + + // MARK: - Instance Management + + /// Statically allocated cache of `HeartbeatStorage` instances keyed by string IDs. + private static let cachedInstances: FIRAllocatedUnfairLock< + [String: WeakContainer] + > = FIRAllocatedUnfairLock(initialState: [:]) + + /// Gets an existing `HeartbeatStorage` instance with the given `id` if one exists. Otherwise, + /// makes a new instance with the given `id`. + /// + /// - Parameter id: A string identifier. + /// - Returns: A `HeartbeatStorage` instance. + static func getInstance(id: String) -> HeartbeatStorage { + cachedInstances.withLock { cachedInstances in + if let cachedInstance = cachedInstances[id]?.object { + return cachedInstance + } else { + let newInstance = HeartbeatStorage.makeHeartbeatStorage(id: id) + cachedInstances[id] = WeakContainer(object: newInstance) + return newInstance + } + } + } + + /// Makes a `HeartbeatStorage` instance using a given `String` identifier. + /// + /// The created persistent storage object is platform dependent. For tvOS, user defaults + /// is used as the underlying storage container due to system storage limits. For all other + /// platforms, + /// the file system is used. + /// + /// - Parameter id: A `String` identifier used to create the `HeartbeatStorage`. + /// - Returns: A `HeartbeatStorage` instance. + private static func makeHeartbeatStorage(id: String) -> HeartbeatStorage { + #if os(tvOS) + let storage = UserDefaultsStorage.makeStorage(id: id) + #else + let storage = FileStorage.makeStorage(id: id) + #endif // os(tvOS) + return HeartbeatStorage(id: id, storage: storage) + } + + deinit { + // Removes the instance if it was cached. + Self.cachedInstances.withLock { value in + value.removeValue(forKey: id) + } + } + + // MARK: - HeartbeatStorageProtocol + + /// Synchronously reads from and writes to storage using the given transform block. + /// - Parameter transform: A block to transform the currently stored heartbeats bundle to a new + /// heartbeats bundle value. + func readAndWriteSync(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) { + queue.sync { + let oldHeartbeatsBundle = try? load(from: storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try? save(newHeartbeatsBundle, to: storage) + } + } + + /// Asynchronously reads from and writes to storage using the given transform block. + /// - Parameter transform: A block to transform the currently stored heartbeats bundle to a new + /// heartbeats bundle value. + func readAndWriteAsync(using transform: @escaping @Sendable (HeartbeatsBundle?) + -> HeartbeatsBundle?) { + queue.async { [self] in + let oldHeartbeatsBundle = try? load(from: storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try? save(newHeartbeatsBundle, to: storage) + } + } + + /// Synchronously gets the current heartbeat data from storage and resets the storage using the + /// given transform block. + /// + /// This API is like any `getAndSet`-style API in that it gets (and returns) the current value and + /// uses + /// a block to transform the current value (or, soon-to-be old value) to a new value. + /// + /// - Parameter transform: An optional block used to reset the currently stored heartbeat. + /// - Returns: The heartbeat data that was stored (before the `transform` was applied). + @discardableResult + func getAndSet(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) throws + -> HeartbeatsBundle? { + let heartbeatsBundle: HeartbeatsBundle? = try queue.sync { + let oldHeartbeatsBundle = try? load(from: storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try save(newHeartbeatsBundle, to: storage) + return oldHeartbeatsBundle + } + return heartbeatsBundle + } + + /// Asynchronously gets the current heartbeat data from storage and resets the storage using the + /// given transform block. + /// - Parameters: + /// - transform: An escaping block used to reset the currently stored heartbeat. + /// - completion: An escaping block used to process the heartbeat data that + /// was stored (before the `transform` was applied); otherwise, the error + /// that occurred. + func getAndSetAsync(using transform: @escaping @Sendable (HeartbeatsBundle?) -> HeartbeatsBundle?, + completion: @escaping @Sendable (Result) -> Void) { + queue.async { + do { + let oldHeartbeatsBundle = try? self.load(from: self.storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try self.save(newHeartbeatsBundle, to: self.storage) + completion(.success(oldHeartbeatsBundle)) + } catch { + completion(.failure(error)) + } + } + } + + /// Loads and decodes the stored heartbeats bundle from a given storage object. + /// - Parameter storage: The storage container to read from. + /// - Returns: The decoded `HeartbeatsBundle` loaded from storage; `nil` if storage is empty. + /// - Throws: An error if storage could not be read or the data could not be decoded. + private func load(from storage: Storage) throws -> HeartbeatsBundle? { + let data = try storage.read() + if data.isEmpty { + return nil + } else { + let heartbeatData = try data.decoded(using: decoder) as HeartbeatsBundle + return heartbeatData + } + } + + /// Saves the encoding of the given value to the given storage container. + /// - Parameters: + /// - heartbeatsBundle: The heartbeats bundle to encode and save. + /// - storage: The storage container to write to. + private func save(_ heartbeatsBundle: HeartbeatsBundle?, to storage: Storage) throws { + if let heartbeatsBundle { + let data = try heartbeatsBundle.encoded(using: encoder) + try storage.write(data) + } else { + try storage.write(nil) + } + } +} + +private extension Data { + /// Returns the decoded value of this `Data` using the given decoder. Defaults to `JSONDecoder`. + /// - Returns: The decoded value. + func decoded(using decoder: JSONDecoder = .init()) throws -> T where T: Decodable { + try decoder.decode(T.self, from: self) + } +} + +private extension Encodable { + /// Returns the `Data` encoding of this value using the given encoder. + /// - Parameter encoder: An encoder used to encode the value. Defaults to `JSONEncoder`. + /// - Returns: The data encoding of the value. + func encoded(using encoder: JSONEncoder = .init()) throws -> Data { + try encoder.encode(self) + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift new file mode 100644 index 0000000..a6e258e --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift @@ -0,0 +1,151 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A type that can be converted to a `HeartbeatsPayload`. +protocol HeartbeatsPayloadConvertible { + func makeHeartbeatsPayload() -> HeartbeatsPayload +} + +/// A codable collection of heartbeats that has a fixed capacity and optimizations for storing +/// heartbeats of +/// multiple time periods. +struct HeartbeatsBundle: Codable, HeartbeatsPayloadConvertible { + /// The maximum number of heartbeats that can be stored in the buffer. + let capacity: Int + /// A cache used for keeping track of the last heartbeat date recorded for a given time period. + /// + /// The cache contains the last added date for each time period. The reason only the date is + /// cached is + /// because it's the only piece of information that should be used by clients to determine whether + /// or not + /// to append a new heartbeat. + private(set) var lastAddedHeartbeatDates: [TimePeriod: Date] + /// A ring buffer of heartbeats. + private var buffer: RingBuffer + + /// A default cache provider that provides a dictionary of all time periods mapping to a default + /// date. + static var cacheProvider: () -> [TimePeriod: Date] { + let timePeriodsAndDates = TimePeriod.allCases.map { ($0, Date.distantPast) } + return { Dictionary(uniqueKeysWithValues: timePeriodsAndDates) } + } + + /// Designated initializer. + /// - Parameters: + /// - capacity: The heartbeat capacity of the initialized collection. + /// - cache: A cache of time periods mapping to dates. Defaults to using static `cacheProvider`. + init(capacity: Int, + cache: [TimePeriod: Date] = cacheProvider()) { + buffer = RingBuffer(capacity: capacity) + self.capacity = capacity + lastAddedHeartbeatDates = cache + } + + /// Appends a heartbeat to this collection. + /// - Parameter heartbeat: The heartbeat to append. + mutating func append(_ heartbeat: Heartbeat) { + guard capacity > 0 else { + return // Do not append if capacity is non-positive. + } + + do { + // Push the heartbeat to the back of the buffer. + if let overwrittenHeartbeat = try buffer.push(heartbeat) { + // If a heartbeat was overwritten, update the cache to ensure it's date + // is removed. + lastAddedHeartbeatDates = lastAddedHeartbeatDates.mapValues { date in + overwrittenHeartbeat.date == date ? .distantPast : date + } + } + + // Update cache with the new heartbeat's date. + for timePeriod in heartbeat.timePeriods { + lastAddedHeartbeatDates[timePeriod] = heartbeat.date + } + + } catch let error as RingBuffer.Error { + // A ring buffer error occurred while pushing to the buffer so the bundle + // is reset. + self = HeartbeatsBundle(capacity: capacity) + + // Create a diagnostic heartbeat to capture the failure and add it to the + // buffer. The failure is added as a key/value pair to the agent string. + // Given that the ring buffer has been reset, it is not expected for the + // second push attempt to fail. + let errorDescription = error.errorDescription.replacingOccurrences(of: " ", with: "-") + let diagnosticHeartbeat = Heartbeat( + agent: "\(heartbeat.agent) error/\(errorDescription)", + date: heartbeat.date, + timePeriods: heartbeat.timePeriods + ) + + let secondPushAttempt = Result { + try buffer.push(diagnosticHeartbeat) + } + + if case .success = secondPushAttempt { + // Update cache with the new heartbeat's date. + for timePeriod in diagnosticHeartbeat.timePeriods { + lastAddedHeartbeatDates[timePeriod] = diagnosticHeartbeat.date + } + } + } catch { + // Ignore other error. + } + } + + /// Removes the heartbeat associated with the given date. + /// - Parameter date: The date of the heartbeat needing removal. + /// - Returns: The heartbeat that was removed or `nil` if there was no heartbeat to remove. + @discardableResult + mutating func removeHeartbeat(from date: Date) -> Heartbeat? { + var removedHeartbeat: Heartbeat? + + var poppedHeartbeats: [Heartbeat] = [] + + while let poppedHeartbeat = buffer.pop() { + if poppedHeartbeat.date == date { + removedHeartbeat = poppedHeartbeat + break + } + poppedHeartbeats.append(poppedHeartbeat) + } + + for poppedHeartbeat in poppedHeartbeats.reversed() { + do { + try buffer.push(poppedHeartbeat) + } catch { + // Ignore error. + } + } + + return removedHeartbeat + } + + /// Makes and returns a `HeartbeatsPayload` from this heartbeats bundle. + /// - Returns: A heartbeats payload. + func makeHeartbeatsPayload() -> HeartbeatsPayload { + let agentAndDates = buffer.map { heartbeat in + (heartbeat.agent, [heartbeat.date]) + } + + let userAgentPayloads = [String: [Date]](agentAndDates, uniquingKeysWith: +) + .map(HeartbeatsPayload.UserAgentPayload.init) + .sorted { $0.agent < $1.agent } // Sort payloads by user agent. + + return HeartbeatsPayload(userAgentPayloads: userAgentPayloads) + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift new file mode 100644 index 0000000..1604933 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift @@ -0,0 +1,181 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +#if SWIFT_PACKAGE + internal import GoogleUtilities_NSData +#else + internal import GoogleUtilities +#endif // SWIFT_PACKAGE + +/// A type that provides a string representation for use in an HTTP header. +public protocol HTTPHeaderRepresentable { + func headerValue() -> String +} + +/// A value type representing a payload of heartbeat data intended for sending in network requests. +/// +/// This type's structure is optimized for type-safe encoding into a HTTP payload format. +/// The current encoding format for the payload's current version is: +/// +/// { +/// "version": 2, +/// "heartbeats": [ +/// { +/// "agent": "dummy_agent_1", +/// "dates": ["2021-11-01", "2021-11-02"] +/// }, +/// { +/// "agent": "dummy_agent_2", +/// "dates": ["2021-11-03"] +/// } +/// ] +/// } +/// +public struct HeartbeatsPayload: Codable, Sendable { + /// The version of the payload. See go/firebase-apple-heartbeats for details regarding current + /// version. + static let version: Int = 2 + + /// A payload component composed of a user agent and array of dates (heartbeats). + struct UserAgentPayload: Codable { + /// An anonymous agent string. + let agent: String + /// An array of dates where each date represents a "heartbeat". + let dates: [Date] + } + + /// An array of user agent payloads. + let userAgentPayloads: [UserAgentPayload] + /// The version of the payload structure. + let version: Int + + /// Alternative keys for properties so encoding follows platform-wide payload structure. + enum CodingKeys: String, CodingKey { + case userAgentPayloads = "heartbeats" + case version + } + + /// Designated initializer. + /// - Parameters: + /// - userAgentPayloads: An array of payloads containing heartbeat data corresponding to a + /// given user agent. + /// - version: A version of the payload. Defaults to the static default. + init(userAgentPayloads: [UserAgentPayload] = [], version: Int = version) { + self.userAgentPayloads = userAgentPayloads + self.version = version + } + + /// A Boolean value indicating whether the payload is empty. + public var isEmpty: Bool { + userAgentPayloads.isEmpty + } +} + +// MARK: - HTTPHeaderRepresentable + +extension HeartbeatsPayload: HTTPHeaderRepresentable { + /// Returns a processed payload string intended for use in a HTTP header. + /// - Returns: A string value from the heartbeats payload. + public func headerValue() -> String { + let encoder = JSONEncoder() + encoder.dateEncodingStrategy = .formatted(Self.dateFormatter) + #if DEBUG + // Sort keys in debug builds to simplify output comparisons in unit tests. + encoder.outputFormatting = .sortedKeys + #endif // DEBUG + + guard let data = try? encoder.encode(self) else { + // If encoding fails, fall back to encoding with an empty payload. + return Self.emptyPayload.headerValue() + } + + do { + let gzippedData = try data.zipped() + return gzippedData.base64URLEncodedString() + } catch { + // If gzipping fails, fall back to encoding with base64URL. + return data.base64URLEncodedString() + } + } +} + +// MARK: - Static Defaults + +extension HeartbeatsPayload { + /// Convenience instance that represents an empty payload. + static let emptyPayload = HeartbeatsPayload() + + /// A default date formatter that uses `yyyy-MM-dd` format. + public static let dateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd" + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) + return formatter + }() +} + +// MARK: - Equatable + +extension HeartbeatsPayload: Equatable {} +extension HeartbeatsPayload.UserAgentPayload: Equatable {} + +// MARK: - Data + +public extension Data { + /// Returns a Base-64 URL-safe encoded string. + /// + /// - parameter options: The options to use for the encoding. Default value is `[]`. + /// - returns: The Base-64 URL-safe encoded string. + func base64URLEncodedString(options: Data.Base64EncodingOptions = []) -> String { + base64EncodedString() + .replacingOccurrences(of: "/", with: "_") + .replacingOccurrences(of: "+", with: "-") + .replacingOccurrences(of: "=", with: "") + } + + /// Initialize a `Data` from a Base-64 URL encoded String using the given options. + /// + /// Returns nil when the input is not recognized as valid Base-64. + /// - parameter base64URLString: The string to parse. + /// - parameter options: Encoding options. Default value is `[]`. + init?(base64URLEncoded base64URLString: String, options: Data.Base64DecodingOptions = []) { + var base64Encoded = base64URLString + .replacingOccurrences(of: "_", with: "/") + .replacingOccurrences(of: "-", with: "+") + + // Pad the string with "=" signs until the string's length is a multiple of 4. + while !base64Encoded.count.isMultiple(of: 4) { + base64Encoded.append("=") + } + + self.init(base64Encoded: base64Encoded, options: options) + } + + /// Returns the compressed data. + /// - Returns: The compressed data. + /// - Throws: An error if compression failed. + func zipped() throws -> Data { + try NSData.gul_data(byGzippingData: self) + } + + /// Returns the uncompressed data. + /// - Returns: The decompressed data. + /// - Throws: An error if decompression failed. + func unzipped() throws -> Data { + try NSData.gul_data(byInflatingGzippedData: self) + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift new file mode 100644 index 0000000..74d08d7 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift @@ -0,0 +1,111 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A generic circular queue structure. +struct RingBuffer: Sequence { + /// An array of heartbeats treated as a circular queue and initialized with a fixed capacity. + private var circularQueue: [Element?] + /// The current "tail" and insert point for the `circularQueue`. + private var tailIndex: Array.Index + + /// Error types for `RingBuffer` operations. + enum Error: Swift.Error { + case outOfBoundsPush(pushIndex: Array.Index, endIndex: Array.Index) + + var errorDescription: String { + switch self { + case let .outOfBoundsPush(pushIndex, endIndex): + return "Out-of-bounds push at index \(pushIndex) to ring buffer with" + + "end index of \(endIndex)." + } + } + } + + /// Designated initializer. + /// - Parameter capacity: An `Int` representing the capacity. + init(capacity: Int) { + circularQueue = Array(repeating: nil, count: capacity) + tailIndex = circularQueue.startIndex + } + + /// Pushes an element to the back of the buffer, returning the element (`Element?`) that was + /// overwritten. + /// - Parameter element: The element to push to the back of the buffer. + /// - Returns: The element that was overwritten or `nil` if nothing was overwritten. + /// - Complexity: O(1) + @discardableResult + mutating func push(_ element: Element) throws -> Element? { + guard circularQueue.count > 0 else { + // Do not push if `circularQueue` is a fixed empty array. + return nil + } + + guard circularQueue.indices.contains(tailIndex) else { + // We have somehow entered an invalid state (#10025). + throw Self.Error.outOfBoundsPush( + pushIndex: tailIndex, + endIndex: circularQueue.endIndex + ) + } + + let replaced = circularQueue[tailIndex] + circularQueue[tailIndex] = element + + // Increment index, wrapping around to the start if needed. + tailIndex += 1 + if tailIndex >= circularQueue.endIndex { + tailIndex = circularQueue.startIndex + } + + return replaced + } + + /// Pops an element from the back of the buffer, returning the element (`Element?`) that was + /// popped. + /// - Returns: The element that was popped or `nil` if there was no element to pop. + /// - Complexity: O(1) + @discardableResult + mutating func pop() -> Element? { + guard circularQueue.count > 0 else { + // Do not pop if `circularQueue` is a fixed empty array. + return nil + } + + // Decrement index, wrapping around to the back if needed. + tailIndex -= 1 + if tailIndex < circularQueue.startIndex { + tailIndex = circularQueue.endIndex - 1 + } + + guard let popped = circularQueue[tailIndex] else { + return nil // There is no element to pop. + } + + circularQueue[tailIndex] = nil + + return popped + } + + func makeIterator() -> IndexingIterator<[Element]> { + circularQueue + .compactMap { $0 } // Remove `nil` elements. + .makeIterator() + } +} + +// MARK: - Codable + +extension RingBuffer: Codable where Element: Codable {} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift new file mode 100644 index 0000000..69bf613 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift @@ -0,0 +1,150 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A type that reads from and writes to an underlying storage container. +protocol Storage: Sendable { + /// Reads and returns the data stored by this storage type. + /// - Returns: The data read from storage. + /// - Throws: An error if the read failed. + func read() throws -> Data + + /// Writes the given data to this storage type. + /// - Throws: An error if the write failed. + func write(_ data: Data?) throws +} + +/// Error types for `Storage` operations. +enum StorageError: Error { + case readError + case writeError +} + +// MARK: - FileStorage + +/// A object that provides API for reading and writing to a file system resource. +final class FileStorage: Storage { + /// A file system URL to the underlying file resource. + private let url: URL + + /// Designated initializer. + /// - Parameters: + /// - url: A file system URL for the underlying file resource. + init(url: URL) { + self.url = url + } + + /// Reads and returns the data from this object's associated file resource. + /// + /// - Returns: The data stored on disk. + /// - Throws: An error if reading the contents of the file resource fails (i.e. file doesn't + /// exist). + func read() throws -> Data { + do { + return try Data(contentsOf: url) + } catch { + throw StorageError.readError + } + } + + /// Writes the given data to this object's associated file resource. + /// + /// When the given `data` is `nil`, this object's associated file resource is emptied. + /// + /// - Parameter data: The `Data?` to write to this object's associated file resource. + func write(_ data: Data?) throws { + do { + try createDirectories(in: url.deletingLastPathComponent()) + if let data { + try data.write(to: url, options: .atomic) + } else { + let emptyData = Data() + try emptyData.write(to: url, options: .atomic) + } + } catch { + throw StorageError.writeError + } + } + + /// Creates all directories in the given file system URL. + /// + /// If the directory for the given URL already exists, the error is ignored because the directory + /// has already been created. + /// + /// - Parameter url: The URL to create directories in. + private func createDirectories(in url: URL) throws { + do { + try FileManager.default.createDirectory( + at: url, + withIntermediateDirectories: true + ) + } catch CocoaError.fileWriteFileExists { + // Directory already exists. + } catch { throw error } + } +} + +// MARK: - UserDefaultsStorage + +/// A object that provides API for reading and writing to a user defaults resource. +final class UserDefaultsStorage: Storage { + /// The suite name for the underlying defaults container. + private let suiteName: String + + /// The key mapping to the object's associated resource in `defaults`. + private let key: String + + /// The underlying defaults container. + private var defaults: UserDefaults { + // It's safe to force unwrap the below defaults instance because the + // initializer only returns `nil` when the bundle id or `globalDomain` + // is passed in as the `suiteName`. + UserDefaults(suiteName: suiteName)! + } + + /// Designated initializer. + /// - Parameters: + /// - suiteName: The suite name for the defaults container. + /// - key: The key mapping to the value stored in the defaults container. + init(suiteName: String, key: String) { + self.suiteName = suiteName + self.key = key + } + + /// Reads and returns the data from this object's associated defaults resource. + /// + /// - Returns: The data stored on disk. + /// - Throws: An error if no data has been stored to the defaults container. + func read() throws -> Data { + if let data = defaults.data(forKey: key) { + return data + } else { + throw StorageError.readError + } + } + + /// Writes the given data to this object's associated defaults. + /// + /// When the given `data` is `nil`, the associated default is removed. + /// + /// - Parameter data: The `Data?` to write to this object's associated defaults. + func write(_ data: Data?) throws { + if let data { + defaults.set(data, forKey: key) + } else { + defaults.removeObject(forKey: key) + } + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift new file mode 100644 index 0000000..d6d97cf --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift @@ -0,0 +1,62 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +private enum Constants { + /// The name of the file system directory where heartbeat data is stored. + static let heartbeatFileStorageDirectoryPath = "google-heartbeat-storage" + /// The name of the user defaults suite where heartbeat data is stored. + static let heartbeatUserDefaultsSuiteName = "com.google.heartbeat.storage" +} + +/// A factory type for `Storage`. +protocol StorageFactory { + static func makeStorage(id: String) -> Storage +} + +// MARK: - FileStorage + StorageFactory + +extension FileStorage: StorageFactory { + static func makeStorage(id: String) -> Storage { + let rootDirectory = FileManager.default.applicationSupportDirectory + let heartbeatDirectoryPath = Constants.heartbeatFileStorageDirectoryPath + + // Sanitize the `id` so the heartbeat file name does not include a ":". + let sanitizedID = id.replacingOccurrences(of: ":", with: "_") + let heartbeatFilePath = "heartbeats-\(sanitizedID)" + + let storageURL = rootDirectory + .appendingPathComponent(heartbeatDirectoryPath, isDirectory: true) + .appendingPathComponent(heartbeatFilePath, isDirectory: false) + + return FileStorage(url: storageURL) + } +} + +extension FileManager { + var applicationSupportDirectory: URL { + urls(for: .applicationSupportDirectory, in: .userDomainMask).first! + } +} + +// MARK: - UserDefaultsStorage + StorageFactory + +extension UserDefaultsStorage: StorageFactory { + static func makeStorage(id: String) -> Storage { + let suiteName = Constants.heartbeatUserDefaultsSuiteName + let key = "heartbeats-\(id)" + return UserDefaultsStorage(suiteName: suiteName, key: key) + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift new file mode 100644 index 0000000..f1dd177 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift @@ -0,0 +1,20 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A structure used to weakly box reference types. +struct WeakContainer { + weak var object: Object? +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift new file mode 100644 index 0000000..520e4f9 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift @@ -0,0 +1,70 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// An object that provides API to log and flush heartbeats from a synchronized storage container. +@objc(FIRHeartbeatController) +@objcMembers +public class _ObjC_HeartbeatController: NSObject { + /// The underlying Swift object. + private let heartbeatController: HeartbeatController + + /// Public initializer. + /// - Parameter id: The `id` to associate this controller's heartbeat storage with. + public init(id: String) { + heartbeatController = HeartbeatController(id: id) + } + + /// Asynchronously logs a new heartbeat, if needed. + /// + /// - Note: This API is thread-safe. + /// - Parameter agent: The string agent (i.e. Firebase User Agent) to associate the logged + /// heartbeat with. + public func log(_ agent: String) { + heartbeatController.log(agent) + } + + /// Synchronously flushes heartbeats from storage into a heartbeats payload. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat(s). + public func flush() -> _ObjC_HeartbeatsPayload { + let heartbeatsPayload = heartbeatController.flush() + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } + + /// Asynchronously flushes heartbeats from storage into a heartbeats payload. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat(s). + public func flushAsync(completionHandler: @escaping @Sendable (_ObjC_HeartbeatsPayload) -> Void) { + // TODO: When minimum version moves to iOS 13.0, restore the async version + // removed in #13952. + heartbeatController.flushAsync { heartbeatsPayload in + completionHandler(_ObjC_HeartbeatsPayload(heartbeatsPayload)) + } + } + + /// Synchronously flushes the heartbeat for today. + /// + /// If no heartbeat was logged today, the returned payload is empty. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat. + public func flushHeartbeatFromToday() -> _ObjC_HeartbeatsPayload { + let heartbeatsPayload = heartbeatController.flushHeartbeatFromToday() + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift new file mode 100644 index 0000000..83d72a2 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift @@ -0,0 +1,40 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A model object representing a payload of heartbeat data intended for sending in network +/// requests. +@objc(FIRHeartbeatsPayload) +public class _ObjC_HeartbeatsPayload: NSObject, HTTPHeaderRepresentable { + /// The underlying Swift structure. + private let heartbeatsPayload: HeartbeatsPayload + + /// Designated initializer. + /// - Parameter heartbeatsPayload: A native-Swift heartbeats payload. + public init(_ heartbeatsPayload: HeartbeatsPayload) { + self.heartbeatsPayload = heartbeatsPayload + } + + /// Returns a processed payload string intended for use in a HTTP header. + /// - Returns: A string value from the heartbeats payload. + @objc public func headerValue() -> String { + heartbeatsPayload.headerValue() + } + + /// A Boolean value indicating whether the payload is empty. + @objc public var isEmpty: Bool { + heartbeatsPayload.isEmpty + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Resources/PrivacyInfo.xcprivacy b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..3fb515f --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,26 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + + + diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift new file mode 100644 index 0000000..6346d05 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift @@ -0,0 +1,45 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +final class AtomicBox { + private var _value: T + private let lock = NSLock() + + public init(_ value: T) { + _value = value + } + + public func value() -> T { + lock.withLock { + _value + } + } + + @discardableResult + public func withLock(_ mutatingBody: (_ value: inout T) -> Void) -> T { + lock.withLock { + mutatingBody(&_value) + return _value + } + } + + @discardableResult + public func withLock(_ mutatingBody: (_ value: inout T) throws -> R) rethrows -> R { + try lock.withLock { + try mutatingBody(&_value) + } + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift new file mode 100644 index 0000000..c94f315 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift @@ -0,0 +1,72 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation +import os.lock + +/// A reference wrapper around `os_unfair_lock`. Replace this class with +/// `OSAllocatedUnfairLock` once we support only iOS 16+. For an explanation +/// on why this is necessary, see the docs: +/// https://developer.apple.com/documentation/os/osallocatedunfairlock +public final class FIRAllocatedUnfairLock: @unchecked Sendable { + private var lockPointer: UnsafeMutablePointer + private var state: State + + public init(initialState: sending State) { + lockPointer = UnsafeMutablePointer + .allocate(capacity: 1) + lockPointer.initialize(to: os_unfair_lock()) + state = initialState + } + + public convenience init() where State == Void { + self.init(initialState: ()) + } + + public func lock() { + os_unfair_lock_lock(lockPointer) + } + + public func unlock() { + os_unfair_lock_unlock(lockPointer) + } + + public func value() -> State { + lock() + defer { unlock() } + return state + } + + @discardableResult + public func withLock(_ body: (inout State) throws -> R) rethrows -> R { + let value: R + lock() + defer { unlock() } + value = try body(&state) + return value + } + + @discardableResult + public func withLock(_ body: () throws -> R) rethrows -> R { + let value: R + lock() + defer { unlock() } + value = try body() + return value + } + + deinit { + lockPointer.deallocate() + } +} diff --git a/frontend/ios/Pods/FirebaseCoreInternal/LICENSE b/frontend/ios/Pods/FirebaseCoreInternal/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/ios/Pods/FirebaseCoreInternal/README.md b/frontend/ios/Pods/FirebaseCoreInternal/README.md new file mode 100644 index 0000000..8c98212 --- /dev/null +++ b/frontend/ios/Pods/FirebaseCoreInternal/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 16.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](docs/AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@20 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRAppInternal.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..96d42ef --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,182 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRAPPINTERNAL_H +#define FIREBASECORE_FIRAPPINTERNAL_H + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRAPPINTERNAL_H diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponent.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..98c7a89 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,89 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRCOMPONENT_H +#define FIREBASECORE_FIRCOMPONENT_H + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRCOMPONENT_H diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentContainer.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6864087 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRCOMPONENTCONTAINER_H +#define FIREBASECORE_FIRCOMPONENTCONTAINER_H + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRCOMPONENTCONTAINER_H diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentType.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..92a5aab --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,40 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRCOMPONENTTYPE_H +#define FIREBASECORE_FIRCOMPONENTTYPE_H + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRCOMPONENTTYPE_H diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRHeartbeatLogger.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..95497d2 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,110 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIREBASECORE_FIRHEARTBEATLOGGER_H +#define FIREBASECORE_FIRHEARTBEATLOGGER_H + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +NS_SWIFT_SENDABLE +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns the header value for the heartbeat logger via the given completion handler.. +- (void)asyncHeaderValueWithCompletionHandler:(void (^)(NSString *_Nullable))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)); + +/// Return the header value for the heartbeat logger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Synchronously flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; + +/// Asynchronously flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @param completionHandler A completion handler to process the flushed payload of heartbeats. +- (void)flushHeartbeatsIntoPayloadWithCompletionHandler: + (void (^)(FIRHeartbeatsPayload *))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)); +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRHEARTBEATLOGGER_H diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLibrary.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..fe256ad --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRLIBRARY_H +#define FIREBASECORE_FIRLIBRARY_H + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ + +#endif // FIREBASECORE_FIRLIBRARY_H diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLogger.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..8117189 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,198 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRLOGGER_H +#define FIREBASECORE_FIRLOGGER_H + +#import + +typedef NS_ENUM(NSInteger, FIRLoggerLevel); + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +void FIRSetLoggerLevelNotice(void); +void FIRSetLoggerLevelWarning(void); +void FIRSetLoggerLevelError(void); +void FIRSetLoggerLevelDebug(void); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +BOOL FIRIsLoggableLevelNotice(void); +BOOL FIRIsLoggableLevelWarning(void); +BOOL FIRIsLoggableLevelError(void); +BOOL FIRIsLoggableLevelDebug(void); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +/** + * This function is similar to the one above, except it takes a `va_list` instead of the listed + * variables. + * + * The following functions accept the following parameters in order: (required) service + * name of type FirebaseLoggerService. + * + * (required) message code starting from "I-" which means iOS, + * followed by a capitalized three-character service identifier and a six digit integer message + * ID that is unique within the service. An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) A va_list + */ +extern void FIRLogBasicError(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicWarning(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicNotice(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicInfo(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicDebug(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - category: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRLOGGER_H diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FirebaseCoreInternal.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..2561008 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,28 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIREBASECORE_FIREBASECOREINTERNAL_H +#define FIREBASECORE_FIREBASECOREINTERNAL_H + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" + +#endif // FIREBASECORE_FIREBASECOREINTERNAL_H diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h new file mode 100644 index 0000000..8aed7b1 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h @@ -0,0 +1,65 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h" + +@class FIRInstallationsHTTPError; +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +void FIRInstallationsItemSetErrorToPointer(NSError *error, NSError **pointer); + +@interface FIRInstallationsErrorUtil : NSObject + ++ (NSError *)keyedArchiverErrorWithException:(NSException *)exception; ++ (NSError *)keyedArchiverErrorWithError:(NSError *)error; + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status; + ++ (NSError *)installationItemNotFoundForAppID:(NSString *)appID appName:(NSString *)appName; + ++ (NSError *)JSONSerializationError:(NSError *)error; + ++ (NSError *)networkErrorWithError:(NSError *)error; + ++ (NSError *)FIDRegistrationErrorWithResponseMissingField:(NSString *)missingFieldName; + ++ (NSError *)corruptedIIDTokenData; + ++ (FIRInstallationsHTTPError *)APIErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data; ++ (BOOL)isAPIError:(NSError *)error withHTTPCode:(NSInteger)HTTPCode; + ++ (NSError *)backoffIntervalWaitError; + +/** + * Returns the passed error if it is already in the public domain or a new error with the passed + * error at `NSUnderlyingErrorKey`. + */ ++ (NSError *)publicDomainErrorWithError:(NSError *)error; + ++ (FBLPromise *)rejectedPromiseWithError:(NSError *)error; + ++ (NSError *)installationsErrorWithCode:(FIRInstallationsErrorCode)code + failureReason:(nullable NSString *)failureReason + underlyingError:(nullable NSError *)underlyingError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m new file mode 100644 index 0000000..5673600 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m @@ -0,0 +1,145 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +NSString *const kFirebaseInstallationsErrorDomain = @"com.firebase.installations"; + +void FIRInstallationsItemSetErrorToPointer(NSError *error, NSError **pointer) { + if (pointer != NULL) { + *pointer = error; + } +} + +@implementation FIRInstallationsErrorUtil + ++ (NSError *)keyedArchiverErrorWithException:(NSException *)exception { + NSString *failureReason = [NSString + stringWithFormat:@"NSKeyedArchiver exception with name: %@, reason: %@, userInfo: %@", + exception.name, exception.reason, exception.userInfo]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)keyedArchiverErrorWithError:(NSError *)error { + NSString *failureReason = [NSString stringWithFormat:@"NSKeyedArchiver error."]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:error]; +} + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { + NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeKeychain + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)installationItemNotFoundForAppID:(NSString *)appID appName:(NSString *)appName { + NSString *failureReason = + [NSString stringWithFormat:@"Installation for appID %@ appName %@ not found", appID, appName]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)corruptedIIDTokenData { + NSString *failureReason = + @"IID token data stored in Keychain is corrupted or in an incompatible format."; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (FIRInstallationsHTTPError *)APIErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data { + return [[FIRInstallationsHTTPError alloc] initWithHTTPResponse:HTTPResponse data:data]; +} + ++ (BOOL)isAPIError:(NSError *)error withHTTPCode:(NSInteger)HTTPCode { + if (![error isKindOfClass:[FIRInstallationsHTTPError class]]) { + return NO; + } + + return [(FIRInstallationsHTTPError *)error HTTPResponse].statusCode == HTTPCode; +} + ++ (NSError *)JSONSerializationError:(NSError *)error { + NSString *failureReason = [NSString stringWithFormat:@"Failed to serialize JSON data."]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)FIDRegistrationErrorWithResponseMissingField:(NSString *)missingFieldName { + NSString *failureReason = [NSString + stringWithFormat:@"A required response field with name %@ is missing", missingFieldName]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)networkErrorWithError:(NSError *)error { + return [self installationsErrorWithCode:FIRInstallationsErrorCodeServerUnreachable + failureReason:@"Network connection error." + underlyingError:error]; +} + ++ (NSError *)backoffIntervalWaitError { + return [self installationsErrorWithCode:FIRInstallationsErrorCodeServerUnreachable + failureReason:@"Too many server requests." + underlyingError:nil]; +} + ++ (NSError *)publicDomainErrorWithError:(NSError *)error { + if ([error.domain isEqualToString:kFirebaseInstallationsErrorDomain]) { + return error; + } + + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:nil + underlyingError:error]; +} + ++ (NSError *)installationsErrorWithCode:(FIRInstallationsErrorCode)code + failureReason:(nullable NSString *)failureReason + underlyingError:(nullable NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSUnderlyingErrorKey] = underlyingError; + userInfo[NSLocalizedFailureReasonErrorKey] = + failureReason + ?: [NSString + stringWithFormat:@"Underlying error: %@", underlyingError.localizedDescription]; + + return [NSError errorWithDomain:kFirebaseInstallationsErrorDomain code:code userInfo:userInfo]; +} + ++ (FBLPromise *)rejectedPromiseWithError:(NSError *)error { + FBLPromise *rejectedPromise = [FBLPromise pendingPromise]; + [rejectedPromise reject:error]; + return rejectedPromise; +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h new file mode 100644 index 0000000..b978b77 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h @@ -0,0 +1,53 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Represents an error caused by an unexpected API response. */ +@interface FIRInstallationsHTTPError : NSError + +@property(nonatomic, readonly) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic, readonly, nonnull) NSData *data; + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse data:(nullable NSData *)data; + +@end + +NS_ASSUME_NONNULL_END + +typedef NS_ENUM(NSInteger, FIRInstallationsHTTPCodes) { + FIRInstallationsHTTPCodesTooManyRequests = 429, + FIRInstallationsHTTPCodesServerInternalError = 500, +}; + +/** Possible response HTTP codes for `CreateInstallation` API request. */ +typedef NS_ENUM(NSInteger, FIRInstallationsRegistrationHTTPCode) { + FIRInstallationsRegistrationHTTPCodeSuccess = 201, + FIRInstallationsRegistrationHTTPCodeInvalidArgument = 400, + FIRInstallationsRegistrationHTTPCodeAPIKeyToProjectIDMismatch = 403, + FIRInstallationsRegistrationHTTPCodeProjectNotFound = 404, + FIRInstallationsRegistrationHTTPCodeTooManyRequests = 429, + FIRInstallationsRegistrationHTTPCodeServerInternalError = 500 +}; + +typedef NS_ENUM(NSInteger, FIRInstallationsAuthTokenHTTPCode) { + FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication = 401, + FIRInstallationsAuthTokenHTTPCodeFIDNotFound = 404, +}; diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m new file mode 100644 index 0000000..4236f45 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m @@ -0,0 +1,79 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +@implementation FIRInstallationsHTTPError + +- (instancetype)initWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data { + NSDictionary *userInfo = [FIRInstallationsHTTPError userInfoWithHTTPResponse:HTTPResponse + data:data]; + self = [super + initWithDomain:kFirebaseInstallationsErrorDomain + code:[FIRInstallationsHTTPError errorCodeWithHTTPCode:HTTPResponse.statusCode] + userInfo:userInfo]; + if (self) { + _HTTPResponse = HTTPResponse; + _data = data; + } + return self; +} + ++ (FIRInstallationsErrorCode)errorCodeWithHTTPCode:(NSInteger)HTTPCode { + return FIRInstallationsErrorCodeUnknown; +} + ++ (NSDictionary *)userInfoWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data { + NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSString *failureReason = + [NSString stringWithFormat:@"The server responded with an error: \n - URL: %@ \n - HTTP " + @"status code: %ld \n - Response body: %@", + HTTPResponse.URL, (long)HTTPResponse.statusCode, responseString]; + return @{NSLocalizedFailureReasonErrorKey : failureReason}; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + return [[FIRInstallationsHTTPError alloc] initWithHTTPResponse:self.HTTPResponse data:self.data]; +} + +#pragma mark - NSSecureCoding + +- (nullable instancetype)initWithCoder:(NSCoder *)coder { + NSHTTPURLResponse *HTTPResponse = [coder decodeObjectOfClass:[NSHTTPURLResponse class] + forKey:@"HTTPResponse"]; + if (!HTTPResponse) { + return nil; + } + NSData *data = [coder decodeObjectOfClass:[NSData class] forKey:@"data"]; + + return [self initWithHTTPResponse:HTTPResponse data:data]; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.HTTPResponse forKey:@"HTTPResponse"]; + [coder encodeObject:self.data forKey:@"data"]; +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m new file mode 100644 index 0000000..4ee099e --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m @@ -0,0 +1,284 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +NS_ASSUME_NONNULL_BEGIN + +static const NSUInteger kExpectedAPIKeyLength = 39; + +@protocol FIRInstallationsInstanceProvider +@end + +@interface FIRInstallations () +@property(nonatomic, readonly) FIROptions *appOptions; +@property(nonatomic, readonly) NSString *appName; + +@property(nonatomic, readonly) FIRInstallationsIDController *installationsIDController; + +@end + +@implementation FIRInstallations + +#pragma mark - Firebase component + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self withName:@"fire-install"]; +} + ++ (nonnull NSArray *)componentsToRegister { + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + *isCacheable = YES; + FIRInstallations *installations = [[FIRInstallations alloc] initWithApp:container.app]; + return installations; + }; + + FIRComponent *installationsProvider = + [FIRComponent componentWithProtocol:@protocol(FIRInstallationsInstanceProvider) + instantiationTiming:FIRInstantiationTimingAlwaysEager + creationBlock:creationBlock]; + return @[ installationsProvider ]; +} + +- (instancetype)initWithApp:(FIRApp *)app { + FIRInstallationsIDController *IDController = + [[FIRInstallationsIDController alloc] initWithApp:app]; + + // `prefetchAuthToken` is disabled due to b/156746574. + return [self initWithAppOptions:app.options + appName:app.name + installationsIDController:IDController + prefetchAuthToken:NO]; +} + +/// This designated initializer can be exposed for testing. +- (instancetype)initWithAppOptions:(FIROptions *)appOptions + appName:(NSString *)appName + installationsIDController:(FIRInstallationsIDController *)installationsIDController + prefetchAuthToken:(BOOL)prefetchAuthToken { + self = [super init]; + if (self) { + [[self class] validateAppOptions:appOptions appName:appName]; + [[self class] assertCompatibleIIDVersion]; + + _appOptions = [appOptions copy]; + _appName = [appName copy]; + _installationsIDController = installationsIDController; + + // Pre-fetch auth token. + if (prefetchAuthToken) { + [self authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error){ + }]; + } + } + return self; +} + ++ (void)validateAppOptions:(FIROptions *)appOptions appName:(NSString *)appName { + NSMutableArray *missingFields = [NSMutableArray array]; + if (appName.length < 1) { + [missingFields addObject:@"`FirebaseApp.name`"]; + } + if (appOptions.APIKey.length < 1) { + [missingFields addObject:@"`FirebaseOptions.APIKey`"]; + } + if (appOptions.googleAppID.length < 1) { + [missingFields addObject:@"`FirebaseOptions.googleAppID`"]; + } + + if (appOptions.projectID.length < 1) { + [missingFields addObject:@"`FirebaseOptions.projectID`"]; + } + + if (missingFields.count > 0) { + [NSException + raise:kFirebaseInstallationsErrorDomain + format: + @"%@[%@] Could not configure Firebase Installations due to invalid FirebaseApp " + @"options. The following parameters are nil or empty: %@. If you use " + @"GoogleServices-Info.plist please download the most recent version from the Firebase " + @"Console. If you configure Firebase in code, please make sure you specify all " + @"required parameters.", + kFIRLoggerInstallations, kFIRInstallationsMessageCodeInvalidFirebaseAppOptions, + [missingFields componentsJoinedByString:@", "]]; + } + + [self validateAPIKey:appOptions.APIKey]; +} + ++ (void)validateAPIKey:(nullable NSString *)APIKey { + NSMutableArray *validationIssues = [[NSMutableArray alloc] init]; + + if (APIKey.length != kExpectedAPIKeyLength) { + [validationIssues addObject:[NSString stringWithFormat:@"API Key length must be %lu characters", + (unsigned long)kExpectedAPIKeyLength]]; + } + + if (![[APIKey substringToIndex:1] isEqualToString:@"A"]) { + [validationIssues addObject:@"API Key must start with `A`"]; + } + + NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedCharacters + formUnionWithCharacterSet:[NSCharacterSet characterSetWithCharactersInString:@"-_"]]; + + NSCharacterSet *characters = [NSCharacterSet characterSetWithCharactersInString:APIKey]; + if (![allowedCharacters isSupersetOfSet:characters]) { + [validationIssues addObject:@"API Key must contain only base64 url-safe characters characters"]; + } + + if (validationIssues.count > 0) { + [NSException + raise:kFirebaseInstallationsErrorDomain + format: + @"%@[%@] Could not configure Firebase Installations due to invalid FirebaseApp " + @"options. `FirebaseOptions.APIKey` doesn't match the expected format: %@. If you use " + @"GoogleServices-Info.plist please download the most recent version from the Firebase " + @"Console. If you configure Firebase in code, please make sure you specify all " + @"required parameters.", + kFIRLoggerInstallations, kFIRInstallationsMessageCodeInvalidFirebaseAppOptions, + [validationIssues componentsJoinedByString:@", "]]; + } +} + +#pragma mark - Public + ++ (FIRInstallations *)installations { + FIRApp *defaultApp = [FIRApp defaultApp]; + if (!defaultApp) { + [NSException raise:kFirebaseInstallationsErrorDomain + format:@"The default FirebaseApp instance must be configured before the default" + @"FirebaseApp instance can be initialized. One way to ensure this is to " + @"call `FirebaseApp.configure()` in the App Delegate's " + @"`application(_:didFinishLaunchingWithOptions:)` " + @"(or the `@main` struct's initializer in SwiftUI)."]; + } + + return [self installationsWithApp:defaultApp]; +} + ++ (FIRInstallations *)installationsWithApp:(FIRApp *)app { + id installations = + FIR_COMPONENT(FIRInstallationsInstanceProvider, app.container); + return (FIRInstallations *)installations; +} + +- (void)installationIDWithCompletion:(FIRInstallationsIDHandler)completion { + [self.installationsIDController getInstallationItem] + .then(^id(FIRInstallationsItem *installation) { + completion(installation.firebaseInstallationID, nil); + return nil; + }) + .catch(^(NSError *error) { + completion(nil, [FIRInstallationsErrorUtil publicDomainErrorWithError:error]); + }); +} + +- (void)authTokenWithCompletion:(FIRInstallationsTokenHandler)completion { + [self authTokenForcingRefresh:NO completion:completion]; +} + +- (void)authTokenForcingRefresh:(BOOL)forceRefresh + completion:(FIRInstallationsTokenHandler)completion { + [self.installationsIDController getAuthTokenForcingRefresh:forceRefresh] + .then(^FIRInstallationsAuthTokenResult *(FIRInstallationsItem *installation) { + FIRInstallationsAuthTokenResult *result = [[FIRInstallationsAuthTokenResult alloc] + initWithToken:installation.authToken.token + expirationDate:installation.authToken.expirationDate]; + return result; + }) + .then(^id(FIRInstallationsAuthTokenResult *token) { + completion(token, nil); + return nil; + }) + .catch(^void(NSError *error) { + completion(nil, [FIRInstallationsErrorUtil publicDomainErrorWithError:error]); + }); +} + +- (void)deleteWithCompletion:(void (^)(NSError *__nullable error))completion { + [self.installationsIDController deleteInstallation] + .then(^id(id result) { + completion(nil); + return nil; + }) + .catch(^void(NSError *error) { + completion([FIRInstallationsErrorUtil publicDomainErrorWithError:error]); + }); +} + +#pragma mark - IID version compatibility + ++ (void)assertCompatibleIIDVersion { + // We use this flag to disable IID compatibility exception for unit tests. +#ifdef FIR_INSTALLATIONS_ALLOWS_INCOMPATIBLE_IID_VERSION + return; +#else + if (![self isIIDVersionCompatible]) { + [NSException + raise:kFirebaseInstallationsErrorDomain + format:@"Firebase Instance ID is not compatible with Firebase 8.x+. Please remove the " + @"dependency from the app. See the documentation at " + @"https://firebase.google.com/docs/cloud-messaging/ios/" + @"client#fetching-the-current-registration-token."]; + } +#endif +} + ++ (BOOL)isIIDVersionCompatible { + Class IIDClass = NSClassFromString(@"FIRInstanceID"); + if (IIDClass == nil) { + // It is OK if there is no IID at all. + return YES; + } + // We expect a compatible version having the method `+[FIRInstanceID usesFIS]` defined. + BOOL isCompatibleVersion = [IIDClass respondsToSelector:NSSelectorFromString(@"usesFIS")]; + return isCompatibleVersion; +} + +#pragma mark - Force Category Linking + +extern void FIRInclude_FIRInstallationsItem_RegisterInstallationAPI_Category(void); + +/// Does nothing when called, and not meant to be called. +/// +/// This method forces the linker to include categories even if +/// users do not include the '-ObjC' linker flag in their project. ++ (void)noop { + FIRInclude_FIRInstallationsItem_RegisterInstallationAPI_Category(); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m new file mode 100644 index 0000000..47a71e8 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m @@ -0,0 +1,30 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h" + +@implementation FIRInstallationsAuthTokenResult + +- (instancetype)initWithToken:(NSString *)token expirationDate:(NSDate *)expirationDate { + self = [super init]; + if (self) { + _authToken = [token copy]; + _expirationDate = expirationDate; + } + return self; +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h new file mode 100644 index 0000000..662802e --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h @@ -0,0 +1,27 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstallationsAuthTokenResult (Internal) + +- (instancetype)initWithToken:(NSString *)token expirationDate:(NSDate *)expirationTime; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h new file mode 100644 index 0000000..8aa3a5e --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h @@ -0,0 +1,93 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h" + +@class FIRInstallationsStoredItem; +@class FIRInstallationsStoredAuthToken; +@class FIRInstallationsStoredIIDCheckin; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class represents the required installation ID and auth token data including possible states. + * The data is stored to Keychain via `FIRInstallationsStoredItem` which has only the storage + * relevant data and does not contain any logic. `FIRInstallationsItem` must be used on the logic + * level (not `FIRInstallationsStoredItem`). + */ +@interface FIRInstallationsItem : NSObject + +/// A `FirebaseApp` identifier. +@property(nonatomic, readonly) NSString *appID; +/// A `FirebaseApp` name. +@property(nonatomic, readonly) NSString *firebaseAppName; +/// A stable identifier that uniquely identifies the app instance. +@property(nonatomic, copy, nullable) NSString *firebaseInstallationID; +/// The `refreshToken` is used to authorize the auth token requests. +@property(nonatomic, copy, nullable) NSString *refreshToken; + +@property(nonatomic, nullable) FIRInstallationsStoredAuthToken *authToken; +@property(nonatomic, assign) FIRInstallationsStatus registrationStatus; + +/// Instance ID default token imported from IID store as a part of IID migration. +@property(nonatomic, nullable) NSString *IIDDefaultToken; + +- (instancetype)initWithAppID:(NSString *)appID firebaseAppName:(NSString *)firebaseAppName; + +/** + * Populates `FIRInstallationsItem` properties with data from `FIRInstallationsStoredItem`. + * @param item An instance of `FIRInstallationsStoredItem` to get data from. + */ +- (void)updateWithStoredItem:(FIRInstallationsStoredItem *)item; + +/** + * Creates a stored item with data from the object. + * @return Returns a `FIRInstallationsStoredItem` instance with the data from the object. + */ +- (FIRInstallationsStoredItem *)storedItem; + +/** + * The installation identifier. + * @return Returns a string uniquely identifying the installation. + */ +- (NSString *)identifier; + +/** Validates if all the required item fields are populated and values don't explicitly conflict + * with each other. + * @param outError A reference to be populated with an error containing validation failure details. + * @return `YES` if the item it valid, `NO` otherwise. + */ +- (BOOL)isValid:(NSError *_Nullable *)outError; + +/** + * The installation identifier. + * @param appID A `FirebaseApp` identifier. + * @param appName A `FirebaseApp` name. + * @return Returns a string uniquely identifying the installation. + */ ++ (NSString *)identifierWithAppID:(NSString *)appID appName:(NSString *)appName; + +/** + * Generate a new Firebase Installation Identifier. + * @return Returns a 22 characters long globally unique string created based on UUID. + */ ++ (NSString *)generateFID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m new file mode 100644 index 0000000..0316e45 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m @@ -0,0 +1,161 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" + +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +@implementation FIRInstallationsItem + +- (instancetype)initWithAppID:(NSString *)appID firebaseAppName:(NSString *)firebaseAppName { + self = [super init]; + if (self) { + _appID = [appID copy]; + _firebaseAppName = [firebaseAppName copy]; + } + return self; +} + +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + FIRInstallationsItem *clone = [[FIRInstallationsItem alloc] initWithAppID:self.appID + firebaseAppName:self.firebaseAppName]; + clone.firebaseInstallationID = [self.firebaseInstallationID copy]; + clone.refreshToken = [self.refreshToken copy]; + clone.authToken = [self.authToken copy]; + clone.registrationStatus = self.registrationStatus; + clone.IIDDefaultToken = [self.IIDDefaultToken copy]; + + return clone; +} + +- (void)updateWithStoredItem:(FIRInstallationsStoredItem *)item { + self.firebaseInstallationID = item.firebaseInstallationID; + self.refreshToken = item.refreshToken; + self.authToken = item.authToken; + self.registrationStatus = item.registrationStatus; + self.IIDDefaultToken = item.IIDDefaultToken; +} + +- (FIRInstallationsStoredItem *)storedItem { + FIRInstallationsStoredItem *storedItem = [[FIRInstallationsStoredItem alloc] init]; + storedItem.firebaseInstallationID = self.firebaseInstallationID; + storedItem.refreshToken = self.refreshToken; + storedItem.authToken = self.authToken; + storedItem.registrationStatus = self.registrationStatus; + storedItem.IIDDefaultToken = self.IIDDefaultToken; + return storedItem; +} + +- (nonnull NSString *)identifier { + return [[self class] identifierWithAppID:self.appID appName:self.firebaseAppName]; +} + +- (BOOL)isValid:(NSError *_Nullable *)outError { + NSMutableArray *validationIssues = [NSMutableArray array]; + + if (self.appID.length == 0) { + [validationIssues addObject:@"`appID` must not be empty"]; + } + + if (self.firebaseAppName.length == 0) { + [validationIssues addObject:@"`firebaseAppName` must not be empty"]; + } + + if (self.firebaseInstallationID.length == 0) { + [validationIssues addObject:@"`firebaseInstallationID` must not be empty"]; + } + + switch (self.registrationStatus) { + case FIRInstallationStatusUnknown: + [validationIssues addObject:@"invalid `registrationStatus`"]; + break; + + case FIRInstallationStatusRegistered: + if (self.refreshToken == 0) { + [validationIssues addObject:@"registered installation must have non-empty `refreshToken`"]; + } + + if (self.authToken.token == 0) { + [validationIssues + addObject:@"registered installation must have non-empty `authToken.token`"]; + } + + if (self.authToken.expirationDate == nil) { + [validationIssues + addObject:@"registered installation must have non-empty `authToken.expirationDate`"]; + } + + case FIRInstallationStatusUnregistered: + break; + } + + BOOL isValid = validationIssues.count == 0; + + if (!isValid && outError) { + NSString *failureReason = + [NSString stringWithFormat:@"FIRInstallationsItem validation errors: %@", + [validationIssues componentsJoinedByString:@", "]]; + *outError = + [FIRInstallationsErrorUtil installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; + } + + return isValid; +} + ++ (NSString *)identifierWithAppID:(NSString *)appID appName:(NSString *)appName { + return [appID stringByAppendingString:appName]; +} + ++ (NSString *)generateFID { + NSUUID *UUID = [NSUUID UUID]; + uuid_t UUIDBytes; + [UUID getUUIDBytes:UUIDBytes]; + + NSUInteger UUIDLength = sizeof(uuid_t); + NSData *UUIDData = [NSData dataWithBytes:UUIDBytes length:UUIDLength]; + + uint8_t UUIDLast4Bits = UUIDBytes[UUIDLength - 1] & 0b00001111; + + // FID first 4 bits must be `0111`. The last 4 UUID bits will be cut later to form a proper FID. + // To keep 16 random bytes we copy these last 4 UUID to the FID 1st byte after `0111` prefix. + uint8_t FIDPrefix = 0b01110000 | UUIDLast4Bits; + NSMutableData *FIDData = [NSMutableData dataWithBytes:&FIDPrefix length:1]; + + [FIDData appendData:UUIDData]; + NSString *FIDString = [self base64URLEncodedStringWithData:FIDData]; + + // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 bytes. + // Our generated ID has 16 bytes UUID + 1 byte prefix which after encoding with base64 will become + // 23 characters plus 1 character for "=" padding. + + // Remove the 23rd character that was added because of the extra 4 bits at the + // end of our 17 byte data and the '=' padding. + return [FIDString substringWithRange:NSMakeRange(0, 22)]; +} + ++ (NSString *)base64URLEncodedStringWithData:(NSData *)data { + NSString *string = [data base64EncodedStringWithOptions:0]; + string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + return string; +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h new file mode 100644 index 0000000..7ad9967 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h @@ -0,0 +1,52 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +extern FIRLoggerService kFIRLoggerInstallations; + +// FIRInstallationsAPIService.m +extern NSString *const kFIRInstallationsMessageCodeSendAPIRequest; +extern NSString *const kFIRInstallationsMessageCodeAPIRequestNetworkError; +extern NSString *const kFIRInstallationsMessageCodeAPIRequestResponse; +extern NSString *const kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse; +extern NSString *const kFIRInstallationsMessageCodeParsingAPIResponse; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed; + +// FIRInstallationsIDController.m +extern NSString *const kFIRInstallationsMessageCodeNewGetInstallationOperationCreated; +extern NSString *const kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated; +extern NSString *const kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated; +extern NSString *const kFIRInstallationsMessageCodeInvalidFirebaseConfiguration; +extern NSString *const kFIRInstallationsMessageCodeCorruptedStoredInstallation; + +// FIRInstallationsStoredItem.m +extern NSString *const kFIRInstallationsMessageCodeInstallationCoderVersionMismatch; + +// FIRInstallationsStoredAuthToken.m +extern NSString *const kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch; + +// FIRInstallationsStoredIIDCheckin.m +extern NSString *const kFIRInstallationsMessageCodeIIDCheckinCoderVersionMismatch; +extern NSString *const kFIRInstallationsMessageCodeIIDCheckinFailedToDecode; + +// FIRInstallations.m +extern NSString *const kFIRInstallationsMessageCodeInvalidFirebaseAppOptions; diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m new file mode 100644 index 0000000..5187f97 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" + +FIRLoggerService kFIRLoggerInstallations = @"[FirebaseInstallations]"; + +// FIRInstallationsAPIService.m +NSString *const kFIRInstallationsMessageCodeSendAPIRequest = @"I-FIS001001"; +NSString *const kFIRInstallationsMessageCodeAPIRequestNetworkError = @"I-FIS001002"; +NSString *const kFIRInstallationsMessageCodeAPIRequestResponse = @"I-FIS001003"; +NSString *const kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse = @"I-FIS001004"; +NSString *const kFIRInstallationsMessageCodeParsingAPIResponse = @"I-FIS001005"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed = @"I-FIS001006"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed = @"I-FIS001007"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed = @"I-FIS001008"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed = @"I-FIS001009"; + +// FIRInstallationsIDController.m +NSString *const kFIRInstallationsMessageCodeNewGetInstallationOperationCreated = @"I-FIS002000"; +NSString *const kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated = @"I-FIS002001"; +NSString *const kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated = @"I-FIS002002"; +NSString *const kFIRInstallationsMessageCodeInvalidFirebaseConfiguration = @"I-FIS002003"; +NSString *const kFIRInstallationsMessageCodeCorruptedStoredInstallation = @"I-FIS002004"; + +// FIRInstallationsStoredItem.m +NSString *const kFIRInstallationsMessageCodeInstallationCoderVersionMismatch = @"I-FIS003000"; + +// FIRInstallationsStoredAuthToken.m +NSString *const kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch = @"I-FIS004000"; + +// FIRInstallationsStoredIIDCheckin.m +NSString *const kFIRInstallationsMessageCodeIIDCheckinCoderVersionMismatch = @"I-FIS007000"; +NSString *const kFIRInstallationsMessageCodeIIDCheckinFailedToDecode = @"I-FIS007001"; + +// FIRInstallations.m +NSString *const kFIRInstallationsMessageCodeInvalidFirebaseAppOptions = @"I-FIS008000"; diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h new file mode 100644 index 0000000..e2408ca --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** The class encapsulates a port of a piece FirebaseInstanceID logic required to migrate IID. */ +@interface FIRInstallationsIIDStore : NSObject + +/** + * Retrieves existing IID if present. + * @return Returns a promise that is resolved with IID string if IID has been found or rejected with + * an error otherwise. + */ +- (FBLPromise *)existingIID; + +/** + * Deletes existing IID if present. + * @return Returns a promise that is resolved with `[NSNull null]` if the IID was successfully. + * deleted or was not found. The promise is rejected otherwise. + */ +- (FBLPromise *)deleteExistingIID; + +#if TARGET_OS_OSX +/// If not `nil`, then only this keychain will be used to save and read data (see +/// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests. +@property(nonatomic, nullable) SecKeychainRef keychainRef; +#endif // TARGET_OSX + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m new file mode 100644 index 0000000..1c2f5d3 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m @@ -0,0 +1,242 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +static NSString *const kFIRInstallationsIIDKeyPairPublicTagPrefix = + @"com.google.iid.keypair.public-"; +static NSString *const kFIRInstallationsIIDKeyPairPrivateTagPrefix = + @"com.google.iid.keypair.private-"; +static NSString *const kFIRInstallationsIIDCreationTimePlistKey = @"|S|cre"; + +@implementation FIRInstallationsIIDStore + +- (FBLPromise *)existingIID { + return [FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + if (![self hasPlistIIDFlag]) { + return nil; + } + + NSData *IIDPublicKeyData = [self IIDPublicKeyData]; + return [self IIDWithPublicKeyData:IIDPublicKeyData]; + }] + .validate(^BOOL(NSString *_Nullable IID) { + return IID.length > 0; + }); +} + +- (FBLPromise *)deleteExistingIID { + return [FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + NSError *error; + if (![self deleteIIDFlagFromPlist:&error]) { + return error; + } + + if (![self deleteIID:&error]) { + return error; + } + + return [NSNull null]; + }]; +} + +#pragma mark - IID decoding + +- (NSString *)IIDWithPublicKeyData:(NSData *)publicKeyData { + NSData *publicKeySHA1 = [self sha1WithData:publicKeyData]; + + const uint8_t *bytes = publicKeySHA1.bytes; + NSMutableData *identityData = [NSMutableData dataWithData:publicKeySHA1]; + + uint8_t b0 = bytes[0]; + // Take the first byte and make the initial four 7 by initially making the initial 4 bits 0 + // and then adding 0x70 to it. + b0 = 0x70 + (0xF & b0); + // failsafe should give you back b0 itself + b0 = (b0 & 0xFF); + [identityData replaceBytesInRange:NSMakeRange(0, 1) withBytes:&b0]; + NSData *data = [identityData subdataWithRange:NSMakeRange(0, 8 * sizeof(Byte))]; + return [self base64URLEncodedStringWithData:data]; +} + +/** FirebaseInstallations SDK uses the SHA1 hash for backwards compatibility with the legacy + * FirebaseInstanceID SDK. The SHA1 hash is used to access Instance IDs stored on the device and not + * for any security-relevant process. This is a one-time step that allows migration of old client + * identifiers. Cryptographic security is not needed here, so potential hash collisions are not a + * problem. + */ +- (NSData *)sha1WithData:(NSData *)data { + unsigned char output[CC_SHA1_DIGEST_LENGTH]; + unsigned int length = (unsigned int)[data length]; + + CC_SHA1(data.bytes, length, output); + return [NSData dataWithBytes:output length:CC_SHA1_DIGEST_LENGTH]; +} + +- (NSString *)base64URLEncodedStringWithData:(NSData *)data { + NSString *string = [data base64EncodedStringWithOptions:0]; + string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + string = [string stringByReplacingOccurrencesOfString:@"=" withString:@""]; + return string; +} + +#pragma mark - Keychain + +- (NSData *)IIDPublicKeyData { + NSString *tag = [self keychainKeyTagWithPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix]; + NSDictionary *query = [self keyPairQueryWithTag:tag returnData:YES]; + + CFTypeRef keyRef = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&keyRef); + + if (status != noErr) { + if (keyRef) { + CFRelease(keyRef); + } + return nil; + } + + return (__bridge NSData *)keyRef; +} + +- (BOOL)deleteIID:(NSError **)outError { + if (![self deleteKeychainKeyWithTagPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix + error:outError]) { + return NO; + } + + if (![self deleteKeychainKeyWithTagPrefix:kFIRInstallationsIIDKeyPairPrivateTagPrefix + error:outError]) { + return NO; + } + + return YES; +} + +- (BOOL)deleteKeychainKeyWithTagPrefix:(NSString *)tagPrefix error:(NSError **)outError { + NSString *keyTag = [self keychainKeyTagWithPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix]; + NSDictionary *keyQuery = [self keyPairQueryWithTag:keyTag returnData:NO]; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)keyQuery); + + // When item is not found, it should NOT be considered as an error. The operation should + // continue. + if (status != noErr && status != errSecItemNotFound) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil keychainErrorWithFunction:@"SecItemDelete" status:status], + outError); + return NO; + } + + return YES; +} + +- (NSDictionary *)keyPairQueryWithTag:(NSString *)tag returnData:(BOOL)shouldReturnData { + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding]; + + query[(__bridge id)kSecClass] = (__bridge id)kSecClassKey; + query[(__bridge id)kSecAttrApplicationTag] = tagData; + query[(__bridge id)kSecAttrKeyType] = (__bridge id)kSecAttrKeyTypeRSA; + if (shouldReturnData) { + query[(__bridge id)kSecReturnData] = @(YES); + } + +#if TARGET_OS_OSX + if (self.keychainRef) { + query[(__bridge NSString *)kSecMatchSearchList] = @[ (__bridge id)(self.keychainRef) ]; + } +#endif // TARGET_OSX + + return query; +} + +- (NSString *)keychainKeyTagWithPrefix:(NSString *)prefix { + NSString *mainAppBundleID = [[NSBundle mainBundle] bundleIdentifier]; + if (mainAppBundleID.length == 0) { + return nil; + } + return [NSString stringWithFormat:@"%@%@", prefix, mainAppBundleID]; +} + +- (NSString *)mainbundleIdentifier { + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + if (!bundleIdentifier.length) { + return nil; + } + return bundleIdentifier; +} + +#pragma mark - Plist + +- (BOOL)deleteIIDFlagFromPlist:(NSError **)outError { + NSString *path = [self plistPath]; + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + return YES; + } + + NSMutableDictionary *plistContent = [[NSMutableDictionary alloc] initWithContentsOfFile:path]; + plistContent[kFIRInstallationsIIDCreationTimePlistKey] = nil; + + if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) { + return [plistContent writeToURL:[NSURL fileURLWithPath:path] error:outError]; + } + + return [plistContent writeToFile:path atomically:YES]; +} + +- (BOOL)hasPlistIIDFlag { + NSString *path = [self plistPath]; + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + return NO; + } + + NSDictionary *plistContent = [[NSDictionary alloc] initWithContentsOfFile:path]; + return plistContent[kFIRInstallationsIIDCreationTimePlistKey] != nil; +} + +- (NSString *)plistPath { + NSString *plistNameWithExtension = @"com.google.iid-keypair.plist"; + NSString *_subDirectoryName = @"Google/FirebaseInstanceID"; + + NSArray *directoryPaths = + NSSearchPathForDirectoriesInDomains([self supportedDirectory], NSUserDomainMask, YES); + NSArray *components = @[ directoryPaths.lastObject, _subDirectoryName, plistNameWithExtension ]; + + return [NSString pathWithComponents:components]; +} + +- (NSSearchPathDirectory)supportedDirectory { +#if TARGET_OS_TV + return NSCachesDirectory; +#else + return NSApplicationSupportDirectory; +#endif +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h new file mode 100644 index 0000000..ed98e3d --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h @@ -0,0 +1,36 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class reads a default IID token from IID store if available. + */ +@interface FIRInstallationsIIDTokenStore : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID; + +- (FBLPromise *)existingIIDDefaultToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m new file mode 100644 index 0000000..5ef3331 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m @@ -0,0 +1,158 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +static NSString *const kFIRInstallationsIIDTokenKeychainId = @"com.google.iid-tokens"; + +@interface FIRInstallationsIIDTokenInfo : NSObject +@property(nonatomic, nullable, copy) NSString *token; +@end + +@implementation FIRInstallationsIIDTokenInfo + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + self = [super init]; + if (self) { + _token = [coder decodeObjectOfClass:[NSString class] forKey:@"token"]; + } + return self; +} + +@end + +@interface FIRInstallationsIIDTokenStore () +@property(nonatomic, readonly) NSString *GCMSenderID; +@end + +@implementation FIRInstallationsIIDTokenStore + +- (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID { + self = [super init]; + if (self) { + _GCMSenderID = GCMSenderID; + } + return self; +} + +- (FBLPromise *)existingIIDDefaultToken { + return [[FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + return [self IIDDefaultTokenData]; + }] onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + then:^id _Nullable(NSData *_Nullable keychainData) { + return [self IIDCheckinWithData:keychainData]; + }]; +} + +- (FBLPromise *)IIDCheckinWithData:(NSData *)data { + FBLPromise *resultPromise = [FBLPromise pendingPromise]; + + NSError *archiverError; + NSKeyedUnarchiver *unarchiver; + if (@available(iOS 11.0, tvOS 11.0, macOS 10.13, *)) { + unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&archiverError]; + } else { + @try { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; +#pragma clang diagnostic pop + } @catch (NSException *exception) { + archiverError = [FIRInstallationsErrorUtil keyedArchiverErrorWithException:exception]; + } + } + + if (!unarchiver) { + NSError *error = archiverError ?: [FIRInstallationsErrorUtil corruptedIIDTokenData]; + [resultPromise reject:error]; + return resultPromise; + } + + [unarchiver setClass:[FIRInstallationsIIDTokenInfo class] forClassName:@"FIRInstanceIDTokenInfo"]; + FIRInstallationsIIDTokenInfo *IIDTokenInfo = + [unarchiver decodeObjectOfClass:[FIRInstallationsIIDTokenInfo class] + forKey:NSKeyedArchiveRootObjectKey]; + + if (IIDTokenInfo.token.length < 1) { + [resultPromise reject:[FIRInstallationsErrorUtil corruptedIIDTokenData]]; + return resultPromise; + } + + [resultPromise fulfill:IIDTokenInfo.token]; + + return resultPromise; +} + +- (FBLPromise *)IIDDefaultTokenData { + FBLPromise *resultPromise = [FBLPromise pendingPromise]; + + NSMutableDictionary *keychainQuery = [self IIDDefaultTokenDataKeychainQuery]; + NSError *error; + NSData *data = [GULKeychainUtils getItemWithQuery:keychainQuery error:&error]; + + if (data) { + [resultPromise fulfill:data]; + return resultPromise; + } else { + NSError *outError = error ?: [FIRInstallationsErrorUtil corruptedIIDTokenData]; + [resultPromise reject:outError]; + return resultPromise; + } +} + +- (NSMutableDictionary *)IIDDefaultTokenDataKeychainQuery { + NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword}; + + NSMutableDictionary *finalQuery = [NSMutableDictionary dictionaryWithDictionary:query]; + finalQuery[(__bridge NSString *)kSecAttrGeneric] = kFIRInstallationsIIDTokenKeychainId; + + NSString *account = [self IIDAppIdentifier]; + if ([account length]) { + finalQuery[(__bridge NSString *)kSecAttrAccount] = account; + } + + finalQuery[(__bridge NSString *)kSecAttrService] = + [self serviceKeyForAuthorizedEntity:self.GCMSenderID scope:@"*"]; + return finalQuery; +} + +- (NSString *)IIDAppIdentifier { + return [[NSBundle mainBundle] bundleIdentifier] ?: @""; +} + +- (NSString *)serviceKeyForAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope { + return [NSString stringWithFormat:@"%@:%@", authorizedEntity, scope]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h new file mode 100644 index 0000000..1601bdc --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h @@ -0,0 +1,65 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; +@class FIRInstallationsItem; + +@protocol FIRHeartbeatLoggerProtocol; + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kFIRInstallationsHeartbeatKey; + +/** + * The class is responsible for interacting with HTTP REST API for Installations. + */ +@interface FIRInstallationsAPIService : NSObject + +/** + * The default initializer. + * @param APIKey The Firebase project API key (see `FIROptions.APIKey`). + * @param projectID The Firebase project ID (see `FIROptions.projectID`). + * @param heartbeatLogger The heartbeat logger used to populate heartbeat data in request headers. + */ +- (instancetype)initWithAPIKey:(NSString *)APIKey + projectID:(NSString *)projectID + heartbeatLogger:(id)heartbeatLogger; + +/** + * Sends a request to register a new FID to get auth and refresh tokens. + * @param installation The `FIRInstallationsItem` instance with the FID to register. + * @return A promise that is resolved with a new `FIRInstallationsItem` instance with valid tokens. + * It is rejected with an error in case of a failure. + */ +- (FBLPromise *)registerInstallation:(FIRInstallationsItem *)installation; + +- (FBLPromise *)refreshAuthTokenForInstallation: + (FIRInstallationsItem *)installation; + +/** + * Sends a request to delete the installation, related auth tokens and all related data from the + * server. + * @param installation The installation to delete. + * @return Returns a promise that is resolved with the passed installation on successful deletion or + * is rejected with an error otherwise. + */ +- (FBLPromise *)deleteInstallation:(FIRInstallationsItem *)installation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m new file mode 100644 index 0000000..99dd215 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m @@ -0,0 +1,382 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h" + +NSString *const kFIRInstallationsAPIBaseURL = @"https://firebaseinstallations.googleapis.com"; +NSString *const kFIRInstallationsAPIKey = @"X-Goog-Api-Key"; +NSString *const kFIRInstallationsBundleId = @"X-Ios-Bundle-Identifier"; +NSString *const kFIRInstallationsIIDMigrationAuthHeader = @"x-goog-fis-ios-iid-migration-auth"; +NSString *const kFIRInstallationsHeartbeatKey = @"X-firebase-client"; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstallationsURLSessionResponse : NSObject +@property(nonatomic) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic) NSData *data; + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response data:(nullable NSData *)data; +@end + +@implementation FIRInstallationsURLSessionResponse + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response data:(nullable NSData *)data { + self = [super init]; + if (self) { + _HTTPResponse = response; + _data = data ?: [NSData data]; + } + return self; +} + +@end + +@interface FIRInstallationsAPIService () +@property(nonatomic, readonly) NSURLSession *URLSession; +@property(nonatomic, readonly) NSString *APIKey; +@property(nonatomic, readonly) NSString *projectID; +@property(readonly) id heartbeatLogger; +@end + +NS_ASSUME_NONNULL_END + +@implementation FIRInstallationsAPIService + +- (instancetype)initWithAPIKey:(NSString *)APIKey + projectID:(NSString *)projectID + heartbeatLogger:(id)heartbeatLogger { + NSURLSession *URLSession = [NSURLSession + sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; + return [self initWithURLSession:URLSession + APIKey:APIKey + projectID:projectID + heartbeatLogger:heartbeatLogger]; +} + +/// The initializer for tests. +- (instancetype)initWithURLSession:(NSURLSession *)URLSession + APIKey:(NSString *)APIKey + projectID:(NSString *)projectID + heartbeatLogger:(id)heartbeatLogger { + self = [super init]; + if (self) { + _URLSession = URLSession; + _APIKey = [APIKey copy]; + _projectID = [projectID copy]; + _heartbeatLogger = heartbeatLogger; + } + return self; +} + +#pragma mark - Public + +- (FBLPromise *)registerInstallation:(FIRInstallationsItem *)installation { + return [self validateInstallation:installation] + .then(^id _Nullable(FIRInstallationsItem *_Nullable validInstallation) { + return [self registerRequestWithInstallation:validInstallation]; + }) + .then(^id _Nullable(NSURLRequest *_Nullable request) { + return [self sendURLRequest:request]; + }) + .then(^id _Nullable(FIRInstallationsURLSessionResponse *response) { + return [self registeredInstallationWithInstallation:installation serverResponse:response]; + }); +} + +- (FBLPromise *)refreshAuthTokenForInstallation: + (FIRInstallationsItem *)installation { + return [self authTokenRequestWithInstallation:installation] + .then(^id _Nullable(NSURLRequest *_Nullable request) { + return [self sendURLRequest:request]; + }) + .then(^FBLPromise *( + FIRInstallationsURLSessionResponse *response) { + return [self authTokenWithServerResponse:response]; + }) + .then(^FIRInstallationsItem *(FIRInstallationsStoredAuthToken *authToken) { + FIRInstallationsItem *updatedInstallation = [installation copy]; + updatedInstallation.authToken = authToken; + return updatedInstallation; + }); +} + +- (FBLPromise *)deleteInstallation:(FIRInstallationsItem *)installation { + return [self deleteInstallationRequestWithInstallation:installation] + .then(^id _Nullable(NSURLRequest *_Nullable request) { + return [self sendURLRequest:request]; + }) + .then(^id _Nullable(FIRInstallationsURLSessionResponse *_Nullable value) { + // Return the original installation on success. + return installation; + }); +} + +#pragma mark - Register Installation + +- (FBLPromise *)registerRequestWithInstallation: + (FIRInstallationsItem *)installation { + NSString *URLString = [NSString stringWithFormat:@"%@/v1/projects/%@/installations/", + kFIRInstallationsAPIBaseURL, self.projectID]; + NSURL *URL = [NSURL URLWithString:URLString]; + + NSDictionary *bodyDict = @{ + // `firebaseInstallationID` is validated before but let's make sure it is not `nil` one more + // time to prevent a crash. + @"fid" : installation.firebaseInstallationID ?: @"", + @"authVersion" : @"FIS_v2", + @"appId" : installation.appID, + @"sdkVersion" : [self SDKVersion] + }; + + NSDictionary *headers; + if (installation.IIDDefaultToken) { + headers = @{kFIRInstallationsIIDMigrationAuthHeader : installation.IIDDefaultToken}; + } + + return [self requestWithURL:URL + HTTPMethod:@"POST" + bodyDict:bodyDict + refreshToken:nil + additionalHeaders:headers]; +} + +- (FBLPromise *) + registeredInstallationWithInstallation:(FIRInstallationsItem *)installation + serverResponse:(FIRInstallationsURLSessionResponse *)response { + return [FBLPromise do:^id { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeParsingAPIResponse, + @"Parsing server response for %@.", response.HTTPResponse.URL); + NSError *error; + FIRInstallationsItem *registeredInstallation = + [installation registeredInstallationWithJSONData:response.data + date:[NSDate date] + error:&error]; + if (registeredInstallation == nil) { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed, + @"Failed to parse FIRInstallationsItem: %@.", error); + return error; + } + + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed, + @"FIRInstallationsItem parsed successfully."); + return registeredInstallation; + }]; +} + +#pragma mark - Auth token + +- (FBLPromise *)authTokenRequestWithInstallation: + (FIRInstallationsItem *)installation { + NSString *URLString = + [NSString stringWithFormat:@"%@/v1/projects/%@/installations/%@/authTokens:generate", + kFIRInstallationsAPIBaseURL, self.projectID, + installation.firebaseInstallationID]; + NSURL *URL = [NSURL URLWithString:URLString]; + + NSDictionary *bodyDict = @{@"installation" : @{@"sdkVersion" : [self SDKVersion]}}; + return [self requestWithURL:URL + HTTPMethod:@"POST" + bodyDict:bodyDict + refreshToken:installation.refreshToken]; +} + +- (FBLPromise *)authTokenWithServerResponse: + (FIRInstallationsURLSessionResponse *)response { + return [FBLPromise do:^id { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeParsingAPIResponse, + @"Parsing server response for %@.", response.HTTPResponse.URL); + NSError *error; + FIRInstallationsStoredAuthToken *token = + [FIRInstallationsItem authTokenWithGenerateTokenAPIJSONData:response.data + date:[NSDate date] + error:&error]; + if (token == nil) { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed, + @"Failed to parse FIRInstallationsStoredAuthToken: %@.", error); + return error; + } + + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed, + @"FIRInstallationsStoredAuthToken parsed successfully."); + return token; + }]; +} + +#pragma mark - Delete Installation + +- (FBLPromise *)deleteInstallationRequestWithInstallation: + (FIRInstallationsItem *)installation { + NSString *URLString = [NSString stringWithFormat:@"%@/v1/projects/%@/installations/%@/", + kFIRInstallationsAPIBaseURL, self.projectID, + installation.firebaseInstallationID]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [self requestWithURL:URL + HTTPMethod:@"DELETE" + bodyDict:@{} + refreshToken:installation.refreshToken]; +} + +#pragma mark - URL Request +- (FBLPromise *)requestWithURL:(NSURL *)requestURL + HTTPMethod:(NSString *)HTTPMethod + bodyDict:(NSDictionary *)bodyDict + refreshToken:(nullable NSString *)refreshToken { + return [self requestWithURL:requestURL + HTTPMethod:HTTPMethod + bodyDict:bodyDict + refreshToken:refreshToken + additionalHeaders:nil]; +} + +- (FBLPromise *)requestWithURL:(NSURL *)requestURL + HTTPMethod:(NSString *)HTTPMethod + bodyDict:(NSDictionary *)bodyDict + refreshToken:(nullable NSString *)refreshToken + additionalHeaders:(nullable NSDictionary *) + additionalHeaders { + return [FBLPromise + onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + __block NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL]; + request.HTTPMethod = HTTPMethod; + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + [request addValue:self.APIKey forHTTPHeaderField:kFIRInstallationsAPIKey]; + [request addValue:bundleIdentifier forHTTPHeaderField:kFIRInstallationsBundleId]; + [self setJSONHTTPBody:bodyDict forRequest:request]; + if (refreshToken) { + NSString *authHeader = [NSString stringWithFormat:@"FIS_v2 %@", refreshToken]; + [request setValue:authHeader forHTTPHeaderField:@"Authorization"]; + } + // Heartbeat Header. + [request setValue:[self.heartbeatLogger headerValue] + forHTTPHeaderField:kFIRInstallationsHeartbeatKey]; + + [additionalHeaders + enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, NSString *_Nonnull obj, + BOOL *_Nonnull stop) { + [request setValue:obj forHTTPHeaderField:key]; + }]; + + return [request copy]; + }]; +} + +- (FBLPromise *)URLRequestPromise:(NSURLRequest *)request { + return [[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeSendAPIRequest, + @"Sending request: %@, body:%@, headers: %@.", request, + [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding], + request.allHTTPHeaderFields); + [[self.URLSession + dataTaskWithRequest:request + completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIRequestNetworkError, + @"Request failed: %@, error: %@.", request, error); + reject(error); + } else { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeAPIRequestResponse, + @"Request response received: %@, error: %@, body: %@.", request, error, + [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); + fulfill([[FIRInstallationsURLSessionResponse alloc] + initWithResponse:(NSHTTPURLResponse *)response + data:data]); + } + }] resume]; + }] then:^id _Nullable(FIRInstallationsURLSessionResponse *response) { + return [self validateHTTPResponseStatusCode:response]; + }]; +} + +- (FBLPromise *)validateHTTPResponseStatusCode: + (FIRInstallationsURLSessionResponse *)response { + NSInteger statusCode = response.HTTPResponse.statusCode; + return [FBLPromise do:^id _Nullable { + if (statusCode < 200 || statusCode >= 300) { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse, + @"Unexpected API response: %@, body: %@.", response.HTTPResponse, + [[NSString alloc] initWithData:response.data encoding:NSUTF8StringEncoding]); + return [FIRInstallationsErrorUtil APIErrorWithHTTPResponse:response.HTTPResponse + data:response.data]; + } + return response; + }]; +} + +- (FBLPromise *)sendURLRequest:(NSURLRequest *)request { + return [FBLPromise attempts:1 + delay:1 + condition:^BOOL(NSInteger remainingAttempts, NSError *_Nonnull error) { + return [FIRInstallationsErrorUtil isAPIError:error + withHTTPCode:FIRInstallationsHTTPCodesServerInternalError]; + } + retry:^id _Nullable { + return [self URLRequestPromise:request]; + }]; +} + +- (NSString *)SDKVersion { + return [NSString stringWithFormat:@"i:%@", FIRFirebaseVersion()]; +} + +#pragma mark - Validation + +- (FBLPromise *)validateInstallation:(FIRInstallationsItem *)installation { + FBLPromise *result = [FBLPromise pendingPromise]; + + NSError *validationError; + if ([installation isValid:&validationError]) { + [result fulfill:installation]; + } else { + [result reject:validationError]; + } + return result; +} + +#pragma mark - JSON + +- (void)setJSONHTTPBody:(NSDictionary *)body + forRequest:(NSMutableURLRequest *)request { + [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; + + NSError *error; + NSData *JSONData = [NSJSONSerialization dataWithJSONObject:body options:0 error:&error]; + if (JSONData == nil) { + // TODO: Log or return an error. + } + request.HTTPBody = JSONData; +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h new file mode 100644 index 0000000..ec0217f --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h @@ -0,0 +1,53 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" + +@class FIRInstallationsStoredAuthToken; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstallationsItem (RegisterInstallationAPI) + +/** + * Parses and validates the Register Installation API response and returns a corresponding + * `FIRInstallationsItem` instance on success. + * @param JSONData The data with JSON encoded API response. + * @param date The installation auth token expiration date will be calculated as `date` + + * `response.authToken.expiresIn`. For most of the cases `[NSDate date]` should be passed there. A + * different value may be passed e.g. for unit tests. + * @param outError A pointer to assign a specific `NSError` instance in case of failure. No error is + * assigned in case of success. + * @return Returns a new `FIRInstallationsItem` instance in the success case or `nil` otherwise. + */ +- (nullable FIRInstallationsItem *)registeredInstallationWithJSONData:(NSData *)JSONData + date:(NSDate *)date + error: + (NSError *_Nullable *)outError; + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithGenerateTokenAPIJSONData:(NSData *)data + date:(NSDate *)date + error:(NSError **) + outError; + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithJSONDict: + (NSDictionary *)dict + date:(NSDate *)date + error:(NSError **)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m new file mode 100644 index 0000000..90696f0 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m @@ -0,0 +1,146 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +@implementation FIRInstallationsItem (RegisterInstallationAPI) + +- (nullable FIRInstallationsItem *) + registeredInstallationWithJSONData:(NSData *)data + date:(NSDate *)date + error:(NSError *__autoreleasing _Nullable *_Nullable)outError { + NSDictionary *responseJSON = [FIRInstallationsItem dictionaryFromJSONData:data error:outError]; + if (!responseJSON) { + return nil; + } + + NSString *refreshToken = [FIRInstallationsItem validStringOrNilForKey:@"refreshToken" + fromDict:responseJSON]; + if (refreshToken == nil) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"refreshToken"], + outError); + return nil; + } + + NSDictionary *authTokenDict = responseJSON[@"authToken"]; + if (![authTokenDict isKindOfClass:[NSDictionary class]]) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"authToken"], + outError); + return nil; + } + + FIRInstallationsStoredAuthToken *authToken = + [FIRInstallationsItem authTokenWithJSONDict:authTokenDict date:date error:outError]; + if (authToken == nil) { + return nil; + } + + FIRInstallationsItem *installation = + [[FIRInstallationsItem alloc] initWithAppID:self.appID firebaseAppName:self.firebaseAppName]; + NSString *installationID = [FIRInstallationsItem validStringOrNilForKey:@"fid" + fromDict:responseJSON]; + installation.firebaseInstallationID = installationID ?: self.firebaseInstallationID; + installation.refreshToken = refreshToken; + installation.authToken = authToken; + installation.registrationStatus = FIRInstallationStatusRegistered; + + return installation; +} + +#pragma mark - Auth token + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithGenerateTokenAPIJSONData:(NSData *)data + date:(NSDate *)date + error:(NSError **) + outError { + NSDictionary *dict = [self dictionaryFromJSONData:data error:outError]; + if (!dict) { + return nil; + } + + return [self authTokenWithJSONDict:dict date:date error:outError]; +} + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithJSONDict: + (NSDictionary *)dict + date:(NSDate *)date + error:(NSError **)outError { + NSString *token = [self validStringOrNilForKey:@"token" fromDict:dict]; + if (token == nil) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"authToken.token"], + outError); + return nil; + } + + NSString *expiresInString = [self validStringOrNilForKey:@"expiresIn" fromDict:dict]; + if (expiresInString == nil) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil + FIDRegistrationErrorWithResponseMissingField:@"authToken.expiresIn"], + outError); + return nil; + } + + // The response should contain the string in format like "604800s". + // The server should never response with anything else except seconds. + // Just drop the last character and parse a number from string. + NSString *expiresInSeconds = [expiresInString substringToIndex:expiresInString.length - 1]; + NSTimeInterval expiresIn = [expiresInSeconds doubleValue]; + NSDate *expirationDate = [date dateByAddingTimeInterval:expiresIn]; + + FIRInstallationsStoredAuthToken *authToken = [[FIRInstallationsStoredAuthToken alloc] init]; + authToken.status = FIRInstallationsAuthTokenStatusTokenReceived; + authToken.token = token; + authToken.expirationDate = expirationDate; + + return authToken; +} + +#pragma mark - JSON + ++ (nullable NSDictionary *)dictionaryFromJSONData:(NSData *)data + error:(NSError **)outError { + NSError *error; + NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + + if (![responseJSON isKindOfClass:[NSDictionary class]]) { + FIRInstallationsItemSetErrorToPointer([FIRInstallationsErrorUtil JSONSerializationError:error], + outError); + return nil; + } + + return responseJSON; +} + ++ (NSString *)validStringOrNilForKey:(NSString *)key fromDict:(NSDictionary *)dict { + NSString *string = dict[key]; + if ([string isKindOfClass:[NSString class]] && string.length > 0) { + return string; + } + return nil; +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void FIRInclude_FIRInstallationsItem_RegisterInstallationAPI_Category(void) { +} diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h new file mode 100644 index 0000000..4d40338 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** A block returning current date. */ +typedef NSDate *_Nonnull (^FIRCurrentDateProvider)(void); + +/** The function returns a `FIRCurrentDateProvider` block that returns a real current date. */ +FIRCurrentDateProvider FIRRealCurrentDateProvider(void); + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m new file mode 100644 index 0000000..d2a1d40 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h" + +FIRCurrentDateProvider FIRRealCurrentDateProvider(void) { + return ^NSDate *(void) { + return [NSDate date]; + }; +} diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h new file mode 100644 index 0000000..5760618 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h @@ -0,0 +1,54 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRInstallationsBackoffEvent) { + FIRInstallationsBackoffEventSuccess, + FIRInstallationsBackoffEventRecoverableFailure, + FIRInstallationsBackoffEventUnrecoverableFailure +}; + +/** The protocol defines API for a class that encapsulates backoff logic that prevents the SDK from + * sending unnecessary server requests. See API docs for the methods for more details. */ + +@protocol FIRInstallationsBackoffControllerProtocol + +/** The client must call the method each time a protected server request succeeds of fails. It will + * affect the `isNextRequestAllowed` method result for the current time, e.g. when 3 recoverable + * errors were logged in a row, then `isNextRequestAllowed` will return `YES` only in `pow(2, 3)` + * seconds. */ +- (void)registerEvent:(FIRInstallationsBackoffEvent)event; + +/** Returns if sending a next protected is recommended based on the time and the sequence of logged + * events and the current time. See also `registerEvent:`. */ +- (BOOL)isNextRequestAllowed; + +@end + +/** An implementation of `FIRInstallationsBackoffControllerProtocol` with exponential backoff for + * recoverable errors and constant backoff for recoverable errors. */ +@interface FIRInstallationsBackoffController : NSObject + +- (instancetype)initWithCurrentDateProvider:(FIRCurrentDateProvider)currentDateProvider; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m new file mode 100644 index 0000000..25f9b42 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m @@ -0,0 +1,132 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h" + +static const NSTimeInterval k24Hours = 24 * 60 * 60; +static const NSTimeInterval k30Minutes = 30 * 60; + +/** The class represents `FIRInstallationsBackoffController` state required to calculate next + allowed request time. The properties of the class are intentionally immutable because changing them + separately leads to an inconsistent state. */ +@interface FIRInstallationsBackoffEventData : NSObject + +@property(nonatomic, readonly) FIRInstallationsBackoffEvent eventType; +@property(nonatomic, readonly) NSDate *lastEventDate; +@property(nonatomic, readonly) NSInteger eventCount; + +@property(nonatomic, readonly) NSTimeInterval backoffTimeInterval; + +@end + +@implementation FIRInstallationsBackoffEventData + +- (instancetype)initWithEvent:(FIRInstallationsBackoffEvent)eventType + lastEventDate:(NSDate *)lastEventDate + eventCount:(NSInteger)eventCount { + self = [super init]; + if (self) { + _eventType = eventType; + _lastEventDate = lastEventDate; + _eventCount = eventCount; + + _backoffTimeInterval = [[self class] backoffTimeIntervalWithEvent:eventType + eventCount:eventCount]; + } + return self; +} + ++ (NSTimeInterval)backoffTimeIntervalWithEvent:(FIRInstallationsBackoffEvent)eventType + eventCount:(NSInteger)eventCount { + switch (eventType) { + case FIRInstallationsBackoffEventSuccess: + return 0; + break; + + case FIRInstallationsBackoffEventRecoverableFailure: + return [self recoverableErrorBackoffTimeForAttemptNumber:eventCount]; + break; + + case FIRInstallationsBackoffEventUnrecoverableFailure: + return k24Hours; + break; + } +} + ++ (NSTimeInterval)recoverableErrorBackoffTimeForAttemptNumber:(NSInteger)attemptNumber { + NSTimeInterval exponentialInterval = pow(2, attemptNumber) + [self randomMilliseconds]; + return MIN(exponentialInterval, k30Minutes); +} + ++ (NSTimeInterval)randomMilliseconds { + int32_t random_millis = ABS(arc4random() % 1000); + return (double)random_millis * 0.001; +} + +@end + +@interface FIRInstallationsBackoffController () + +@property(nonatomic, readonly) FIRCurrentDateProvider currentDateProvider; + +@property(nonatomic, nullable) FIRInstallationsBackoffEventData *lastEventData; + +@end + +@implementation FIRInstallationsBackoffController + +- (instancetype)init { + return [self initWithCurrentDateProvider:FIRRealCurrentDateProvider()]; +} + +- (instancetype)initWithCurrentDateProvider:(FIRCurrentDateProvider)currentDateProvider { + self = [super init]; + if (self) { + _currentDateProvider = [currentDateProvider copy]; + } + return self; +} + +- (BOOL)isNextRequestAllowed { + @synchronized(self) { + if (self.lastEventData == nil) { + return YES; + } + + NSTimeInterval timeSinceLastEvent = + [self.currentDateProvider() timeIntervalSinceDate:self.lastEventData.lastEventDate]; + return timeSinceLastEvent >= self.lastEventData.backoffTimeInterval; + } +} + +- (void)registerEvent:(FIRInstallationsBackoffEvent)event { + @synchronized(self) { + // Event of the same type as was registered before. + if (self.lastEventData && self.lastEventData.eventType == event) { + self.lastEventData = [[FIRInstallationsBackoffEventData alloc] + initWithEvent:event + lastEventDate:self.currentDateProvider() + eventCount:self.lastEventData.eventCount + 1]; + } else { // A different event. + self.lastEventData = + [[FIRInstallationsBackoffEventData alloc] initWithEvent:event + lastEventDate:self.currentDateProvider() + eventCount:1]; + } + } +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h new file mode 100644 index 0000000..8e66af9 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h @@ -0,0 +1,40 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FBLPromise; +@class FIRApp; +@class FIRInstallationsItem; + +/** + * The class is responsible for managing FID for a given `FIRApp`. + */ +@interface FIRInstallationsIDController : NSObject + +- (instancetype)initWithApp:(FIRApp *)app; + +- (FBLPromise *)getInstallationItem; + +- (FBLPromise *)getAuthTokenForcingRefresh:(BOOL)forceRefresh; + +- (FBLPromise *)deleteInstallation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m new file mode 100644 index 0000000..6ade8cc --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m @@ -0,0 +1,530 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h" +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h" +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h" +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h" +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +const NSNotificationName FIRInstallationIDDidChangeNotification = + @"FIRInstallationIDDidChangeNotification"; +NSString *const kFIRInstallationIDDidChangeNotificationAppNameKey = + @"FIRInstallationIDDidChangeNotification"; + +NSTimeInterval const kFIRInstallationsTokenExpirationThreshold = 60 * 60; // 1 hour. + +static NSString *const kKeychainService = @"com.firebase.FIRInstallations.installations"; + +@interface FIRInstallationsIDController () +@property(nonatomic, readonly) NSString *appID; +@property(nonatomic, readonly) NSString *appName; + +@property(nonatomic, readonly) FIRInstallationsStore *installationsStore; +@property(nonatomic, readonly) FIRInstallationsIIDStore *IIDStore; +@property(nonatomic, readonly) FIRInstallationsIIDTokenStore *IIDTokenStore; + +@property(nonatomic, readonly) FIRInstallationsAPIService *APIService; + +@property(nonatomic, readonly) id backoffController; + +@property(nonatomic, readonly) FIRInstallationsSingleOperationPromiseCache + *getInstallationPromiseCache; +@property(nonatomic, readonly) + FIRInstallationsSingleOperationPromiseCache *authTokenPromiseCache; +@property(nonatomic, readonly) FIRInstallationsSingleOperationPromiseCache + *authTokenForcingRefreshPromiseCache; +@property(nonatomic, readonly) + FIRInstallationsSingleOperationPromiseCache *deleteInstallationPromiseCache; +@end + +@implementation FIRInstallationsIDController + +- (instancetype)initWithApp:(FIRApp *)app { + NSString *serviceName = + [FIRInstallationsIDController keychainServiceWithAppID:app.options.googleAppID]; + GULKeychainStorage *secureStorage = [[GULKeychainStorage alloc] initWithService:serviceName]; + FIRInstallationsStore *installationsStore = + [[FIRInstallationsStore alloc] initWithSecureStorage:secureStorage + accessGroup:app.options.appGroupID]; + + FIRInstallationsAPIService *apiService = + [[FIRInstallationsAPIService alloc] initWithAPIKey:app.options.APIKey + projectID:app.options.projectID + heartbeatLogger:app.heartbeatLogger]; + + FIRInstallationsIIDStore *IIDStore = [[FIRInstallationsIIDStore alloc] init]; + FIRInstallationsIIDTokenStore *IIDCheckingStore = + [[FIRInstallationsIIDTokenStore alloc] initWithGCMSenderID:app.options.GCMSenderID]; + + FIRInstallationsBackoffController *backoffController = + [[FIRInstallationsBackoffController alloc] init]; + + return [self initWithGoogleAppID:app.options.googleAppID + appName:app.name + installationsStore:installationsStore + APIService:apiService + IIDStore:IIDStore + IIDTokenStore:IIDCheckingStore + backoffController:backoffController]; +} + +/// The initializer is supposed to be used by tests to inject `installationsStore`. +- (instancetype)initWithGoogleAppID:(NSString *)appID + appName:(NSString *)appName + installationsStore:(FIRInstallationsStore *)installationsStore + APIService:(FIRInstallationsAPIService *)APIService + IIDStore:(FIRInstallationsIIDStore *)IIDStore + IIDTokenStore:(FIRInstallationsIIDTokenStore *)IIDTokenStore + backoffController: + (id)backoffController { + self = [super init]; + if (self) { + _appID = appID; + _appName = appName; + _installationsStore = installationsStore; + _APIService = APIService; + _IIDStore = IIDStore; + _IIDTokenStore = IIDTokenStore; + _backoffController = backoffController; + + __weak FIRInstallationsIDController *weakSelf = self; + + _getInstallationPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf createGetInstallationItemPromise]; + }]; + + _authTokenPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf installationWithValidAuthTokenForcingRefresh:NO]; + }]; + + _authTokenForcingRefreshPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf installationWithValidAuthTokenForcingRefresh:YES]; + }]; + + _deleteInstallationPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf createDeleteInstallationPromise]; + }]; + } + return self; +} + +#pragma mark - Get Installation. + +- (FBLPromise *)getInstallationItem { + return [self.getInstallationPromiseCache getExistingPendingOrCreateNewPromise]; +} + +- (FBLPromise *)createGetInstallationItemPromise { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeNewGetInstallationOperationCreated, @"%s, appName: %@", + __PRETTY_FUNCTION__, self.appName); + + FBLPromise *installationItemPromise = + [self getStoredInstallation].recover(^id(NSError *error) { + return [self createAndSaveFID]; + }); + + // Initiate registration process on success if needed, but return the installation without waiting + // for it. + installationItemPromise.then(^id(FIRInstallationsItem *installation) { + [self getAuthTokenForcingRefresh:NO]; + return nil; + }); + + return installationItemPromise; +} + +- (FBLPromise *)getStoredInstallation { + return [self.installationsStore installationForAppID:self.appID appName:self.appName].validate( + ^BOOL(FIRInstallationsItem *installation) { + NSError *validationError; + BOOL isValid = [installation isValid:&validationError]; + + if (!isValid) { + FIRLogWarning( + kFIRLoggerInstallations, kFIRInstallationsMessageCodeCorruptedStoredInstallation, + @"Stored installation validation error: %@", validationError.localizedDescription); + } + + return isValid; + }); +} + +- (FBLPromise *)createAndSaveFID { + return [self migrateOrGenerateInstallation] + .then(^FBLPromise *(FIRInstallationsItem *installation) { + return [self saveInstallation:installation]; + }) + .then(^FIRInstallationsItem *(FIRInstallationsItem *installation) { + [self postFIDDidChangeNotification]; + return installation; + }); +} + +- (FBLPromise *)saveInstallation:(FIRInstallationsItem *)installation { + return [self.installationsStore saveInstallation:installation].then( + ^FIRInstallationsItem *(NSNull *result) { + return installation; + }); +} + +/** + * Tries to migrate IID data stored by FirebaseInstanceID SDK or generates a new Installation ID if + * not found. + */ +- (FBLPromise *)migrateOrGenerateInstallation { + if (![self isDefaultApp]) { + // Existing IID should be used only for default FirebaseApp. + FIRInstallationsItem *installation = + [self createInstallationWithFID:[FIRInstallationsItem generateFID] IIDDefaultToken:nil]; + return [FBLPromise resolvedWith:installation]; + } + + return [[[FBLPromise + all:@[ [self.IIDStore existingIID], [self.IIDTokenStore existingIIDDefaultToken] ]] + then:^id _Nullable(NSArray *_Nullable results) { + NSString *existingIID = results[0]; + NSString *IIDDefaultToken = results[1]; + + return [self createInstallationWithFID:existingIID IIDDefaultToken:IIDDefaultToken]; + }] recover:^id _Nullable(NSError *_Nonnull error) { + return [self createInstallationWithFID:[FIRInstallationsItem generateFID] IIDDefaultToken:nil]; + }]; +} + +- (FIRInstallationsItem *)createInstallationWithFID:(NSString *)FID + IIDDefaultToken:(nullable NSString *)IIDDefaultToken { + FIRInstallationsItem *installation = [[FIRInstallationsItem alloc] initWithAppID:self.appID + firebaseAppName:self.appName]; + installation.firebaseInstallationID = FID; + installation.IIDDefaultToken = IIDDefaultToken; + installation.registrationStatus = FIRInstallationStatusUnregistered; + return installation; +} + +#pragma mark - FID registration + +- (FBLPromise *)registerInstallationIfNeeded: + (FIRInstallationsItem *)installation { + switch (installation.registrationStatus) { + case FIRInstallationStatusRegistered: + // Already registered. Do nothing. + return [FBLPromise resolvedWith:installation]; + + case FIRInstallationStatusUnknown: + case FIRInstallationStatusUnregistered: + // Registration required. Proceed. + break; + } + + // Check for backoff. + if (![self.backoffController isNextRequestAllowed]) { + return [FIRInstallationsErrorUtil + rejectedPromiseWithError:[FIRInstallationsErrorUtil backoffIntervalWaitError]]; + } + + return [self.APIService registerInstallation:installation] + .catch(^(NSError *_Nonnull error) { + [self updateBackoffWithSuccess:NO APIError:error]; + + if ([self doesRegistrationErrorRequireConfigChange:error]) { + FIRLogError(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeInvalidFirebaseConfiguration, + @"Firebase Installation registration failed for app with name: %@, error:\n" + @"%@\nPlease make sure you use valid GoogleService-Info.plist", + self.appName, error.userInfo[NSLocalizedFailureReasonErrorKey]); + } + }) + .then(^id(FIRInstallationsItem *registeredInstallation) { + [self updateBackoffWithSuccess:YES APIError:nil]; + return [self saveInstallation:registeredInstallation]; + }) + .then(^FIRInstallationsItem *(FIRInstallationsItem *registeredInstallation) { + // Server may respond with a different FID if the sent one cannot be accepted. + if (![registeredInstallation.firebaseInstallationID + isEqualToString:installation.firebaseInstallationID]) { + [self postFIDDidChangeNotification]; + } + return registeredInstallation; + }); +} + +- (BOOL)doesRegistrationErrorRequireConfigChange:(NSError *)error { + FIRInstallationsHTTPError *HTTPError = (FIRInstallationsHTTPError *)error; + if (![HTTPError isKindOfClass:[FIRInstallationsHTTPError class]]) { + return NO; + } + + switch (HTTPError.HTTPResponse.statusCode) { + // These are the errors that require Firebase configuration change. + case FIRInstallationsRegistrationHTTPCodeInvalidArgument: + case FIRInstallationsRegistrationHTTPCodeAPIKeyToProjectIDMismatch: + case FIRInstallationsRegistrationHTTPCodeProjectNotFound: + return YES; + + default: + return NO; + } +} + +#pragma mark - Auth Token + +- (FBLPromise *)getAuthTokenForcingRefresh:(BOOL)forceRefresh { + if (forceRefresh || [self.authTokenForcingRefreshPromiseCache getExistingPendingPromise] != nil) { + return [self.authTokenForcingRefreshPromiseCache getExistingPendingOrCreateNewPromise]; + } else { + return [self.authTokenPromiseCache getExistingPendingOrCreateNewPromise]; + } +} + +- (FBLPromise *)installationWithValidAuthTokenForcingRefresh: + (BOOL)forceRefresh { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated, + @"-[FIRInstallationsIDController installationWithValidAuthTokenForcingRefresh:%@], " + @"appName: %@", + @(forceRefresh), self.appName); + + return [self getInstallationItem] + .then(^FBLPromise *(FIRInstallationsItem *installation) { + return [self registerInstallationIfNeeded:installation]; + }) + .then(^id(FIRInstallationsItem *registeredInstallation) { + BOOL isTokenExpiredOrExpiresSoon = + [registeredInstallation.authToken.expirationDate timeIntervalSinceDate:[NSDate date]] < + kFIRInstallationsTokenExpirationThreshold; + if (forceRefresh || isTokenExpiredOrExpiresSoon) { + return [self refreshAuthTokenForInstallation:registeredInstallation]; + } else { + return registeredInstallation; + } + }) + .recover(^id(NSError *error) { + return [self regenerateFIDOnRefreshTokenErrorIfNeeded:error]; + }); +} + +- (FBLPromise *)refreshAuthTokenForInstallation: + (FIRInstallationsItem *)installation { + // Check for backoff. + if (![self.backoffController isNextRequestAllowed]) { + return [FIRInstallationsErrorUtil + rejectedPromiseWithError:[FIRInstallationsErrorUtil backoffIntervalWaitError]]; + } + + return [[[self.APIService refreshAuthTokenForInstallation:installation] + then:^id _Nullable(FIRInstallationsItem *_Nullable refreshedInstallation) { + [self updateBackoffWithSuccess:YES APIError:nil]; + return [self saveInstallation:refreshedInstallation]; + }] recover:^id _Nullable(NSError *_Nonnull error) { + // Pass the error to the backoff controller. + [self updateBackoffWithSuccess:NO APIError:error]; + return error; + }]; +} + +- (id)regenerateFIDOnRefreshTokenErrorIfNeeded:(NSError *)error { + if (![error isKindOfClass:[FIRInstallationsHTTPError class]]) { + // No recovery possible. Return the same error. + return error; + } + + FIRInstallationsHTTPError *HTTPError = (FIRInstallationsHTTPError *)error; + switch (HTTPError.HTTPResponse.statusCode) { + case FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication: + case FIRInstallationsAuthTokenHTTPCodeFIDNotFound: + // The stored installation was damaged or blocked by the server. + // Delete the stored installation then generate and register a new one. + return [self getInstallationItem] + .then(^FBLPromise *(FIRInstallationsItem *installation) { + return [self deleteInstallationLocally:installation]; + }) + .then(^FBLPromise *(id result) { + return [self installationWithValidAuthTokenForcingRefresh:NO]; + }); + + default: + // No recovery possible. Return the same error. + return error; + } +} + +#pragma mark - Delete FID + +- (FBLPromise *)deleteInstallation { + return [self.deleteInstallationPromiseCache getExistingPendingOrCreateNewPromise]; +} + +- (FBLPromise *)createDeleteInstallationPromise { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated, @"%s, appName: %@", + __PRETTY_FUNCTION__, self.appName); + + // Check for ongoing requests first, if there is no a request, then check local storage for + // existing installation. + FBLPromise *currentInstallationPromise = + [self mostRecentInstallationOperation] ?: [self getStoredInstallation]; + + return currentInstallationPromise + .then(^id(FIRInstallationsItem *installation) { + return [self sendDeleteInstallationRequestIfNeeded:installation]; + }) + .then(^id(FIRInstallationsItem *installation) { + // Remove the installation from the local storage. + return [self deleteInstallationLocally:installation]; + }); +} + +- (FBLPromise *)deleteInstallationLocally:(FIRInstallationsItem *)installation { + return [self.installationsStore removeInstallationForAppID:installation.appID + appName:installation.firebaseAppName] + .then(^FBLPromise *(NSNull *result) { + return [self deleteExistingIIDIfNeeded]; + }) + .then(^NSNull *(NSNull *result) { + [self postFIDDidChangeNotification]; + return result; + }); +} + +- (FBLPromise *)sendDeleteInstallationRequestIfNeeded: + (FIRInstallationsItem *)installation { + switch (installation.registrationStatus) { + case FIRInstallationStatusUnknown: + case FIRInstallationStatusUnregistered: + // The installation is not registered, so it is safe to be deleted as is, so return early. + return [FBLPromise resolvedWith:installation]; + break; + + case FIRInstallationStatusRegistered: + // Proceed to de-register the installation on the server. + break; + } + + return [self.APIService deleteInstallation:installation].recover(^id(NSError *APIError) { + if ([FIRInstallationsErrorUtil isAPIError:APIError withHTTPCode:404]) { + // The installation was not found on the server. + // Return success. + return installation; + } else { + // Re-throw the error otherwise. + return APIError; + } + }); +} + +- (FBLPromise *)deleteExistingIIDIfNeeded { + if ([self isDefaultApp]) { + return [self.IIDStore deleteExistingIID]; + } else { + return [FBLPromise resolvedWith:[NSNull null]]; + } +} + +- (nullable FBLPromise *)mostRecentInstallationOperation { + return [self.authTokenForcingRefreshPromiseCache getExistingPendingPromise] + ?: [self.authTokenPromiseCache getExistingPendingPromise] + ?: [self.getInstallationPromiseCache getExistingPendingPromise]; +} + +#pragma mark - Backoff + +- (void)updateBackoffWithSuccess:(BOOL)success APIError:(nullable NSError *)APIError { + if (success) { + [self.backoffController registerEvent:FIRInstallationsBackoffEventSuccess]; + } else if ([APIError isKindOfClass:[FIRInstallationsHTTPError class]]) { + FIRInstallationsHTTPError *HTTPResponseError = (FIRInstallationsHTTPError *)APIError; + NSInteger statusCode = HTTPResponseError.HTTPResponse.statusCode; + + if (statusCode == FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication || + statusCode == FIRInstallationsAuthTokenHTTPCodeFIDNotFound) { + // These errors are explicitly excluded because they are handled by FIS SDK itself so don't + // require backoff. + } else if (statusCode == 400 || statusCode == 403) { // Explicitly unrecoverable errors. + [self.backoffController registerEvent:FIRInstallationsBackoffEventUnrecoverableFailure]; + } else if (statusCode == 429 || + (statusCode >= 500 && statusCode < 600)) { // Explicitly recoverable errors. + [self.backoffController registerEvent:FIRInstallationsBackoffEventRecoverableFailure]; + } else { // Treat all unknown errors as recoverable. + [self.backoffController registerEvent:FIRInstallationsBackoffEventRecoverableFailure]; + } + } + + // If the error class is not `FIRInstallationsHTTPError` it indicates a connection error. Such + // errors should not change backoff interval. +} + +#pragma mark - Notifications + +- (void)postFIDDidChangeNotification { + [[NSNotificationCenter defaultCenter] + postNotificationName:FIRInstallationIDDidChangeNotification + object:nil + userInfo:@{kFIRInstallationIDDidChangeNotificationAppNameKey : self.appName}]; +} + +#pragma mark - Default App + +- (BOOL)isDefaultApp { + return [self.appName isEqualToString:kFIRDefaultAppName]; +} + +#pragma mark - Keychain + ++ (NSString *)keychainServiceWithAppID:(NSString *)appID { +#if TARGET_OS_MACCATALYST || TARGET_OS_OSX + // We need to keep service name unique per application on macOS. + // Applications on macOS may request access to Keychain items stored by other applications. It + // means that when the app looks up for a relevant Keychain item in the service scope it will + // request user password to grant access to the Keychain if there are other Keychain items from + // other applications stored under the same Keychain Service. + return [kKeychainService stringByAppendingFormat:@".%@", appID]; +#else + // Use a constant Keychain service for non-macOS because: + // 1. Keychain items cannot be shared between apps until configured specifically so the service + // name collisions are not a concern + // 2. We don't want to change the service name to avoid doing a migration. + return kKeychainService; +#endif +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h new file mode 100644 index 0000000..aeb54e5 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h @@ -0,0 +1,58 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class makes sure the a single operation (represented by a promise) is performed at a time. If + * there is an ongoing operation, then its existing corresponding promise will be returned instead + * of starting a new operation. + */ +@interface FIRInstallationsSingleOperationPromiseCache<__covariant ResultType> : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * The designated initializer. + * @param newOperationHandler The block that must return a new promise representing the + * single-at-a-time operation. The promise should be fulfilled when the operation is completed. The + * factory block will be used to create a new promise when needed. + */ +- (instancetype)initWithNewOperationHandler: + (FBLPromise *_Nonnull (^)(void))newOperationHandler NS_DESIGNATED_INITIALIZER; + +/** + * Creates a new promise or returns an existing pending one. + * @return Returns and existing pending promise if exists. If the pending promise does not exist + * then a new one will be created using the `factory` block passed in the initializer. Once the + * pending promise gets resolved, it is removed, so calling the method again will lead to creating + * and caching another promise. + */ +- (FBLPromise *)getExistingPendingOrCreateNewPromise; + +/** + * Returns an existing pending promise or `nil`. + * @return Returns an existing pending promise if there is one or `nil` otherwise. + */ +- (nullable FBLPromise *)getExistingPendingPromise; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m new file mode 100644 index 0000000..7ae8781 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m @@ -0,0 +1,75 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +@interface FIRInstallationsSingleOperationPromiseCache () +@property(nonatomic, readonly) FBLPromise *_Nonnull (^newOperationHandler)(void); +@property(nonatomic, nullable) FBLPromise *pendingPromise; +@end + +@implementation FIRInstallationsSingleOperationPromiseCache + +- (instancetype)initWithNewOperationHandler: + (FBLPromise *_Nonnull (^)(void))newOperationHandler { + if (newOperationHandler == nil) { + [NSException raise:NSInvalidArgumentException + format:@"`newOperationHandler` must not be `nil`."]; + } + + self = [super init]; + if (self) { + _newOperationHandler = [newOperationHandler copy]; + } + return self; +} + +- (FBLPromise *)getExistingPendingOrCreateNewPromise { + @synchronized(self) { + if (!self.pendingPromise) { + self.pendingPromise = self.newOperationHandler(); + + self.pendingPromise + .then(^id(id result) { + @synchronized(self) { + self.pendingPromise = nil; + return nil; + } + }) + .catch(^void(NSError *error) { + @synchronized(self) { + self.pendingPromise = nil; + } + }); + } + + return self.pendingPromise; + } +} + +- (nullable FBLPromise *)getExistingPendingPromise { + @synchronized(self) { + return self.pendingPromise; + } +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h new file mode 100644 index 0000000..3edc692 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * The enum represent possible states of the installation ID. + * + * WARNING: The enum is stored to Keychain as a part of `FIRInstallationsStoredItem`. Modification + * of it can lead to incompatibility with previous version. Any modification must be evaluated and, + * if it is really needed, the `storageVersion` must be bumped and proper migration code added. + */ +typedef NS_ENUM(NSInteger, FIRInstallationsStatus) { + /** Represents either an initial status when a FIRInstallationsItem instance was created but not + * stored to Keychain or an undefined status (e.g. when the status failed to deserialize). + */ + FIRInstallationStatusUnknown, + /// The Firebase Installation has not yet been registered with FIS. + FIRInstallationStatusUnregistered, + /// The Firebase Installation has successfully been registered with FIS. + FIRInstallationStatusRegistered, +}; diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h new file mode 100644 index 0000000..b86fb39 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h @@ -0,0 +1,71 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; +@class FIRInstallationsItem; +@class GULKeychainStorage; + +NS_ASSUME_NONNULL_BEGIN + +/// The user defaults suite name used to store data. +extern NSString *const kFIRInstallationsStoreUserDefaultsID; + +/// The class is responsible for storing and accessing the installations data. +@interface FIRInstallationsStore : NSObject + +/** + * The default initializer. + * @param storage The secure storage to save installations data. + * @param accessGroup The Keychain Access Group to store and request the installations data. + */ +- (instancetype)initWithSecureStorage:(GULKeychainStorage *)storage + accessGroup:(nullable NSString *)accessGroup; + +/** + * Retrieves existing installation ID if there is. + * @param appID The Firebase(Google) Application ID. + * @param appName The Firebase Application Name. + * + * @return Returns a `FBLPromise` instance. The promise is resolved with a FIRInstallationsItem + * instance if there is a valid installation stored for `appID` and `appName`. The promise is + * rejected with a specific error when the installation has not been found or with another possible + * error. + */ +- (FBLPromise *)installationForAppID:(NSString *)appID + appName:(NSString *)appName; + +/** + * Saves the given installation. + * + * @param installationItem The installation data. + * @return Returns a promise that is resolved with `[NSNull null]` on success. + */ +- (FBLPromise *)saveInstallation:(FIRInstallationsItem *)installationItem; + +/** + * Removes installation data for the given app parameters. + * @param appID The Firebase(Google) Application ID. + * @param appName The Firebase Application Name. + * + * @return Returns a promise that is resolved with `[NSNull null]` on success. + */ +- (FBLPromise *)removeInstallationForAppID:(NSString *)appID appName:(NSString *)appName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m new file mode 100644 index 0000000..617b2d9 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m @@ -0,0 +1,140 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h" + +#import + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h" + +NSString *const kFIRInstallationsStoreUserDefaultsID = @"com.firebase.FIRInstallations"; + +@interface FIRInstallationsStore () +@property(nonatomic, readonly) GULKeychainStorage *secureStorage; +@property(nonatomic, readonly, nullable) NSString *accessGroup; +@property(nonatomic, readonly) dispatch_queue_t queue; +@property(nonatomic, readonly) GULUserDefaults *userDefaults; +@end + +@implementation FIRInstallationsStore + +- (instancetype)initWithSecureStorage:(GULKeychainStorage *)storage + accessGroup:(NSString *)accessGroup { + self = [super init]; + if (self) { + _secureStorage = storage; + _accessGroup = [accessGroup copy]; + _queue = dispatch_queue_create("com.firebase.FIRInstallationsStore", DISPATCH_QUEUE_SERIAL); + + NSString *userDefaultsSuiteName = _accessGroup ?: kFIRInstallationsStoreUserDefaultsID; + _userDefaults = [[GULUserDefaults alloc] initWithSuiteName:userDefaultsSuiteName]; + } + return self; +} + +- (FBLPromise *)installationForAppID:(NSString *)appID + appName:(NSString *)appName { + NSString *itemID = [FIRInstallationsItem identifierWithAppID:appID appName:appName]; + return [self installationExistsForAppID:appID appName:appName] + .then(^id(id result) { + return [FBLPromise + wrapObjectOrErrorCompletion:^(FBLPromiseObjectOrErrorCompletion _Nonnull handler) { + [self.secureStorage getObjectForKey:itemID + objectClass:[FIRInstallationsStoredItem class] + accessGroup:self.accessGroup + completionHandler:handler]; + }]; + }) + .then(^id(FIRInstallationsStoredItem *_Nullable storedItem) { + if (storedItem == nil) { + return [FIRInstallationsErrorUtil installationItemNotFoundForAppID:appID appName:appName]; + } + + FIRInstallationsItem *item = [[FIRInstallationsItem alloc] initWithAppID:appID + firebaseAppName:appName]; + [item updateWithStoredItem:storedItem]; + return item; + }); +} + +- (FBLPromise *)saveInstallation:(FIRInstallationsItem *)installationItem { + FIRInstallationsStoredItem *storedItem = [installationItem storedItem]; + NSString *identifier = [installationItem identifier]; + + return + [FBLPromise wrapObjectOrErrorCompletion:^( + FBLPromiseObjectOrErrorCompletion _Nonnull handler) { + [self.secureStorage setObject:storedItem + forKey:identifier + accessGroup:self.accessGroup + completionHandler:handler]; + }].then(^id(id __unused unusedResult) { + return [self setInstallationExists:YES forItemWithIdentifier:identifier]; + }); +} + +- (FBLPromise *)removeInstallationForAppID:(NSString *)appID appName:(NSString *)appName { + NSString *identifier = [FIRInstallationsItem identifierWithAppID:appID appName:appName]; + + return + [FBLPromise wrapErrorCompletion:^(FBLPromiseErrorCompletion _Nonnull handler) { + [self.secureStorage removeObjectForKey:identifier + accessGroup:self.accessGroup + completionHandler:handler]; + }].then(^id(id __unused result) { + return [self setInstallationExists:NO forItemWithIdentifier:identifier]; + }); +} + +#pragma mark - User defaults + +- (FBLPromise *)installationExistsForAppID:(NSString *)appID appName:(NSString *)appName { + NSString *identifier = [FIRInstallationsItem identifierWithAppID:appID appName:appName]; + return [FBLPromise onQueue:self.queue + do:^id _Nullable { + return [[self userDefaults] objectForKey:identifier] != nil + ? [NSNull null] + : [FIRInstallationsErrorUtil + installationItemNotFoundForAppID:appID + appName:appName]; + }]; +} + +- (FBLPromise *)setInstallationExists:(BOOL)exists + forItemWithIdentifier:(NSString *)identifier { + return [FBLPromise onQueue:self.queue + do:^id _Nullable { + if (exists) { + [[self userDefaults] setBool:YES forKey:identifier]; + } else { + [[self userDefaults] removeObjectForKey:identifier]; + } + + return [NSNull null]; + }]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h new file mode 100644 index 0000000..4da2337 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h @@ -0,0 +1,58 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The enum represent possible states of the installation auth token. + * + * WARNING: The enum is stored to Keychain as a part of `FIRInstallationsStoredAuthToken`. + * Modification of it can lead to incompatibility with previous version. Any modification must be + * evaluated and, if it is really needed, the `storageVersion` must be bumped and proper migration + * code added. + */ +typedef NS_ENUM(NSInteger, FIRInstallationsAuthTokenStatus) { + /// An initial status or an undefined value. + FIRInstallationsAuthTokenStatusUnknown, + /// The auth token has been received from the server. + FIRInstallationsAuthTokenStatusTokenReceived +}; + +/** + * This class serializes and deserializes the installation data into/from `NSData` to be stored in + * Keychain. This class is primarily used by `FIRInstallationsStore`. It is also used on the logic + * level as a data object (see `FIRInstallationsItem.authToken`). + * + * WARNING: Modification of the class properties can lead to incompatibility with the stored data + * encoded by the previous class versions. Any modification must be evaluated and, if it is really + * needed, the `storageVersion` must be bumped and proper migration code added. + */ +@interface FIRInstallationsStoredAuthToken : NSObject +@property FIRInstallationsAuthTokenStatus status; + +/// The installation auth token string that can be used to authorize requests to Firebase backend. +@property(nullable, copy) NSString *token; +/// The installation auth token expiration date. +@property(nullable, copy) NSDate *expirationDate; + +/// The version of local storage. +@property(nonatomic, readonly) NSInteger storageVersion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m new file mode 100644 index 0000000..8236f2a --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m @@ -0,0 +1,77 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" + +NSString *const kFIRInstallationsStoredAuthTokenStatusKey = @"status"; +NSString *const kFIRInstallationsStoredAuthTokenTokenKey = @"token"; +NSString *const kFIRInstallationsStoredAuthTokenExpirationDateKey = @"expirationDate"; +NSString *const kFIRInstallationsStoredAuthTokenStorageVersionKey = @"storageVersion"; + +NSInteger const kFIRInstallationsStoredAuthTokenStorageVersion = 1; + +@implementation FIRInstallationsStoredAuthToken + +- (NSInteger)storageVersion { + return kFIRInstallationsStoredAuthTokenStorageVersion; +} + +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + FIRInstallationsStoredAuthToken *clone = [[FIRInstallationsStoredAuthToken alloc] init]; + clone.status = self.status; + clone.token = [self.token copy]; + clone.expirationDate = self.expirationDate; + return clone; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)aCoder { + [aCoder encodeInteger:self.status forKey:kFIRInstallationsStoredAuthTokenStatusKey]; + [aCoder encodeObject:self.token forKey:kFIRInstallationsStoredAuthTokenTokenKey]; + [aCoder encodeObject:self.expirationDate + forKey:kFIRInstallationsStoredAuthTokenExpirationDateKey]; + [aCoder encodeInteger:self.storageVersion + forKey:kFIRInstallationsStoredAuthTokenStorageVersionKey]; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder { + NSInteger storageVersion = + [aDecoder decodeIntegerForKey:kFIRInstallationsStoredAuthTokenStorageVersionKey]; + if (storageVersion > kFIRInstallationsStoredAuthTokenStorageVersion) { + FIRLogWarning(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch, + @"FIRInstallationsStoredAuthToken was encoded by a newer coder version %ld. " + @"Current coder version is %ld. Some auth token data may be lost.", + (long)storageVersion, (long)kFIRInstallationsStoredAuthTokenStorageVersion); + } + + FIRInstallationsStoredAuthToken *object = [[FIRInstallationsStoredAuthToken alloc] init]; + object.status = [aDecoder decodeIntegerForKey:kFIRInstallationsStoredAuthTokenStatusKey]; + object.token = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredAuthTokenTokenKey]; + object.expirationDate = + [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kFIRInstallationsStoredAuthTokenExpirationDateKey]; + + return object; +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h new file mode 100644 index 0000000..0126eb0 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h @@ -0,0 +1,51 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h" + +@class FIRInstallationsStoredAuthToken; +@class FIRInstallationsStoredIIDCheckin; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class is supposed to be used by `FIRInstallationsStore` only. It is required to + * serialize/deserialize the installation data into/from `NSData` to be stored in Keychain. + * + * WARNING: Modification of the class properties can lead to incompatibility with the stored data + * encoded by the previous class versions. Any modification must be evaluated and, if it is really + * needed, the `storageVersion` must be bumped and proper migration code added. + */ +@interface FIRInstallationsStoredItem : NSObject + +/// A stable identifier that uniquely identifies the app instance. +@property(nonatomic, copy, nullable) NSString *firebaseInstallationID; +/// The `refreshToken` is used to authorize the installation auth token requests. +@property(nonatomic, copy, nullable) NSString *refreshToken; + +@property(nonatomic, nullable) FIRInstallationsStoredAuthToken *authToken; +@property(nonatomic) FIRInstallationsStatus registrationStatus; + +/// Instance ID default auth token imported from IID store as a part of IID migration. +@property(nonatomic, nullable) NSString *IIDDefaultToken; + +/// The version of local storage. +@property(nonatomic, readonly) NSInteger storageVersion; +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m new file mode 100644 index 0000000..4e19955 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m @@ -0,0 +1,80 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h" + +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +NSString *const kFIRInstallationsStoredItemFirebaseInstallationIDKey = @"firebaseInstallationID"; +NSString *const kFIRInstallationsStoredItemRefreshTokenKey = @"refreshToken"; +NSString *const kFIRInstallationsStoredItemAuthTokenKey = @"authToken"; +NSString *const kFIRInstallationsStoredItemRegistrationStatusKey = @"registrationStatus"; +NSString *const kFIRInstallationsStoredItemIIDDefaultTokenKey = @"IIDDefaultToken"; +NSString *const kFIRInstallationsStoredItemStorageVersionKey = @"storageVersion"; + +NSInteger const kFIRInstallationsStoredItemStorageVersion = 1; + +@implementation FIRInstallationsStoredItem + +- (NSInteger)storageVersion { + return kFIRInstallationsStoredItemStorageVersion; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)aCoder { + [aCoder encodeObject:self.firebaseInstallationID + forKey:kFIRInstallationsStoredItemFirebaseInstallationIDKey]; + [aCoder encodeObject:self.refreshToken forKey:kFIRInstallationsStoredItemRefreshTokenKey]; + [aCoder encodeObject:self.authToken forKey:kFIRInstallationsStoredItemAuthTokenKey]; + [aCoder encodeInteger:self.registrationStatus + forKey:kFIRInstallationsStoredItemRegistrationStatusKey]; + [aCoder encodeObject:self.IIDDefaultToken forKey:kFIRInstallationsStoredItemIIDDefaultTokenKey]; + [aCoder encodeInteger:self.storageVersion forKey:kFIRInstallationsStoredItemStorageVersionKey]; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder { + NSInteger storageVersion = + [aDecoder decodeIntegerForKey:kFIRInstallationsStoredItemStorageVersionKey]; + if (storageVersion > self.storageVersion) { + FIRLogWarning(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeInstallationCoderVersionMismatch, + @"FIRInstallationsStoredItem was encoded by a newer coder version %ld. Current " + @"coder version is %ld. Some installation data may be lost.", + (long)storageVersion, (long)kFIRInstallationsStoredItemStorageVersion); + } + + FIRInstallationsStoredItem *item = [[FIRInstallationsStoredItem alloc] init]; + item.firebaseInstallationID = + [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredItemFirebaseInstallationIDKey]; + item.refreshToken = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredItemRefreshTokenKey]; + item.authToken = [aDecoder decodeObjectOfClass:[FIRInstallationsStoredAuthToken class] + forKey:kFIRInstallationsStoredItemAuthTokenKey]; + item.registrationStatus = + [aDecoder decodeIntegerForKey:kFIRInstallationsStoredItemRegistrationStatusKey]; + item.IIDDefaultToken = + [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredItemIIDDefaultTokenKey]; + + return item; +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h new file mode 100644 index 0000000..0c850e9 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h @@ -0,0 +1,19 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An umbrella header, for any other libraries in this repo to access Firebase +// Installations Public headers. Any package manager complexity should be +// handled here. + +#import diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h new file mode 100644 index 0000000..7670d40 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h @@ -0,0 +1,126 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; +@class FIRInstallationsAuthTokenResult; + +NS_ASSUME_NONNULL_BEGIN + +/** A notification with this name is sent each time an installation is created or deleted. */ +// clang-format off +// clang-format12 merges the next two lines. +FOUNDATION_EXPORT const NSNotificationName FIRInstallationIDDidChangeNotification + NS_SWIFT_NAME(InstallationIDDidChange); +/** `userInfo` key for the `FirebaseApp.name` in `InstallationIDDidChangeNotification`. */ +FOUNDATION_EXPORT NSString *const kFIRInstallationIDDidChangeNotificationAppNameKey + NS_SWIFT_NAME(InstallationIDDidChangeAppNameKey); +// clang-format on + +/** + * An installation ID handler block. + * @param identifier The installation ID string if exists or `nil` otherwise. + * @param error The error when `identifier == nil` or `nil` otherwise. + */ +typedef void (^FIRInstallationsIDHandler)(NSString *__nullable identifier, + NSError *__nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * An authorization token handler block. + * @param tokenResult An instance of `InstallationsAuthTokenResult` in case of success or `nil` + * otherwise. + * @param error The error when `tokenResult == nil` or `nil` otherwise. + */ +typedef void (^FIRInstallationsTokenHandler)( + FIRInstallationsAuthTokenResult *__nullable tokenResult, NSError *__nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * The class provides API for Firebase Installations. + * Each configured `FirebaseApp` has a corresponding single instance of `Installations`. + * An instance of the class provides access to the installation info for the `FirebaseApp` as well + * as the ability to delete it. A Firebase Installation is unique by `FirebaseApp.name` and + * `FirebaseApp.options.googleAppID` . + */ +NS_SWIFT_NAME(Installations) NS_SWIFT_SENDABLE @interface FIRInstallations : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Returns a default instance of `Installations`. + * @return An instance of `Installations` for `FirebaseApp.defaultApp(). + * @throw Throws an exception if the default app is not configured yet or required `FirebaseApp` + * options are missing. + */ ++ (FIRInstallations *)installations NS_SWIFT_NAME(installations()); + +/** + * Returns an instance of `Installations` for an application. + * @param application A configured `FirebaseApp` instance. + * @return An instance of `Installations` corresponding to the passed application. + * @throw Throws an exception if required `FirebaseApp` options are missing. + */ ++ (FIRInstallations *)installationsWithApp:(FIRApp *)application NS_SWIFT_NAME(installations(app:)); + +/** + * The method creates or retrieves an installation ID. The installation ID is a stable identifier + * that uniquely identifies the app instance. NOTE: If the application already has an existing + * FirebaseInstanceID then the InstanceID identifier will be used. + * @param completion A completion handler which is invoked when the operation completes. + */ +- (void)installationIDWithCompletion:(void (^)(NSString *__nullable identifier, + NSError *__nullable error))completion; + +/** + * Retrieves (locally if it exists or from the server) a valid installation auth token. An existing + * token may be invalidated or expired, so it is recommended to fetch the installation auth token + * before each server request. The method does the same as + * `Installations.authToken(forcingRefresh:completion:)` with forcing refresh `false`. + * @param completion A completion handler which is invoked when the operation completes. + */ +- (void)authTokenWithCompletion:(void (^)(FIRInstallationsAuthTokenResult *__nullable tokenResult, + NSError *__nullable error))completion; + +/** + * Retrieves (locally or from the server depending on `forceRefresh` value) a valid installation + * auth token. An existing token may be invalidated or expire, so it is recommended to fetch the + * installation auth token before each server request. This method should be used with `forceRefresh + * == true` when e.g. a request with the previously fetched installation auth token failed with "Not + * Authorized" error. + * @param forceRefresh If `true` then the locally cached installation auth token will be ignored and + * a new one will be requested from the server. If `false`, then the locally cached installation + * auth token will be returned if exists and has not expired yet. + * @param completion A completion handler which is invoked when the operation completes. See + * `InstallationsTokenHandler` for additional details. + */ +- (void)authTokenForcingRefresh:(BOOL)forceRefresh + completion:(void (^)(FIRInstallationsAuthTokenResult *__nullable tokenResult, + NSError *__nullable error))completion; + +/** + * Deletes all the installation data including the unique identifier, auth tokens and + * all related data on the server side. A network connection is required for the method to + * succeed. If fails, the existing installation data remains untouched. + * @param completion A completion handler which is invoked when the operation completes. `error == + * nil` indicates success. + */ +- (void)deleteWithCompletion:(void (^)(NSError *__nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h new file mode 100644 index 0000000..501ac4e --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h @@ -0,0 +1,33 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** The class represents a result of the installation auth token request. */ +NS_SWIFT_NAME(InstallationsAuthTokenResult) +@interface FIRInstallationsAuthTokenResult : NSObject + +/** The installation auth token string. */ +@property(nonatomic, readonly) NSString *authToken; + +/** The installation auth token expiration date. */ +@property(nonatomic, readonly) NSDate *expirationDate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h new file mode 100644 index 0000000..939ca0a --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +extern NSString *const kFirebaseInstallationsErrorDomain NS_SWIFT_NAME(InstallationsErrorDomain); + +typedef NS_ERROR_ENUM(kFirebaseInstallationsErrorDomain, FIRInstallationsErrorCode){ + /** Unknown error. See `userInfo` for details. */ + FIRInstallationsErrorCodeUnknown = 0, + + /** Keychain error. See `userInfo` for details. */ + FIRInstallationsErrorCodeKeychain = 1, + + /** Server unreachable. A network error or server is unavailable. See `userInfo` for details. */ + FIRInstallationsErrorCodeServerUnreachable = 2, + + /** FirebaseApp configuration issues e.g. invalid GMP-App-ID, etc. See `userInfo` for details. + */ + FIRInstallationsErrorCodeInvalidConfiguration = 3, + +} NS_SWIFT_NAME(InstallationsErrorCode); diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h new file mode 100644 index 0000000..8a9b3c1 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h @@ -0,0 +1,19 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRInstallations.h" +#import "FIRInstallationsAuthTokenResult.h" +#import "FIRInstallationsErrors.h" diff --git a/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Resources/PrivacyInfo.xcprivacy b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..1e83fa6 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,30 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDiagnosticData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + + + diff --git a/frontend/ios/Pods/FirebaseInstallations/LICENSE b/frontend/ios/Pods/FirebaseInstallations/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/ios/Pods/FirebaseInstallations/README.md b/frontend/ios/Pods/FirebaseInstallations/README.md new file mode 100644 index 0000000..8c98212 --- /dev/null +++ b/frontend/ios/Pods/FirebaseInstallations/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 16.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](docs/AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@20 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRAppInternal.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..96d42ef --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,182 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRAPPINTERNAL_H +#define FIREBASECORE_FIRAPPINTERNAL_H + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRAPPINTERNAL_H diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRComponent.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..98c7a89 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,89 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRCOMPONENT_H +#define FIREBASECORE_FIRCOMPONENT_H + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRCOMPONENT_H diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRComponentContainer.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6864087 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,51 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRCOMPONENTCONTAINER_H +#define FIREBASECORE_FIRCOMPONENTCONTAINER_H + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRCOMPONENTCONTAINER_H diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRComponentType.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..92a5aab --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,40 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRCOMPONENTTYPE_H +#define FIREBASECORE_FIRCOMPONENTTYPE_H + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRCOMPONENTTYPE_H diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRHeartbeatLogger.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..95497d2 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,110 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIREBASECORE_FIRHEARTBEATLOGGER_H +#define FIREBASECORE_FIRHEARTBEATLOGGER_H + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +NS_SWIFT_SENDABLE +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns the header value for the heartbeat logger via the given completion handler.. +- (void)asyncHeaderValueWithCompletionHandler:(void (^)(NSString *_Nullable))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)); + +/// Return the header value for the heartbeat logger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Synchronously flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; + +/// Asynchronously flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @param completionHandler A completion handler to process the flushed payload of heartbeats. +- (void)flushHeartbeatsIntoPayloadWithCompletionHandler: + (void (^)(FIRHeartbeatsPayload *))completionHandler + API_AVAILABLE(ios(13.0), macosx(10.15), macCatalyst(13.0), tvos(13.0), watchos(6.0)); +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRHEARTBEATLOGGER_H diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRLibrary.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..fe256ad --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRLIBRARY_H +#define FIREBASECORE_FIRLIBRARY_H + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ + +#endif // FIREBASECORE_FIRLIBRARY_H diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRLogger.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..8117189 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,198 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIREBASECORE_FIRLOGGER_H +#define FIREBASECORE_FIRLOGGER_H + +#import + +typedef NS_ENUM(NSInteger, FIRLoggerLevel); + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +void FIRSetLoggerLevelNotice(void); +void FIRSetLoggerLevelWarning(void); +void FIRSetLoggerLevelError(void); +void FIRSetLoggerLevelDebug(void); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +BOOL FIRIsLoggableLevelNotice(void); +BOOL FIRIsLoggableLevelWarning(void); +BOOL FIRIsLoggableLevelError(void); +BOOL FIRIsLoggableLevelDebug(void); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +/** + * This function is similar to the one above, except it takes a `va_list` instead of the listed + * variables. + * + * The following functions accept the following parameters in order: (required) service + * name of type FirebaseLoggerService. + * + * (required) message code starting from "I-" which means iOS, + * followed by a capitalized three-character service identifier and a six digit integer message + * ID that is unique within the service. An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) A va_list + */ +extern void FIRLogBasicError(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicWarning(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicNotice(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicInfo(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); +extern void FIRLogBasicDebug(NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - category: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END + +#endif // FIREBASECORE_FIRLOGGER_H diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FirebaseCoreInternal.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..2561008 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,28 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIREBASECORE_FIREBASECOREINTERNAL_H +#define FIREBASECORE_FIREBASECOREINTERNAL_H + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" + +#endif // FIREBASECORE_FIREBASECOREINTERNAL_H diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h new file mode 100644 index 0000000..0c850e9 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h @@ -0,0 +1,19 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An umbrella header, for any other libraries in this repo to access Firebase +// Installations Public headers. Any package manager complexity should be +// handled here. + +#import diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Interop/FIRMessagingInterop.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Interop/FIRMessagingInterop.h new file mode 100644 index 0000000..ef5d528 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Interop/FIRMessagingInterop.h @@ -0,0 +1,41 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Connector for bridging communication between Firebase SDKs and FIRMessaging API. */ +NS_SWIFT_NAME(MessagingInterop) @protocol FIRMessagingInterop + +/** + * The FCM registration token is used to identify this device so that FCM can send notifications to + * it. It is associated with your APNs token when the APNs token is supplied, so messages sent to + * the FCM token will be delivered over APNs. + * + * The FCM registration token is sometimes refreshed automatically. In your FIRMessaging delegate, + * the delegate method `messaging:didReceiveRegistrationToken:` will be called once a token is + * available, or has been refreshed. Typically it should be called once per app start, but + * may be called more often if the token is invalidated or updated. + * + * Once you have an FCM registration token, you should send it to your application server, so it can + * use the FCM token to send notifications to your device. + */ +@property(nonatomic, readonly, nullable) NSString *FCMToken NS_SWIFT_NAME(fcmToken); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessaging+ExtensionHelper.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessaging+ExtensionHelper.m new file mode 100644 index 0000000..0ff8d3d --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessaging+ExtensionHelper.m @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging+ExtensionHelper.h" + +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessagingExtensionHelper.h" + +@implementation FIRMessaging (ExtensionHelper) + ++ (FIRMessagingExtensionHelper *)extensionHelper { + static dispatch_once_t once; + static FIRMessagingExtensionHelper *extensionHelper; + dispatch_once(&once, ^{ + extensionHelper = [[FIRMessagingExtensionHelper alloc] init]; + }); + return extensionHelper; +} + +#if SWIFT_PACKAGE || COCOAPODS || FIREBASE_BUILD_CARTHAGE || FIREBASE_BUILD_ZIP_FILE +/// Stub used to force the linker to include the categories in this file. +void FIRInclude_FIRMessaging_ExtensionHelper_Category(void) { +} +#endif // SWIFT_PACKAGE || COCOAPODS || FIREBASE_BUILD_CARTHAGE || FIREBASE_BUILD_ZIP_FILE + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessaging.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessaging.m new file mode 100644 index 0000000..e2bb09b --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessaging.m @@ -0,0 +1,1040 @@ + +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !__has_feature(objc_arc) +#error FIRMessagingLib should be compiled with ARC. +#endif + +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" +#import +#import +#import +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h" +#import "FirebaseMessaging/Interop/FIRMessagingInterop.h" +#import "FirebaseMessaging/Sources/FIRMessagingAnalytics.h" +#import "FirebaseMessaging/Sources/FIRMessagingCode.h" +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingContextManagerService.h" +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingPubSub.h" +#import "FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.h" +#import "FirebaseMessaging/Sources/FIRMessagingRmqManager.h" +#import "FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/FIRMessaging_Private.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingAuthService.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.h" +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +static NSString *const kFIRMessagingMessageViaAPNSRootKey = @"aps"; +static NSString *const kFIRMessagingReachabilityHostname = @"www.google.com"; + +const NSNotificationName FIRMessagingRegistrationTokenRefreshedNotification = + @"com.firebase.messaging.notif.fcm-token-refreshed"; + +NSString *const kFIRMessagingUserDefaultsKeyAutoInitEnabled = + @"com.firebase.messaging.auto-init.enabled"; // Auto Init Enabled key stored in NSUserDefaults + +NSString *const kFIRMessagingPlistAutoInitEnabled = + @"FirebaseMessagingAutoInitEnabled"; // Auto Init Enabled key stored in Info.plist + +NSString *const FIRMessagingErrorDomain = @"com.google.fcm"; + +BOOL FIRMessagingIsAPNSSyncMessage(NSDictionary *message) { + if ([message[kFIRMessagingMessageViaAPNSRootKey] isKindOfClass:[NSDictionary class]]) { + NSDictionary *aps = message[kFIRMessagingMessageViaAPNSRootKey]; + if (aps && [aps isKindOfClass:[NSDictionary class]]) { + return [aps[kFIRMessagingMessageAPNSContentAvailableKey] boolValue]; + } + } + return NO; +} + +BOOL FIRMessagingIsContextManagerMessage(NSDictionary *message) { + return [FIRMessagingContextManagerService isContextManagerMessage:message]; +} + +@interface FIRMessagingMessageInfo () + +@property(nonatomic, readwrite, assign) FIRMessagingMessageStatus status; + +@end + +@implementation FIRMessagingMessageInfo + +- (instancetype)init { + FIRMessagingInvalidateInitializer(); +} + +- (instancetype)initWithStatus:(FIRMessagingMessageStatus)status { + self = [super init]; + if (self) { + _status = status; + } + return self; +} + +@end + +@interface FIRMessaging () + +// FIRApp properties +@property(nonatomic, readwrite, strong) NSData *apnsTokenData; +@property(nonatomic, readwrite, strong) FIRMessagingClient *client; +@property(nonatomic, readwrite, strong) GULReachabilityChecker *reachability; +@property(nonatomic, readwrite, strong) FIRMessagingPubSub *pubsub; +@property(nonatomic, readwrite, strong) FIRMessagingRmqManager *rmq2Manager; +@property(nonatomic, readwrite, strong) FIRMessagingSyncMessageManager *syncMessageManager; +@property(nonatomic, readwrite, strong) GULUserDefaults *messagingUserDefaults; +@property(nonatomic, readwrite, strong) FIRInstallations *installations; +@property(nonatomic, readwrite, strong) FIRMessagingTokenManager *tokenManager; +@property(nonatomic, readwrite, strong) FIRHeartbeatLogger *heartbeatLogger; + +/// Message ID's logged for analytics. This prevents us from logging the same message twice +/// which can happen if the user inadvertently calls `appDidReceiveMessage` along with us +/// calling it implicitly during swizzling. +@property(nonatomic, readwrite, strong) NSMutableSet *loggedMessageIDs; +@property(nonatomic, readwrite, strong) id _Nullable analytics; + +@end + +@interface FIRMessaging () +@end + +@implementation FIRMessaging + ++ (FIRMessaging *)messaging { + FIRApp *defaultApp = [FIRApp defaultApp]; // Missing configure will be logged here. + id instance = FIR_COMPONENT(FIRMessagingInterop, defaultApp.container); + + // We know the instance coming from the container is a FIRMessaging instance, cast it and move on. + return (FIRMessaging *)instance; +} + +- (instancetype)initWithAnalytics:(nullable id)analytics + userDefaults:(GULUserDefaults *)defaults + heartbeatLogger:(FIRHeartbeatLogger *)heartbeatLogger { + self = [super init]; + if (self != nil) { + _loggedMessageIDs = [NSMutableSet set]; + _messagingUserDefaults = defaults; + _analytics = analytics; + _heartbeatLogger = heartbeatLogger; + } + return self; +} + +- (void)dealloc { + [self.reachability stop]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [self teardown]; +} + +#pragma mark - Config + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self withName:@"fire-fcm"]; +} + ++ (nonnull NSArray *)componentsToRegister { + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + if (!container.app.isDefaultApp) { + // Only start for the default FIRApp. + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeFIRApp001, + @"Firebase Messaging only works with the default app."); + return nil; + } + + // Ensure it's cached so it returns the same instance every time messaging is called. + *isCacheable = YES; + id analytics = FIR_COMPONENT(FIRAnalyticsInterop, container); + FIRMessaging *messaging = + [[FIRMessaging alloc] initWithAnalytics:analytics + userDefaults:[GULUserDefaults standardUserDefaults] + heartbeatLogger:container.app.heartbeatLogger]; + [messaging start]; + [messaging configureMessagingWithOptions:container.app.options]; + + [messaging configureNotificationSwizzlingIfEnabled]; + return messaging; + }; + FIRComponent *messagingProvider = + [FIRComponent componentWithProtocol:@protocol(FIRMessagingInterop) + instantiationTiming:FIRInstantiationTimingEagerInDefaultApp + creationBlock:creationBlock]; + + return @[ messagingProvider ]; +} + +- (void)configureMessagingWithOptions:(FIROptions *)options { + NSString *GCMSenderID = options.GCMSenderID; + if (!GCMSenderID.length) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeFIRApp000, + @"Firebase not set up correctly, nil or empty senderID."); + [NSException raise:FIRMessagingErrorDomain + format:@"Could not configure Firebase Messaging. GCMSenderID must not be nil or " + @"empty."]; + } + + self.tokenManager.fcmSenderID = GCMSenderID; + self.tokenManager.firebaseAppID = options.googleAppID; + + // FCM generates a FCM token during app start for sending push notification to device. + // This is not needed for app extension except for watch. +#if TARGET_OS_WATCH + [self didCompleteConfigure]; +#else // TARGET_OS_WATCH + if (![GULAppEnvironmentUtil isAppExtension]) { + [self didCompleteConfigure]; + } +#endif // TARGET_OS_WATCH +} + +- (void)didCompleteConfigure { + NSString *cachedToken = + [self.tokenManager cachedTokenInfoWithAuthorizedEntity:self.tokenManager.fcmSenderID + scope:kFIRMessagingDefaultTokenScope] + .token; + // When there is a cached token, do the token refresh. + // Before fetching FCM token, confirm there is an APNS token to avoid validation error + // This error is innocuous since we refetch after APNS token is set but it can seem alarming + if (cachedToken) { + // Clean up expired tokens by checking the token refresh policy. + [self.installations installationIDWithCompletion:^(NSString *_Nullable identifier, + NSError *_Nullable error) { + if ([self.tokenManager checkTokenRefreshPolicyWithIID:identifier] && self.APNSToken) { + // Default token is expired, fetch default token from server. + [self retrieveFCMTokenForSenderID:self.tokenManager.fcmSenderID + completion:^(NSString *_Nullable FCMToken, NSError *_Nullable error){ + }]; + } + // Set the default FCM token, there's an issue that FIRApp configure + // happens before developers able to set the delegate + // Hence first token set must be happen here after listener is set + // TODO(chliangGoogle) Need to investigate better solution. + [self updateDefaultFCMToken:self.FCMToken]; + }]; + } else if (self.isAutoInitEnabled && self.APNSToken) { + // When there is no cached token, must check auto init is enabled. + // If it's disabled, don't initiate token generation/refresh. + // If no cache token and auto init is enabled, fetch a token from server. + [self retrieveFCMTokenForSenderID:self.tokenManager.fcmSenderID + completion:^(NSString *_Nullable FCMToken, NSError *_Nullable error){ + }]; + } +} + +- (void)configureNotificationSwizzlingIfEnabled { + // Swizzle remote-notification-related methods (app delegate and UNUserNotificationCenter) + if ([FIRMessagingRemoteNotificationsProxy canSwizzleMethods]) { + NSString *docsURLString = @"https://firebase.google.com/docs/cloud-messaging/ios/client" + @"#method_swizzling_in_firebase_messaging"; + FIRMessagingLoggerNotice(kFIRMessagingMessageCodeFIRApp000, + @"FIRMessaging Remote Notifications proxy enabled, will swizzle " + @"remote notification receiver handlers. If you'd prefer to manually " + @"integrate Firebase Messaging, add \"%@\" to your Info.plist, " + @"and set it to NO. Follow the instructions at:\n%@\nto ensure " + @"proper integration.", + kFIRMessagingRemoteNotificationsProxyEnabledInfoPlistKey, + docsURLString); + [[FIRMessagingRemoteNotificationsProxy sharedProxy] swizzleMethodsIfPossible]; + } +} + +- (void)start { + [self setupFileManagerSubDirectory]; + [self setupNotificationListeners]; + + self.tokenManager = + [[FIRMessagingTokenManager alloc] initWithHeartbeatLogger:self.heartbeatLogger]; + self.installations = [FIRInstallations installations]; + [self setupTopics]; + + // Print the library version for logging. + NSString *currentLibraryVersion = FIRFirebaseVersion(); + FIRMessagingLoggerInfo(kFIRMessagingMessageCodeMessagingPrintLibraryVersion, + @"FIRMessaging library version %@", currentLibraryVersion); + + NSString *hostname = kFIRMessagingReachabilityHostname; + self.reachability = [[GULReachabilityChecker alloc] initWithReachabilityDelegate:self + withHost:hostname]; + [self.reachability start]; + + // setup FIRMessaging objects + [self setupRmqManager]; + [self setupSyncMessageManager]; +} + +- (void)setupFileManagerSubDirectory { + if (![[self class] hasSubDirectory:kFIRMessagingSubDirectoryName]) { + [[self class] createSubDirectory:kFIRMessagingSubDirectoryName]; + } + if (![[self class] hasSubDirectory:kFIRMessagingInstanceIDSubDirectoryName]) { + [[self class] createSubDirectory:kFIRMessagingInstanceIDSubDirectoryName]; + } +} + +- (void)setupNotificationListeners { + // To prevent multiple notifications remove self as observer for all events. + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center removeObserver:self]; + [center addObserver:self + selector:@selector(defaultFCMTokenWasRefreshed:) + name:kFIRMessagingRegistrationTokenRefreshNotification + object:nil]; +} + +- (void)setupRmqManager { + self.rmq2Manager = [[FIRMessagingRmqManager alloc] initWithDatabaseName:@"rmq2"]; + [self.rmq2Manager loadRmqId]; +} + +- (void)setupTopics { + self.pubsub = [[FIRMessagingPubSub alloc] initWithTokenManager:self.tokenManager]; +} + +- (void)setupSyncMessageManager { + self.syncMessageManager = + [[FIRMessagingSyncMessageManager alloc] initWithRmqManager:self.rmq2Manager]; + [self.syncMessageManager removeExpiredSyncMessages]; +} + +- (void)teardown { + self.pubsub = nil; + self.syncMessageManager = nil; + self.rmq2Manager = nil; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeMessaging001, @"Did successfully teardown"); +} + +#pragma mark - Messages + +- (FIRMessagingMessageInfo *)appDidReceiveMessage:(NSDictionary *)message { + if (!message.count) { + return [[FIRMessagingMessageInfo alloc] initWithStatus:FIRMessagingMessageStatusUnknown]; + } + + // For downstream messages that go via MCS we should strip out this key before sending + // the message to the device. + BOOL isOldMessage = NO; + NSString *messageID = message[kFIRMessagingMessageIDKey]; + if (messageID.length) { + [self.rmq2Manager saveS2dMessageWithRmqId:messageID]; + + BOOL isSyncMessage = FIRMessagingIsAPNSSyncMessage(message); + if (isSyncMessage) { + isOldMessage = [self.syncMessageManager didReceiveAPNSSyncMessage:message]; + } + + // Prevent duplicates by keeping a cache of all the logged messages during each session. + // The duplicates only happen when the 3P app calls `appDidReceiveMessage:` along with + // us swizzling their implementation to call the same method implicitly. + // We need to rule out the contextual message because it shares the same message ID + // as the local notification it will schedule. And because it is also a APNSSync message + // its duplication is already checked previously. + if (!isOldMessage && !FIRMessagingIsContextManagerMessage(message)) { + isOldMessage = [self.loggedMessageIDs containsObject:messageID]; + if (!isOldMessage) { + [self.loggedMessageIDs addObject:messageID]; + } + } + } + + if (!isOldMessage) { + [FIRMessagingAnalytics logMessage:message toAnalytics:_analytics]; + [self handleContextManagerMessage:message]; + [self handleIncomingLinkIfNeededFromMessage:message]; + } + return [[FIRMessagingMessageInfo alloc] initWithStatus:FIRMessagingMessageStatusNew]; +} + +- (BOOL)handleContextManagerMessage:(NSDictionary *)message { + if (FIRMessagingIsContextManagerMessage(message)) { + return [FIRMessagingContextManagerService handleContextManagerMessage:message]; + } + return NO; +} + +- (void)handleIncomingLinkIfNeededFromMessage:(NSDictionary *)message { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + NSURL *url = [self linkURLFromMessage:message]; + if (url == nil) { + return; + } + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self handleIncomingLinkIfNeededFromMessage:message]; + }); + return; + } + UIApplication *application = [GULAppDelegateSwizzler sharedApplication]; + if (!application) { + return; + } + id appDelegate = application.delegate; + SEL continueUserActivitySelector = @selector(application: + continueUserActivity:restorationHandler:); + + // Due to FIRAAppDelegateProxy swizzling, this selector will most likely get chosen, whether or + // not the actual application has implemented + // |application:continueUserActivity:restorationHandler:|. A warning will be displayed to the user + // if they haven't implemented it. + if ([NSUserActivity class] != nil && + [appDelegate respondsToSelector:continueUserActivitySelector]) { + NSUserActivity *userActivity = + [[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb]; + userActivity.webpageURL = url; + [appDelegate application:application + continueUserActivity:userActivity + restorationHandler:^(NSArray *_Nullable restorableObjects){ + // Do nothing, as we don't support the app calling this block + }]; + } +#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION +} + +- (NSURL *)linkURLFromMessage:(NSDictionary *)message { + NSString *urlString = message[kFIRMessagingMessageLinkKey]; + if (urlString == nil || ![urlString isKindOfClass:[NSString class]] || urlString.length == 0) { + return nil; + } + NSURL *url = [NSURL URLWithString:urlString]; + return url; +} + +#pragma mark - APNS + +- (NSData *)APNSToken { + return self.apnsTokenData; +} + +- (void)setAPNSToken:(NSData *)APNSToken { + [self setAPNSToken:APNSToken type:FIRMessagingAPNSTokenTypeUnknown]; +} + +- (void)setAPNSToken:(NSData *)apnsToken type:(FIRMessagingAPNSTokenType)type { + if ([apnsToken isEqual:self.apnsTokenData]) { + return; + } + self.apnsTokenData = apnsToken; + + // Notify InstanceID that APNS Token has been set. + NSDictionary *userInfo = @{kFIRMessagingAPNSTokenType : @(type)}; + // TODO(chliang) This is sent to InstanceID in case users are still using the deprecated SDK. + // Should be safe to remove once InstanceID is removed. + NSNotification *notification = + [NSNotification notificationWithName:kFIRMessagingAPNSTokenNotification + object:[apnsToken copy] + userInfo:userInfo]; + [[NSNotificationQueue defaultQueue] enqueueNotification:notification postingStyle:NSPostASAP]; + + [self.tokenManager setAPNSToken:[apnsToken copy] withUserInfo:userInfo]; +} + +#pragma mark - FCM Token + +- (BOOL)isAutoInitEnabled { + // Defer to the class method since we're just reading from regular userDefaults and we need to + // read this from IID without instantiating the Messaging singleton. + return [[self class] isAutoInitEnabledWithUserDefaults:_messagingUserDefaults]; +} + +/// Checks if Messaging auto-init is enabled in the user defaults instance passed in. This is +/// exposed as a class property for IID to fetch the property without instantiating an instance of +/// Messaging. Since Messaging can only be used with the default FIRApp, we can have one point of +/// entry without context of which FIRApp instance is being used. +/// ** THIS METHOD IS DEPENDED ON INTERNALLY BY IID USING REFLECTION. PLEASE DO NOT CHANGE THE +/// SIGNATURE, AS IT WOULD BREAK AUTOINIT FUNCTIONALITY WITHIN IID. ** ++ (BOOL)isAutoInitEnabledWithUserDefaults:(GULUserDefaults *)userDefaults { + // Check storage + id isAutoInitEnabledObject = + [userDefaults objectForKey:kFIRMessagingUserDefaultsKeyAutoInitEnabled]; + if (isAutoInitEnabledObject) { + return [isAutoInitEnabledObject boolValue]; + } + + // Check Info.plist + isAutoInitEnabledObject = + [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRMessagingPlistAutoInitEnabled]; + if (isAutoInitEnabledObject) { + return [isAutoInitEnabledObject boolValue]; + } + + // If none of above exists, we default to the global switch that comes from FIRApp. + return [[FIRApp defaultApp] isDataCollectionDefaultEnabled]; +} + +- (void)setAutoInitEnabled:(BOOL)autoInitEnabled { + BOOL isFCMAutoInitEnabled = [self isAutoInitEnabled]; + [_messagingUserDefaults setBool:autoInitEnabled + forKey:kFIRMessagingUserDefaultsKeyAutoInitEnabled]; + if (!isFCMAutoInitEnabled && autoInitEnabled) { + [self.tokenManager tokenAndRequestIfNotExist]; + } +} + +- (NSString *)FCMToken { + // Gets the current default token, and requests a new one if it doesn't exist. + NSString *token = [self.tokenManager tokenAndRequestIfNotExist]; + return token; +} + +- (void)tokenWithCompletion:(FIRMessagingFCMTokenFetchCompletion)completion { + FIROptions *options = FIRApp.defaultApp.options; + [self retrieveFCMTokenForSenderID:options.GCMSenderID completion:completion]; +} +- (void)deleteTokenWithCompletion:(FIRMessagingDeleteFCMTokenCompletion)completion { + FIROptions *options = FIRApp.defaultApp.options; + [self deleteFCMTokenForSenderID:options.GCMSenderID completion:completion]; +} + +- (void)retrieveFCMTokenForSenderID:(nonnull NSString *)senderID + completion:(nonnull FIRMessagingFCMTokenFetchCompletion)completion { + if (!senderID.length) { + NSString *description = @"Couldn't fetch token because a Sender ID was not supplied. A valid " + @"Sender ID is required to fetch an FCM token"; + FIRMessagingLoggerError(kFIRMessagingMessageCodeSenderIDNotSuppliedForTokenFetch, @"%@", + description); + if (completion) { + NSError *error = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeMissingAuthorizedEntity + failureReason:description]; + completion(nil, error); + } + return; + } + NSDictionary *options = nil; + if (self.APNSToken) { + options = @{kFIRMessagingTokenOptionsAPNSKey : self.APNSToken}; + } else { + FIRMessagingLoggerWarn(kFIRMessagingMessageCodeAPNSTokenNotAvailableDuringTokenFetch, + @"APNS device token not set before retrieving FCM Token for Sender ID " + @"'%@'." + @"Be sure to re-retrieve the FCM token once the APNS device token is " + @"set.", + senderID); + } + [self.tokenManager + tokenWithAuthorizedEntity:senderID + scope:kFIRMessagingDefaultTokenScope + options:options + handler:^(NSString *_Nullable FCMToken, NSError *_Nullable error) { + if (completion) { + completion(FCMToken, error); + } + }]; +} + +- (void)deleteFCMTokenForSenderID:(nonnull NSString *)senderID + completion:(nonnull FIRMessagingDeleteFCMTokenCompletion)completion { + if (!senderID.length) { + NSString *description = @"Couldn't delete token because a Sender ID was not supplied. A " + @"valid Sender ID is required to delete an FCM token"; + FIRMessagingLoggerError(kFIRMessagingMessageCodeSenderIDNotSuppliedForTokenDelete, @"%@", + description); + if (completion) { + NSError *error = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeInvalidRequest + failureReason:description]; + completion(error); + } + return; + } + FIRMessaging_WEAKIFY(self); + [self.installations + installationIDWithCompletion:^(NSString *_Nullable identifier, NSError *_Nullable error) { + FIRMessaging_STRONGIFY(self); + if (error) { + NSError *newError = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeInvalidIdentity + failureReason:@"Failed to get installation ID."]; + completion(newError); + } else { + [self.tokenManager deleteTokenWithAuthorizedEntity:senderID + scope:kFIRMessagingDefaultTokenScope + instanceID:identifier + handler:^(NSError *_Nullable error) { + if (completion) { + completion(error); + } + }]; + } + }]; +} + +- (void)deleteDataWithCompletion:(void (^)(NSError *_Nullable))completion { + FIRMessaging_WEAKIFY(self); + [self.tokenManager deleteWithHandler:^(NSError *error) { + FIRMessaging_STRONGIFY(self); + if (error) { + if (completion) { + completion(error); + } + return; + } + // Only request new token if FCM auto initialization is + // enabled. + if ([self isAutoInitEnabled]) { + // Deletion succeeds! Requesting new checkin, IID and token. + [self tokenWithCompletion:^(NSString *_Nullable token, NSError *_Nullable error) { + if (completion) { + completion(error); + } + }]; + return; + } + if (completion) { + completion(nil); + } + }]; +} + +#pragma mark - FIRMessagingDelegate helper methods +- (void)setDelegate:(id)delegate { + _delegate = delegate; + [self validateDelegateConformsToTokenAvailabilityMethods]; +} + +// Check if the delegate conforms to |didReceiveRegistrationToken:| +// and display a warning to the developer if not. +// NOTE: Once |didReceiveRegistrationToken:| can be made a required method, this +// check can be removed. +- (void)validateDelegateConformsToTokenAvailabilityMethods { + if (self.delegate && ![self.delegate respondsToSelector:@selector(messaging: + didReceiveRegistrationToken:)]) { + FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTokenDelegateMethodsNotImplemented, + @"The object %@ does not respond to " + @"-messaging:didReceiveRegistrationToken:. Please implement " + @"-messaging:didReceiveRegistrationToken: to be provided with an FCM " + @"token.", + self.delegate.description); + } +} + +- (void)notifyRefreshedFCMToken { + __weak FIRMessaging *weakSelf = self; + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf notifyRefreshedFCMToken]; + }); + return; + } + if ([self.delegate respondsToSelector:@selector(messaging:didReceiveRegistrationToken:)]) { + [self.delegate messaging:self didReceiveRegistrationToken:self.tokenManager.defaultFCMToken]; + } + + // Should always trigger the token refresh notification when the delegate method is called + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center postNotificationName:FIRMessagingRegistrationTokenRefreshedNotification + object:self.tokenManager.defaultFCMToken]; +} + +#pragma mark - Topics + ++ (NSString *)normalizeTopic:(NSString *)topic { + if (!topic.length) { + return nil; + } + if (![FIRMessagingPubSub hasTopicsPrefix:topic]) { + topic = [FIRMessagingPubSub addPrefixToTopic:topic]; + } + if ([FIRMessagingPubSub isValidTopicWithPrefix:topic]) { + return [topic copy]; + } + return nil; +} + +- (void)subscribeToTopic:(NSString *)topic { + [self subscribeToTopic:topic completion:nil]; +} + +- (void)subscribeToTopic:(NSString *)topic + completion:(nullable FIRMessagingTopicOperationCompletion)completion { + if ([FIRMessagingPubSub hasTopicsPrefix:topic]) { + FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicFormatIsDeprecated, + @"Format '%@' is deprecated. Only '%@' should be used in " + @"subscribeToTopic.", + topic, [FIRMessagingPubSub removePrefixFromTopic:topic]); + } + __weak FIRMessaging *weakSelf = self; + [self + retrieveFCMTokenForSenderID:self.tokenManager.fcmSenderID + completion:^(NSString *_Nullable FCMToken, NSError *_Nullable error) { + if (error) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging010, + @"The subscription operation failed due to an " + @"error getting the FCM token: %@.", + error); + if (completion) { + completion(error); + } + return; + } + FIRMessaging *strongSelf = weakSelf; + NSString *normalizeTopic = [[strongSelf class] normalizeTopic:topic]; + if (normalizeTopic.length) { + [strongSelf.pubsub subscribeToTopic:normalizeTopic handler:completion]; + return; + } + NSString *failureReason = [NSString + stringWithFormat:@"Cannot parse topic name: '%@'. Will not subscribe.", + topic]; + FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging009, @"%@", + failureReason); + if (completion) { + completion([NSError + messagingErrorWithCode:kFIRMessagingErrorCodeInvalidTopicName + failureReason:failureReason]); + } + }]; +} + +- (void)unsubscribeFromTopic:(NSString *)topic { + [self unsubscribeFromTopic:topic completion:nil]; +} + +- (void)unsubscribeFromTopic:(NSString *)topic + completion:(nullable FIRMessagingTopicOperationCompletion)completion { + if ([FIRMessagingPubSub hasTopicsPrefix:topic]) { + FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicFormatIsDeprecated, + @"Format '%@' is deprecated. Only '%@' should be used in " + @"unsubscribeFromTopic.", + topic, [FIRMessagingPubSub removePrefixFromTopic:topic]); + } + __weak FIRMessaging *weakSelf = self; + [self retrieveFCMTokenForSenderID:self.tokenManager.fcmSenderID + completion:^(NSString *_Nullable FCMToken, NSError *_Nullable error) { + if (error) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging012, + @"The unsubscription operation failed due to " + @"an error getting the FCM token: %@.", + error); + if (completion) { + completion(error); + } + return; + } + FIRMessaging *strongSelf = weakSelf; + NSString *normalizeTopic = [[strongSelf class] normalizeTopic:topic]; + if (normalizeTopic.length) { + [strongSelf.pubsub unsubscribeFromTopic:normalizeTopic + handler:completion]; + return; + } + NSString *failureReason = [NSString + stringWithFormat: + @"Cannot parse topic name: '%@'. Will not unsubscribe.", topic]; + FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging011, @"%@", + failureReason); + if (completion) { + completion([NSError + messagingErrorWithCode:kFIRMessagingErrorCodeInvalidTopicName + failureReason:failureReason]); + } + }]; +} + +#pragma mark - GULReachabilityDelegate + +- (void)reachability:(GULReachabilityChecker *)reachability + statusChanged:(GULReachabilityStatus)status { + [self onNetworkStatusChanged]; +} + +#pragma mark - Network + +- (void)onNetworkStatusChanged { + if ([self isNetworkAvailable]) { + [self.pubsub scheduleSync:YES]; + } +} + +- (BOOL)isNetworkAvailable { + GULReachabilityStatus status = self.reachability.reachabilityStatus; + return (status == kGULReachabilityViaCellular || status == kGULReachabilityViaWifi); +} + +- (FIRMessagingNetworkStatus)networkType { + GULReachabilityStatus status = self.reachability.reachabilityStatus; + if (![self isNetworkAvailable]) { + return kFIRMessagingReachabilityNotReachable; + } else if (status == kGULReachabilityViaCellular) { + return kFIRMessagingReachabilityReachableViaWWAN; + } else { + return kFIRMessagingReachabilityReachableViaWiFi; + } +} + +#pragma mark - Notifications + +- (void)defaultFCMTokenWasRefreshed:(NSNotification *)notification { + if (notification.object && ![notification.object isKindOfClass:[NSString class]]) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeMessaging015, + @"Invalid default FCM token type %@", + NSStringFromClass([notification.object class])); + return; + } + NSString *newToken = [(NSString *)notification.object copy]; + [self updateDefaultFCMToken:newToken]; +} + +- (void)updateDefaultFCMToken:(NSString *)defaultFCMToken { + NSString *oldToken = self.tokenManager.defaultFCMToken; + NSString *newToken = defaultFCMToken; + if ([self.tokenManager hasTokenChangedFromOldToken:oldToken toNewToken:newToken]) { + // Make sure to set default token first before notifying others. + [self.tokenManager saveDefaultTokenInfoInKeychain:newToken]; + [self notifyDelegateOfFCMTokenAvailability]; + [self.pubsub scheduleSync:YES]; + } +} + +- (void)notifyDelegateOfFCMTokenAvailability { + __weak FIRMessaging *weakSelf = self; + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf notifyDelegateOfFCMTokenAvailability]; + }); + return; + } + if ([self.delegate respondsToSelector:@selector(messaging:didReceiveRegistrationToken:)]) { + [self.delegate messaging:self didReceiveRegistrationToken:self.tokenManager.defaultFCMToken]; + } + // Should always trigger the token refresh notification when the delegate method is called + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center postNotificationName:FIRMessagingRegistrationTokenRefreshedNotification + object:self.tokenManager.defaultFCMToken]; +} + +#pragma mark - Application Support Directory + ++ (BOOL)hasSubDirectory:(NSString *)subDirectoryName { + NSString *subDirectoryPath = [self pathForSubDirectory:subDirectoryName]; + BOOL isDirectory; + if (![[NSFileManager defaultManager] fileExistsAtPath:subDirectoryPath + isDirectory:&isDirectory]) { + return NO; + } else if (!isDirectory) { + return NO; + } + return YES; +} + ++ (NSString *)pathForSubDirectory:(NSString *)subDirectoryName { + NSArray *directoryPaths = + NSSearchPathForDirectoriesInDomains(FIRMessagingSupportedDirectory(), NSUserDomainMask, YES); + NSString *dirPath = directoryPaths.lastObject; + NSArray *components = @[ dirPath, subDirectoryName ]; + return [NSString pathWithComponents:components]; +} + ++ (BOOL)createSubDirectory:(NSString *)subDirectoryName { + NSString *subDirectoryPath = [self pathForSubDirectory:subDirectoryName]; + BOOL hasSubDirectory; + + if (![[NSFileManager defaultManager] fileExistsAtPath:subDirectoryPath + isDirectory:&hasSubDirectory]) { + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:subDirectoryPath + withIntermediateDirectories:YES + attributes:nil + error:&error]; + if (error) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging017, + @"Cannot create directory %@, error: %@", subDirectoryPath, error); + return NO; + } + } else { + if (!hasSubDirectory) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeMessaging018, + @"Found file instead of directory at %@", subDirectoryPath); + return NO; + } + } + return YES; +} + +#pragma mark - Locales + ++ (NSString *)currentLocale { + NSArray *locales = [self firebaseLocales]; + NSArray *preferredLocalizations = + [NSBundle preferredLocalizationsFromArray:locales + forPreferences:[NSLocale preferredLanguages]]; + NSString *legalDocsLanguage = [preferredLocalizations firstObject]; + // Use en as the default language + return legalDocsLanguage ? legalDocsLanguage : @"en"; +} + ++ (NSArray *)firebaseLocales { + NSMutableArray *locales = [NSMutableArray array]; + NSDictionary *localesMap = [self firebaselocalesMap]; + for (NSString *key in localesMap) { + [locales addObjectsFromArray:localesMap[key]]; + } + return locales; +} + ++ (NSDictionary *)firebaselocalesMap { + return @{ + // Albanian + @"sq" : @[ @"sq_AL" ], + // Belarusian + @"be" : @[ @"be_BY" ], + // Bulgarian + @"bg" : @[ @"bg_BG" ], + // Catalan + @"ca" : @[ @"ca", @"ca_ES" ], + // Croatian + @"hr" : @[ @"hr", @"hr_HR" ], + // Czech + @"cs" : @[ @"cs", @"cs_CZ" ], + // Danish + @"da" : @[ @"da", @"da_DK" ], + // Estonian + @"et" : @[ @"et_EE" ], + // Finnish + @"fi" : @[ @"fi", @"fi_FI" ], + // Hebrew + @"he" : @[ @"he", @"iw_IL" ], + // Hindi + @"hi" : @[ @"hi_IN" ], + // Hungarian + @"hu" : @[ @"hu", @"hu_HU" ], + // Icelandic + @"is" : @[ @"is_IS" ], + // Indonesian + @"id" : @[ @"id", @"in_ID", @"id_ID" ], + // Irish + @"ga" : @[ @"ga_IE" ], + // Korean + @"ko" : @[ @"ko", @"ko_KR", @"ko-KR" ], + // Latvian + @"lv" : @[ @"lv_LV" ], + // Lithuanian + @"lt" : @[ @"lt_LT" ], + // Macedonian + @"mk" : @[ @"mk_MK" ], + // Malay + @"ms" : @[ @"ms_MY" ], + // Maltese + @"mt" : @[ @"mt_MT" ], + // Polish + @"pl" : @[ @"pl", @"pl_PL", @"pl-PL" ], + // Romanian + @"ro" : @[ @"ro", @"ro_RO" ], + // Russian + @"ru" : @[ @"ru_RU", @"ru", @"ru_BY", @"ru_KZ", @"ru-RU" ], + // Slovak + @"sk" : @[ @"sk", @"sk_SK" ], + // Slovenian + @"sl" : @[ @"sl_SI" ], + // Swedish + @"sv" : @[ @"sv", @"sv_SE", @"sv-SE" ], + // Turkish + @"tr" : @[ @"tr", @"tr-TR", @"tr_TR" ], + // Ukrainian + @"uk" : @[ @"uk", @"uk_UA" ], + // Vietnamese + @"vi" : @[ @"vi", @"vi_VN" ], + // The following are groups of locales or locales that sub-divide a + // language). + // Arabic + @"ar" : @[ + @"ar", @"ar_DZ", @"ar_BH", @"ar_EG", @"ar_IQ", @"ar_JO", @"ar_KW", + @"ar_LB", @"ar_LY", @"ar_MA", @"ar_OM", @"ar_QA", @"ar_SA", @"ar_SD", + @"ar_SY", @"ar_TN", @"ar_AE", @"ar_YE", @"ar_GB", @"ar-IQ", @"ar_US" + ], + // Simplified Chinese + @"zh_Hans" : @[ @"zh_CN", @"zh_SG", @"zh-Hans" ], + // Traditional Chinese + @"zh_Hant" : @[ @"zh_HK", @"zh_TW", @"zh-Hant", @"zh-HK", @"zh-TW" ], + // Dutch + @"nl" : @[ @"nl", @"nl_BE", @"nl_NL", @"nl-NL" ], + // English + @"en" : @[ + @"en", @"en_AU", @"en_CA", @"en_IN", @"en_IE", @"en_MT", @"en_NZ", @"en_PH", + @"en_SG", @"en_ZA", @"en_GB", @"en_US", @"en_AE", @"en-AE", @"en_AS", @"en-AU", + @"en_BD", @"en-CA", @"en_EG", @"en_ES", @"en_GB", @"en-GB", @"en_HK", @"en_ID", + @"en-IN", @"en_NG", @"en-PH", @"en_PK", @"en-SG", @"en-US" + ], + // French + + @"fr" : + @[ @"fr", @"fr_BE", @"fr_CA", @"fr_FR", @"fr_LU", @"fr_CH", @"fr-CA", @"fr-FR", @"fr_MA" ], + // German + @"de" : @[ @"de", @"de_AT", @"de_DE", @"de_LU", @"de_CH", @"de-DE" ], + // Greek + @"el" : @[ @"el", @"el_CY", @"el_GR" ], + // Italian + @"it" : @[ @"it", @"it_IT", @"it_CH", @"it-IT" ], + // Japanese + @"ja" : @[ @"ja", @"ja_JP", @"ja_JP_JP", @"ja-JP" ], + // Norwegian + @"no" : @[ @"nb", @"no_NO", @"no_NO_NY", @"nb_NO" ], + // Brazilian Portuguese + @"pt_BR" : @[ @"pt_BR", @"pt-BR" ], + // European Portuguese + @"pt_PT" : @[ @"pt", @"pt_PT", @"pt-PT" ], + // Serbian + @"sr" : @[ @"sr_BA", @"sr_ME", @"sr_RS", @"sr_Latn_BA", @"sr_Latn_ME", @"sr_Latn_RS" ], + // European Spanish + @"es_ES" : @[ @"es", @"es_ES", @"es-ES" ], + // Mexican Spanish + @"es_MX" : @[ @"es-MX", @"es_MX", @"es_US", @"es-US" ], + // Latin American Spanish + @"es_419" : @[ + @"es_AR", @"es_BO", @"es_CL", @"es_CO", @"es_CR", @"es_DO", @"es_EC", + @"es_SV", @"es_GT", @"es_HN", @"es_NI", @"es_PA", @"es_PY", @"es_PE", + @"es_PR", @"es_UY", @"es_VE", @"es-AR", @"es-CL", @"es-CO" + ], + // Thai + @"th" : @[ @"th", @"th_TH", @"th_TH_TH" ], + }; +} + +#pragma mark - Utilities used by InstanceID + ++ (NSString *)FIRMessagingSDKVersion { + return FIRFirebaseVersion(); +} + ++ (NSString *)FIRMessagingSDKCurrentLocale { + return [self currentLocale]; +} + +#pragma mark - Force Category Linking +#if SWIFT_PACKAGE || COCOAPODS || FIREBASE_BUILD_CARTHAGE || FIREBASE_BUILD_ZIP_FILE +extern void FIRInclude_FIRMessaging_ExtensionHelper_Category(void); +#endif // SWIFT_PACKAGE || COCOAPODS || FIREBASE_BUILD_CARTHAGE || FIREBASE_BUILD_ZIP_FILE +extern void FIRInclude_NSDictionary_FIRMessaging_Category(void); +extern void FIRInclude_NSError_FIRMessaging_Category(void); + +/// Does nothing when called, and not meant to be called. +/// +/// This method forces the linker to include categories even if +/// users do not include the '-ObjC' linker flag in their project. ++ (void)noop { +#if SWIFT_PACKAGE || COCOAPODS || FIREBASE_BUILD_CARTHAGE || FIREBASE_BUILD_ZIP_FILE + FIRInclude_FIRMessaging_ExtensionHelper_Category(); +#endif // SWIFT_PACKAGE || COCOAPODS || FIREBASE_BUILD_CARTHAGE || FIREBASE_BUILD_ZIP_FILE + FIRInclude_NSDictionary_FIRMessaging_Category(); + FIRInclude_NSError_FIRMessaging_Category(); +} +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingAnalytics.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingAnalytics.h new file mode 100644 index 0000000..92eeb05 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingAnalytics.h @@ -0,0 +1,44 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Provides integration between FIRMessaging and Analytics. + * + * All Analytics dependencies should be kept in this class, and missing dependencies should be + * handled gracefully. + * + */ +@interface FIRMessagingAnalytics : NSObject + +/** + * Determine whether a notification has the properties to be loggable to Analytics. + * If so, send the notification. + * @param notification The notification payload from APNs + * @param analytics The class to be used as the receiver of the logging method + */ + ++ (void)logMessage:(NSDictionary *)notification + toAnalytics:(id _Nullable)analytics; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingAnalytics.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingAnalytics.m new file mode 100644 index 0000000..d377be5 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingAnalytics.m @@ -0,0 +1,237 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingAnalytics.h" + +#import +#import +#import "Interop/Analytics/Public/FIRInteropEventNames.h" +#import "Interop/Analytics/Public/FIRInteropParameterNames.h" + +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" + +static NSString *const kLogTag = @"FIRMessagingAnalytics"; + +// aps Key +static NSString *const kApsKey = @"aps"; +static NSString *const kApsAlertKey = @"alert"; +static NSString *const kApsSoundKey = @"sound"; +static NSString *const kApsBadgeKey = @"badge"; +static NSString *const kApsContentAvailableKey = @"badge"; + +// Data Key +static NSString *const kDataKey = @"data"; + +static NSString *const kFIRParameterLabel = @"label"; + +static NSString *const kReengagementSource = @"Firebase"; +static NSString *const kReengagementMedium = @"notification"; + +// Analytics +static NSString *const kAnalyticsEnabled = @"google.c.a.e"; +static NSString *const kAnalyticsMessageTimestamp = @"google.c.a.ts"; +static NSString *const kAnalyticsMessageUseDeviceTime = @"google.c.a.udt"; +static NSString *const kAnalyticsTrackConversions = @"google.c.a.tc"; + +@implementation FIRMessagingAnalytics + ++ (BOOL)canLogNotification:(NSDictionary *)notification { + if (!notification.count) { + // Payload is empty + return NO; + } + NSString *isAnalyticsLoggingEnabled = notification[kAnalyticsEnabled]; + if (![isAnalyticsLoggingEnabled isKindOfClass:[NSString class]] || + ![isAnalyticsLoggingEnabled isEqualToString:@"1"]) { + // Analytics logging is not enabled + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics001, + @"Analytics logging is disabled. Do not log event."); + return NO; + } + return YES; +} + ++ (void)logOpenNotification:(NSDictionary *)notification + toAnalytics:(id _Nullable)analytics { + [self logUserPropertyForConversionTracking:notification toAnalytics:analytics]; + [self logEvent:kFIRIEventNotificationOpen withNotification:notification toAnalytics:analytics]; +} + ++ (void)logForegroundNotification:(NSDictionary *)notification + toAnalytics:(id _Nullable)analytics { + [self logEvent:kFIRIEventNotificationForeground + withNotification:notification + toAnalytics:analytics]; +} + ++ (void)logEvent:(NSString *)event + withNotification:(NSDictionary *)notification + toAnalytics:(id _Nullable)analytics { + if (!event.length) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalyticsInvalidEvent, + @"Can't log analytics with empty event."); + return; + } + NSMutableDictionary *params = [self paramsForEvent:event withNotification:notification]; + + [analytics logEventWithOrigin:@"fcm" name:event parameters:params]; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics005, @"%@: Sending event: %@ params: %@", + kLogTag, event, params); +} + ++ (NSMutableDictionary *)paramsForEvent:(NSString *)event + withNotification:(NSDictionary *)notification { + NSDictionary *analyticsDataMap = notification; + if (!analyticsDataMap.count) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics000, + @"No data found in notification. Will not log any analytics events."); + return nil; + } + + if (![self canLogNotification:analyticsDataMap]) { + return nil; + } + + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + NSString *composerIdentifier = analyticsDataMap[kFIRMessagingAnalyticsComposerIdentifier]; + if ([composerIdentifier isKindOfClass:[NSString class]] && composerIdentifier.length) { + params[kFIRIParameterMessageIdentifier] = [composerIdentifier copy]; + } + + NSString *composerLabel = analyticsDataMap[kFIRMessagingAnalyticsComposerLabel]; + if ([composerLabel isKindOfClass:[NSString class]] && composerLabel.length) { + params[kFIRIParameterMessageName] = [composerLabel copy]; + } + + NSString *messageLabel = analyticsDataMap[kFIRMessagingAnalyticsMessageLabel]; + if ([messageLabel isKindOfClass:[NSString class]] && messageLabel.length) { + params[kFIRParameterLabel] = [messageLabel copy]; + } + + NSString *from = analyticsDataMap[kFIRMessagingFromKey]; + if ([from isKindOfClass:[NSString class]] && [from containsString:@"/topics/"]) { + params[kFIRIParameterTopic] = [from copy]; + } + + id timestamp = analyticsDataMap[kAnalyticsMessageTimestamp]; + if ([timestamp respondsToSelector:@selector(longLongValue)]) { + int64_t timestampValue = [timestamp longLongValue]; + if (timestampValue != 0) { + params[kFIRIParameterMessageTime] = @(timestampValue); + } + } + + if (analyticsDataMap[kAnalyticsMessageUseDeviceTime]) { + params[kFIRIParameterMessageDeviceTime] = analyticsDataMap[kAnalyticsMessageUseDeviceTime]; + } + + return params; +} + ++ (void)logUserPropertyForConversionTracking:(NSDictionary *)notification + toAnalytics:(id _Nullable)analytics { + NSInteger shouldTrackConversions = [notification[kAnalyticsTrackConversions] integerValue]; + if (shouldTrackConversions != 1) { + return; + } + + NSString *composerIdentifier = notification[kFIRMessagingAnalyticsComposerIdentifier]; + if ([composerIdentifier isKindOfClass:[NSString class]] && composerIdentifier.length) { + // Set user property for event. + [analytics setUserPropertyWithOrigin:@"fcm" + name:kFIRIUserPropertyLastNotification + value:composerIdentifier]; + + // Set the re-engagement attribution properties. + NSMutableDictionary *params = [NSMutableDictionary dictionaryWithCapacity:3]; + params[kFIRIParameterSource] = kReengagementSource; + params[kFIRIParameterMedium] = kReengagementMedium; + params[kFIRIParameterCampaign] = composerIdentifier; + [analytics logEventWithOrigin:@"fcm" name:kFIRIEventFirebaseCampaign parameters:params]; + + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics003, + @"%@: Sending event: %@ params: %@", kLogTag, + kFIRIEventFirebaseCampaign, params); + + } else { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAnalytics004, + @"%@: Failed to set user property: %@ value: %@", kLogTag, + kFIRIUserPropertyLastNotification, composerIdentifier); + } +} + ++ (void)logMessage:(NSDictionary *)notification + toAnalytics:(id _Nullable)analytics { + // iOS only because Analytics doesn't support other platforms. + +#if TARGET_OS_IOS + if (![self canLogNotification:notification]) { + return; + } + + UIApplication *application = [GULAppDelegateSwizzler sharedApplication]; + if (!application) { + return; + } + UIApplicationState applicationState = application.applicationState; + switch (applicationState) { + case UIApplicationStateInactive: + // App was in background and in transition to open when user tapped + // on a display notification. + // Needs to check notification is displayed. + if ([[self class] isDisplayNotification:notification]) { + [self logOpenNotification:notification toAnalytics:analytics]; + } + break; + + case UIApplicationStateActive: + // App was in foreground when it received the notification. + [self logForegroundNotification:notification toAnalytics:analytics]; + break; + + default: + // App was either in background state or in transition from closed + // to open. + // Needs to check notification is displayed. + if ([[self class] isDisplayNotification:notification]) { + [self logOpenNotification:notification toAnalytics:analytics]; + } + break; + } +#endif +} + ++ (BOOL)isDisplayNotification:(NSDictionary *)notification { + NSDictionary *aps = notification[kApsKey]; + if (!aps || ![aps isKindOfClass:[NSDictionary class]]) { + return NO; + } + NSDictionary *alert = aps[kApsAlertKey]; + if (!alert) { + return NO; + } + if ([alert isKindOfClass:[NSDictionary class]]) { + return alert.allKeys.count > 0; + } + // alert can be string sometimes (if only body is specified) + if ([alert isKindOfClass:[NSString class]]) { + return YES; + } + return NO; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingCode.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingCode.h new file mode 100644 index 0000000..af06130 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingCode.h @@ -0,0 +1,261 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +typedef NS_ENUM(NSInteger, FIRMessagingMessageCode) { + // FIRMessaging+FIRApp.m + kFIRMessagingMessageCodeFIRApp000 = 1000, // I-FCM001000 + kFIRMessagingMessageCodeFIRApp001 = 1001, // I-FCM001001 + // FIRMessaging.m + kFIRMessagingMessageCodeMessagingPrintLibraryVersion = 2000, // I-FCM002000 + kFIRMessagingMessageCodeMessaging001 = 2001, // I-FCM002001 + kFIRMessagingMessageCodeMessaging002 = 2002, // I-FCM002002 - no longer used + kFIRMessagingMessageCodeMessaging003 = 2003, // I-FCM002003 + kFIRMessagingMessageCodeMessaging004 = 2004, // I-FCM002004 + kFIRMessagingMessageCodeMessaging005 = 2005, // I-FCM002005 + kFIRMessagingMessageCodeMessaging006 = 2006, // I-FCM002006 - no longer used + kFIRMessagingMessageCodeMessaging007 = 2007, // I-FCM002007 - no longer used + kFIRMessagingMessageCodeMessaging008 = 2008, // I-FCM002008 - no longer used + kFIRMessagingMessageCodeMessaging009 = 2009, // I-FCM002009 + kFIRMessagingMessageCodeMessaging010 = 2010, // I-FCM002010 + kFIRMessagingMessageCodeMessaging011 = 2011, // I-FCM002011 + kFIRMessagingMessageCodeMessaging012 = 2012, // I-FCM002012 + kFIRMessagingMessageCodeMessaging013 = 2013, // I-FCM002013 + kFIRMessagingMessageCodeMessaging014 = 2014, // I-FCM002014 + kFIRMessagingMessageCodeMessaging015 = 2015, + kFIRMessagingMessageCodeMessaging016 = 2016, // I-FCM002016 - no longer used + kFIRMessagingMessageCodeMessaging017 = 2017, // I-FCM002017 + kFIRMessagingMessageCodeMessaging018 = 2018, // I-FCM002018 + kFIRMessagingMessageCodeRemoteMessageDelegateMethodNotImplemented = 2019, // I-FCM002019 + kFIRMessagingMessageCodeSenderIDNotSuppliedForTokenFetch = 2020, // I-FCM002020 + kFIRMessagingMessageCodeSenderIDNotSuppliedForTokenDelete = 2021, // I-FCM002021 + kFIRMessagingMessageCodeAPNSTokenNotAvailableDuringTokenFetch = 2022, // I-FCM002022 + kFIRMessagingMessageCodeTokenDelegateMethodsNotImplemented = 2023, // I-FCM002023 + kFIRMessagingMessageCodeTopicFormatIsDeprecated = 2024, + kFIRMessagingMessageCodeDirectChannelConnectionFailed = 2025, + kFIRMessagingMessageCodeInvalidClient = 2026, // no longer used + + // DO NOT USE 4000, 4004 - 4013 + kFIRMessagingMessageCodeClient001 = 4001, // I-FCM004000 + kFIRMessagingMessageCodeClient002 = 4002, // I-FCM004001 + kFIRMessagingMessageCodeClient003 = 4003, // I-FCM004002 + + // DO NOT USE 5000 - 5023 + // FIRMessagingContextManagerService.m + kFIRMessagingMessageCodeContextManagerService000 = 6000, // I-FCM006000 + kFIRMessagingMessageCodeContextManagerService001 = 6001, // I-FCM006001 + kFIRMessagingMessageCodeContextManagerService002 = 6002, // I-FCM006002 + kFIRMessagingMessageCodeContextManagerService003 = 6003, // I-FCM006003 + kFIRMessagingMessageCodeContextManagerService004 = 6004, // I-FCM006004 + kFIRMessagingMessageCodeContextManagerService005 = 6005, // I-FCM006005 + kFIRMessagingMessageCodeContextManagerServiceFailedLocalSchedule = 6006, // I-FCM006006 + // DO NOT USE 7000 - 7013 + + // FIRMessagingPendingTopicsList.m + kFIRMessagingMessageCodePendingTopicsList000 = 8000, // I-FCM008000 + // FIRMessagingPubSub.m + kFIRMessagingMessageCodePubSub000 = 9000, // I-FCM009000 + kFIRMessagingMessageCodePubSub001 = 9001, // I-FCM009001 + kFIRMessagingMessageCodePubSub002 = 9002, // I-FCM009002 + kFIRMessagingMessageCodePubSub003 = 9003, // I-FCM009003 + kFIRMessagingMessageCodePubSubArchiveError = 9004, + kFIRMessagingMessageCodePubSubUnarchiveError = 9005, + + // FIRMessagingReceiver.m + kFIRMessagingMessageCodeReceiver000 = 10000, // I-FCM010000 + kFIRMessagingMessageCodeReceiver001 = 10001, // I-FCM010001 + kFIRMessagingMessageCodeReceiver002 = 10002, // I-FCM010002 + kFIRMessagingMessageCodeReceiver003 = 10003, // I-FCM010003 + kFIRMessagingMessageCodeReceiver004 = 10004, // I-FCM010004 - no longer used + kFIRMessagingMessageCodeReceiver005 = 10005, // I-FCM010005 + // FIRMessagingRegistrar.m + kFIRMessagingMessageCodeRegistrar000 = 11000, // I-FCM011000 + // FIRMessagingRemoteNotificationsProxy.m + kFIRMessagingMessageCodeRemoteNotificationsProxy000 = 12000, // I-FCM012000 + kFIRMessagingMessageCodeRemoteNotificationsProxy001 = 12001, // I-FCM012001 + kFIRMessagingMessageCodeRemoteNotificationsProxyAPNSFailed = 12002, // I-FCM012002 + kFIRMessagingMessageCodeRemoteNotificationsProxyMethodNotAdded = 12003, // I-FCM012003 + // FIRMessagingRmq2PersistentStore.m + // DO NOT USE 13000, 13001, 13009 + kFIRMessagingMessageCodeRmq2PersistentStore002 = 13002, // I-FCM013002 + kFIRMessagingMessageCodeRmq2PersistentStore003 = 13003, // I-FCM013003 + kFIRMessagingMessageCodeRmq2PersistentStore004 = 13004, // I-FCM013004 + kFIRMessagingMessageCodeRmq2PersistentStore005 = 13005, // I-FCM013005 + kFIRMessagingMessageCodeRmq2PersistentStore006 = 13006, // I-FCM013006 + kFIRMessagingMessageCodeRmq2PersistentStoreErrorCreatingDatabase = 13007, // I-FCM013007 + kFIRMessagingMessageCodeRmq2PersistentStoreErrorOpeningDatabase = 13008, // I-FCM013008 + kFIRMessagingMessageCodeRmq2PersistentStoreErrorCreatingTable = 13010, // I-FCM013010 + // FIRMessagingRmqManager.m + kFIRMessagingMessageCodeRmqManager000 = 14000, // I-FCM014000 + // FIRMessagingSyncMessageManager.m + // DO NOT USE 16000, 16003 + kFIRMessagingMessageCodeSyncMessageManager001 = 16001, // I-FCM016001 + kFIRMessagingMessageCodeSyncMessageManager002 = 16002, // I-FCM016002 + kFIRMessagingMessageCodeSyncMessageManager004 = 16004, // I-FCM016004 + kFIRMessagingMessageCodeSyncMessageManager005 = 16005, // I-FCM016005 + kFIRMessagingMessageCodeSyncMessageManager006 = 16006, // I-FCM016006 + kFIRMessagingMessageCodeSyncMessageManager007 = 16007, // I-FCM016007 + kFIRMessagingMessageCodeSyncMessageManager008 = 16008, // I-FCM016008 + // FIRMessagingTopicOperation.m + kFIRMessagingMessageCodeTopicOption000 = 17000, // I-FCM017000 + kFIRMessagingMessageCodeTopicOption001 = 17001, // I-FCM017001 + kFIRMessagingMessageCodeTopicOption002 = 17002, // I-FCM017002 + kFIRMessagingMessageCodeTopicOptionTopicEncodingFailed = 17003, // I-FCM017003 + kFIRMessagingMessageCodeTopicOperationEmptyResponse = 17004, // I-FCM017004 + // FIRMessagingUtilities.m + kFIRMessagingMessageCodeUtilities000 = 18000, // I-FCM018000 + kFIRMessagingMessageCodeUtilities001 = 18001, // I-FCM018001 + kFIRMessagingMessageCodeUtilities002 = 18002, // I-FCM018002 + // FIRMessagingAnalytics.m + kFIRMessagingMessageCodeAnalytics000 = 19000, // I-FCM019000 + kFIRMessagingMessageCodeAnalytics001 = 19001, // I-FCM019001 + kFIRMessagingMessageCodeAnalytics002 = 19002, // I-FCM019002 + kFIRMessagingMessageCodeAnalytics003 = 19003, // I-FCM019003 + kFIRMessagingMessageCodeAnalytics004 = 19004, // I-FCM019004 + kFIRMessagingMessageCodeAnalytics005 = 19005, // I-FCM019005 + kFIRMessagingMessageCodeAnalyticsInvalidEvent = 19006, // I-FCM019006 + kFIRMessagingMessageCodeAnalytics007 = 19007, // I-FCM019007 + kFIRMessagingMessageCodeAnalyticsCouldNotInvokeAnalyticsLog = 19008, // I-FCM019008 + + // FIRMessagingExtensionHelper.m + kFIRMessagingServiceExtensionImageInvalidURL = 20000, + kFIRMessagingServiceExtensionImageNotDownloaded = 20001, + kFIRMessagingServiceExtensionLocalFileNotCreated = 20002, + kFIRMessagingServiceExtensionImageNotAttached = 20003, + kFIRMessagingServiceExtensionTransportBytesError = 20004, + kFIRMessagingServiceExtensionInvalidProjectID = 2005, + kFIRMessagingServiceExtensionInvalidMessageID = 2006, + kFIRMessagingServiceExtensionInvalidInstanceID = 2007, + + kFIRMessagingMessageCodeFIRApp002 = 22002, + kFIRMessagingMessageCodeInternal001 = 22001, + kFIRMessagingMessageCodeInternal002 = 22002, + // FIRMessaging.m + // DO NOT USE 4000. + kFIRMessagingMessageCodeInstanceID000 = 23000, + kFIRMessagingMessageCodeInstanceID001 = 23001, + kFIRMessagingMessageCodeInstanceID002 = 23002, + kFIRMessagingMessageCodeInstanceID003 = 23003, + kFIRMessagingMessageCodeInstanceID004 = 23004, + kFIRMessagingMessageCodeInstanceID005 = 23005, + kFIRMessagingMessageCodeInstanceID006 = 23006, + kFIRMessagingMessageCodeInstanceID007 = 23007, + kFIRMessagingMessageCodeInstanceID008 = 23008, + kFIRMessagingMessageCodeInstanceID009 = 23009, + kFIRMessagingMessageCodeInstanceID010 = 23010, + kFIRMessagingMessageCodeInstanceID011 = 23011, + kFIRMessagingMessageCodeInstanceID012 = 23012, + kFIRMessagingMessageCodeInstanceID013 = 23013, + kFIRMessagingMessageCodeInstanceID014 = 23014, + kFIRMessagingMessageCodeInstanceID015 = 23015, + kFIRMessagingMessageCodeRefetchingTokenForAPNS = 23016, + kFIRMessagingMessageCodeInstanceID017 = 23017, + kFIRMessagingMessageCodeInstanceID018 = 23018, + // FIRMessagingAuthService.m + kFIRMessagingMessageCodeAuthService000 = 25000, + kFIRMessagingMessageCodeAuthService001 = 25001, + kFIRMessagingMessageCodeAuthService002 = 25002, + kFIRMessagingMessageCodeAuthService003 = 25003, + kFIRMessagingMessageCodeAuthService004 = 25004, + kFIRMessagingMessageCodeAuthServiceCheckinInProgress = 25004, + + // FIRMessagingBackupExcludedPlist.m + // Do NOT USE 6003 + kFIRMessagingMessageCodeBackupExcludedPlist000 = 26000, + kFIRMessagingMessageCodeBackupExcludedPlist001 = 26001, + kFIRMessagingMessageCodeBackupExcludedPlist002 = 26002, + // FIRMessagingCheckinService.m + kFIRMessagingMessageCodeService000 = 27000, + kFIRMessagingMessageCodeService001 = 27001, + kFIRMessagingMessageCodeService002 = 27002, + kFIRMessagingMessageCodeService003 = 27003, + kFIRMessagingMessageCodeService004 = 27004, + kFIRMessagingMessageCodeService005 = 27005, + kFIRMessagingMessageCodeService006 = 27006, + kFIRMessagingInvalidSettingResponse = 27008, + // FIRMessagingCheckinStore.m + // DO NOT USE 8002, 8004 - 8008 + kFIRMessagingMessageCodeCheckinStore000 = 28000, + kFIRMessagingMessageCodeCheckinStore001 = 28001, + kFIRMessagingMessageCodeCheckinStore003 = 28003, + kFIRMessagingMessageCodeCheckinStoreCheckinPlistDeleted = 28009, + kFIRMessagingMessageCodeCheckinStoreCheckinPlistSaved = 28010, + + // DO NOT USE 9000 - 9006 + + // DO NOT USE 10000 - 10009 + + // DO NOT USE 11000 - 11002 + + // DO NOT USE 12000 - 12014 + + // DO NOT USE 13004, 13005, 13007, 13008, 13010, 13011, 13013, 13014 + kFIRMessagingMessageCodeStore000 = 33000, + kFIRMessagingMessageCodeStore002 = 33002, + kFIRMessagingMessageCodeStore003 = 33003, + kFIRMessagingMessageCodeStore006 = 33006, + kFIRMessagingMessageCodeStore009 = 33009, + kFIRMessagingMessageCodeStore012 = 33012, + // FIRMessagingTokenManager.m + // DO NOT USE 14002, 14005 + kFIRMessagingMessageCodeTokenManager000 = 34000, + kFIRMessagingMessageCodeTokenManager001 = 34001, + kFIRMessagingMessageCodeTokenManager003 = 34003, + kFIRMessagingMessageCodeTokenManager004 = 34004, + kFIRMessagingMessageCodeTokenManagerErrorDeletingFCMTokensOnAppReset = 34006, + kFIRMessagingMessageCodeTokenManagerDeletedFCMTokensOnAppReset = 34007, + kFIRMessagingMessageCodeTokenManagerSavedAppVersion = 34008, + kFIRMessagingMessageCodeTokenManagerErrorInvalidatingAllTokens = 34009, + kFIRMessagingMessageCodeTokenManagerAPNSChanged = 34010, + kFIRMessagingMessageCodeTokenManagerAPNSChangedTokenInvalidated = 34011, + kFIRMessagingMessageCodeTokenManagerInvalidateStaleToken = 34012, + // FIRMessagingTokenStore.m + // DO NOT USE 15002 - 15013 + kFIRMessagingMessageCodeTokenStore000 = 35000, + kFIRMessagingMessageCodeTokenStore001 = 35001, + kFIRMessagingMessageCodeTokenStoreExceptionUnarchivingTokenInfo = 35015, + + // DO NOT USE 16000, 18004 + + // FIRMessagingUtilities.m + kFIRMessagingMessageCodeUtilitiesMissingBundleIdentifier = 38000, + kFIRMessagingMessageCodeUtilitiesAppEnvironmentUtilNotAvailable = 38001, + kFIRMessagingMessageCodeUtilitiesCannotGetHardwareModel = 38002, + kFIRMessagingMessageCodeUtilitiesCannotGetSystemVersion = 38003, + // FIRMessagingTokenOperation.m + kFIRMessagingMessageCodeTokenOperationFailedToSignParams = 39000, + // FIRMessagingTokenFetchOperation.m + // DO NOT USE 40004, 40005 + kFIRMessagingMessageCodeTokenFetchOperationFetchRequest = 40000, + kFIRMessagingMessageCodeTokenFetchOperationRequestError = 40001, + kFIRMessagingMessageCodeTokenFetchOperationBadResponse = 40002, + kFIRMessagingMessageCodeTokenFetchOperationBadTokenStructure = 40003, + // FIRMessagingTokenDeleteOperation.m + kFIRMessagingMessageCodeTokenDeleteOperationFetchRequest = 41000, + kFIRMessagingMessageCodeTokenDeleteOperationRequestError = 41001, + kFIRMessagingMessageCodeTokenDeleteOperationBadResponse = 41002, + // FIRMessagingTokenInfo.m + kFIRMessagingMessageCodeTokenInfoBadAPNSInfo = 42000, + kFIRMessagingMessageCodeTokenInfoFirebaseAppIDChanged = 42001, + kFIRMessagingMessageCodeTokenInfoLocaleChanged = 42002, + // FIRMessagingKeychain.m + kFIRMessagingKeychainReadItemError = 43000, + kFIRMessagingKeychainAddItemError = 43001, + kFIRMessagingKeychainDeleteItemError = 43002, + kFIRMessagingKeychainCreateKeyPairError = 43003, + kFIRMessagingKeychainUpdateItemError = 43004, +}; diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingConstants.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingConstants.h new file mode 100644 index 0000000..b3eac74 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingConstants.h @@ -0,0 +1,90 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Global constants to be put here. + * + */ +#import + +#ifndef _FIRMessaging_CONSTANTS_H +#define _FIRMessaging_CONSTANTS_H + +FOUNDATION_EXPORT NSString *const kFIRMessagingFromKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingMessageIDKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingMessageAPNSContentAvailableKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingMessageSyncMessageTTLKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingMessageLinkKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingSenderID; +FOUNDATION_EXPORT NSString *const kFIRMessagingFID; +FOUNDATION_EXPORT NSString *const kFIRMessagingAnalyticsComposerIdentifier; +FOUNDATION_EXPORT NSString *const kFIRMessagingAnalyticsMessageLabel; +FOUNDATION_EXPORT NSString *const kFIRMessagingAnalyticsComposerLabel; +FOUNDATION_EXPORT NSString *const kFIRMessagingProductID; + +FOUNDATION_EXPORT NSString *const kFIRMessagingRemoteNotificationsProxyEnabledInfoPlistKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingSubDirectoryName; + +#pragma mark - Notifications + +FOUNDATION_EXPORT NSString *const kFIRMessagingCheckinFetchedNotification; +FOUNDATION_EXPORT NSString *const kFIRMessagingAPNSTokenNotification; +FOUNDATION_EXPORT NSString *const kFIRMessagingDefaultGCMTokenFailNotification; +FOUNDATION_EXPORT NSString *const kFIRMessagingRegistrationTokenRefreshNotification; + +FOUNDATION_EXPORT const int kFIRMessagingSendTtlDefault; // 24 hours + +/** + * Value included in a structured response indicating an identity reset. + */ +FOUNDATION_EXPORT NSString *const kFIRMessaging_CMD_RST; + +#pragma mark - Miscellaneous + +/// The scope used to save the IID "*" scope token. This is used for saving the +/// IID auth token that we receive from the server. This feature was never +/// implemented on the server side. +FOUNDATION_EXPORT NSString *const kFIRMessagingAllScopeIdentifier; +/// The scope used to save the IID "*" scope token. +FOUNDATION_EXPORT NSString *const kFIRMessagingDefaultTokenScope; +/// Denylisted "fiam" token scope. +FOUNDATION_EXPORT NSString *const kFIRMessagingFIAMTokenScope; + +/// Subdirectory in search path directory to store InstanceID preferences. +FOUNDATION_EXPORT NSString *const kFIRMessagingInstanceIDSubDirectoryName; + +/// The key for APNS token in options dictionary. +FOUNDATION_EXPORT NSString *const kFIRMessagingTokenOptionsAPNSKey; + +/// The key for APNS token environment type in options dictionary. +FOUNDATION_EXPORT NSString *const kFIRMessagingTokenOptionsAPNSIsSandboxKey; + +/// The key for GMP AppID sent in registration requests. +FOUNDATION_EXPORT NSString *const kFIRMessagingTokenOptionsFirebaseAppIDKey; + +FOUNDATION_EXPORT NSString *const kFIRMessagingAPNSTokenType; + +/// The key to enable auto-register by swizzling AppDelegate's methods. +FOUNDATION_EXPORT NSString *const kFIRMessagingAppDelegateProxyEnabledInfoPlistKey; + +/// Error code for missing entitlements in Keychain. iOS Keychain error +/// https://forums.developer.apple.com/thread/4743 +FOUNDATION_EXPORT const int kFIRMessagingSecMissingEntitlementErrorCode; + +/// The key for InstallationID or InstanceID in token request. +FOUNDATION_EXPORT NSString *const kFIRMessagingParamInstanceID; + +#endif diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingConstants.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingConstants.m new file mode 100644 index 0000000..88536eb --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingConstants.m @@ -0,0 +1,88 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" + +NSString *const kFIRMessagingFromKey = @"from"; + +NSString *const kFIRMessagingSendTo = @"google." + @"to"; +NSString *const kFIRMessagingSendTTL = @"google." + @"ttl"; +NSString *const kFIRMessagingSendDelay = @"google." + @"delay"; +NSString *const kFIRMessagingSendMessageID = @"google." + @"msg_id"; +NSString *const KFIRMessagingSendMessageAppData = @"google." + @"data"; + +NSString *const kFIRMessagingMessageInternalReservedKeyword = @"gcm."; +NSString *const kFIRMessagingMessagePersistentIDKey = @"persistent_id"; + +NSString *const kFIRMessagingMessageIDKey = @"gcm.message_id"; +NSString *const kFIRMessagingMessageAPNSContentAvailableKey = @"content-available"; +NSString *const kFIRMessagingMessageSyncMessageTTLKey = @"gcm." + @"ttl"; +NSString *const kFIRMessagingMessageLinkKey = @"gcm." + @"app_link"; +NSString *const kFIRMessagingSenderID = @"google.c.sender.id"; +NSString *const kFIRMessagingFID = @"google.c.fid"; +NSString *const kFIRMessagingAnalyticsComposerIdentifier = @"google.c.a.c_id"; +NSString *const kFIRMessagingAnalyticsMessageLabel = @"google.c.a.m_l"; +NSString *const kFIRMessagingAnalyticsComposerLabel = @"google.c.a.c_l"; +NSString *const kFIRMessagingProductID = @"google.product_id"; + +NSString *const kFIRMessagingRemoteNotificationsProxyEnabledInfoPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +NSString *const kFIRMessagingSubDirectoryName = @"Google/FirebaseMessaging"; + +// Notifications +NSString *const kFIRMessagingCheckinFetchedNotification = @"com.google.gcm.notif-checkin-fetched"; +NSString *const kFIRMessagingAPNSTokenNotification = @"com.firebase.iid.notif.apns-token"; +NSString *const kFIRMessagingRegistrationTokenRefreshNotification = + @"com.firebase.iid.notif.refresh-token"; + +const int kFIRMessagingSendTtlDefault = 24 * 60 * 60; // 24 hours + +// Commands +NSString *const kFIRMessaging_CMD_RST = @"RST"; + +// NOTIFICATIONS +NSString *const kFIRMessagingDefaultGCMTokenFailNotification = + @"com.firebase.iid.notif.fcm-token-fail"; + +// Miscellaneous +NSString *const kFIRMessagingAllScopeIdentifier = @"iid-all"; +NSString *const kFIRMessagingDefaultTokenScope = @"*"; +NSString *const kFIRMessagingFIAMTokenScope = @"fiam"; +NSString *const kFIRMessagingInstanceIDSubDirectoryName = @"Google/FirebaseInstanceID"; + +// Registration Options +NSString *const kFIRMessagingTokenOptionsAPNSKey = @"apns_token"; +NSString *const kFIRMessagingTokenOptionsAPNSIsSandboxKey = @"apns_sandbox"; +NSString *const kFIRMessagingTokenOptionsFirebaseAppIDKey = @"gmp_app_id"; +NSString *const kFIRMessagingParamInstanceID = @"appid"; + +NSString *const kFIRMessagingAPNSTokenType = + @"APNSTokenType"; // APNS Token type key stored in user info. + +NSString *const kFIRMessagingAppDelegateProxyEnabledInfoPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +// iOS Keychain error https://forums.developer.apple.com/thread/4743 +// An undocumented error code hence need to be redeclared. +const int kFIRMessagingSecMissingEntitlementErrorCode = -34018; diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingContextManagerService.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingContextManagerService.h new file mode 100644 index 0000000..83e6444 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingContextManagerService.h @@ -0,0 +1,44 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +FOUNDATION_EXPORT NSString *const kFIRMessagingContextManagerCategory; +FOUNDATION_EXPORT NSString *const kFIRMessagingContextManagerLocalTimeStart; +FOUNDATION_EXPORT NSString *const kFIRMessagingContextManagerLocalTimeEnd; +FOUNDATION_EXPORT NSString *const kFIRMessagingContextManagerBodyKey; + +@interface FIRMessagingContextManagerService : NSObject + +/** + * Check if the message is a context manager message or not. + * + * @param message The message to verify. + * + * @return YES if the message is a context manager message else NO. + */ ++ (BOOL)isContextManagerMessage:(NSDictionary *)message; + +/** + * Handle context manager message. + * + * @param message The message to handle. + * + * @return YES if the message was handled successfully else NO. + */ ++ (BOOL)handleContextManagerMessage:(NSDictionary *)message; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingContextManagerService.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingContextManagerService.m new file mode 100644 index 0000000..61e88d1 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingContextManagerService.m @@ -0,0 +1,236 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseMessaging/Sources/FIRMessagingContextManagerService.h" + +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" + +#import + +#define kFIRMessagingContextManagerPrefix @"gcm." +#define kFIRMessagingContextManagerPrefixKey @"google.c.cm." +#define kFIRMessagingContextManagerNotificationKeyPrefix @"gcm.notification." + +static NSString *const kLogTag = @"FIRMessagingAnalytics"; + +static NSString *const kLocalTimeFormatString = @"yyyy-MM-dd HH:mm:ss"; + +static NSString *const kContextManagerPrefixKey = kFIRMessagingContextManagerPrefixKey; + +// Local timed messages (format yyyy-mm-dd HH:mm:ss) +NSString *const kFIRMessagingContextManagerLocalTimeStart = + kFIRMessagingContextManagerPrefixKey @"lt_start"; +NSString *const kFIRMessagingContextManagerLocalTimeEnd = + kFIRMessagingContextManagerPrefixKey @"lt_end"; + +// Local Notification Params +NSString *const kFIRMessagingContextManagerBodyKey = + kFIRMessagingContextManagerNotificationKeyPrefix @"body"; +NSString *const kFIRMessagingContextManagerTitleKey = + kFIRMessagingContextManagerNotificationKeyPrefix @"title"; +NSString *const kFIRMessagingContextManagerBadgeKey = + kFIRMessagingContextManagerNotificationKeyPrefix @"badge"; +NSString *const kFIRMessagingContextManagerCategoryKey = + kFIRMessagingContextManagerNotificationKeyPrefix @"click_action"; +NSString *const kFIRMessagingContextManagerSoundKey = + kFIRMessagingContextManagerNotificationKeyPrefix @"sound"; +NSString *const kFIRMessagingContextManagerContentAvailableKey = + kFIRMessagingContextManagerNotificationKeyPrefix @"content-available"; +static NSString *const kFIRMessagingID = kFIRMessagingContextManagerPrefix @"message_id"; +static NSString *const kFIRMessagingAPNSPayloadKey = @"aps"; + +typedef NS_ENUM(NSUInteger, FIRMessagingContextManagerMessageType) { + FIRMessagingContextManagerMessageTypeNone, + FIRMessagingContextManagerMessageTypeLocalTime, +}; + +@implementation FIRMessagingContextManagerService + ++ (BOOL)isContextManagerMessage:(NSDictionary *)message { + // For now we only support local time in ContextManager. + if (![message[kFIRMessagingContextManagerLocalTimeStart] length]) { + FIRMessagingLoggerDebug( + kFIRMessagingMessageCodeContextManagerService000, + @"Received message missing local start time, not a contextual message."); + return NO; + } + + return YES; +} + ++ (BOOL)handleContextManagerMessage:(NSDictionary *)message { + NSString *startTimeString = message[kFIRMessagingContextManagerLocalTimeStart]; + if (startTimeString.length) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeContextManagerService001, + @"%@ Received context manager message with local time %@", kLogTag, + startTimeString); + return [self handleContextManagerLocalTimeMessage:message]; + } + + return NO; +} + ++ (BOOL)handleContextManagerLocalTimeMessage:(NSDictionary *)message { + NSString *startTimeString = message[kFIRMessagingContextManagerLocalTimeStart]; + if (!startTimeString) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeContextManagerService002, + @"Invalid local start date format %@. Message dropped", + startTimeString); + return NO; + } + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; + [dateFormatter setDateFormat:kLocalTimeFormatString]; + NSDate *startDate = [dateFormatter dateFromString:startTimeString]; + NSDate *currentDate = [NSDate date]; + + if ([currentDate compare:startDate] == NSOrderedAscending) { + [self scheduleLocalNotificationForMessage:message atDate:startDate]; + } else { + // check end time has not passed + NSString *endTimeString = message[kFIRMessagingContextManagerLocalTimeEnd]; + if (!endTimeString) { + FIRMessagingLoggerInfo( + kFIRMessagingMessageCodeContextManagerService003, + @"No end date specified for message, start date elapsed. Message dropped."); + return YES; + } + + NSDate *endDate = [dateFormatter dateFromString:endTimeString]; + if (!endTimeString) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeContextManagerService004, + @"Invalid local end date format %@. Message dropped", endTimeString); + return NO; + } + + if ([endDate compare:currentDate] == NSOrderedAscending) { + // end date has already passed drop the message + FIRMessagingLoggerInfo(kFIRMessagingMessageCodeContextManagerService005, + @"End date %@ has already passed. Message dropped.", endTimeString); + return YES; + } + + // schedule message right now (buffer 10s) + [self scheduleLocalNotificationForMessage:message + atDate:[currentDate dateByAddingTimeInterval:10]]; + } + return YES; +} + ++ (void)scheduleiOS10LocalNotificationForMessage:(NSDictionary *)message + atDate:(NSDate *)date + API_AVAILABLE(macosx(10.14), ios(10.0), watchos(3.0), tvos(10.0)) { + NSCalendar *calendar = [NSCalendar currentCalendar]; + NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | + NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; + NSDateComponents *dateComponents = [calendar components:(NSCalendarUnit)unit fromDate:date]; + UNCalendarNotificationTrigger *trigger = + [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:NO]; + + UNMutableNotificationContent *content = [self contentFromContextualMessage:message]; + NSString *identifier = message[kFIRMessagingID]; + if (!identifier) { + identifier = [NSUUID UUID].UUIDString; + } + + UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier + content:content + trigger:trigger]; + UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; + [center + addNotificationRequest:request + withCompletionHandler:^(NSError *_Nullable error) { + if (error) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeContextManagerServiceFailedLocalSchedule, + @"Failed scheduling local timezone notification: %@.", error); + } + }]; +} + ++ (UNMutableNotificationContent *)contentFromContextualMessage:(NSDictionary *)message + API_AVAILABLE(macosx(10.14), ios(10.0), watchos(3.0), tvos(10.0)) { + UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; + NSDictionary *apsDictionary = message; + + // Badge is universal + if (apsDictionary[kFIRMessagingContextManagerBadgeKey]) { + content.badge = apsDictionary[kFIRMessagingContextManagerBadgeKey]; + } +#if !TARGET_OS_TV + // The following fields are not available on tvOS + if ([apsDictionary[kFIRMessagingContextManagerBodyKey] length]) { + content.body = apsDictionary[kFIRMessagingContextManagerBodyKey]; + } + + if ([apsDictionary[kFIRMessagingContextManagerTitleKey] length]) { + content.title = apsDictionary[kFIRMessagingContextManagerTitleKey]; + } + + if (apsDictionary[kFIRMessagingContextManagerSoundKey]) { +#if !TARGET_OS_WATCH + // UNNotificationSound soundNamded: is not available in watchOS + content.sound = + [UNNotificationSound soundNamed:apsDictionary[kFIRMessagingContextManagerSoundKey]]; +#else // !TARGET_OS_WATCH + content.sound = [UNNotificationSound defaultSound]; +#endif // !TARGET_OS_WATCH + } + + if (apsDictionary[kFIRMessagingContextManagerCategoryKey]) { + content.categoryIdentifier = apsDictionary[kFIRMessagingContextManagerCategoryKey]; + } + + NSDictionary *userInfo = [self parseDataFromMessage:message]; + if (userInfo.count) { + content.userInfo = userInfo; + } +#endif // !TARGET_OS_TV + return content; +} + ++ (void)scheduleLocalNotificationForMessage:(NSDictionary *)message atDate:(NSDate *)date { + if (@available(macOS 10.14, *)) { + [self scheduleiOS10LocalNotificationForMessage:message atDate:date]; + return; + } +} + ++ (NSDictionary *)parseDataFromMessage:(NSDictionary *)message { + NSMutableDictionary *data = [NSMutableDictionary dictionary]; + for (NSObject *key in message) { + if ([key isKindOfClass:[NSString class]]) { + NSString *keyString = (NSString *)key; + if ([keyString isEqualToString:kFIRMessagingContextManagerContentAvailableKey]) { + continue; + } else if ([keyString hasPrefix:kContextManagerPrefixKey]) { + continue; + } else if ([keyString isEqualToString:kFIRMessagingAPNSPayloadKey]) { + // Local timezone message is scheduled with FCM payload. APNS payload with + // content_available should be ignored and not passed to the scheduled + // messages. + continue; + } + } + data[[key copy]] = message[key]; + } + return [data copy]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingDefines.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingDefines.h new file mode 100644 index 0000000..e7643ae --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingDefines.h @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIRMessaging_xcodeproj_FIRMessagingDefines_h +#define FIRMessaging_xcodeproj_FIRMessagingDefines_h + +// WEAKIFY & STRONGIFY +// Helper macro. +#define _FIRMessaging_WEAKNAME(VAR) VAR##_weak_ + +#define FIRMessaging_WEAKIFY(VAR) __weak __typeof__(VAR) _FIRMessaging_WEAKNAME(VAR) = (VAR); + +#define FIRMessaging_STRONGIFY(VAR) \ + _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wshadow\"") \ + __strong __typeof__(VAR) VAR = _FIRMessaging_WEAKNAME(VAR); \ + _Pragma("clang diagnostic pop") + +#ifndef _FIRMessaging_UL +#define _FIRMessaging_UL(v) (unsigned long)(v) +#endif + +#endif + +// Invalidates the initializer from which it's called. +#ifndef FIRMessagingInvalidateInitializer +#define FIRMessagingInvalidateInitializer() \ + do { \ + [self class]; /* Avoid warning of dead store to |self|. */ \ + NSAssert(NO, @"Invalid initializer."); \ + return nil; \ + } while (0) +#endif diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingExtensionHelper.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingExtensionHelper.m new file mode 100644 index 0000000..7c98727 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingExtensionHelper.m @@ -0,0 +1,294 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import +#import + +#import +#import +#import "FirebaseMessaging/Sources/FIRMessagingCode.h" +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.h" +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessagingExtensionHelper.h" + +static NSString *const kPayloadOptionsName = @"fcm_options"; +static NSString *const kPayloadOptionsImageURLName = @"image"; +static NSString *const kNoExtension = @""; +static NSString *const kImagePathPrefix = @"image/"; + +#pragma mark - nanopb helper functions + +/** Callocs a pb_bytes_array and copies the given NSData bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param data The data to copy into the new bytes array. + */ +pb_bytes_array_t *FIRMessagingEncodeData(NSData *data) { + pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + if (pbBytesArray != NULL) { + [data getBytes:pbBytesArray->bytes length:data.length]; + pbBytesArray->size = (pb_size_t)data.length; + } + return pbBytesArray; +} +/** Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param string The string to encode as pb_bytes. + */ +pb_bytes_array_t *FIRMessagingEncodeString(NSString *string) { + NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding]; + return FIRMessagingEncodeData(stringBytes); +} + +@interface FIRMessagingMetricsLog : NSObject + +@property(nonatomic) fm_MessagingClientEventExtension eventExtension; + +@end + +@implementation FIRMessagingMetricsLog + +- (instancetype)initWithEventExtension:(fm_MessagingClientEventExtension)eventExtension { + self = [super init]; + if (self) { + _eventExtension = eventExtension; + } + return self; +} + +- (NSData *)transportBytes { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, fm_MessagingClientEventExtension_fields, &_eventExtension)) { + FIRMessagingLoggerError(kFIRMessagingServiceExtensionTransportBytesError, + @"Error in nanopb encoding for size: %s", PB_GET_ERROR(&sizestream)); + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, fm_MessagingClientEventExtension_fields, &_eventExtension)) { + FIRMessagingLoggerError(kFIRMessagingServiceExtensionTransportBytesError, + @"Error in nanopb encoding for bytes: %s", PB_GET_ERROR(&ostream)); + } + CFDataSetLength(dataRef, ostream.bytes_written); + + return CFBridgingRelease(dataRef); +} + +@end + +@interface FIRMessagingExtensionHelper () +@property(nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver); +@property(nonatomic, strong) UNMutableNotificationContent *bestAttemptContent; + +@end + +@implementation FIRMessagingExtensionHelper + +- (void)populateNotificationContent:(UNMutableNotificationContent *)content + withContentHandler:(void (^)(UNNotificationContent *_Nonnull))contentHandler { + self.contentHandler = [contentHandler copy]; + self.bestAttemptContent = content; + + // The `userInfo` property isn't available on newer versions of tvOS. +#if !TARGET_OS_TV + NSObject *currentImageURL = content.userInfo[kPayloadOptionsName][kPayloadOptionsImageURLName]; + if (!currentImageURL || currentImageURL == [NSNull null]) { + [self deliverNotification]; + return; + } + NSURL *attachmentURL = [NSURL URLWithString:(NSString *)currentImageURL]; + if (attachmentURL) { + [self loadAttachmentForURL:attachmentURL + completionHandler:^(UNNotificationAttachment *attachment) { + if (attachment != nil) { + self.bestAttemptContent.attachments = @[ attachment ]; + } + [self deliverNotification]; + }]; + } else { + FIRMessagingLoggerError(kFIRMessagingServiceExtensionImageInvalidURL, + @"The Image URL provided is invalid %@.", currentImageURL); + [self deliverNotification]; + } +#else // !TARGET_OS_TV + [self deliverNotification]; +#endif // !TARGET_OS_TV +} + +#if !TARGET_OS_TV +- (NSString *)fileExtensionForResponse:(NSURLResponse *)response { + NSString *suggestedPathExtension = [response.suggestedFilename pathExtension]; + if (suggestedPathExtension.length > 0) { + return [NSString stringWithFormat:@".%@", suggestedPathExtension]; + } + if ([response.MIMEType containsString:kImagePathPrefix]) { + return [response.MIMEType stringByReplacingOccurrencesOfString:kImagePathPrefix + withString:@"."]; + } + return kNoExtension; +} + +- (void)loadAttachmentForURL:(NSURL *)attachmentURL + completionHandler:(void (^)(UNNotificationAttachment *))completionHandler { + __block UNNotificationAttachment *attachment = nil; + + NSURLSession *session = [NSURLSession + sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; + [[session + downloadTaskWithURL:attachmentURL + completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) { + if (error != nil) { + FIRMessagingLoggerError(kFIRMessagingServiceExtensionImageNotDownloaded, + @"Failed to download image given URL %@, error: %@\n", + attachmentURL, error); + completionHandler(attachment); + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *fileExtension = [self fileExtensionForResponse:response]; + NSURL *localURL = [NSURL + fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:fileExtension]]; + [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error]; + if (error) { + FIRMessagingLoggerError( + kFIRMessagingServiceExtensionLocalFileNotCreated, + @"Failed to move the image file to local location: %@, error: %@\n", localURL, + error); + completionHandler(attachment); + return; + } + + attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" + URL:localURL + options:nil + error:&error]; + if (error) { + FIRMessagingLoggerError(kFIRMessagingServiceExtensionImageNotAttached, + @"Failed to create attachment with URL %@, error: %@\n", + localURL, error); + completionHandler(attachment); + return; + } + completionHandler(attachment); + }] resume]; +} +#endif // !TARGET_OS_TV + +- (void)deliverNotification { + if (self.contentHandler) { + self.contentHandler(self.bestAttemptContent); + } +} + +- (void)exportDeliveryMetricsToBigQueryWithMessageInfo:(NSDictionary *)info { + GDTCORTransport *transport = [[GDTCORTransport alloc] initWithMappingID:@"1249" + transformers:nil + target:kGDTCORTargetCCT]; + + fm_MessagingClientEventExtension eventExtension = fm_MessagingClientEventExtension_init_default; + + fm_MessagingClientEvent clientEvent = fm_MessagingClientEvent_init_default; + if (!info[kFIRMessagingSenderID]) { + FIRMessagingLoggerError(kFIRMessagingServiceExtensionInvalidProjectID, + @"Delivery logging failed: Invalid project ID"); + return; + } + clientEvent.project_number = (int64_t)[info[kFIRMessagingSenderID] longLongValue]; + + if (!info[kFIRMessagingMessageIDKey] || + ![info[kFIRMessagingMessageIDKey] isKindOfClass:NSString.class]) { + FIRMessagingLoggerWarn(kFIRMessagingServiceExtensionInvalidMessageID, + @"Delivery logging failed: Invalid Message ID"); + return; + } + clientEvent.message_id = FIRMessagingEncodeString(info[kFIRMessagingMessageIDKey]); + + if (!info[kFIRMessagingFID] || ![info[kFIRMessagingFID] isKindOfClass:NSString.class]) { + FIRMessagingLoggerWarn(kFIRMessagingServiceExtensionInvalidInstanceID, + @"Delivery logging failed: Invalid Instance ID"); + return; + } + clientEvent.instance_id = FIRMessagingEncodeString(info[kFIRMessagingFID]); + + if ([info[@"aps"][kFIRMessagingMessageAPNSContentAvailableKey] intValue] == 1 && + ![GULAppEnvironmentUtil isAppExtension]) { + clientEvent.message_type = fm_MessagingClientEvent_MessageType_DATA_MESSAGE; + } else { + clientEvent.message_type = fm_MessagingClientEvent_MessageType_DISPLAY_NOTIFICATION; + } + clientEvent.sdk_platform = fm_MessagingClientEvent_SDKPlatform_IOS; + + NSString *bundleID = [NSBundle mainBundle].bundleIdentifier; + if ([GULAppEnvironmentUtil isAppExtension]) { + bundleID = [[self class] bundleIdentifierByRemovingLastPartFrom:bundleID]; + } + if (bundleID) { + clientEvent.package_name = FIRMessagingEncodeString(bundleID); + } + clientEvent.event = fm_MessagingClientEvent_Event_MESSAGE_DELIVERED; + + if (info[kFIRMessagingAnalyticsMessageLabel]) { + clientEvent.analytics_label = + FIRMessagingEncodeString(info[kFIRMessagingAnalyticsMessageLabel]); + } + if (info[kFIRMessagingAnalyticsComposerIdentifier]) { + clientEvent.campaign_id = + (int64_t)[info[kFIRMessagingAnalyticsComposerIdentifier] longLongValue]; + } + if (info[kFIRMessagingAnalyticsComposerLabel]) { + clientEvent.composer_label = + FIRMessagingEncodeString(info[kFIRMessagingAnalyticsComposerLabel]); + } + + eventExtension.messaging_client_event = &clientEvent; + FIRMessagingMetricsLog *log = + [[FIRMessagingMetricsLog alloc] initWithEventExtension:eventExtension]; + + GDTCOREvent *event; + if (info[kFIRMessagingProductID]) { + int32_t productID = [info[kFIRMessagingProductID] intValue]; + GDTCORProductData *productData = [[GDTCORProductData alloc] initWithProductID:productID]; + event = [transport eventForTransportWithProductData:productData]; + } else { + event = [transport eventForTransport]; + } + event.dataObject = log; + event.qosTier = GDTCOREventQoSFast; + + // Use this API for SDK service data events. + [transport sendDataEvent:event]; +} + ++ (NSString *)bundleIdentifierByRemovingLastPartFrom:(NSString *)bundleIdentifier { + NSString *bundleIDComponentsSeparator = @"."; + + NSMutableArray *bundleIDComponents = + [[bundleIdentifier componentsSeparatedByString:bundleIDComponentsSeparator] mutableCopy]; + [bundleIDComponents removeLastObject]; + + return [bundleIDComponents componentsJoinedByString:bundleIDComponentsSeparator]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingLogger.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingLogger.h new file mode 100644 index 0000000..17fba45 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingLogger.h @@ -0,0 +1,67 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingCode.h" + +// The convenience macros are only defined if they haven't already been defined. +#ifndef FIRMessagingLoggerInfo + +// Convenience macros that log to the shared FIRMessagingLogger instance. These macros +// are how users should typically log to FIRMessagingLogger. +#define FIRMessagingLoggerDebug(code, ...) \ + [FIRMessagingSharedLogger() logFuncDebug:__func__ messageCode:code msg:__VA_ARGS__] +#define FIRMessagingLoggerInfo(code, ...) \ + [FIRMessagingSharedLogger() logFuncInfo:__func__ messageCode:code msg:__VA_ARGS__] +#define FIRMessagingLoggerNotice(code, ...) \ + [FIRMessagingSharedLogger() logFuncNotice:__func__ messageCode:code msg:__VA_ARGS__] +#define FIRMessagingLoggerWarn(code, ...) \ + [FIRMessagingSharedLogger() logFuncWarning:__func__ messageCode:code msg:__VA_ARGS__] +#define FIRMessagingLoggerError(code, ...) \ + [FIRMessagingSharedLogger() logFuncError:__func__ messageCode:code msg:__VA_ARGS__] + +#endif // !defined(FIRMessagingLoggerInfo) + +@interface FIRMessagingLogger : NSObject + +- (void)logFuncDebug:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... NS_FORMAT_FUNCTION(3, 4); + +- (void)logFuncInfo:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... NS_FORMAT_FUNCTION(3, 4); + +- (void)logFuncNotice:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... NS_FORMAT_FUNCTION(3, 4); + +- (void)logFuncWarning:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... NS_FORMAT_FUNCTION(3, 4); + +- (void)logFuncError:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... NS_FORMAT_FUNCTION(3, 4); + +@end + +/** + * Instantiates and/or returns a shared FIRMessagingLogger used exclusively + * for FIRMessaging log messages. + * + * @return the shared FIRMessagingLogger instance + */ +FIRMessagingLogger *FIRMessagingSharedLogger(void); diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingLogger.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingLogger.m new file mode 100644 index 0000000..0eb73d0 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingLogger.m @@ -0,0 +1,95 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +FIRLoggerService kFIRLoggerMessaging = @"[FirebaseMessaging]"; + +@implementation FIRMessagingLogger + ++ (instancetype)standardLogger { + return [[FIRMessagingLogger alloc] init]; +} + +#pragma mark - Log Helpers + ++ (NSString *)formatMessageCode:(FIRMessagingMessageCode)messageCode { + return [NSString stringWithFormat:@"I-FCM%06ld", (long)messageCode]; +} + +- (void)logFuncDebug:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + FIRLogBasic(FIRLoggerLevelDebug, kFIRLoggerMessaging, + [FIRMessagingLogger formatMessageCode:messageCode], fmt, args); + va_end(args); +} + +- (void)logFuncInfo:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + FIRLogBasic(FIRLoggerLevelInfo, kFIRLoggerMessaging, + [FIRMessagingLogger formatMessageCode:messageCode], fmt, args); + va_end(args); +} + +- (void)logFuncNotice:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + FIRLogBasic(FIRLoggerLevelNotice, kFIRLoggerMessaging, + [FIRMessagingLogger formatMessageCode:messageCode], fmt, args); + va_end(args); +} + +- (void)logFuncWarning:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + FIRLogBasic(FIRLoggerLevelWarning, kFIRLoggerMessaging, + [FIRMessagingLogger formatMessageCode:messageCode], fmt, args); + va_end(args); +} + +- (void)logFuncError:(const char *)func + messageCode:(FIRMessagingMessageCode)messageCode + msg:(NSString *)fmt, ... { + va_list args; + va_start(args, fmt); + FIRLogBasic(FIRLoggerLevelError, kFIRLoggerMessaging, + [FIRMessagingLogger formatMessageCode:messageCode], fmt, args); + va_end(args); +} + +@end + +FIRMessagingLogger *FIRMessagingSharedLogger(void) { + static dispatch_once_t onceToken; + static FIRMessagingLogger *logger; + dispatch_once(&onceToken, ^{ + logger = [FIRMessagingLogger standardLogger]; + }); + + return logger; +} diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h new file mode 100644 index 0000000..ad02e6b --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h @@ -0,0 +1,119 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" + +#import "FirebaseMessaging/Sources/FIRMessagingTopicsCommon.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Represents a single batch of topics, with the same action. + * + * Topic operations which have the same action (subscribe or unsubscribe) can be executed + * simultaneously, as the order of operations do not matter with the same action. The set of + * topics is unique, as it doesn't make sense to apply the same action to the same topic + * repeatedly; the result would be the same as the first time. + */ +@interface FIRMessagingTopicBatch : NSObject + +@property(nonatomic, readonly, assign) FIRMessagingTopicAction action; +@property(nonatomic, readonly, copy) NSMutableSet *topics; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithAction:(FIRMessagingTopicAction)action NS_DESIGNATED_INITIALIZER; + +@end + +@class FIRMessagingPendingTopicsList; +/** + * This delegate must be supplied to the instance of FIRMessagingPendingTopicsList, via the + * @cdelegate property. It lets the + * pending topics list know whether or not it can begin making requests via + * @c-pendingTopicsListCanRequestTopicUpdates:, and handles the request to actually + * perform the topic operation. The delegate also handles when the pending topics list is updated, + * so that it can be archived or persisted. + * + * @see FIRMessagingPendingTopicsList + */ +@protocol FIRMessagingPendingTopicsListDelegate + +- (void)pendingTopicsList:(FIRMessagingPendingTopicsList *)list + requestedUpdateForTopic:(NSString *)topic + action:(FIRMessagingTopicAction)action + completion:(FIRMessagingTopicOperationCompletion)completion; +- (void)pendingTopicsListDidUpdate:(FIRMessagingPendingTopicsList *)list; +- (BOOL)pendingTopicsListCanRequestTopicUpdates:(FIRMessagingPendingTopicsList *)list; + +@end + +/** + * FIRMessagingPendingTopicsList manages a list of topic subscription updates, batched by the same + * action (subscribe or unsubscribe). The list roughly maintains the order of the topic operations, + * batched together whenever the topic action (subscribe or unsubscribe) changes. + * + * Topics operations are batched by action because it is safe to perform the same topic action + * (subscribe or unsubscribe) on many topics simultaneously. After each batch is successfully + * completed, the next batch operations can begin. + * + * When asked to resume its operations, FIRMessagingPendingTopicsList will begin performing updates + * of its current batch of topics. For example, it may begin subscription operations for topics + * [A, B, C] simultaneously. + * + * When the current batch is completed, the next batch of operations will be started. For example + * the list may begin unsubscribe operations for [D, A, E]. Note that because A is in both batches, + * A will be correctly subscribed in the first batch, then unsubscribed as part of the second batch + * of operations. Without batching, it would be ambiguous whether A's subscription operation or the + * unsubscription operation would be completed first. + * + * An app can subscribe and unsubscribe from many topics, and this class helps persist the pending + * topics and perform the operation safely and correctly. + * + * When a topic fails to subscribe or unsubscribe due to a network error, it is considered a + * recoverable error, and so it remains in the current batch until it is successfully completed. + * Topic updates are completed when they either (a) succeed, (b) are cancelled, or (c) result in an + * unrecoverable error. Any error outside of `NSURLErrorDomain` is considered an unrecoverable + * error. + * + * In addition to maintaining the list of pending topic updates, FIRMessagingPendingTopicsList also + * can track completion handlers for topic operations. + * + * @discussion Completion handlers for topic updates are not maintained if it was restored from a + * keyed archive. They are only called if the topic operation finished within the same app session. + * + * You must supply an object conforming to FIRMessagingPendingTopicsListDelegate in order for the + * topic operations to execute. + * + * @see FIRMessagingPendingTopicsListDelegate + */ +@interface FIRMessagingPendingTopicsList : NSObject + +@property(nonatomic, weak) NSObject *delegate; + +@property(nonatomic, readonly, strong, nullable) NSDate *archiveDate; +@property(nonatomic, readonly) NSUInteger numberOfBatches; + +- (instancetype)init NS_DESIGNATED_INITIALIZER; +- (void)addOperationForTopic:(NSString *)topic + withAction:(FIRMessagingTopicAction)action + completion:(nullable FIRMessagingTopicOperationCompletion)completion; +- (void)resumeOperationsIfNeeded; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.m new file mode 100644 index 0000000..3a1afcb --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.m @@ -0,0 +1,271 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h" + +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingPubSub.h" +#import "FirebaseMessaging/Sources/FIRMessaging_Private.h" + +NSString *const kPendingTopicBatchActionKey = @"action"; +NSString *const kPendingTopicBatchTopicsKey = @"topics"; + +NSString *const kPendingBatchesEncodingKey = @"batches"; +NSString *const kPendingTopicsTimestampEncodingKey = @"ts"; + +#pragma mark - FIRMessagingTopicBatch + +@interface FIRMessagingTopicBatch () + +@property(nonatomic, strong, nonnull) + NSMutableDictionary *> + *topicHandlers; + +@end + +@implementation FIRMessagingTopicBatch + +- (instancetype)initWithAction:(FIRMessagingTopicAction)action { + if (self = [super init]) { + _action = action; + _topics = [NSMutableSet set]; + _topicHandlers = [NSMutableDictionary dictionary]; + } + return self; +} + +#pragma mark NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeInteger:self.action forKey:kPendingTopicBatchActionKey]; + [aCoder encodeObject:self.topics forKey:kPendingTopicBatchTopicsKey]; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + // Ensure that our integer -> enum casting is safe + NSInteger actionRawValue = [aDecoder decodeIntegerForKey:kPendingTopicBatchActionKey]; + FIRMessagingTopicAction action = FIRMessagingTopicActionSubscribe; + if (actionRawValue == FIRMessagingTopicActionUnsubscribe) { + action = FIRMessagingTopicActionUnsubscribe; + } + + if (self = [self initWithAction:action]) { + _topics = [aDecoder + decodeObjectOfClasses:[NSSet setWithObjects:NSMutableSet.class, NSString.class, nil] + forKey:kPendingTopicBatchTopicsKey]; + _topicHandlers = [NSMutableDictionary dictionary]; + } + return self; +} + +@end + +#pragma mark - FIRMessagingPendingTopicsList + +@interface FIRMessagingPendingTopicsList () + +@property(nonatomic, readwrite, strong) NSDate *archiveDate; +@property(nonatomic, strong) NSMutableArray *topicBatches; + +@property(nonatomic, strong) FIRMessagingTopicBatch *currentBatch; +@property(nonatomic, strong) NSMutableSet *topicsInFlight; + +@end + +@implementation FIRMessagingPendingTopicsList + +- (instancetype)init { + if (self = [super init]) { + _topicBatches = [NSMutableArray array]; + _topicsInFlight = [NSMutableSet set]; + } + return self; +} + ++ (void)pruneTopicBatches:(NSMutableArray *)topicBatches { + // For now, just remove empty batches. In the future we can use this to make the subscriptions + // more efficient, by actually pruning topic actions that cancel each other out, for example. + for (NSInteger i = topicBatches.count - 1; i >= 0; i--) { + FIRMessagingTopicBatch *batch = topicBatches[i]; + if (batch.topics.count == 0) { + [topicBatches removeObjectAtIndex:i]; + } + } +} + +#pragma mark NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:[NSDate date] forKey:kPendingTopicsTimestampEncodingKey]; + [aCoder encodeObject:self.topicBatches forKey:kPendingBatchesEncodingKey]; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + if (self = [self init]) { + _archiveDate = + [aDecoder decodeObjectOfClass:NSDate.class forKey:kPendingTopicsTimestampEncodingKey]; + _topicBatches = + [aDecoder decodeObjectOfClasses:[NSSet setWithObjects:NSMutableArray.class, + FIRMessagingTopicBatch.class, nil] + forKey:kPendingBatchesEncodingKey]; + if (_topicBatches) { + [FIRMessagingPendingTopicsList pruneTopicBatches:_topicBatches]; + } + _topicsInFlight = [NSMutableSet set]; + } + return self; +} + +#pragma mark Getters + +- (NSUInteger)numberOfBatches { + return self.topicBatches.count; +} + +#pragma mark Adding/Removing topics + +- (void)addOperationForTopic:(NSString *)topic + withAction:(FIRMessagingTopicAction)action + completion:(nullable FIRMessagingTopicOperationCompletion)completion { + FIRMessagingTopicBatch *lastBatch = nil; + @synchronized(self) { + lastBatch = self.topicBatches.lastObject; + if (!lastBatch || lastBatch.action != action) { + // There either was no last batch, or our last batch's action was not the same, so we have to + // create a new batch + lastBatch = [[FIRMessagingTopicBatch alloc] initWithAction:action]; + [self.topicBatches addObject:lastBatch]; + } + BOOL topicExistedBefore = ([lastBatch.topics member:topic] != nil); + if (!topicExistedBefore) { + [lastBatch.topics addObject:topic]; + [self.delegate pendingTopicsListDidUpdate:self]; + } + // Add the completion handler to the batch + if (completion) { + NSMutableArray *handlers = lastBatch.topicHandlers[topic]; + if (!handlers) { + handlers = [[NSMutableArray alloc] init]; + } + [handlers addObject:completion]; + lastBatch.topicHandlers[topic] = handlers; + } + if (!self.currentBatch) { + self.currentBatch = lastBatch; + } + // This may have been the first topic added, or was added to an ongoing batch + if (self.currentBatch == lastBatch && !topicExistedBefore) { + // Add this topic to our ongoing operations + FIRMessaging_WEAKIFY(self); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + FIRMessaging_STRONGIFY(self); + [self resumeOperationsIfNeeded]; + }); + } + } +} + +- (void)resumeOperationsIfNeeded { + @synchronized(self) { + // If current batch is not set, set it now + if (!self.currentBatch) { + self.currentBatch = self.topicBatches.firstObject; + } + if (self.currentBatch.topics.count == 0) { + return; + } + if (!self.delegate) { + FIRMessagingLoggerError(kFIRMessagingMessageCodePendingTopicsList000, + @"Attempted to update pending topics without a delegate"); + return; + } + if (![self.delegate pendingTopicsListCanRequestTopicUpdates:self]) { + return; + } + for (NSString *topic in self.currentBatch.topics) { + if ([self.topicsInFlight member:topic]) { + // This topic is already active, so skip + continue; + } + [self beginUpdateForCurrentBatchTopic:topic]; + } + } +} + +- (BOOL)subscriptionErrorIsRecoverable:(NSError *)error { + return [error.domain isEqualToString:NSURLErrorDomain]; +} + +- (void)beginUpdateForCurrentBatchTopic:(NSString *)topic { + @synchronized(self) { + [self.topicsInFlight addObject:topic]; + } + FIRMessaging_WEAKIFY(self); + [self.delegate + pendingTopicsList:self + requestedUpdateForTopic:topic + action:self.currentBatch.action + completion:^(NSError *error) { + dispatch_async( + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + FIRMessaging_STRONGIFY(self); + @synchronized(self) { + [self.topicsInFlight removeObject:topic]; + + BOOL recoverableError = [self subscriptionErrorIsRecoverable:error]; + if (!error || !recoverableError) { + // Notify our handlers and remove the topic from our batch + NSMutableArray *handlers = self.currentBatch.topicHandlers[topic]; + if (handlers.count) { + dispatch_async(dispatch_get_main_queue(), ^{ + for (FIRMessagingTopicOperationCompletion handler in handlers) { + handler(error); + } + [handlers removeAllObjects]; + }); + } + [self.currentBatch.topics removeObject:topic]; + [self.currentBatch.topicHandlers removeObjectForKey:topic]; + if (self.currentBatch.topics.count == 0) { + // All topic updates successfully finished in this batch, move on + // to the next batch + [self.topicBatches removeObject:self.currentBatch]; + self.currentBatch = nil; + } + [self.delegate pendingTopicsListDidUpdate:self]; + FIRMessaging_WEAKIFY(self); + dispatch_async( + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), + ^{ + FIRMessaging_STRONGIFY(self); + [self resumeOperationsIfNeeded]; + }); + } + } + }); + }]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.h new file mode 100644 index 0000000..5a48e99 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.h @@ -0,0 +1,28 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@interface FIRMessagingPersistentSyncMessage : NSObject + +@property(nonatomic, readonly, strong) NSString *rmqID; +@property(nonatomic, readwrite, assign) BOOL apnsReceived; +@property(nonatomic, readwrite, assign) BOOL mcsReceived; +@property(nonatomic, readonly, assign) int64_t expirationTime; + +- (instancetype)initWithRMQID:(NSString *)rmqID expirationTime:(int64_t)expirationTime; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.m new file mode 100644 index 0000000..db032a9 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.m @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.h" + +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" + +@interface FIRMessagingPersistentSyncMessage () + +@property(nonatomic, readwrite, strong) NSString *rmqID; +@property(nonatomic, readwrite, assign) int64_t expirationTime; + +@end + +@implementation FIRMessagingPersistentSyncMessage + +- (instancetype)init { + FIRMessagingInvalidateInitializer(); +} + +- (instancetype)initWithRMQID:(NSString *)rmqID expirationTime:(int64_t)expirationTime { + self = [super init]; + if (self) { + _rmqID = [rmqID copy]; + _expirationTime = expirationTime; + } + return self; +} + +- (NSString *)description { + NSString *classDescription = NSStringFromClass([self class]); + NSDate *date = [NSDate dateWithTimeIntervalSince1970:self.expirationTime]; + return + [NSString stringWithFormat:@"%@: (rmqID: %@, apns: %d, mcs: %d, expiry: %@", classDescription, + self.rmqID, self.mcsReceived, self.apnsReceived, date]; +} + +- (NSString *)debugDescription { + return [self description]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPubSub.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPubSub.h new file mode 100644 index 0000000..8d04a9a --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPubSub.h @@ -0,0 +1,162 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRMessagingTokenManager; + +/** + * FIRMessagingPubSub provides a publish-subscribe model for sending FIRMessaging topic messages. + * + * An app can subscribe to different topics defined by the + * developer. The app server can then send messages to the subscribed devices + * without having to maintain topic-subscribers mapping. Topics do not + * need to be explicitly created before subscribing or publishing—they + * are automatically created when publishing or subscribing. + * + * Messages published to the topic will be received as regular FIRMessaging messages + * with `"from"` set to `"/topics/myTopic"`. + * + * Only topic names that match the pattern `"/topics/[a-zA-Z0-9-_.~%]{1,900}"` + * are allowed for subscribing and publishing. + */ +@interface FIRMessagingPubSub : NSObject + +- (instancetype)initWithTokenManager:(FIRMessagingTokenManager *)tokenManager; + +/** + * Subscribes an app instance to a topic, enabling it to receive messages + * sent to that topic. + * + * This is an asynchronous call. If subscription fails, FIRMessaging + * invokes the completion callback with the appropriate error. + * + * @see FIRMessagingPubSub unsubscribeWithToken:topic:handler: + * + * @param token The registration token as received from the InstanceID + * library for a given `authorizedEntity` and "gcm" scope. + * @param topic The topic to subscribe to. Should be of the form + * `"/topics/"`. + * @param options Unused parameter, please pass nil or empty dictionary. + * @param handler The callback handler invoked when the subscribe call + * ends. In case of success, a nil error is returned. Otherwise, + * an appropriate error object is returned. + * @discussion This method is thread-safe. However, it is not guaranteed to + * return on the main thread. + */ +- (void)subscribeWithToken:(NSString *)token + topic:(NSString *)topic + options:(nullable NSDictionary *)options + handler:(FIRMessagingTopicOperationCompletion)handler; + +/** + * Unsubscribes an app instance from a topic, stopping it from receiving + * any further messages sent to that topic. + * + * This is an asynchronous call. If the attempt to unsubscribe fails, + * we invoke the `completion` callback passed in with an appropriate error. + * + * @param token The token used to subscribe to this topic. + * @param topic The topic to unsubscribe from. Should be of the form + * `"/topics/"`. + * @param options Unused parameter, please pass nil or empty dictionary. + * @param handler The handler that is invoked once the unsubscribe call ends. + * In case of success, nil error is returned. Otherwise, an + * appropriate error object is returned. + * @discussion This method is thread-safe. However, it is not guaranteed to + * return on the main thread. + */ +- (void)unsubscribeWithToken:(NSString *)token + topic:(NSString *)topic + options:(nullable NSDictionary *)options + handler:(FIRMessagingTopicOperationCompletion)handler; + +/** + * Asynchronously subscribe to the topic. Adds to the pending list of topic operations. + * Retry in case of failures. This makes a repeated attempt to subscribe to the topic + * as compared to the `subscribe` method above which tries once. + * + * @param topic The topic name to subscribe to. Should be of the form `"/topics/"`. + * @param handler The handler that is invoked once the unsubscribe call ends. + * In case of success, nil error is returned. Otherwise, an + * appropriate error object is returned. + */ +- (void)subscribeToTopic:(NSString *)topic + handler:(nullable FIRMessagingTopicOperationCompletion)handler; + +/** + * Asynchronously unsubscribe from the topic. Adds to the pending list of topic operations. + * Retry in case of failures. This makes a repeated attempt to unsubscribe from the topic + * as compared to the `unsubscribe` method above which tries once. + * + * @param topic The topic name to unsubscribe from. Should be of the form `"/topics/"`. + * @param handler The handler that is invoked once the unsubscribe call ends. + * In case of success, nil error is returned. Otherwise, an + * appropriate error object is returned. + */ +- (void)unsubscribeFromTopic:(NSString *)topic + handler:(nullable FIRMessagingTopicOperationCompletion)handler; + +/** + * Schedule subscriptions sync. + * + * @param immediately YES if the sync should be scheduled immediately else NO if we can delay + * the sync. + */ +- (void)scheduleSync:(BOOL)immediately; + +/** + * Adds the "/topics/" prefix to the topic. + * + * @param topic The topic to add the prefix to. + * + * @return The new topic name with the "/topics/" prefix added. + */ ++ (NSString *)addPrefixToTopic:(NSString *)topic; + +/** + * Removes the "/topics/" prefix from the topic. + * + * @param topic The topic to remove the prefix from. + * + * @return The new topic name with the "/topics/" prefix removed. + */ + ++ (NSString *)removePrefixFromTopic:(NSString *)topic; + +/** + * Check if the topic name has "/topics/" prefix. + * + * @param topic The topic name to verify. + * + * @return YES if the topic name has "/topics/" prefix else NO. + */ ++ (BOOL)hasTopicsPrefix:(NSString *)topic; + +/** + * Check if it's a valid topic name. This includes "/topics/" prefix in the topic name. + * + * @param topic The topic name to verify. + * + * @return YES if the topic name satisfies the regex "/topics/[a-zA-Z0-9-_.~%]{1,900}". + */ ++ (BOOL)isValidTopicWithPrefix:(NSString *)topic; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPubSub.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPubSub.m new file mode 100644 index 0000000..9f95c16 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingPubSub.m @@ -0,0 +1,327 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingPubSub.h" + +#import +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h" +#import "FirebaseMessaging/Sources/FIRMessagingTopicOperation.h" +#import "FirebaseMessaging/Sources/FIRMessagingTopicsCommon.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/FIRMessaging_Private.h" +#import "FirebaseMessaging/Sources/NSDictionary+FIRMessaging.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.h" + +static NSString *const kPendingSubscriptionsListKey = + @"com.firebase.messaging.pending-subscriptions"; + +@interface FIRMessagingPubSub () + +@property(nonatomic, readwrite, strong) FIRMessagingPendingTopicsList *pendingTopicUpdates; +@property(nonatomic, readonly, strong) NSOperationQueue *topicOperations; +// Common errors, instantiated, to avoid generating multiple copies +@property(nonatomic, readwrite, strong) NSError *operationInProgressError; +@property(nonatomic, readwrite, strong) FIRMessagingTokenManager *tokenManager; + +@end + +@implementation FIRMessagingPubSub + +- (instancetype)initWithTokenManager:(FIRMessagingTokenManager *)tokenManager { + self = [super init]; + if (self) { + _topicOperations = [[NSOperationQueue alloc] init]; + // Do 10 topic operations at a time; it's enough to keep the TCP connection to the host alive, + // saving hundreds of milliseconds on each request (compared to a serial queue). + _topicOperations.maxConcurrentOperationCount = 10; + _tokenManager = tokenManager; + [self restorePendingTopicsList]; + } + return self; +} + +- (void)subscribeWithToken:(NSString *)token + topic:(NSString *)topic + options:(NSDictionary *)options + handler:(FIRMessagingTopicOperationCompletion)handler { + token = [token copy]; + topic = [topic copy]; + + if (![options count]) { + options = @{}; + } + + if (![[self class] isValidTopicWithPrefix:topic]) { + NSString *failureReason = + [NSString stringWithFormat:@"Invalid subscription topic :'%@'", topic]; + FIRMessagingLoggerError(kFIRMessagingMessageCodePubSub000, @"%@", failureReason); + handler([NSError messagingErrorWithCode:kFIRMessagingErrorCodeInvalidTopicName + failureReason:failureReason]); + return; + } + + if (![self verifyPubSubOptions:options]) { + // we do not want to quit even if options have some invalid values. + FIRMessagingLoggerError(kFIRMessagingMessageCodePubSub001, + @"Invalid options passed to FIRMessagingPubSub with non-string keys or " + "values."); + } + // copy the dictionary would trim non-string keys or values if any. + options = [options fcm_trimNonStringValues]; + + [self updateSubscriptionWithToken:token + topic:topic + options:options + shouldDelete:NO + handler:handler]; +} + +- (void)dealloc { + [self.topicOperations cancelAllOperations]; +} + +#pragma mark - FIRMessaging subscribe + +- (void)updateSubscriptionWithToken:(NSString *)token + topic:(NSString *)topic + options:(NSDictionary *)options + shouldDelete:(BOOL)shouldDelete + handler:(FIRMessagingTopicOperationCompletion)handler { + if ([_tokenManager hasValidCheckinInfo]) { + FIRMessagingTopicAction action = + shouldDelete ? FIRMessagingTopicActionUnsubscribe : FIRMessagingTopicActionSubscribe; + FIRMessagingTopicOperation *operation = [[FIRMessagingTopicOperation alloc] + initWithTopic:topic + action:action + tokenManager:_tokenManager + options:options + completion:^(NSError *_Nullable error) { + if (error) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeClient001, + @"Failed to subscribe to topic %@", error); + } else { + if (shouldDelete) { + FIRMessagingLoggerInfo(kFIRMessagingMessageCodeClient002, + @"Successfully unsubscribed from topic %@", topic); + } else { + FIRMessagingLoggerInfo(kFIRMessagingMessageCodeClient003, + @"Successfully subscribed to topic %@", topic); + } + } + if (handler) { + handler(error); + } + }]; + [self.topicOperations addOperation:operation]; + } else { + NSString *failureReason = @"Device ID and checkin info is not found. Will not proceed with " + @"subscription/unsubscription."; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeRegistrar000, @"%@", failureReason); + NSError *error = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeMissingDeviceID + failureReason:failureReason]; + handler(error); + } +} + +- (void)unsubscribeWithToken:(NSString *)token + topic:(NSString *)topic + options:(NSDictionary *)options + handler:(FIRMessagingTopicOperationCompletion)handler { + token = [token copy]; + topic = [topic copy]; + if (![options count]) { + options = @{}; + } + + if (![[self class] isValidTopicWithPrefix:topic]) { + NSString *failureReason = + [NSString stringWithFormat:@"Invalid topic name : '%@' for unsubscription.", topic]; + FIRMessagingLoggerError(kFIRMessagingMessageCodePubSub002, @"%@", failureReason); + handler([NSError messagingErrorWithCode:kFIRMessagingErrorCodeInvalidTopicName + failureReason:failureReason]); + return; + } + if (![self verifyPubSubOptions:options]) { + // we do not want to quit even if options have some invalid values. + FIRMessagingLoggerError( + kFIRMessagingMessageCodePubSub003, + @"Invalid options passed to FIRMessagingPubSub with non-string keys or values."); + } + // copy the dictionary would trim non-string keys or values if any. + options = [options fcm_trimNonStringValues]; + + [self updateSubscriptionWithToken:token + topic:topic + options:options + shouldDelete:YES + handler:^void(NSError *error) { + handler(error); + }]; +} + +- (void)subscribeToTopic:(NSString *)topic + handler:(nullable FIRMessagingTopicOperationCompletion)handler { + [self.pendingTopicUpdates addOperationForTopic:topic + withAction:FIRMessagingTopicActionSubscribe + completion:handler]; +} + +- (void)unsubscribeFromTopic:(NSString *)topic + handler:(nullable FIRMessagingTopicOperationCompletion)handler { + [self.pendingTopicUpdates addOperationForTopic:topic + withAction:FIRMessagingTopicActionUnsubscribe + completion:handler]; +} + +- (void)scheduleSync:(BOOL)immediately { + NSString *fcmToken = _tokenManager.defaultFCMToken; + if (fcmToken.length) { + [self.pendingTopicUpdates resumeOperationsIfNeeded]; + } +} + +#pragma mark - FIRMessagingPendingTopicsListDelegate + +- (void)pendingTopicsList:(FIRMessagingPendingTopicsList *)list + requestedUpdateForTopic:(NSString *)topic + action:(FIRMessagingTopicAction)action + completion:(FIRMessagingTopicOperationCompletion)completion { + NSString *fcmToken = _tokenManager.defaultFCMToken; + if (action == FIRMessagingTopicActionSubscribe) { + [self subscribeWithToken:fcmToken topic:topic options:nil handler:completion]; + } else { + [self unsubscribeWithToken:fcmToken topic:topic options:nil handler:completion]; + } +} + +- (void)pendingTopicsListDidUpdate:(FIRMessagingPendingTopicsList *)list { + [self archivePendingTopicsList:list]; +} + +- (BOOL)pendingTopicsListCanRequestTopicUpdates:(FIRMessagingPendingTopicsList *)list { + NSString *fcmToken = _tokenManager.defaultFCMToken; + return (fcmToken.length > 0); +} + +#pragma mark - Storing Pending Topics + +- (void)archivePendingTopicsList:(FIRMessagingPendingTopicsList *)topicsList { + GULUserDefaults *defaults = [GULUserDefaults standardUserDefaults]; + NSError *error; + NSData *pendingData = [NSKeyedArchiver archivedDataWithRootObject:topicsList + requiringSecureCoding:YES + error:&error]; + if (error) { + FIRMessagingLoggerError(kFIRMessagingMessageCodePubSubArchiveError, + @"Failed to archive topic list data %@", error); + return; + } + [defaults setObject:pendingData forKey:kPendingSubscriptionsListKey]; +} + +- (void)restorePendingTopicsList { + GULUserDefaults *defaults = [GULUserDefaults standardUserDefaults]; + NSData *pendingData = [defaults objectForKey:kPendingSubscriptionsListKey]; + FIRMessagingPendingTopicsList *subscriptions; + if (pendingData) { + NSError *error; + subscriptions = [NSKeyedUnarchiver + unarchivedObjectOfClasses:[NSSet setWithObjects:FIRMessagingPendingTopicsList.class, nil] + fromData:pendingData + error:&error]; + if (error) { + FIRMessagingLoggerError(kFIRMessagingMessageCodePubSubUnarchiveError, + @"Failed to unarchive topic list data %@", error); + } + } + if (subscriptions) { + self.pendingTopicUpdates = subscriptions; + } else { + self.pendingTopicUpdates = [[FIRMessagingPendingTopicsList alloc] init]; + } + self.pendingTopicUpdates.delegate = self; +} + +#pragma mark - Private Helpers + +- (BOOL)verifyPubSubOptions:(NSDictionary *)options { + return ![options fcm_hasNonStringKeysOrValues]; +} + +#pragma mark - Topic Name Helpers + +static NSString *const kTopicsPrefix = @"/topics/"; +static NSString *const kTopicRegexPattern = @"/topics/([a-zA-Z0-9-_.~%]+)"; + ++ (NSString *)addPrefixToTopic:(NSString *)topic { + if (![self hasTopicsPrefix:topic]) { + return [NSString stringWithFormat:@"%@%@", kTopicsPrefix, topic]; + } else { + return [topic copy]; + } +} + ++ (NSString *)removePrefixFromTopic:(NSString *)topic { + if ([self hasTopicsPrefix:topic]) { + return [topic substringFromIndex:kTopicsPrefix.length]; + } else { + return [topic copy]; + } +} + ++ (BOOL)hasTopicsPrefix:(NSString *)topic { + return [topic hasPrefix:kTopicsPrefix]; +} + +/** + * Returns a regular expression for matching a topic sender. + * + * @return The topic matching regular expression + */ ++ (NSRegularExpression *)topicRegex { + // Since this is a static regex pattern, we only only need to declare it once. + static NSRegularExpression *topicRegex; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSError *error; + topicRegex = + [NSRegularExpression regularExpressionWithPattern:kTopicRegexPattern + options:NSRegularExpressionAnchorsMatchLines + error:&error]; + }); + return topicRegex; +} + +/** + * Gets the class describing occurrences of topic names and sender IDs in the sender. + * + * @param topic The topic expression used to generate a pubsub topic + * + * @return Representation of captured subexpressions in topic regular expression + */ ++ (BOOL)isValidTopicWithPrefix:(NSString *)topic { + NSRange topicRange = NSMakeRange(0, topic.length); + NSRange regexMatchRange = [[self topicRegex] rangeOfFirstMatchInString:topic + options:NSMatchingAnchored + range:topicRange]; + return NSEqualRanges(topicRange, regexMatchRange); +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.h new file mode 100644 index 0000000..f0010b3 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.h @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * Swizzle remote-notification callbacks to invoke FIRMessaging methods + * before calling original implementations. + */ +@interface FIRMessagingRemoteNotificationsProxy : NSObject + +/** + * Checks the `FirebaseAppDelegateProxyEnabled` key in the App's Info.plist. If the key is + * missing or incorrectly formatted, returns `YES`. + * + * @return YES if the Application Delegate and User Notification Center methods can be swizzled. + * Otherwise, returns NO. + */ ++ (BOOL)canSwizzleMethods; + +/** + * A shared instance of `FIRMessagingRemoteNotificationsProxy` + */ ++ (instancetype)sharedProxy; + +/** + * Swizzles Application Delegate's remote-notification callbacks and User Notification Center + * delegate callback, and invokes the original selectors once done. + */ +- (void)swizzleMethodsIfPossible; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.m new file mode 100644 index 0000000..8d9de09 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.m @@ -0,0 +1,585 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.h" + +#import + +#import +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/FIRMessaging_Private.h" + +static void *UserNotificationObserverContext = &UserNotificationObserverContext; + +static NSString *kUserNotificationWillPresentSelectorString = + @"userNotificationCenter:willPresentNotification:withCompletionHandler:"; +static NSString *kUserNotificationDidReceiveResponseSelectorString = + @"userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:"; + +@interface FIRMessagingRemoteNotificationsProxy () + +@property(strong, nonatomic) NSMutableDictionary *originalAppDelegateImps; +@property(strong, nonatomic) NSMutableDictionary *swizzledSelectorsByClass; + +@property(nonatomic) BOOL didSwizzleMethods; + +@property(nonatomic) BOOL hasSwizzledUserNotificationDelegate; +@property(nonatomic) BOOL isObservingUserNotificationDelegateChanges; + +@property(strong, nonatomic) id userNotificationCenter; +@property(strong, nonatomic) id currentUserNotificationCenterDelegate; + +@property(strong, nonatomic) GULAppDelegateInterceptorID appDelegateInterceptorID; + +@end + +@implementation FIRMessagingRemoteNotificationsProxy + ++ (BOOL)canSwizzleMethods { + return [GULAppDelegateSwizzler isAppDelegateProxyEnabled]; +} + ++ (instancetype)sharedProxy { + static FIRMessagingRemoteNotificationsProxy *proxy; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + proxy = [[FIRMessagingRemoteNotificationsProxy alloc] init]; + }); + return proxy; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _originalAppDelegateImps = [[NSMutableDictionary alloc] init]; + _swizzledSelectorsByClass = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)dealloc { + [self unswizzleAllMethods]; + self.swizzledSelectorsByClass = nil; + [self.originalAppDelegateImps removeAllObjects]; + self.originalAppDelegateImps = nil; + [self removeUserNotificationCenterDelegateObserver]; +} + +- (void)swizzleMethodsIfPossible { + // Already swizzled. + if (self.didSwizzleMethods) { + return; + } + + [GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods]; + self.appDelegateInterceptorID = [GULAppDelegateSwizzler registerAppDelegateInterceptor:self]; + + // Add KVO listener on [UNUserNotificationCenter currentNotificationCenter]'s delegate property + Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter"); + if (notificationCenterClass) { + // We are linked against iOS 10 SDK or above + id notificationCenter = FIRMessagingPropertyNameFromObject( + notificationCenterClass, @"currentNotificationCenter", notificationCenterClass); + if (notificationCenter) { + [self listenForDelegateChangesInUserNotificationCenter:notificationCenter]; + } + } + + self.didSwizzleMethods = YES; +} + +- (void)unswizzleAllMethods { + if (self.appDelegateInterceptorID) { + [GULAppDelegateSwizzler unregisterAppDelegateInterceptorWithID:self.appDelegateInterceptorID]; + } + + for (NSString *className in self.swizzledSelectorsByClass) { + Class klass = NSClassFromString(className); + NSArray *selectorStrings = self.swizzledSelectorsByClass[className]; + for (NSString *selectorString in selectorStrings) { + SEL selector = NSSelectorFromString(selectorString); + [self unswizzleSelector:selector inClass:klass]; + } + } + [self.swizzledSelectorsByClass removeAllObjects]; +} + +- (void)listenForDelegateChangesInUserNotificationCenter:(id)notificationCenter { + Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter"); + if (![notificationCenter isKindOfClass:notificationCenterClass]) { + return; + } + id delegate = FIRMessagingPropertyNameFromObject(notificationCenter, @"delegate", nil); + Protocol *delegateProtocol = NSProtocolFromString(@"UNUserNotificationCenterDelegate"); + if ([delegate conformsToProtocol:delegateProtocol]) { + // Swizzle this object now, if available + [self swizzleUserNotificationCenterDelegate:delegate]; + } + // Add KVO observer for "delegate" keyPath for future changes + [self addDelegateObserverToUserNotificationCenter:notificationCenter]; +} + +#pragma mark - UNNotificationCenter Swizzling + +- (void)swizzleUserNotificationCenterDelegate:(id _Nonnull)delegate { + if (self.currentUserNotificationCenterDelegate == delegate) { + // Via pointer-check, compare if we have already swizzled this item. + return; + } + Protocol *userNotificationCenterProtocol = + NSProtocolFromString(@"UNUserNotificationCenterDelegate"); + if ([delegate conformsToProtocol:userNotificationCenterProtocol]) { + SEL willPresentNotificationSelector = + NSSelectorFromString(kUserNotificationWillPresentSelectorString); + // Swizzle the optional method + // "userNotificationCenter:willPresentNotification:withCompletionHandler:", if it is + // implemented. Do not swizzle otherwise, as an implementation *will* be created, which will + // fool iOS into thinking that this method is implemented, and therefore not send notifications + // to the fallback method in the app delegate + // "application:didReceiveRemoteNotification:fetchCompletionHandler:". + if ([delegate respondsToSelector:willPresentNotificationSelector]) { + [self swizzleSelector:willPresentNotificationSelector + inClass:[delegate class] + withImplementation:(IMP)FCMSwizzleWillPresentNotificationWithHandler + inProtocol:userNotificationCenterProtocol]; + } + SEL didReceiveNotificationResponseSelector = + NSSelectorFromString(kUserNotificationDidReceiveResponseSelectorString); + if ([delegate respondsToSelector:didReceiveNotificationResponseSelector]) { + [self swizzleSelector:didReceiveNotificationResponseSelector + inClass:[delegate class] + withImplementation:(IMP)FCMSwizzleDidReceiveNotificationResponseWithHandler + inProtocol:userNotificationCenterProtocol]; + } + self.currentUserNotificationCenterDelegate = delegate; + self.hasSwizzledUserNotificationDelegate = YES; + } +} + +- (void)unswizzleUserNotificationCenterDelegate:(id _Nonnull)delegate { + if (self.currentUserNotificationCenterDelegate != delegate) { + // We aren't swizzling this delegate, so don't do anything. + return; + } + SEL willPresentNotificationSelector = + NSSelectorFromString(kUserNotificationWillPresentSelectorString); + // Call unswizzle methods, even if the method was not implemented (it will fail gracefully). + [self unswizzleSelector:willPresentNotificationSelector + inClass:[self.currentUserNotificationCenterDelegate class]]; + SEL didReceiveNotificationResponseSelector = + NSSelectorFromString(kUserNotificationDidReceiveResponseSelectorString); + [self unswizzleSelector:didReceiveNotificationResponseSelector + inClass:[self.currentUserNotificationCenterDelegate class]]; + self.currentUserNotificationCenterDelegate = nil; + self.hasSwizzledUserNotificationDelegate = NO; +} + +#pragma mark - KVO for UNUserNotificationCenter + +- (void)addDelegateObserverToUserNotificationCenter:(id)userNotificationCenter { + [self removeUserNotificationCenterDelegateObserver]; + @try { + [userNotificationCenter addObserver:self + forKeyPath:NSStringFromSelector(@selector(delegate)) + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld + context:UserNotificationObserverContext]; + self.userNotificationCenter = userNotificationCenter; + self.isObservingUserNotificationDelegateChanges = YES; + } @catch (NSException *exception) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxy000, + @"Encountered exception trying to add a KVO observer for " + @"UNUserNotificationCenter's 'delegate' property: %@", + exception); + } @finally { + } +} + +- (void)removeUserNotificationCenterDelegateObserver { + if (!self.userNotificationCenter) { + return; + } + @try { + [self.userNotificationCenter removeObserver:self + forKeyPath:NSStringFromSelector(@selector(delegate)) + context:UserNotificationObserverContext]; + self.userNotificationCenter = nil; + self.isObservingUserNotificationDelegateChanges = NO; + } @catch (NSException *exception) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxy001, + @"Encountered exception trying to remove a KVO observer for " + @"UNUserNotificationCenter's 'delegate' property: %@", + exception); + } @finally { + } +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if (context == UserNotificationObserverContext) { + if ([keyPath isEqualToString:NSStringFromSelector(@selector(delegate))]) { + id oldDelegate = change[NSKeyValueChangeOldKey]; + if (oldDelegate && oldDelegate != [NSNull null]) { + [self unswizzleUserNotificationCenterDelegate:oldDelegate]; + } + id newDelegate = change[NSKeyValueChangeNewKey]; + if (newDelegate && newDelegate != [NSNull null]) { + [self swizzleUserNotificationCenterDelegate:newDelegate]; + } + } + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +#pragma mark - NSProxy methods + +- (void)saveOriginalImplementation:(IMP)imp forSelector:(SEL)selector { + if (imp && selector) { + NSValue *IMPValue = [NSValue valueWithPointer:imp]; + NSString *selectorString = NSStringFromSelector(selector); + self.originalAppDelegateImps[selectorString] = IMPValue; + } +} + +- (IMP)originalImplementationForSelector:(SEL)selector { + NSString *selectorString = NSStringFromSelector(selector); + NSValue *implementationValue = self.originalAppDelegateImps[selectorString]; + if (!implementationValue) { + return nil; + } + + IMP imp; + [implementationValue getValue:&imp]; + return imp; +} + +- (void)trackSwizzledSelector:(SEL)selector ofClass:(Class)klass { + NSString *className = NSStringFromClass(klass); + NSString *selectorString = NSStringFromSelector(selector); + NSArray *selectors = self.swizzledSelectorsByClass[selectorString]; + if (selectors) { + selectors = [selectors arrayByAddingObject:selectorString]; + } else { + selectors = @[ selectorString ]; + } + self.swizzledSelectorsByClass[className] = selectors; +} + +- (void)removeImplementationForSelector:(SEL)selector { + NSString *selectorString = NSStringFromSelector(selector); + [self.originalAppDelegateImps removeObjectForKey:selectorString]; +} + +- (void)swizzleSelector:(SEL)originalSelector + inClass:(Class)klass + withImplementation:(IMP)swizzledImplementation + inProtocol:(Protocol *)protocol { + Method originalMethod = class_getInstanceMethod(klass, originalSelector); + + if (originalMethod) { + // This class implements this method, so replace the original implementation + // with our new implementation and save the old implementation. + + IMP originalMethodImplementation = + method_setImplementation(originalMethod, swizzledImplementation); + + IMP nonexistentMethodImplementation = [self nonExistentMethodImplementationForClass:klass]; + + if (originalMethodImplementation && + originalMethodImplementation != nonexistentMethodImplementation && + originalMethodImplementation != swizzledImplementation) { + [self saveOriginalImplementation:originalMethodImplementation forSelector:originalSelector]; + } + } else { + // The class doesn't have this method, so add our swizzled implementation as the + // original implementation of the original method. + struct objc_method_description methodDescription = + protocol_getMethodDescription(protocol, originalSelector, NO, YES); + + BOOL methodAdded = + class_addMethod(klass, originalSelector, swizzledImplementation, methodDescription.types); + if (!methodAdded) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxyMethodNotAdded, + @"Could not add method for %@ to class %@", + NSStringFromSelector(originalSelector), NSStringFromClass(klass)); + } + } + [self trackSwizzledSelector:originalSelector ofClass:klass]; +} + +- (void)unswizzleSelector:(SEL)selector inClass:(Class)klass { + Method swizzledMethod = class_getInstanceMethod(klass, selector); + if (!swizzledMethod) { + // This class doesn't seem to have this selector as an instance method? Bail out. + return; + } + + IMP originalImp = [self originalImplementationForSelector:selector]; + if (originalImp) { + // Restore the original implementation as the current implementation + method_setImplementation(swizzledMethod, originalImp); + [self removeImplementationForSelector:selector]; + } else { + // This class originally did not have an implementation for this selector. + + // We can't actually remove methods in Objective-C 2.0, but we could set + // its method to something non-existent. This should give us the same + // behavior as if the method was not implemented. + // See: http://stackoverflow.com/a/8276527/9849 + + IMP nonExistentMethodImplementation = [self nonExistentMethodImplementationForClass:klass]; + method_setImplementation(swizzledMethod, nonExistentMethodImplementation); + } +} + +#pragma mark - Reflection Helpers + +// This is useful to generate from a stable, "known missing" selector, as the IMP can be compared +// in case we are setting an implementation for a class that was previously "unswizzled" into a +// non-existent implementation. +- (IMP)nonExistentMethodImplementationForClass:(Class)klass { + SEL nonExistentSelector = NSSelectorFromString(@"aNonExistentMethod"); + IMP nonExistentMethodImplementation = class_getMethodImplementation(klass, nonExistentSelector); + return nonExistentMethodImplementation; +} + +// A safe, non-leaky way return a property object by its name +id FIRMessagingPropertyNameFromObject(id object, NSString *propertyName, Class klass) { + SEL selector = NSSelectorFromString(propertyName); + if (![object respondsToSelector:selector]) { + return nil; + } + if (!klass) { + klass = [NSObject class]; + } + // Suppress clang warning about leaks in performSelector + // The alternative way to perform this is to invoke + // the method as a block (see http://stackoverflow.com/a/20058585), + // but this approach sometimes returns incomplete objects. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + id property = [object performSelector:selector]; +#pragma clang diagnostic pop + if (![property isKindOfClass:klass]) { + return nil; + } + return property; +} + +#pragma mark - GULApplicationDelegate + +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION +- (void)application:(UIApplication *)application + didReceiveRemoteNotification:(NSDictionary *)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { + [[FIRMessaging messaging] appDidReceiveMessage:userInfo]; + completionHandler(UIBackgroundFetchResultNoData); +} + +- (void)application:(UIApplication *)application + didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { + // Log the fact that we failed to register for remote notifications + FIRMessagingLoggerError(kFIRMessagingMessageCodeRemoteNotificationsProxyAPNSFailed, + @"Error in " + @"application:didFailToRegisterForRemoteNotificationsWithError: %@", + error.localizedDescription); +} +#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + +- (void)application:(GULApplication *)application + didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + [FIRMessaging messaging].APNSToken = deviceToken; +} + +#pragma mark - Swizzled Methods + +/** + * Swizzle the notification handler for iOS 10+ devices. + * Signature of original handler is as below: + * - (void)userNotificationCenter:(UNUserNotificationCenter *)center + * willPresentNotification:(UNNotification *)notification + * withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler + * In order to make FCM SDK compile and compatible with iOS SDKs before iOS 10, hide the + * parameter types from the swizzling implementation. + */ +static void FCMSwizzleWillPresentNotificationWithHandler( + id self, SEL cmd, id center, id notification, void (^handler)(NSUInteger)) { + FIRMessagingRemoteNotificationsProxy *proxy = [FIRMessagingRemoteNotificationsProxy sharedProxy]; + IMP originalImp = [proxy originalImplementationForSelector:cmd]; + + void (^callOriginalMethodIfAvailable)(void) = ^{ + if (originalImp) { + ((void (*)(id, SEL, id, id, void (^)(NSUInteger)))originalImp)(self, cmd, center, + notification, handler); + } + return; + }; + + Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter"); + Class notificationClass = NSClassFromString(@"UNNotification"); + if (!notificationCenterClass || !notificationClass) { + // Can't find UserNotifications framework. Do not swizzle, just execute the original method. + callOriginalMethodIfAvailable(); + } + + if (!center || ![center isKindOfClass:[notificationCenterClass class]]) { + // Invalid parameter type from the original method. + // Do not swizzle, just execute the original method. + callOriginalMethodIfAvailable(); + return; + } + + if (!notification || ![notification isKindOfClass:[notificationClass class]]) { + // Invalid parameter type from the original method. + // Do not swizzle, just execute the original method. + callOriginalMethodIfAvailable(); + return; + } + + if (!handler) { + // Invalid parameter type from the original method. + // Do not swizzle, just execute the original method. + callOriginalMethodIfAvailable(); + return; + } + + // Attempt to access the user info + id notificationUserInfo = FIRMessagingUserInfoFromNotification(notification); + + if (!notificationUserInfo) { + // Could not access notification.request.content.userInfo. + callOriginalMethodIfAvailable(); + return; + } + + [[FIRMessaging messaging] appDidReceiveMessage:notificationUserInfo]; + // Execute the original implementation. + callOriginalMethodIfAvailable(); +} + +/** + * Swizzle the notification handler for iOS 10+ devices. + * Signature of original handler is as below: + * - (void)userNotificationCenter:(UNUserNotificationCenter *)center + * didReceiveNotificationResponse:(UNNotificationResponse *)response + * withCompletionHandler:(void (^)(void))completionHandler + * In order to make FCM SDK compile and compatible with iOS SDKs before iOS 10, hide the + * parameter types from the swizzling implementation. + */ +static void FCMSwizzleDidReceiveNotificationResponseWithHandler( + id self, SEL cmd, id center, id response, void (^handler)(void)) { + FIRMessagingRemoteNotificationsProxy *proxy = [FIRMessagingRemoteNotificationsProxy sharedProxy]; + IMP originalImp = [proxy originalImplementationForSelector:cmd]; + + void (^callOriginalMethodIfAvailable)(void) = ^{ + if (originalImp) { + ((void (*)(id, SEL, id, id, void (^)(void)))originalImp)(self, cmd, center, response, + handler); + } + return; + }; + + Class notificationCenterClass = NSClassFromString(@"UNUserNotificationCenter"); + Class responseClass = NSClassFromString(@"UNNotificationResponse"); + if (!center || ![center isKindOfClass:[notificationCenterClass class]]) { + // Invalid parameter type from the original method. + // Do not swizzle, just execute the original method. + callOriginalMethodIfAvailable(); + return; + } + + if (!response || ![response isKindOfClass:[responseClass class]]) { + // Invalid parameter type from the original method. + // Do not swizzle, just execute the original method. + callOriginalMethodIfAvailable(); + return; + } + + if (!handler) { + // Invalid parameter type from the original method. + // Do not swizzle, just execute the original method. + callOriginalMethodIfAvailable(); + return; + } + + // Try to access the response.notification property + SEL notificationSelector = NSSelectorFromString(@"notification"); + if (![response respondsToSelector:notificationSelector]) { + // Cannot access the .notification property. + callOriginalMethodIfAvailable(); + return; + } + id notificationClass = NSClassFromString(@"UNNotification"); + id notification = + FIRMessagingPropertyNameFromObject(response, @"notification", notificationClass); + + // With a notification object, use the common code to reach deep into notification + // (notification.request.content.userInfo) + id notificationUserInfo = FIRMessagingUserInfoFromNotification(notification); + if (!notificationUserInfo) { + // Could not access notification.request.content.userInfo. + callOriginalMethodIfAvailable(); + return; + } + + [[FIRMessaging messaging] appDidReceiveMessage:notificationUserInfo]; + // Execute the original implementation. + callOriginalMethodIfAvailable(); +} + +static id FIRMessagingUserInfoFromNotification(id notification) { + // Select the userInfo field from UNNotification.request.content.userInfo. + SEL requestSelector = NSSelectorFromString(@"request"); + if (![notification respondsToSelector:requestSelector]) { + // Cannot access the request property. + return nil; + } + Class requestClass = NSClassFromString(@"UNNotificationRequest"); + id notificationRequest = + FIRMessagingPropertyNameFromObject(notification, @"request", requestClass); + + SEL notificationContentSelector = NSSelectorFromString(@"content"); + if (!notificationRequest || + ![notificationRequest respondsToSelector:notificationContentSelector]) { + // Cannot access the content property. + return nil; + } + Class contentClass = NSClassFromString(@"UNNotificationContent"); + id notificationContent = + FIRMessagingPropertyNameFromObject(notificationRequest, @"content", contentClass); + + SEL notificationUserInfoSelector = NSSelectorFromString(@"userInfo"); + if (!notificationContent || + ![notificationContent respondsToSelector:notificationUserInfoSelector]) { + // Cannot access the userInfo property. + return nil; + } + id notificationUserInfo = + FIRMessagingPropertyNameFromObject(notificationContent, @"userInfo", [NSDictionary class]); + + if (!notificationUserInfo) { + // This is not the expected notification handler. + return nil; + } + + return notificationUserInfo; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRmqManager.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRmqManager.h new file mode 100644 index 0000000..48e555c --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRmqManager.h @@ -0,0 +1,88 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRMessagingPersistentSyncMessage; + +/** + * This manages the RMQ persistent store. + * + * The store is used to store all the S2D id's that were received by the client and were ACK'ed + * by us but the server hasn't confirmed the ACK. We don't delete these id's until the server + * ACK's us that they have received them. + * + * We also store the upstream messages(d2s) that were sent by the client. + * + * Also store the lastRMQId that was sent by us so that for a new connection being setup we don't + * duplicate RMQ Id's for the new messages. + */ +@interface FIRMessagingRmqManager : NSObject +// designated initializer +- (instancetype)initWithDatabaseName:(NSString *)databaseName; + +- (void)loadRmqId; + +/** + * Save Server to device message with the given RMQ-ID. + * + * @param rmqID The rmqID of the s2d message to save. + * + */ +- (void)saveS2dMessageWithRmqId:(NSString *)rmqID; + +#pragma mark - Sync Messages + +/** + * Get persisted sync message with rmqID. + * + * @param rmqID The rmqID of the persisted sync message. + * + * @return A valid persistent sync message with the given rmqID if found in the RMQ else nil. + */ +- (FIRMessagingPersistentSyncMessage *)querySyncMessageWithRmqID:(NSString *)rmqID; + +/** + * Delete the expired sync messages from persistent store. Also deletes messages that have been + * delivered both via APNS and MCS. + */ +- (void)deleteExpiredOrFinishedSyncMessages; + +/** + * Save sync message received by the device. + * + * @param rmqID The rmqID of the message received. + * @param expirationTime The expiration time of the sync message received. + * + */ +- (void)saveSyncMessageWithRmqID:(NSString *)rmqID expirationTime:(int64_t)expirationTime; + +/** + * Update sync message received via APNS. + * + * @param rmqID The rmqID of the received message. + * + */ +- (void)updateSyncMessageViaAPNSWithRmqID:(NSString *)rmqID; + +/** + * Returns path for database with specified name. + * @param databaseName The database name without extension: ".sqlite". + * @return Path to the database with the specified name. + */ ++ (NSString *)pathForDatabaseWithName:(NSString *)databaseName; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRmqManager.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRmqManager.m new file mode 100644 index 0000000..6a28d1d --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingRmqManager.m @@ -0,0 +1,696 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingRmqManager.h" + +#import + +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" + +#ifndef _FIRMessagingRmqLogAndExit +#define _FIRMessagingRmqLogAndExit(stmt, return_value) \ + do { \ + [self logErrorAndFinalizeStatement:stmt]; \ + return return_value; \ + } while (0) +#endif + +#ifndef FIRMessagingRmqLogAndReturn +#define FIRMessagingRmqLogAndReturn(stmt) \ + do { \ + [self logErrorAndFinalizeStatement:stmt]; \ + return; \ + } while (0) +#endif + +#ifndef FIRMessaging_MUST_NOT_BE_MAIN_THREAD +#define FIRMessaging_MUST_NOT_BE_MAIN_THREAD() \ + do { \ + NSAssert(![NSThread isMainThread], @"Must not be executing on the main thread."); \ + } while (0); +#endif + +// table names +NSString *const kTableOutgoingRmqMessages = @"outgoingRmqMessages"; +NSString *const kTableLastRmqId = @"lastrmqid"; +NSString *const kOldTableS2DRmqIds = @"s2dRmqIds"; +NSString *const kTableS2DRmqIds = @"s2dRmqIds_1"; + +// Used to prevent de-duping of sync messages received both via APNS and MCS. +NSString *const kTableSyncMessages = @"incomingSyncMessages"; + +static NSString *const kTablePrefix = @""; + +// create tables +static NSString *const kCreateTableOutgoingRmqMessages = @"create TABLE IF NOT EXISTS %@%@ " + @"(_id INTEGER PRIMARY KEY, " + @"rmq_id INTEGER, " + @"type INTEGER, " + @"ts INTEGER, " + @"data BLOB)"; + +static NSString *const kCreateTableLastRmqId = @"create TABLE IF NOT EXISTS %@%@ " + @"(_id INTEGER PRIMARY KEY, " + @"rmq_id INTEGER)"; + +static NSString *const kCreateTableS2DRmqIds = @"create TABLE IF NOT EXISTS %@%@ " + @"(_id INTEGER PRIMARY KEY, " + @"rmq_id TEXT)"; + +static NSString *const kCreateTableSyncMessages = @"create TABLE IF NOT EXISTS %@%@ " + @"(_id INTEGER PRIMARY KEY, " + @"rmq_id TEXT, " + @"expiration_ts INTEGER, " + @"apns_recv INTEGER, " + @"mcs_recv INTEGER)"; + +static NSString *const kDropTableCommand = @"drop TABLE if exists %@%@"; + +// table infos +static NSString *const kRmqIdColumn = @"rmq_id"; +static NSString *const kDataColumn = @"data"; +static NSString *const kProtobufTagColumn = @"type"; +static NSString *const kIdColumn = @"_id"; + +static NSString *const kOutgoingRmqMessagesColumns = @"rmq_id, type, data"; + +// Sync message columns +static NSString *const kSyncMessagesColumns = @"rmq_id, expiration_ts, apns_recv, mcs_recv"; +// Message time expiration in seconds since 1970 +static NSString *const kSyncMessageExpirationTimestampColumn = @"expiration_ts"; +static NSString *const kSyncMessageAPNSReceivedColumn = @"apns_recv"; +static NSString *const kSyncMessageMCSReceivedColumn = @"mcs_recv"; + +// Utility to create an NSString from a sqlite3 result code +NSString *_Nonnull FIRMessagingStringFromSQLiteResult(int result) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + const char *errorStr = sqlite3_errstr(result); +#pragma clang diagnostic pop + NSString *errorString = [NSString stringWithFormat:@"%d - %s", result, errorStr]; + return errorString; +} + +@interface FIRMessagingRmqManager () { + sqlite3 *_database; + /// Serial queue for database read/write operations. + dispatch_queue_t _databaseOperationQueue; +} + +@property(nonatomic, readwrite, strong) NSString *databaseName; +// map the category of an outgoing message with the number of messages for that category +// should always have two keys -- the app, gcm +@property(nonatomic, readwrite, strong) NSMutableDictionary *outstandingMessages; + +// Outgoing RMQ persistent id +@property(nonatomic, readwrite, assign) int64_t rmqId; +@end + +@implementation FIRMessagingRmqManager + +- (instancetype)initWithDatabaseName:(NSString *)databaseName { + self = [super init]; + if (self) { + _databaseOperationQueue = + dispatch_queue_create("com.google.firebase.messaging.database.rmq", DISPATCH_QUEUE_SERIAL); + _databaseName = [databaseName copy]; + [self openDatabase]; + _outstandingMessages = [NSMutableDictionary dictionaryWithCapacity:2]; + _rmqId = -1; + } + return self; +} + +- (void)dealloc { + sqlite3_close(_database); +} + +#pragma mark - RMQ ID + +- (void)loadRmqId { + if (self.rmqId >= 0) { + return; // already done + } + + [self loadInitialOutgoingPersistentId]; + if (self.outstandingMessages.count) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeRmqManager000, @"Outstanding categories %ld", + _FIRMessaging_UL(self.outstandingMessages.count)); + } +} + +/** + * Initialize the 'initial RMQ': + * - max ID of any message in the queue + * - if the queue is empty, stored value in separate DB. + * + * Stream acks will remove from RMQ, when we remove the highest message we keep track + * of its ID. + */ +- (void)loadInitialOutgoingPersistentId { + // we shouldn't always trust the lastRmqId stored in the LastRmqId table, because + // we only save to the LastRmqId table once in a while (after getting the lastRmqId sent + // by the server after reconnect, and after getting a rmq ack from the server). The + // rmq message with the highest rmq id tells the real story, so check against that first. + + __block int64_t rmqId; + dispatch_sync(_databaseOperationQueue, ^{ + rmqId = [self queryHighestRmqId]; + }); + if (rmqId == 0) { + dispatch_sync(_databaseOperationQueue, ^{ + rmqId = [self queryLastRmqId]; + }); + } + self.rmqId = rmqId + 1; +} + +/** + * This is called when we delete the largest outgoing message from queue. + */ +- (void)saveLastOutgoingRmqId:(int64_t)rmqID { + dispatch_async(_databaseOperationQueue, ^{ + NSString *queryFormat = @"INSERT OR REPLACE INTO %@ (%@, %@) VALUES (?, ?)"; + NSString *query = [NSString stringWithFormat:queryFormat, + kTableLastRmqId, // table + kIdColumn, kRmqIdColumn]; // columns + sqlite3_stmt *statement; + if (sqlite3_prepare_v2(self->_database, [query UTF8String], -1, &statement, NULL) != + SQLITE_OK) { + FIRMessagingRmqLogAndReturn(statement); + } + if (sqlite3_bind_int(statement, 1, 1) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(statement); + } + if (sqlite3_bind_int64(statement, 2, rmqID) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(statement); + } + if (sqlite3_step(statement) != SQLITE_DONE) { + FIRMessagingRmqLogAndReturn(statement); + } + sqlite3_finalize(statement); + }); +} + +- (void)saveS2dMessageWithRmqId:(NSString *)rmqId { + dispatch_async(_databaseOperationQueue, ^{ + NSString *insertFormat = @"INSERT INTO %@ (%@) VALUES (?)"; + NSString *insertSQL = [NSString stringWithFormat:insertFormat, kTableS2DRmqIds, kRmqIdColumn]; + sqlite3_stmt *insert_statement; + if (sqlite3_prepare_v2(self->_database, [insertSQL UTF8String], -1, &insert_statement, NULL) != + SQLITE_OK) { + FIRMessagingRmqLogAndReturn(insert_statement); + } + if (sqlite3_bind_text(insert_statement, 1, [rmqId UTF8String], (int)[rmqId length], + SQLITE_STATIC) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(insert_statement); + } + if (sqlite3_step(insert_statement) != SQLITE_DONE) { + FIRMessagingRmqLogAndReturn(insert_statement); + } + sqlite3_finalize(insert_statement); + }); +} + +#pragma mark - Query + +- (int64_t)queryHighestRmqId { + NSString *queryFormat = @"SELECT %@ FROM %@ ORDER BY %@ DESC LIMIT %d"; + NSString *query = [NSString stringWithFormat:queryFormat, + kRmqIdColumn, // column + kTableOutgoingRmqMessages, // table + kRmqIdColumn, // order by column + 1]; // limit + + sqlite3_stmt *statement; + int64_t highestRmqId = 0; + if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, NULL) != SQLITE_OK) { + _FIRMessagingRmqLogAndExit(statement, highestRmqId); + } + if (sqlite3_step(statement) == SQLITE_ROW) { + highestRmqId = sqlite3_column_int64(statement, 0); + } + sqlite3_finalize(statement); + return highestRmqId; +} + +- (int64_t)queryLastRmqId { + NSString *queryFormat = @"SELECT %@ FROM %@ ORDER BY %@ DESC LIMIT %d"; + NSString *query = [NSString stringWithFormat:queryFormat, + kRmqIdColumn, // column + kTableLastRmqId, // table + kRmqIdColumn, // order by column + 1]; // limit + + sqlite3_stmt *statement; + int64_t lastRmqId = 0; + if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, NULL) != SQLITE_OK) { + _FIRMessagingRmqLogAndExit(statement, lastRmqId); + } + if (sqlite3_step(statement) == SQLITE_ROW) { + lastRmqId = sqlite3_column_int64(statement, 0); + } + sqlite3_finalize(statement); + return lastRmqId; +} + +#pragma mark - Sync Messages + +- (FIRMessagingPersistentSyncMessage *)querySyncMessageWithRmqID:(NSString *)rmqID { + __block FIRMessagingPersistentSyncMessage *persistentMessage; + dispatch_sync(_databaseOperationQueue, ^{ + NSString *queryFormat = @"SELECT %@ FROM %@ WHERE %@ = ?"; + NSString *query = + [NSString stringWithFormat:queryFormat, + kSyncMessagesColumns, // SELECT (rmq_id, expiration_ts, + // apns_recv, mcs_recv) + kTableSyncMessages, // FROM sync_rmq + kRmqIdColumn // WHERE rmq_id + ]; + + sqlite3_stmt *stmt; + if (sqlite3_prepare_v2(self->_database, [query UTF8String], -1, &stmt, NULL) != SQLITE_OK) { + [self logError]; + sqlite3_finalize(stmt); + return; + } + + if (sqlite3_bind_text(stmt, 1, [rmqID UTF8String], (int)[rmqID length], SQLITE_STATIC) != + SQLITE_OK) { + [self logError]; + sqlite3_finalize(stmt); + return; + } + + const int rmqIDColumn = 0; + const int expirationTimestampColumn = 1; + const int apnsReceivedColumn = 2; + const int mcsReceivedColumn = 3; + + int count = 0; + + while (sqlite3_step(stmt) == SQLITE_ROW) { + NSString *rmqID = + [NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt, rmqIDColumn)]; + int64_t expirationTimestamp = sqlite3_column_int64(stmt, expirationTimestampColumn); + BOOL apnsReceived = sqlite3_column_int(stmt, apnsReceivedColumn); + BOOL mcsReceived = sqlite3_column_int(stmt, mcsReceivedColumn); + + // create a new persistent message + persistentMessage = + [[FIRMessagingPersistentSyncMessage alloc] initWithRMQID:rmqID + expirationTime:expirationTimestamp]; + persistentMessage.apnsReceived = apnsReceived; + persistentMessage.mcsReceived = mcsReceived; + + count++; + } + sqlite3_finalize(stmt); + }); + + return persistentMessage; +} + +- (void)deleteExpiredOrFinishedSyncMessages { + dispatch_async(_databaseOperationQueue, ^{ + int64_t now = FIRMessagingCurrentTimestampInSeconds(); + NSString *deleteSQL = @"DELETE FROM %@ " + @"WHERE %@ < %lld OR " // expirationTime < now + @"(%@ = 1 AND %@ = 1)"; // apns_received = 1 AND mcs_received = 1 + NSString *query = [NSString + stringWithFormat:deleteSQL, kTableSyncMessages, kSyncMessageExpirationTimestampColumn, now, + kSyncMessageAPNSReceivedColumn, kSyncMessageMCSReceivedColumn]; + sqlite3_stmt *stmt; + if (sqlite3_prepare_v2(self->_database, [query UTF8String], -1, &stmt, NULL) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(stmt); + } + + if (sqlite3_step(stmt) != SQLITE_DONE) { + FIRMessagingRmqLogAndReturn(stmt); + } + + sqlite3_finalize(stmt); + int deleteCount = sqlite3_changes(self->_database); + if (deleteCount > 0) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeSyncMessageManager001, + @"Successfully deleted %d sync messages from store", deleteCount); + } + }); +} + +- (void)saveSyncMessageWithRmqID:(NSString *)rmqID expirationTime:(int64_t)expirationTime { + BOOL apnsReceived = YES; + BOOL mcsReceived = NO; + dispatch_async(_databaseOperationQueue, ^{ + NSString *insertFormat = @"INSERT INTO %@ (%@, %@, %@, %@) VALUES (?, ?, ?, ?)"; + NSString *insertSQL = + [NSString stringWithFormat:insertFormat, + kTableSyncMessages, // Table name + kRmqIdColumn, // rmq_id + kSyncMessageExpirationTimestampColumn, // expiration_ts + kSyncMessageAPNSReceivedColumn, // apns_recv + kSyncMessageMCSReceivedColumn /* mcs_recv */]; + + sqlite3_stmt *stmt; + + if (sqlite3_prepare_v2(self->_database, [insertSQL UTF8String], -1, &stmt, NULL) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(stmt); + } + + if (sqlite3_bind_text(stmt, 1, [rmqID UTF8String], (int)[rmqID length], NULL) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(stmt); + } + + if (sqlite3_bind_int64(stmt, 2, expirationTime) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(stmt); + } + + if (sqlite3_bind_int(stmt, 3, apnsReceived ? 1 : 0) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(stmt); + } + + if (sqlite3_bind_int(stmt, 4, mcsReceived ? 1 : 0) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(stmt); + } + + if (sqlite3_step(stmt) != SQLITE_DONE) { + FIRMessagingRmqLogAndReturn(stmt); + } + sqlite3_finalize(stmt); + FIRMessagingLoggerInfo(kFIRMessagingMessageCodeSyncMessageManager004, + @"Added sync message to cache: %@", rmqID); + }); +} + +- (void)updateSyncMessageViaAPNSWithRmqID:(NSString *)rmqID { + dispatch_async(_databaseOperationQueue, ^{ + if (![self updateSyncMessageWithRmqID:rmqID column:kSyncMessageAPNSReceivedColumn value:YES]) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager005, + @"Failed to update APNS state for sync message %@", rmqID); + } + }); +} + +- (BOOL)updateSyncMessageWithRmqID:(NSString *)rmqID column:(NSString *)column value:(BOOL)value { + FIRMessaging_MUST_NOT_BE_MAIN_THREAD(); + NSString *queryFormat = @"UPDATE %@ " // Table name + @"SET %@ = %d " // column=value + @"WHERE %@ = ?"; // condition + NSString *query = [NSString + stringWithFormat:queryFormat, kTableSyncMessages, column, value ? 1 : 0, kRmqIdColumn]; + sqlite3_stmt *stmt; + + if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &stmt, NULL) != SQLITE_OK) { + _FIRMessagingRmqLogAndExit(stmt, NO); + } + + if (sqlite3_bind_text(stmt, 1, [rmqID UTF8String], (int)[rmqID length], NULL) != SQLITE_OK) { + _FIRMessagingRmqLogAndExit(stmt, NO); + } + + if (sqlite3_step(stmt) != SQLITE_DONE) { + _FIRMessagingRmqLogAndExit(stmt, NO); + } + + sqlite3_finalize(stmt); + return YES; +} + +#pragma mark - Database + +- (NSString *)pathForDatabase { + return [[self class] pathForDatabaseWithName:_databaseName]; +} + ++ (NSString *)pathForDatabaseWithName:(NSString *)databaseName { + NSString *dbNameWithExtension = [NSString stringWithFormat:@"%@.sqlite", databaseName]; + NSArray *paths = + NSSearchPathForDirectoriesInDomains(FIRMessagingSupportedDirectory(), NSUserDomainMask, YES); + NSArray *components = @[ paths.lastObject, kFIRMessagingSubDirectoryName, dbNameWithExtension ]; + return [NSString pathWithComponents:components]; +} + +- (void)createTableWithName:(NSString *)tableName command:(NSString *)command { + FIRMessaging_MUST_NOT_BE_MAIN_THREAD(); + char *error = NULL; + NSString *createDatabase = [NSString stringWithFormat:command, kTablePrefix, tableName]; + if (sqlite3_exec(self->_database, [createDatabase UTF8String], NULL, NULL, &error) != SQLITE_OK) { + // remove db before failing + [self removeDatabase]; + NSString *sqlError; + if (error != NULL) { + sqlError = [NSString stringWithCString:error encoding:NSUTF8StringEncoding]; + sqlite3_free(error); + } else { + sqlError = @"(null)"; + } + NSString *errorMessage = + [NSString stringWithFormat:@"Couldn't create table: %@ with command: %@ error: %@", + kCreateTableOutgoingRmqMessages, createDatabase, sqlError]; + FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStoreErrorCreatingTable, @"%@", + errorMessage); + NSAssert(NO, errorMessage); + } +} + +- (void)dropTableWithName:(NSString *)tableName { + FIRMessaging_MUST_NOT_BE_MAIN_THREAD(); + char *error; + NSString *dropTableSQL = [NSString stringWithFormat:kDropTableCommand, kTablePrefix, tableName]; + if (sqlite3_exec(self->_database, [dropTableSQL UTF8String], NULL, NULL, &error) != SQLITE_OK) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStore002, + @"Failed to remove table %@", tableName); + } +} + +- (void)removeDatabase { + // Ensure database is removed in a sync queue as this sometimes makes test have race conditions. + dispatch_async(_databaseOperationQueue, ^{ + NSString *path = [self pathForDatabase]; + [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + }); +} + +- (void)openDatabase { + dispatch_async(_databaseOperationQueue, ^{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *path = [self pathForDatabase]; + + BOOL didOpenDatabase = YES; + if (![fileManager fileExistsAtPath:path]) { + // We've to separate between different versions here because of backward compatibility issues. + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; +#ifdef SQLITE_OPEN_FILEPROTECTION_NONE + flags |= SQLITE_OPEN_FILEPROTECTION_NONE; +#endif + int result = sqlite3_open_v2([path UTF8String], &self -> _database, flags, NULL); + if (result != SQLITE_OK) { + NSString *errorString = FIRMessagingStringFromSQLiteResult(result); + NSString *errorMessage = [NSString + stringWithFormat:@"Could not open existing RMQ database at path %@, error: %@", path, + errorString]; + FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStoreErrorOpeningDatabase, + @"%@", errorMessage); + NSAssert(NO, errorMessage); + return; + } + [self createTableWithName:kTableOutgoingRmqMessages command:kCreateTableOutgoingRmqMessages]; + + [self createTableWithName:kTableLastRmqId command:kCreateTableLastRmqId]; + [self createTableWithName:kTableS2DRmqIds command:kCreateTableS2DRmqIds]; + } else { + // Calling sqlite3_open should create the database, since the file doesn't exist. + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; +#ifdef SQLITE_OPEN_FILEPROTECTION_NONE + flags |= SQLITE_OPEN_FILEPROTECTION_NONE; +#endif + int result = sqlite3_open_v2([path UTF8String], &self -> _database, flags, NULL); + if (result != SQLITE_OK) { + NSString *errorString = FIRMessagingStringFromSQLiteResult(result); + NSString *errorMessage = + [NSString stringWithFormat:@"Could not create RMQ database at path %@, error: %@", path, + errorString]; + FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStoreErrorCreatingDatabase, + @"%@", errorMessage); + NSAssert(NO, errorMessage); + didOpenDatabase = NO; + } else { + [self updateDBWithStringRmqID]; + } + } + + if (didOpenDatabase) { + [self createTableWithName:kTableSyncMessages command:kCreateTableSyncMessages]; + } + }); +} + +- (void)updateDBWithStringRmqID { + dispatch_async(_databaseOperationQueue, ^{ + [self createTableWithName:kTableS2DRmqIds command:kCreateTableS2DRmqIds]; + [self dropTableWithName:kOldTableS2DRmqIds]; + }); +} + +#pragma mark - Private + +- (BOOL)saveMessageWithRmqId:(int64_t)rmqId tag:(int8_t)tag data:(NSData *)data { + FIRMessaging_MUST_NOT_BE_MAIN_THREAD(); + NSString *insertFormat = @"INSERT INTO %@ (%@, %@, %@) VALUES (?, ?, ?)"; + NSString *insertSQL = + [NSString stringWithFormat:insertFormat, + kTableOutgoingRmqMessages, // table + kRmqIdColumn, kProtobufTagColumn, kDataColumn /* columns */]; + sqlite3_stmt *insert_statement; + if (sqlite3_prepare_v2(self->_database, [insertSQL UTF8String], -1, &insert_statement, NULL) != + SQLITE_OK) { + _FIRMessagingRmqLogAndExit(insert_statement, NO); + } + if (sqlite3_bind_int64(insert_statement, 1, rmqId) != SQLITE_OK) { + _FIRMessagingRmqLogAndExit(insert_statement, NO); + } + if (sqlite3_bind_int(insert_statement, 2, tag) != SQLITE_OK) { + _FIRMessagingRmqLogAndExit(insert_statement, NO); + } + if (sqlite3_bind_blob(insert_statement, 3, [data bytes], (int)[data length], NULL) != SQLITE_OK) { + _FIRMessagingRmqLogAndExit(insert_statement, NO); + } + if (sqlite3_step(insert_statement) != SQLITE_DONE) { + _FIRMessagingRmqLogAndExit(insert_statement, NO); + } + + sqlite3_finalize(insert_statement); + + return YES; +} + +- (void)deleteMessagesFromTable:(NSString *)tableName withRmqIds:(NSArray *)rmqIds { + dispatch_async(_databaseOperationQueue, ^{ + BOOL isRmqIDString = NO; + // RmqID is a string only for outgoing messages + if ([tableName isEqualToString:kTableS2DRmqIds] || + [tableName isEqualToString:kTableSyncMessages]) { + isRmqIDString = YES; + } + + NSMutableString *delete = + [NSMutableString stringWithFormat:@"DELETE FROM %@ WHERE ", tableName]; + + NSString *toDeleteArgument = [NSString stringWithFormat:@"%@ = ? OR ", kRmqIdColumn]; + + int toDelete = (int)[rmqIds count]; + if (toDelete == 0) { + return; + } + int maxBatchSize = 100; + int start = 0; + int deleteCount = 0; + while (start < toDelete) { + // construct the WHERE argument + int end = MIN(start + maxBatchSize, toDelete); + NSMutableString *whereArgument = [NSMutableString string]; + for (int i = start; i < end; i++) { + [whereArgument appendString:toDeleteArgument]; + } + // remove the last * OR * from argument + NSRange range = NSMakeRange([whereArgument length] - 4, 4); + [whereArgument deleteCharactersInRange:range]; + NSString *deleteQuery = [NSString stringWithFormat:@"%@ %@", delete, whereArgument]; + + // sqlite update + sqlite3_stmt *delete_statement; + if (sqlite3_prepare_v2(self->_database, [deleteQuery UTF8String], -1, &delete_statement, + NULL) != SQLITE_OK) { + FIRMessagingRmqLogAndReturn(delete_statement); + } + + // bind values + int rmqIndex = 0; + int placeholderIndex = 1; // placeholders in sqlite3 start with 1 + for (NSString *rmqId in rmqIds) { // objectAtIndex: is O(n) -- would make it slow + if (rmqIndex < start) { + rmqIndex++; + continue; + } else if (rmqIndex >= end) { + break; + } else { + if (isRmqIDString) { + if (sqlite3_bind_text(delete_statement, placeholderIndex, [rmqId UTF8String], + (int)[rmqId length], SQLITE_STATIC) != SQLITE_OK) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeRmq2PersistentStore003, + @"Failed to bind rmqID %@", rmqId); + FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager007, + @"Failed to delete sync message %@", rmqId); + continue; + } + } else { + int64_t rmqIdValue = [rmqId longLongValue]; + sqlite3_bind_int64(delete_statement, placeholderIndex, rmqIdValue); + } + placeholderIndex++; + } + rmqIndex++; + FIRMessagingLoggerInfo(kFIRMessagingMessageCodeSyncMessageManager008, + @"Successfully deleted sync message from cache %@", rmqId); + } + if (sqlite3_step(delete_statement) != SQLITE_DONE) { + FIRMessagingRmqLogAndReturn(delete_statement); + } + sqlite3_finalize(delete_statement); + deleteCount += sqlite3_changes(self->_database); + start = end; + } + + // if we are here all of our sqlite queries should have succeeded + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeRmq2PersistentStore004, + @"Trying to delete %d s2D ID's, successfully deleted %d", toDelete, + deleteCount); + }); +} + +- (int64_t)nextRmqId { + return ++self.rmqId; +} + +- (NSString *)lastErrorMessage { + return [NSString stringWithFormat:@"%s", sqlite3_errmsg(_database)]; +} + +- (int)lastErrorCode { + return sqlite3_errcode(_database); +} + +- (void)logError { + FIRMessagingLoggerError(kFIRMessagingMessageCodeRmq2PersistentStore006, + @"Error: code (%d) message: %@", [self lastErrorCode], + [self lastErrorMessage]); +} + +- (void)logErrorAndFinalizeStatement:(sqlite3_stmt *)stmt { + [self logError]; + sqlite3_finalize(stmt); +} + +- (dispatch_queue_t)databaseOperationQueue { + return _databaseOperationQueue; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.h new file mode 100644 index 0000000..96d15b3 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.h @@ -0,0 +1,50 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRMessagingRmqManager; + +/** + * Handle sync messages being received via APNS. + */ +@interface FIRMessagingSyncMessageManager : NSObject + +/** + * Initialize sync message manager. + * + * @param rmqManager The RMQ manager on the client. + * + * @return Sync message manager. + */ +- (instancetype)initWithRmqManager:(FIRMessagingRmqManager *)rmqManager; + +/** + * Remove expired sync message from persistent store. Also removes messages that have + * been received via APNS. + */ +- (void)removeExpiredSyncMessages; + +/** + * App did receive a sync message via APNS. + * + * @param message The sync message received. + * + * @return YES if the message is a duplicate of an already received sync message else NO. + */ +- (BOOL)didReceiveAPNSSyncMessage:(NSDictionary *)message; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.m new file mode 100644 index 0000000..925f701 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.m @@ -0,0 +1,87 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.h" + +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.h" +#import "FirebaseMessaging/Sources/FIRMessagingRmqManager.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" + +static const int64_t kDefaultSyncMessageTTL = 4 * 7 * 24 * 60 * 60; // 4 weeks + +@interface FIRMessagingSyncMessageManager () + +@property(nonatomic, readwrite, strong) FIRMessagingRmqManager *rmqManager; + +@end + +@implementation FIRMessagingSyncMessageManager + +- (instancetype)init { + FIRMessagingInvalidateInitializer(); +} + +- (instancetype)initWithRmqManager:(FIRMessagingRmqManager *)rmqManager { + self = [super init]; + if (self) { + _rmqManager = rmqManager; + } + return self; +} + +- (void)removeExpiredSyncMessages { + [self.rmqManager deleteExpiredOrFinishedSyncMessages]; +} + +- (BOOL)didReceiveAPNSSyncMessage:(NSDictionary *)message { + NSString *rmqID = message[kFIRMessagingMessageIDKey]; + if (![rmqID length]) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeSyncMessageManager002, + @"Invalid nil rmqID for sync message."); + return NO; + } + + FIRMessagingPersistentSyncMessage *persistentMessage = + [self.rmqManager querySyncMessageWithRmqID:rmqID]; + + if (!persistentMessage) { + int64_t expirationTime = [[self class] expirationTimeForSyncMessage:message]; + [self.rmqManager saveSyncMessageWithRmqID:rmqID expirationTime:expirationTime]; + return NO; + } + + if (!persistentMessage.apnsReceived) { + persistentMessage.apnsReceived = YES; + [self.rmqManager updateSyncMessageViaAPNSWithRmqID:rmqID]; + } + + // Already received this message either via MCS or APNS. + return YES; +} + ++ (int64_t)expirationTimeForSyncMessage:(NSDictionary *)message { + int64_t ttl = kDefaultSyncMessageTTL; + if (message[kFIRMessagingMessageSyncMessageTTLKey]) { + ttl = [message[kFIRMessagingMessageSyncMessageTTLKey] longLongValue]; + } + int64_t currentTime = FIRMessagingCurrentTimestampInSeconds(); + return currentTime + ttl; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingTopicOperation.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingTopicOperation.h new file mode 100644 index 0000000..9321c6f --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingTopicOperation.h @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" + +#import "FirebaseMessaging/Sources/FIRMessagingTopicsCommon.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRMessagingTokenManager; + +/** + * An asynchronous NSOperation subclass which performs a single network request for a topic + * subscription operation. Once completed, it calls its provided completion handler. + */ +@interface FIRMessagingTopicOperation : NSOperation + +@property(nonatomic, readonly, copy) NSString *topic; +@property(nonatomic, readonly, assign) FIRMessagingTopicAction action; +@property(nonatomic, readonly, copy) NSString *token; +@property(nonatomic, readonly, copy, nullable) NSDictionary *options; + +- (instancetype)initWithTopic:(NSString *)topic + action:(FIRMessagingTopicAction)action + tokenManager:(FIRMessagingTokenManager *)tokenManager + options:(nullable NSDictionary *)options + completion:(FIRMessagingTopicOperationCompletion)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingTopicOperation.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingTopicOperation.m new file mode 100644 index 0000000..56da806 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingTopicOperation.m @@ -0,0 +1,245 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingTopicOperation.h" + +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.h" + +static NSString *const kFIRMessagingSubscribeServerHost = + @"https://iid.googleapis.com/iid/register"; + +NSString *FIRMessagingSubscriptionsServer(void) { + static NSString *serverHost = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSDictionary *environment = [[NSProcessInfo processInfo] environment]; + NSString *customServerHost = environment[@"FCM_SERVER_ENDPOINT"]; + if (customServerHost.length) { + serverHost = customServerHost; + } else { + serverHost = kFIRMessagingSubscribeServerHost; + } + }); + return serverHost; +} + +@interface FIRMessagingTopicOperation () { + BOOL _isFinished; + BOOL _isExecuting; +} + +@property(nonatomic, readwrite, copy) NSString *topic; +@property(nonatomic, readwrite, assign) FIRMessagingTopicAction action; +@property(nonatomic, readwrite, strong) FIRMessagingTokenManager *tokenManager; +@property(nonatomic, readwrite, copy) NSDictionary *options; +@property(nonatomic, readwrite, copy) FIRMessagingTopicOperationCompletion completion; + +@property(atomic, strong) NSURLSessionDataTask *dataTask; + +@end + +@implementation FIRMessagingTopicOperation + ++ (NSURLSession *)sharedSession { + static NSURLSession *subscriptionOperationSharedSession; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; + config.timeoutIntervalForResource = 60.0f; // 1 minute + subscriptionOperationSharedSession = [NSURLSession sessionWithConfiguration:config]; + subscriptionOperationSharedSession.sessionDescription = @"com.google.fcm.topics.session"; + }); + return subscriptionOperationSharedSession; +} + +- (instancetype)initWithTopic:(NSString *)topic + action:(FIRMessagingTopicAction)action + tokenManager:(FIRMessagingTokenManager *)tokenManager + options:(NSDictionary *)options + completion:(FIRMessagingTopicOperationCompletion)completion { + if (self = [super init]) { + _topic = topic; + _action = action; + _tokenManager = tokenManager; + _options = options; + _completion = completion; + + _isExecuting = NO; + _isFinished = NO; + } + return self; +} + +- (void)dealloc { + _topic = nil; + _completion = nil; +} + +- (BOOL)isAsynchronous { + return YES; +} + +- (BOOL)isExecuting { + return _isExecuting; +} + +- (void)setExecuting:(BOOL)executing { + [self willChangeValueForKey:@"isExecuting"]; + _isExecuting = executing; + [self didChangeValueForKey:@"isExecuting"]; +} + +- (BOOL)isFinished { + return _isFinished; +} + +- (void)setFinished:(BOOL)finished { + [self willChangeValueForKey:@"isFinished"]; + _isFinished = finished; + [self didChangeValueForKey:@"isFinished"]; +} + +- (void)start { + if (self.isCancelled) { + NSError *error = [NSError + messagingErrorWithCode:kFIRMessagingErrorCodePubSubOperationIsCancelled + failureReason: + @"Failed to start the pubsub service as the topic operation is cancelled."]; + [self finishWithError:error]; + return; + } + + [self setExecuting:YES]; + + [self performSubscriptionChange]; +} + +- (void)finishWithError:(NSError *)error { + // Add a check to prevent this finish from being called more than once. + if (self.isFinished) { + return; + } + self.dataTask = nil; + if (self.completion) { + self.completion(error); + } + + [self setExecuting:NO]; + [self setFinished:YES]; +} + +- (void)cancel { + [super cancel]; + [self.dataTask cancel]; + NSError *error = [NSError messagingErrorWithCode:kFIRMessagingErrorCodePubSubOperationIsCancelled + failureReason:@"The topic operation is cancelled."]; + [self finishWithError:error]; +} + +- (void)performSubscriptionChange { + NSURL *url = [NSURL URLWithString:FIRMessagingSubscriptionsServer()]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + NSString *appIdentifier = FIRMessagingAppIdentifier(); + NSString *authString = [NSString + stringWithFormat:@"AidLogin %@:%@", _tokenManager.deviceAuthID, _tokenManager.secretToken]; + [request setValue:authString forHTTPHeaderField:@"Authorization"]; + [request setValue:appIdentifier forHTTPHeaderField:@"app"]; + [request setValue:_tokenManager.versionInfo forHTTPHeaderField:@"info"]; + // Topic can contain special characters (like `%`) so encode the value. + NSCharacterSet *characterSet = [NSCharacterSet URLQueryAllowedCharacterSet]; + NSString *encodedTopic = + [self.topic stringByAddingPercentEncodingWithAllowedCharacters:characterSet]; + if (encodedTopic == nil) { + // The transformation was somehow not possible, so use the original topic. + FIRMessagingLoggerWarn(kFIRMessagingMessageCodeTopicOptionTopicEncodingFailed, + @"Unable to encode the topic '%@' during topic subscription change. " + @"Please ensure that the topic name contains only valid characters.", + self.topic); + encodedTopic = self.topic; + } + + NSMutableString *content = [NSMutableString + stringWithFormat:@"sender=%@&app=%@&device=%@&" + @"app_ver=%@&X-gcm.topic=%@&X-scope=%@", + _tokenManager.defaultFCMToken, appIdentifier, _tokenManager.deviceAuthID, + FIRMessagingCurrentAppVersion(), encodedTopic, encodedTopic]; + + if (self.action == FIRMessagingTopicActionUnsubscribe) { + [content appendString:@"&delete=true"]; + } + + FIRMessagingLoggerInfo(kFIRMessagingMessageCodeTopicOption000, @"Topic subscription request: %@", + content); + + request.HTTPBody = [content dataUsingEncoding:NSUTF8StringEncoding]; + [request setHTTPMethod:@"POST"]; + + FIRMessaging_WEAKIFY(self) void (^requestHandler)(NSData *, NSURLResponse *, NSError *) = + ^(NSData *data, NSURLResponse *URLResponse, NSError *error) { + FIRMessaging_STRONGIFY(self) if (error) { + // Our operation could have been cancelled, which would result in our data task's error + // being NSURLErrorCancelled + if (error.code == NSURLErrorCancelled) { + // We would only have been cancelled in the -cancel method, which will call finish for + // us so just return and do nothing. + return; + } + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTopicOption001, + @"Device registration HTTP fetch error. Error Code: %ld", + (long)error.code); + [self finishWithError:error]; + return; + } + NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (response.length == 0) { + NSString *failureReason = @"Invalid registration response - zero length."; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTopicOperationEmptyResponse, @"%@", + failureReason); + [self finishWithError:[NSError messagingErrorWithCode:kFIRMessagingErrorCodeUnknown + failureReason:failureReason]]; + return; + } + NSArray *parts = [response componentsSeparatedByString:@"="]; + if (![parts[0] isEqualToString:@"token"] || parts.count <= 1) { + NSString *failureReason = [NSString + stringWithFormat:@"Invalid registration response :'%@'. It is missing 'token' field.", + response]; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTopicOption002, @"%@", failureReason); + [self finishWithError:[NSError messagingErrorWithCode:kFIRMessagingErrorCodeUnknown + failureReason:failureReason]]; + return; + } + [self finishWithError:nil]; + }; + + NSURLSession *urlSession = [FIRMessagingTopicOperation sharedSession]; + + self.dataTask = [urlSession dataTaskWithRequest:request completionHandler:requestHandler]; + NSString *description; + if (_action == FIRMessagingTopicActionSubscribe) { + description = [NSString stringWithFormat:@"com.google.fcm.topics.subscribe: %@", _topic]; + } else { + description = [NSString stringWithFormat:@"com.google.fcm.topics.unsubscribe: %@", _topic]; + } + self.dataTask.taskDescription = description; + [self.dataTask resume]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingTopicsCommon.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingTopicsCommon.h new file mode 100644 index 0000000..030b3ff --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingTopicsCommon.h @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Represents the action taken on a subscription topic. + */ +typedef NS_ENUM(NSInteger, FIRMessagingTopicAction) { + FIRMessagingTopicActionSubscribe, + FIRMessagingTopicActionUnsubscribe +}; + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingUtilities.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingUtilities.h new file mode 100644 index 0000000..f2b10d9 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingUtilities.h @@ -0,0 +1,49 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#pragma mark - URL Helpers + +FOUNDATION_EXPORT NSString *FIRMessagingTokenRegisterServer(void); + +#pragma mark - Time + +FOUNDATION_EXPORT int64_t FIRMessagingCurrentTimestampInSeconds(void); +FOUNDATION_EXPORT int64_t FIRMessagingCurrentTimestampInMilliseconds(void); + +#pragma mark - App Info + +FOUNDATION_EXPORT NSString *FIRMessagingCurrentAppVersion(void); +FOUNDATION_EXPORT NSString *FIRMessagingAppIdentifier(void); +FOUNDATION_EXPORT NSString *FIRMessagingFirebaseAppID(void); +FOUNDATION_EXPORT BOOL FIRMessagingIsWatchKitExtension(void); + +#pragma mark - Others + +FOUNDATION_EXPORT NSSearchPathDirectory FIRMessagingSupportedDirectory(void); + +#pragma mark - Device Info +FOUNDATION_EXPORT NSString *FIRMessagingCurrentLocale(void); +FOUNDATION_EXPORT BOOL FIRMessagingHasLocaleChanged(void); +/// locale key stored in GULUserDefaults +FOUNDATION_EXPORT NSString *const kFIRMessagingInstanceIDUserDefaultsKeyLocale; + +FOUNDATION_EXPORT NSString *FIRMessagingStringForAPNSDeviceToken(NSData *deviceToken); +FOUNDATION_EXPORT NSString *FIRMessagingAPNSTupleStringForTokenAndServerType(NSData *deviceToken, + BOOL isSandbox); + +FOUNDATION_EXPORT BOOL FIRMessagingIsSandboxApp(void); diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingUtilities.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingUtilities.m new file mode 100644 index 0000000..70939e7 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessagingUtilities.m @@ -0,0 +1,428 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" + +#import +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" + +NSString *const kFIRMessagingInstanceIDUserDefaultsKeyLocale = + @"com.firebase.instanceid.user_defaults.locale"; // locale key stored in GULUserDefaults +static NSString *const kFIRMessagingAPNSSandboxPrefix = @"s_"; +static NSString *const kFIRMessagingAPNSProdPrefix = @"p_"; + +static NSString *const kFIRMessagingWatchKitExtensionPoint = @"com.apple.watchkit"; + +#if TARGET_OS_OSX +// macOS uses a different entitlement key than the rest of Apple's platforms: +// https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_aps-environment +static NSString *const kEntitlementsAPSEnvironmentKey = + @"Entitlements.com.apple.developer.aps-environment"; +#else +// Entitlement key for all non-macOS platforms: +// https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment +static NSString *const kEntitlementsAPSEnvironmentKey = @"Entitlements.aps-environment"; +#endif // TARGET_OS_OSX +static NSString *const kAPSEnvironmentDevelopmentValue = @"development"; + +#pragma mark - URL Helpers + +NSString *FIRMessagingTokenRegisterServer(void) { + return @"https://fcmtoken.googleapis.com/register"; +} + +#pragma mark - Time + +int64_t FIRMessagingCurrentTimestampInSeconds(void) { + return (int64_t)[[NSDate date] timeIntervalSince1970]; +} + +int64_t FIRMessagingCurrentTimestampInMilliseconds(void) { + return (int64_t)(FIRMessagingCurrentTimestampInSeconds() * 1000.0); +} + +#pragma mark - App Info + +NSString *FIRMessagingCurrentAppVersion(void) { + NSString *version = [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"]; + if (![version length]) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeUtilities000, + @"Could not find current app version"); + return @""; + } + return version; +} + +NSString *FIRMessagingBundleIDByRemovingLastPartFrom(NSString *bundleID) { + NSString *bundleIDComponentsSeparator = @"."; + + NSMutableArray *bundleIDComponents = + [[bundleID componentsSeparatedByString:bundleIDComponentsSeparator] mutableCopy]; + [bundleIDComponents removeLastObject]; + + return [bundleIDComponents componentsJoinedByString:bundleIDComponentsSeparator]; +} + +NSString *FIRMessagingAppIdentifier(void) { + NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; +#if TARGET_OS_WATCH + if (FIRMessagingIsWatchKitExtension()) { + // The code is running in watchKit extension target but the actually bundleID is in the watchKit + // target. So we need to remove the last part of the bundle ID in watchKit extension to match + // the one in watchKit target. + return FIRMessagingBundleIDByRemovingLastPartFrom(bundleID); + } else { + return bundleID; + } +#else // TARGET_OS_WATCH + return bundleID; +#endif // TARGET_OS_WATCH +} + +NSString *FIRMessagingFirebaseAppID(void) { + return [FIROptions defaultOptions].googleAppID; +} + +BOOL FIRMessagingIsWatchKitExtension(void) { +#if TARGET_OS_WATCH + NSDictionary *infoDict = [[NSBundle mainBundle] infoDictionary]; + NSDictionary *extensionAttrDict = infoDict[@"NSExtension"]; + if (!extensionAttrDict) { + return NO; + } + + NSString *extensionPointId = extensionAttrDict[@"NSExtensionPointIdentifier"]; + if (extensionPointId) { + return [extensionPointId isEqualToString:kFIRMessagingWatchKitExtensionPoint]; + } else { + return NO; + } +#else // TARGET_OS_WATCH + return NO; +#endif // TARGET_OS_WATCH +} + +NSSearchPathDirectory FIRMessagingSupportedDirectory(void) { +#if TARGET_OS_TV + return NSCachesDirectory; +#else // TARGET_OS_TV + return NSApplicationSupportDirectory; +#endif // TARGET_OS_TV +} + +#pragma mark - Locales + +NSDictionary *FIRMessagingFirebaselocalesMap(void) { + return @{ + // Albanian + @"sq" : @[ @"sq_AL" ], + // Belarusian + @"be" : @[ @"be_BY" ], + // Bulgarian + @"bg" : @[ @"bg_BG" ], + // Catalan + @"ca" : @[ @"ca", @"ca_ES" ], + // Croatian + @"hr" : @[ @"hr", @"hr_HR" ], + // Czech + @"cs" : @[ @"cs", @"cs_CZ" ], + // Danish + @"da" : @[ @"da", @"da_DK" ], + // Estonian + @"et" : @[ @"et_EE" ], + // Finnish + @"fi" : @[ @"fi", @"fi_FI" ], + // Hebrew + @"he" : @[ @"he", @"iw_IL" ], + // Hindi + @"hi" : @[ @"hi_IN" ], + // Hungarian + @"hu" : @[ @"hu", @"hu_HU" ], + // Icelandic + @"is" : @[ @"is_IS" ], + // Indonesian + @"id" : @[ @"id", @"in_ID", @"id_ID" ], + // Irish + @"ga" : @[ @"ga_IE" ], + // Korean + @"ko" : @[ @"ko", @"ko_KR", @"ko-KR" ], + // Latvian + @"lv" : @[ @"lv_LV" ], + // Lithuanian + @"lt" : @[ @"lt_LT" ], + // Macedonian + @"mk" : @[ @"mk_MK" ], + // Malay + @"ms" : @[ @"ms_MY" ], + // Maltese + @"mt" : @[ @"mt_MT" ], + // Polish + @"pl" : @[ @"pl", @"pl_PL", @"pl-PL" ], + // Romanian + @"ro" : @[ @"ro", @"ro_RO" ], + // Russian + @"ru" : @[ @"ru_RU", @"ru", @"ru_BY", @"ru_KZ", @"ru-RU" ], + // Slovak + @"sk" : @[ @"sk", @"sk_SK" ], + // Slovenian + @"sl" : @[ @"sl_SI" ], + // Swedish + @"sv" : @[ @"sv", @"sv_SE", @"sv-SE" ], + // Turkish + @"tr" : @[ @"tr", @"tr-TR", @"tr_TR" ], + // Ukrainian + @"uk" : @[ @"uk", @"uk_UA" ], + // Vietnamese + @"vi" : @[ @"vi", @"vi_VN" ], + // The following are groups of locales or locales that sub-divide a + // language). + // Arabic + @"ar" : @[ + @"ar", @"ar_DZ", @"ar_BH", @"ar_EG", @"ar_IQ", @"ar_JO", @"ar_KW", + @"ar_LB", @"ar_LY", @"ar_MA", @"ar_OM", @"ar_QA", @"ar_SA", @"ar_SD", + @"ar_SY", @"ar_TN", @"ar_AE", @"ar_YE", @"ar_GB", @"ar-IQ", @"ar_US" + ], + // Simplified Chinese + @"zh_Hans" : @[ @"zh_CN", @"zh_SG", @"zh-Hans" ], + // Traditional Chinese + @"zh_Hant" : @[ @"zh_HK", @"zh_TW", @"zh-Hant", @"zh-HK", @"zh-TW" ], + // Dutch + @"nl" : @[ @"nl", @"nl_BE", @"nl_NL", @"nl-NL" ], + // English + @"en" : @[ + @"en", @"en_AU", @"en_CA", @"en_IN", @"en_IE", @"en_MT", @"en_NZ", @"en_PH", + @"en_SG", @"en_ZA", @"en_GB", @"en_US", @"en_AE", @"en-AE", @"en_AS", @"en-AU", + @"en_BD", @"en-CA", @"en_EG", @"en_ES", @"en_GB", @"en-GB", @"en_HK", @"en_ID", + @"en-IN", @"en_NG", @"en-PH", @"en_PK", @"en-SG", @"en-US" + ], + // French + + @"fr" : + @[ @"fr", @"fr_BE", @"fr_CA", @"fr_FR", @"fr_LU", @"fr_CH", @"fr-CA", @"fr-FR", @"fr_MA" ], + // German + @"de" : @[ @"de", @"de_AT", @"de_DE", @"de_LU", @"de_CH", @"de-DE" ], + // Greek + @"el" : @[ @"el", @"el_CY", @"el_GR" ], + // Italian + @"it" : @[ @"it", @"it_IT", @"it_CH", @"it-IT" ], + // Japanese + @"ja" : @[ @"ja", @"ja_JP", @"ja_JP_JP", @"ja-JP" ], + // Norwegian + @"no" : @[ @"nb", @"no_NO", @"no_NO_NY", @"nb_NO" ], + // Brazilian Portuguese + @"pt_BR" : @[ @"pt_BR", @"pt-BR" ], + // European Portuguese + @"pt_PT" : @[ @"pt", @"pt_PT", @"pt-PT" ], + // Serbian + @"sr" : @[ @"sr_BA", @"sr_ME", @"sr_RS", @"sr_Latn_BA", @"sr_Latn_ME", @"sr_Latn_RS" ], + // European Spanish + @"es_ES" : @[ @"es", @"es_ES", @"es-ES" ], + // Mexican Spanish + @"es_MX" : @[ @"es-MX", @"es_MX", @"es_US", @"es-US" ], + // Latin American Spanish + @"es_419" : @[ + @"es_AR", @"es_BO", @"es_CL", @"es_CO", @"es_CR", @"es_DO", @"es_EC", + @"es_SV", @"es_GT", @"es_HN", @"es_NI", @"es_PA", @"es_PY", @"es_PE", + @"es_PR", @"es_UY", @"es_VE", @"es-AR", @"es-CL", @"es-CO" + ], + // Thai + @"th" : @[ @"th", @"th_TH", @"th_TH_TH" ], + }; +} + +NSArray *FIRMessagingFirebaseLocales(void) { + NSMutableArray *locales = [NSMutableArray array]; + NSDictionary *localesMap = FIRMessagingFirebaselocalesMap(); + for (NSString *key in localesMap) { + [locales addObjectsFromArray:localesMap[key]]; + } + return locales; +} + +NSString *FIRMessagingCurrentLocale(void) { + NSArray *locales = FIRMessagingFirebaseLocales(); + NSArray *preferredLocalizations = + [NSBundle preferredLocalizationsFromArray:locales + forPreferences:[NSLocale preferredLanguages]]; + NSString *legalDocsLanguage = [preferredLocalizations firstObject]; + // Use en as the default language + return legalDocsLanguage ? legalDocsLanguage : @"en"; +} + +BOOL FIRMessagingHasLocaleChanged(void) { + NSString *lastLocale = [[GULUserDefaults standardUserDefaults] + stringForKey:kFIRMessagingInstanceIDUserDefaultsKeyLocale]; + NSString *currentLocale = FIRMessagingCurrentLocale(); + if (lastLocale) { + if ([currentLocale isEqualToString:lastLocale]) { + return NO; + } + } + return YES; +} + +NSString *FIRMessagingStringForAPNSDeviceToken(NSData *deviceToken) { + NSMutableString *APNSToken = [NSMutableString string]; + unsigned char *bytes = (unsigned char *)[deviceToken bytes]; + for (int i = 0; i < (int)deviceToken.length; i++) { + [APNSToken appendFormat:@"%02x", bytes[i]]; + } + return APNSToken; +} + +NSString *FIRMessagingAPNSTupleStringForTokenAndServerType(NSData *deviceToken, BOOL isSandbox) { + if (deviceToken == nil) { + // A nil deviceToken leads to an invalid tuple string, so return nil. + return nil; + } + NSString *prefix = isSandbox ? kFIRMessagingAPNSSandboxPrefix : kFIRMessagingAPNSProdPrefix; + NSString *APNSString = FIRMessagingStringForAPNSDeviceToken(deviceToken); + NSString *APNSTupleString = [NSString stringWithFormat:@"%@%@", prefix, APNSString]; + + return APNSTupleString; +} + +BOOL FIRMessagingIsProductionApp(void) { + const BOOL defaultAppTypeProd = YES; + + NSError *error = nil; + if ([GULAppEnvironmentUtil isSimulator]) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeInstanceID014, + @"Running InstanceID on a simulator doesn't have APNS. " + @"Use prod profile by default."); + return defaultAppTypeProd; + } + + if ([GULAppEnvironmentUtil isFromAppStore]) { + // Apps distributed via AppStore or TestFlight use the Production APNS certificates. + return defaultAppTypeProd; + } +#if TARGET_OS_OSX || TARGET_OS_MACCATALYST + NSString *path = [[[[NSBundle mainBundle] resourcePath] stringByDeletingLastPathComponent] + stringByAppendingPathComponent:@"embedded.provisionprofile"]; +#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST + NSString *path = [[[NSBundle mainBundle] bundlePath] + stringByAppendingPathComponent:@"embedded.mobileprovision"]; +#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST + + if ([GULAppEnvironmentUtil isAppStoreReceiptSandbox] && !path.length) { + // Distributed via TestFlight + return defaultAppTypeProd; + } + + NSMutableData *profileData = [NSMutableData dataWithContentsOfFile:path options:0 error:&error]; + + if (!profileData.length || error) { + NSString *errorString = + [NSString stringWithFormat:@"Error while reading embedded mobileprovision %@", error]; + FIRMessagingLoggerError(kFIRMessagingMessageCodeInstanceID014, @"%@", errorString); + return defaultAppTypeProd; + } + + // The "embedded.mobileprovision" sometimes contains characters with value 0, which signals the + // end of a c-string and halts the ASCII parser, or with value > 127, which violates strict 7-bit + // ASCII. Replace any 0s or invalid characters in the input. + uint8_t *profileBytes = (uint8_t *)profileData.bytes; + for (int i = 0; i < profileData.length; i++) { + uint8_t currentByte = profileBytes[i]; + if (!currentByte || currentByte > 127) { + profileBytes[i] = '.'; + } + } + + NSString *embeddedProfile = [[NSString alloc] initWithBytesNoCopy:profileBytes + length:profileData.length + encoding:NSASCIIStringEncoding + freeWhenDone:NO]; + + if (error || !embeddedProfile.length) { + NSString *errorString = + [NSString stringWithFormat:@"Error while reading embedded mobileprovision %@", error]; + FIRMessagingLoggerError(kFIRMessagingMessageCodeInstanceID014, @"%@", errorString); + return defaultAppTypeProd; + } + + NSScanner *scanner = [NSScanner scannerWithString:embeddedProfile]; + NSString *plistContents; + if ([scanner scanUpToString:@"" intoString:&plistContents]) { + plistContents = [plistContents stringByAppendingString:@""]; + } + } + + if (!plistContents.length) { + return defaultAppTypeProd; + } + + NSData *data = [plistContents dataUsingEncoding:NSUTF8StringEncoding]; + if (!data.length) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeInstanceID014, + @"Couldn't read plist fetched from embedded mobileprovision"); + return defaultAppTypeProd; + } + + NSError *plistMapError; + id plistData = [NSPropertyListSerialization propertyListWithData:data + options:NSPropertyListImmutable + format:nil + error:&plistMapError]; + if (plistMapError || ![plistData isKindOfClass:[NSDictionary class]]) { + NSString *errorString = + [NSString stringWithFormat:@"Error while converting assumed plist to dict %@", + plistMapError.localizedDescription]; + FIRMessagingLoggerError(kFIRMessagingMessageCodeInstanceID014, @"%@", errorString); + return defaultAppTypeProd; + } + NSDictionary *plistMap = (NSDictionary *)plistData; + + if ([plistMap valueForKeyPath:@"ProvisionedDevices"]) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeInstanceID012, + @"Provisioning profile has specifically provisioned devices, " + @"most likely a Dev profile."); + } + + NSString *apsEnvironment = [plistMap valueForKeyPath:kEntitlementsAPSEnvironmentKey]; + NSString *debugString __unused = + [NSString stringWithFormat:@"APNS Environment in profile: %@", apsEnvironment]; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeInstanceID013, @"%@", debugString); + + // No aps-environment in the profile. + if (!apsEnvironment.length) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeInstanceID014, + @"No aps-environment set. If testing on a device APNS is not " + @"correctly configured. Please recheck your provisioning " + @"profiles. If testing on a simulator this is fine since APNS " + @"doesn't work on the simulator."); + return defaultAppTypeProd; + } + + if ([apsEnvironment isEqualToString:kAPSEnvironmentDevelopmentValue]) { + return NO; + } + + return defaultAppTypeProd; +} + +BOOL FIRMessagingIsSandboxApp(void) { + static BOOL isSandboxApp = YES; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + isSandboxApp = !FIRMessagingIsProductionApp(); + }); + return isSandboxApp; +} diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessaging_Private.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessaging_Private.h new file mode 100644 index 0000000..721433a --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FIRMessaging_Private.h @@ -0,0 +1,43 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" + +@class FIRMessagingClient; +@class FIRMessagingPubSub; + +typedef NS_ENUM(int8_t, FIRMessagingNetworkStatus) { + kFIRMessagingReachabilityNotReachable = 0, + kFIRMessagingReachabilityReachableViaWiFi, + kFIRMessagingReachabilityReachableViaWWAN, +}; + +FOUNDATION_EXPORT NSString *const kFIRMessagingPlistAutoInitEnabled; +FOUNDATION_EXPORT NSString *const kFIRMessagingUserDefaultsKeyAutoInitEnabled; +FOUNDATION_EXPORT NSString *const kFIRMessagingUserDefaultsKeyUseMessagingDelegate; +FOUNDATION_EXPORT NSString *const kFIRMessagingPlistUseMessagingDelegate; + +@interface FIRMessaging () + +#pragma mark - Private API + +- (FIRMessagingPubSub *)pubsub; + +- (BOOL)isNetworkAvailable; +- (FIRMessagingNetworkStatus)networkType; ++ (NSString *)FIRMessagingSDKVersion; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FirebaseMessaging.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FirebaseMessaging.h new file mode 100644 index 0000000..1b48f4b --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/FirebaseMessaging.h @@ -0,0 +1,17 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSDictionary+FIRMessaging.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSDictionary+FIRMessaging.h new file mode 100644 index 0000000..fe14451 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSDictionary+FIRMessaging.h @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@interface NSDictionary (FIRMessaging) + +/** + * Returns a string representation for the given dictionary. Assumes that all + * keys and values are strings. + * + * @return A string representation of all keys and values in the dictionary. + * The returned string is not pretty-printed. + */ +- (NSString *)fcm_string; + +/** + * Check if the dictionary has any non-string keys or values. + * + * @return YES if the dictionary has any non-string keys or values else NO. + */ +- (BOOL)fcm_hasNonStringKeysOrValues; + +/** + * Trims all (key, value) pair in a dictionary that are not strings. + * + * @return A new copied dictionary with all the non-string keys or values + * removed from the original dictionary. + */ +- (NSDictionary *)fcm_trimNonStringValues; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSDictionary+FIRMessaging.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSDictionary+FIRMessaging.m new file mode 100644 index 0000000..d9f9450 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSDictionary+FIRMessaging.m @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/NSDictionary+FIRMessaging.h" + +@implementation NSDictionary (FIRMessaging) + +- (NSString *)fcm_string { + NSMutableString *dictAsString = [NSMutableString string]; + NSString *separator = @"|"; + for (id key in self) { + id value = self[key]; + if ([key isKindOfClass:[NSString class]] && [value isKindOfClass:[NSString class]]) { + [dictAsString appendFormat:@"%@:%@%@", key, value, separator]; + } + } + // remove the last separator + if ([dictAsString length]) { + [dictAsString deleteCharactersInRange:NSMakeRange(dictAsString.length - 1, 1)]; + } + return [dictAsString copy]; +} + +- (BOOL)fcm_hasNonStringKeysOrValues { + for (id key in self) { + id value = self[key]; + if (![key isKindOfClass:[NSString class]] || ![value isKindOfClass:[NSString class]]) { + return YES; + } + } + return NO; +} + +- (NSDictionary *)fcm_trimNonStringValues { + NSMutableDictionary *trimDictionary = [NSMutableDictionary dictionaryWithCapacity:self.count]; + for (id key in self) { + id value = self[key]; + if ([key isKindOfClass:[NSString class]] && [value isKindOfClass:[NSString class]]) { + trimDictionary[(NSString *)key] = value; + } + } + return trimDictionary; +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void FIRInclude_NSDictionary_FIRMessaging_Category(void) { +} diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSError+FIRMessaging.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSError+FIRMessaging.h new file mode 100644 index 0000000..0e10144 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSError+FIRMessaging.h @@ -0,0 +1,61 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +// FIRMessaging Internal Error Code +typedef NS_ENUM(NSUInteger, FIRMessagingErrorCode) { + kFIRMessagingErrorCodeUnknown = 0, + kFIRMessagingErrorCodeInternal = 1, + + kFIRMessagingErrorCodeNetwork = 4, + + // Failed to perform device check in. + kFIRMessagingErrorCodeRegistrarFailedToCheckIn = 6, + + kFIRMessagingErrorCodeInvalidRequest = 7, + + kFIRMessagingErrorCodeInvalidTopicName = 8, + + // FIRMessaging generic errors + kFIRMessagingErrorCodeMissingDeviceID = 501, + kFIRMessagingErrorCodeMissingAuthorizedEntity = 502, + kFIRMessagingErrorCodeMissingScope = 503, + kFIRMessagingErrorCodeMissingFid = 504, + kFIRMessagingErrorCodeMissingDeviceToken = 505, + + // Upstream send errors + kFIRMessagingErrorCodeServiceNotAvailable = 1001, + kFIRMessagingErrorCodeMissingTo = 1003, + kFIRMessagingErrorCodeSave = 1004, + kFIRMessagingErrorCodeSizeExceeded = 1005, + + kFIRMessagingErrorCodeInvalidIdentity = 2001, + + // PubSub errors + kFIRMessagingErrorCodePubSubOperationIsCancelled = 3005, +}; + +@interface NSError (FIRMessaging) + ++ (NSError *)messagingErrorWithCode:(FIRMessagingErrorCode)fcmErrorCode + failureReason:(NSString *)failureReason; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSError+FIRMessaging.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSError+FIRMessaging.m new file mode 100644 index 0000000..dcd1ecf --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/NSError+FIRMessaging.m @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" + +@implementation NSError (FIRMessaging) + ++ (NSError *)messagingErrorWithCode:(FIRMessagingErrorCode)errorCode + failureReason:(NSString *)failureReason { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSLocalizedFailureReasonErrorKey] = failureReason; + return [NSError errorWithDomain:FIRMessagingErrorDomain code:errorCode userInfo:userInfo]; +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void FIRInclude_NSError_FIRMessaging_Category(void) { +} diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.c b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.c new file mode 100644 index 0000000..b50571e --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.c @@ -0,0 +1,52 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t fm_MessagingClientEvent_fields[11] = { + PB_FIELD( 1, INT64 , SINGULAR, STATIC , FIRST, fm_MessagingClientEvent, project_number, project_number, 0), + PB_FIELD( 2, BYTES , SINGULAR, POINTER , OTHER, fm_MessagingClientEvent, message_id, project_number, 0), + PB_FIELD( 3, BYTES , SINGULAR, POINTER , OTHER, fm_MessagingClientEvent, instance_id, message_id, 0), + PB_FIELD( 4, UENUM , SINGULAR, STATIC , OTHER, fm_MessagingClientEvent, message_type, instance_id, 0), + PB_FIELD( 5, UENUM , SINGULAR, STATIC , OTHER, fm_MessagingClientEvent, sdk_platform, message_type, 0), + PB_FIELD( 6, BYTES , SINGULAR, POINTER , OTHER, fm_MessagingClientEvent, package_name, sdk_platform, 0), + PB_FIELD( 12, UENUM , SINGULAR, STATIC , OTHER, fm_MessagingClientEvent, event, package_name, 0), + PB_FIELD( 13, BYTES , SINGULAR, POINTER , OTHER, fm_MessagingClientEvent, analytics_label, event, 0), + PB_FIELD( 14, INT64 , SINGULAR, STATIC , OTHER, fm_MessagingClientEvent, campaign_id, analytics_label, 0), + PB_FIELD( 15, BYTES , SINGULAR, POINTER , OTHER, fm_MessagingClientEvent, composer_label, campaign_id, 0), + PB_LAST_FIELD +}; + +const pb_field_t fm_MessagingClientEventExtension_fields[2] = { + PB_FIELD( 1, MESSAGE , SINGULAR, POINTER , FIRST, fm_MessagingClientEventExtension, messaging_client_event, messaging_client_event, &fm_MessagingClientEvent_fields), + PB_LAST_FIELD +}; + + + + + +/* @@protoc_insertion_point(eof) */ diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.h new file mode 100644 index 0000000..90886bb --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.h @@ -0,0 +1,119 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_FM_ME_NANOPB_H_INCLUDED +#define PB_FM_ME_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _fm_MessagingClientEvent_MessageType { + fm_MessagingClientEvent_MessageType_UNKNOWN = 0, + fm_MessagingClientEvent_MessageType_DATA_MESSAGE = 1, + fm_MessagingClientEvent_MessageType_TOPIC = 2, + fm_MessagingClientEvent_MessageType_DISPLAY_NOTIFICATION = 3 +} fm_MessagingClientEvent_MessageType; +#define _fm_MessagingClientEvent_MessageType_MIN fm_MessagingClientEvent_MessageType_UNKNOWN +#define _fm_MessagingClientEvent_MessageType_MAX fm_MessagingClientEvent_MessageType_DISPLAY_NOTIFICATION +#define _fm_MessagingClientEvent_MessageType_ARRAYSIZE ((fm_MessagingClientEvent_MessageType)(fm_MessagingClientEvent_MessageType_DISPLAY_NOTIFICATION+1)) + +typedef enum _fm_MessagingClientEvent_SDKPlatform { + fm_MessagingClientEvent_SDKPlatform_UNKNOWN_OS = 0, + fm_MessagingClientEvent_SDKPlatform_ANDROID = 1, + fm_MessagingClientEvent_SDKPlatform_IOS = 2, + fm_MessagingClientEvent_SDKPlatform_WEB = 3 +} fm_MessagingClientEvent_SDKPlatform; +#define _fm_MessagingClientEvent_SDKPlatform_MIN fm_MessagingClientEvent_SDKPlatform_UNKNOWN_OS +#define _fm_MessagingClientEvent_SDKPlatform_MAX fm_MessagingClientEvent_SDKPlatform_WEB +#define _fm_MessagingClientEvent_SDKPlatform_ARRAYSIZE ((fm_MessagingClientEvent_SDKPlatform)(fm_MessagingClientEvent_SDKPlatform_WEB+1)) + +typedef enum _fm_MessagingClientEvent_Event { + fm_MessagingClientEvent_Event_UNKNOWN_EVENT = 0, + fm_MessagingClientEvent_Event_MESSAGE_DELIVERED = 1, + fm_MessagingClientEvent_Event_MESSAGE_OPEN = 2 +} fm_MessagingClientEvent_Event; +#define _fm_MessagingClientEvent_Event_MIN fm_MessagingClientEvent_Event_UNKNOWN_EVENT +#define _fm_MessagingClientEvent_Event_MAX fm_MessagingClientEvent_Event_MESSAGE_OPEN +#define _fm_MessagingClientEvent_Event_ARRAYSIZE ((fm_MessagingClientEvent_Event)(fm_MessagingClientEvent_Event_MESSAGE_OPEN+1)) + +/* Struct definitions */ +typedef struct _fm_MessagingClientEventExtension { + struct _fm_MessagingClientEvent *messaging_client_event; +/* @@protoc_insertion_point(struct:fm_MessagingClientEventExtension) */ +} fm_MessagingClientEventExtension; + +typedef struct _fm_MessagingClientEvent { + int64_t project_number; + pb_bytes_array_t *message_id; + pb_bytes_array_t *instance_id; + fm_MessagingClientEvent_MessageType message_type; + fm_MessagingClientEvent_SDKPlatform sdk_platform; + pb_bytes_array_t *package_name; + fm_MessagingClientEvent_Event event; + pb_bytes_array_t *analytics_label; + int64_t campaign_id; + pb_bytes_array_t *composer_label; +/* @@protoc_insertion_point(struct:fm_MessagingClientEvent) */ +} fm_MessagingClientEvent; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define fm_MessagingClientEvent_init_default {0, NULL, NULL, _fm_MessagingClientEvent_MessageType_MIN, _fm_MessagingClientEvent_SDKPlatform_MIN, NULL, _fm_MessagingClientEvent_Event_MIN, NULL, 0, NULL} +#define fm_MessagingClientEventExtension_init_default {NULL} +#define fm_MessagingClientEvent_init_zero {0, NULL, NULL, _fm_MessagingClientEvent_MessageType_MIN, _fm_MessagingClientEvent_SDKPlatform_MIN, NULL, _fm_MessagingClientEvent_Event_MIN, NULL, 0, NULL} +#define fm_MessagingClientEventExtension_init_zero {NULL} + +/* Field tags (for use in manual encoding/decoding) */ +#define fm_MessagingClientEventExtension_messaging_client_event_tag 1 +#define fm_MessagingClientEvent_project_number_tag 1 +#define fm_MessagingClientEvent_message_id_tag 2 +#define fm_MessagingClientEvent_instance_id_tag 3 +#define fm_MessagingClientEvent_message_type_tag 4 +#define fm_MessagingClientEvent_sdk_platform_tag 5 +#define fm_MessagingClientEvent_package_name_tag 6 +#define fm_MessagingClientEvent_event_tag 12 +#define fm_MessagingClientEvent_analytics_label_tag 13 +#define fm_MessagingClientEvent_campaign_id_tag 14 +#define fm_MessagingClientEvent_composer_label_tag 15 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t fm_MessagingClientEvent_fields[11]; +extern const pb_field_t fm_MessagingClientEventExtension_fields[2]; + +/* Maximum encoded size of messages (where known) */ +/* fm_MessagingClientEvent_size depends on runtime parameters */ +/* fm_MessagingClientEventExtension_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define ME_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging+ExtensionHelper.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging+ExtensionHelper.h new file mode 100644 index 0000000..7f0fe7c --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging+ExtensionHelper.h @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRMessaging.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRMessagingExtensionHelper; + +@interface FIRMessaging (ExtensionHelper) + +/** + * Use the MessagingExtensionHelper to populate rich UI content for your notifications. + * For example, if an image URL is set in your notification payload or on the console, + * you can use the MessagingExtensionHelper instance returned from this method to render + * the image in your notification. + * + * @return An instance of MessagingExtensionHelper that handles the extensions API. + */ ++ (FIRMessagingExtensionHelper *)extensionHelper NS_SWIFT_NAME(serviceExtension()); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h new file mode 100644 index 0000000..fded673 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h @@ -0,0 +1,394 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * @related FIRMessaging + * + * The completion handler invoked when the registration token returns. + * If the call fails we return the appropriate `error code`, described by + * `FIRMessagingError`. + * + * @param FCMToken The valid registration token returned by FCM. + * @param error The error describing why a token request failed. The error code + * will match a value from the FIRMessagingError enumeration. + */ +typedef void (^FIRMessagingFCMTokenFetchCompletion)(NSString *_Nullable FCMToken, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * @related FIRMessaging + * + * The completion handler invoked when the registration token deletion request is + * completed. If the call fails we return the appropriate `error code`, described + * by `FIRMessagingError`. + * + * @param error The error describing why a token deletion failed. The error code + * will match a value from the FIRMessagingError enumeration. + */ +typedef void (^FIRMessagingDeleteFCMTokenCompletion)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * Callback to invoke once the HTTP call to FIRMessaging backend for updating + * subscription finishes. + * + * @param error The error which occurred while updating the subscription topic + * on the FIRMessaging server. This will be nil in case the operation + * was successful, or if the operation was cancelled. + */ +typedef void (^FIRMessagingTopicOperationCompletion)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * Notification sent when the FCM registration token has been refreshed. Please use the + * FIRMessaging delegate method `messaging:didReceiveRegistrationToken:` to receive current and + * updated tokens. + */ +// clang-format off +// clang-format12 merges the next two lines. +FOUNDATION_EXPORT const NSNotificationName FIRMessagingRegistrationTokenRefreshedNotification + NS_SWIFT_NAME(MessagingRegistrationTokenRefreshed); +// clang-format on + +/** + * The domain used for all errors in Messaging. + */ +FOUNDATION_EXPORT NSString *const FIRMessagingErrorDomain NS_SWIFT_NAME(MessagingErrorDomain); +/** + * @enum FIRMessagingError + */ +typedef NS_ERROR_ENUM(FIRMessagingErrorDomain, FIRMessagingError){ + /// Unknown error. + FIRMessagingErrorUnknown = 0, + + /// FIRMessaging couldn't validate request from this client. + FIRMessagingErrorAuthentication = 1, + + /// InstanceID service cannot be accessed. + FIRMessagingErrorNoAccess = 2, + + /// Request to InstanceID backend timed out. + FIRMessagingErrorTimeout = 3, + + /// No network available to reach the servers. + FIRMessagingErrorNetwork = 4, + + /// Another similar operation in progress, bailing this one. + FIRMessagingErrorOperationInProgress = 5, + + /// Some parameters of the request were invalid. + FIRMessagingErrorInvalidRequest = 7, + + /// Topic name is invalid for subscription/unsubscription. + FIRMessagingErrorInvalidTopicName = 8, + +} NS_SWIFT_NAME(MessagingError); + +/// Status for the downstream message received by the app. +typedef NS_ENUM(NSInteger, FIRMessagingMessageStatus) { + /// Unknown status. + FIRMessagingMessageStatusUnknown, + /// New downstream message received by the app. + FIRMessagingMessageStatusNew, +} NS_SWIFT_NAME(MessagingMessageStatus); + +/** + * The APNs token type for the app. If the token type is set to `UNKNOWN` + * Firebase Messaging will implicitly try to figure out what the actual token type + * is from the provisioning profile. + * Unless you really need to specify the type, you should use the `APNSToken` + * property instead. + */ +typedef NS_ENUM(NSInteger, FIRMessagingAPNSTokenType) { + /// Unknown token type. + FIRMessagingAPNSTokenTypeUnknown, + /// Sandbox token type. + FIRMessagingAPNSTokenTypeSandbox, + /// Production token type. + FIRMessagingAPNSTokenTypeProd, +} NS_SWIFT_NAME(MessagingAPNSTokenType); + +/// Information about a downstream message received by the app. +NS_SWIFT_NAME(MessagingMessageInfo) +@interface FIRMessagingMessageInfo : NSObject + +/// The status of the downstream message +@property(nonatomic, readonly, assign) FIRMessagingMessageStatus status; + +@end + +@class FIRMessaging; + +/** + * A protocol to handle token update or data message delivery from FCM. + * + */ +NS_SWIFT_NAME(MessagingDelegate) +@protocol FIRMessagingDelegate + +@optional +/// This method will be called once a token is available, or has been refreshed. Typically it +/// will be called once per app start, but may be called more often, if token is invalidated or +/// updated. In this method, you should perform operations such as: +/// +/// * Uploading the FCM token to your application server, so targeted notifications can be sent. +/// +/// * Subscribing to any topics. +- (void)messaging:(FIRMessaging *)messaging + didReceiveRegistrationToken:(nullable NSString *)fcmToken + NS_SWIFT_NAME(messaging(_:didReceiveRegistrationToken:)); +@end + +/** + * Firebase Messaging lets you reliably deliver messages. + * + * To send or receive messages, the app must get a + * registration token. This token authorizes an + * app server to send messages to an app instance. + * + * In order to handle incoming Messaging messages, set the + * `UNUserNotificationCenter`'s `delegate` property + * and implement the appropriate methods. + */ +NS_SWIFT_NAME(Messaging) +@interface FIRMessaging : NSObject + +/** + * Delegate to handle FCM token refreshes, and remote data messages received via FCM direct channel. + */ +@property(nonatomic, weak, nullable) id delegate; + +/** + * FIRMessaging + * + * @return An instance of Messaging. + */ ++ (instancetype)messaging NS_SWIFT_NAME(messaging()); + +/** + * Unavailable. Use +messaging instead. + */ +- (instancetype)init __attribute__((unavailable("Use +messaging instead."))); + +#pragma mark - APNs + +/** + * This property is used to set the APNs Token received by the application delegate. + * + * Messaging uses method swizzling to ensure that the APNs token is set + * automatically. However, if you have disabled swizzling by setting + * `FirebaseAppDelegateProxyEnabled` to `NO` in your app's + * Info.plist, you should manually set the APNs token in your application + * delegate's `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)` + * method. + * + * If you would like to set the type of the APNs token, rather than relying on + * automatic detection, see `setAPNSToken(_:type:)`. + */ +@property(nonatomic, copy, nullable) NSData *APNSToken NS_SWIFT_NAME(apnsToken); + +/** + * Set the APNs token for the application. This token will be used to register + * with Firebase Messaging, and will be associated with the app's installation ID + * in the form of an FCM token. + * + * @param apnsToken The APNs token for the application. + * @param type The type of APNs token. Debug builds should use + * `MessagingAPNSTokenTypeSandbox`. Alternatively, you can supply + * `MessagingAPNSTokenTypeUnknown` to have the type automatically + * detected based on your provisioning profile. + */ +- (void)setAPNSToken:(NSData *)apnsToken type:(FIRMessagingAPNSTokenType)type; + +#pragma mark - FCM Tokens + +/** + * Is Firebase Messaging token auto generation enabled? If this flag is disabled, Firebase + * Messaging will not generate an FCM token automatically for message delivery. + * + * If this flag is disabled, Firebase Messaging does not generate new tokens automatically for + * message delivery. If this flag is enabled, FCM generates a registration token on application + * start when there is no existing valid token and periodically refreshes the token and sends + * data to the Firebase backend. + * + * This setting is persisted, and is applied on future invocations of your application. Once + * explicitly set, it overrides any settings in your Info.plist. + * + * By default, FCM automatic initialization is enabled. If you need to change the + * default (for example, because you want to prompt the user before getting a token), + * set `FirebaseMessagingAutoInitEnabled` to NO in your application's Info.plist. + */ +@property(nonatomic, assign, getter=isAutoInitEnabled) BOOL autoInitEnabled; + +/** + * The FCM registration token is used to identify this device so that FCM can send notifications to + * it. It is associated with your APNs token when the APNs token is supplied, so messages sent to + * the FCM token will be delivered over APNs. + * + * The FCM registration token is sometimes refreshed automatically. In your Messaging delegate, + * the delegate method `messaging(_:didReceiveRegistrationToken:)` will be called once a token is + * available, or has been refreshed. Typically it should be called once per app start, but + * may be called more often if the token is invalidated or updated. + * + * Once you have an FCM registration token, you should send it to your application server, where + * it can be used to send notifications to your device. + */ +@property(nonatomic, readonly, nullable) NSString *FCMToken NS_SWIFT_NAME(fcmToken); + +/** + * Asynchronously gets the default FCM registration token. + * + * This creates a Firebase Installations ID, if one does not exist, and sends information about the + * application and the device to the Firebase backend. A network connection is required for the + * method to succeed. To stop this, see `Messaging.isAutoInitEnabled`, + * `Messaging.delete(completion:)` and `Installations.delete(completion:)`. + * + * @param completion The completion handler to handle the token request. + */ + +- (void)tokenWithCompletion:(void (^)(NSString *_Nullable token, + NSError *_Nullable error))completion; + +/** + * Asynchronously deletes the default FCM registration token. + * + * This does not delete all tokens for non-default sender IDs, See `Messaging.delete(completion:)` + * for deleting all of them. To prevent token auto generation, see `Messaging.isAutoInitEnabled`. + * + * @param completion The completion handler to handle the token deletion. + */ + +- (void)deleteTokenWithCompletion:(void (^)(NSError *_Nullable error))completion; + +/** + * Retrieves an FCM registration token for a particular Sender ID. This can be used to allow + * multiple senders to send notifications to the same device. By providing a different Sender + * ID than your default when fetching a token, you can create a new FCM token which you can + * give to a different sender. Both tokens will deliver notifications to your device, and you + * can revoke a token when you need to. + * + * This registration token is not cached by FIRMessaging. FIRMessaging should have an APNs + * token set before calling this to ensure that notifications can be delivered via APNs using + * this FCM token. You may re-retrieve the FCM token once you have the APNs token set, to + * associate it with the FCM token. The default FCM token is automatically associated with + * the APNs token, if the APNs token data is available. + * + * This creates a Firebase Installations ID, if one does not exist, and sends information + * about the application and the device to the Firebase backend. + * + * @param senderID The Sender ID for a particular Firebase project. + * @param completion The completion handler to handle the token request. + */ +- (void)retrieveFCMTokenForSenderID:(NSString *)senderID + completion:(void (^)(NSString *_Nullable FCMToken, + NSError *_Nullable error))completion + NS_SWIFT_NAME(retrieveFCMToken(forSenderID:completion:)); + +/** + * Invalidates an FCM token for a particular Sender ID. That Sender ID cannot no longer send + * notifications to that FCM token. This does not delete the Firebase Installations ID that may have + * been created when generating the token. See `Installations.delete(completion:)`. + * + * @param senderID The senderID for a particular Firebase project. + * @param completion The completion handler to handle the token deletion. + */ +- (void)deleteFCMTokenForSenderID:(NSString *)senderID + completion:(void (^)(NSError *_Nullable error))completion + NS_SWIFT_NAME(deleteFCMToken(forSenderID:completion:)); + +#pragma mark - Topics + +/** + * Asynchronously subscribes to a topic. This uses the default FCM registration token to identify + * the app instance and periodically sends data to the Firebase backend. To stop this, see + * `Messaging.delete(completion:)` and `Installations.delete(completion:)`. + * + * @param topic The name of the topic, for example, @"sports". + */ +- (void)subscribeToTopic:(NSString *)topic NS_SWIFT_NAME(subscribe(toTopic:)); + +/** + * Asynchronously subscribe to the provided topic, retrying on failure. This uses the default FCM + * registration token to identify the app instance and periodically sends data to the Firebase + * backend. To stop this, see `Messaging.delete(completion:)` and + * `Installations.delete(completion:)`. + * + * @param topic The topic name to subscribe to, for example, @"sports". + * @param completion The completion that is invoked once the subscribe call ends. + * On success, the error parameter is always `nil`. Otherwise, an + * appropriate error object is returned. + */ +- (void)subscribeToTopic:(nonnull NSString *)topic + completion:(void (^_Nullable)(NSError *_Nullable error))completion; + +/** + * Asynchronously unsubscribe from a topic. This uses a FCM Token + * to identify the app instance and periodically sends data to the Firebase backend. To stop this, + * see `Messaging.delete(completion:)` and `Installations.delete(completion:)`. + * + * @param topic The name of the topic, for example @"sports". + */ +- (void)unsubscribeFromTopic:(NSString *)topic NS_SWIFT_NAME(unsubscribe(fromTopic:)); + +/** + * Asynchronously unsubscribe from the provided topic, retrying on failure. This uses a FCM Token + * to identify the app instance and periodically sends data to the Firebase backend. To stop this, + * see `Messaging.delete(completion:)` and `Installations.delete(completion:)`. + * + * @param topic The topic name to unsubscribe from, for example @"sports". + * @param completion The completion that is invoked once the unsubscribe call ends. + * In case of success, nil error is returned. Otherwise, an + * appropriate error object is returned. + */ +- (void)unsubscribeFromTopic:(nonnull NSString *)topic + completion:(void (^_Nullable)(NSError *_Nullable error))completion; + +#pragma mark - Analytics + +/** + * Use this to track message delivery and analytics for messages, typically + * when you receive a notification in `application:didReceiveRemoteNotification:`. + * However, you only need to call this if you set the `FirebaseAppDelegateProxyEnabled` + * flag to `NO` in your Info.plist. If `FirebaseAppDelegateProxyEnabled` is either missing + * or set to `YES` in your Info.plist, the library will call this automatically. + * + * @param message The downstream message received by the application. + * + * @return Information about the downstream message. + */ +- (FIRMessagingMessageInfo *)appDidReceiveMessage:(NSDictionary *)message; + +#pragma mark - GDPR +/** + * Deletes all the tokens and checkin data of the Firebase project and related data on the server + * side. A network connection is required for the method to succeed. + * + * This does not delete the Firebase Installations ID. See `Installations.delete(completion:)`. + * To prevent token auto generation, see `Messaging.isAutoInitEnabled`. + * + * @param completion A completion handler which is invoked when the operation completes. `error == + * nil` indicates success. + */ +- (void)deleteDataWithCompletion:(void (^)(NSError *__nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessagingExtensionHelper.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessagingExtensionHelper.h new file mode 100644 index 0000000..eb25919 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessagingExtensionHelper.h @@ -0,0 +1,52 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRMessaging+ExtensionHelper.h" + +@class UNMutableNotificationContent, UNNotificationContent; + +#if __has_include() +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +/// This class is used to automatically populate a notification with an image if it is +/// specified in the notification body via the `image` parameter. Images and other +/// rich content can be populated manually without the use of this class. See the +/// `UNNotificationServiceExtension` type for more details. +__OSX_AVAILABLE(10.14) @interface FIRMessagingExtensionHelper : NSObject + +/// Call this API to complete your notification content modification. If you like to +/// overwrite some properties of the content instead of using the default payload, +/// make sure to make your customized motification to the content before passing it to +/// this call. +- (void)populateNotificationContent:(UNMutableNotificationContent *)content + withContentHandler:(void (^)(UNNotificationContent *_Nonnull))contentHandler; + +/// Exports delivery metrics to BigQuery. Call this API to enable logging delivery of alert +/// notification or background notification and export to BigQuery. +/// If you log alert notifications, enable Notification Service Extension and calls this API +/// under `UNNotificationServiceExtension didReceiveNotificationRequest: withContentHandler:`. +/// If you log background notifications, call the API under `UIApplicationDelegate +/// application:didReceiveRemoteNotification:fetchCompletionHandler:`. +- (void)exportDeliveryMetricsToBigQueryWithMessageInfo:(NSDictionary *)info; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FirebaseMessaging.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FirebaseMessaging.h new file mode 100644 index 0000000..d285c07 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Public/FirebaseMessaging/FirebaseMessaging.h @@ -0,0 +1,19 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRMessaging+ExtensionHelper.h" +#import "FIRMessaging.h" +#import "FIRMessagingExtensionHelper.h" diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Resources/PrivacyInfo.xcprivacy b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..3b29f79 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,54 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeDeviceID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDataTypes + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDiagnosticData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyAccessedAPITypes + + + + + diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h new file mode 100644 index 0000000..dae9ff4 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Represents an APNS device token and whether its environment is for sandbox. + * It can read from and write to an NSDictionary for simple serialization. + */ +@interface FIRMessagingAPNSInfo : NSObject + +/// The APNs device token, provided by the OS to the application delegate +@property(nonatomic, readonly, copy) NSData *deviceToken; +/// Represents whether or not this is deviceToken is for the sandbox +/// environment, or production. +@property(nonatomic, readonly, getter=isSandbox) BOOL sandbox; + +/** + * Initializes the receiver with an APNs device token, and boolean + * representing whether that token is for the sandbox environment. + * + * @param deviceToken The APNs device token typically provided by the + * operating system. + * @param isSandbox YES if the APNs device token is for the sandbox + * environment, or NO if it is for production. + * @return An instance of FIRInstanceIDAPNSInfo. + */ +- (instancetype)initWithDeviceToken:(NSData *)deviceToken isSandbox:(BOOL)isSandbox; + +/** + * Initializes the receiver from a token options dictionary containing data + * within the `kFIRInstanceIDTokenOptionsAPNSKey` and + * `kFIRInstanceIDTokenOptionsAPNSIsSandboxKey` keys. The token should be an + * NSData blob, and the sandbox value should be an NSNumber + * representing a boolean value. + * + * @param dictionary A dictionary containing values under the keys + * `kFIRInstanceIDTokenOptionsAPNSKey` and + * `kFIRInstanceIDTokenOptionsAPNSIsSandboxKey`. + * @return An instance of FIRInstanceIDAPNSInfo, or nil if the + * dictionary data was invalid or missing. + */ +- (nullable instancetype)initWithTokenOptionsDictionary:(NSDictionary *)dictionary; + +- (BOOL)isEqualToAPNSInfo:(FIRMessagingAPNSInfo *)otherInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.m new file mode 100644 index 0000000..5f23d34 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.m @@ -0,0 +1,98 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h" + +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" + +/// The key used to find the APNs device token in an archive. +static NSString *const kFIRInstanceIDAPNSInfoTokenKey = @"device_token"; +/// The key used to find the sandbox value in an archive. +static NSString *const kFIRInstanceIDAPNSInfoSandboxKey = @"sandbox"; + +@interface FIRMessagingAPNSInfo () +/// The APNs device token, provided by the OS to the application delegate +@property(nonatomic, copy) NSData *deviceToken; +/// Represents whether or not this is deviceToken is for the sandbox +/// environment, or production. +@property(nonatomic, getter=isSandbox) BOOL sandbox; +@end + +@implementation FIRMessagingAPNSInfo + +- (instancetype)initWithDeviceToken:(NSData *)deviceToken isSandbox:(BOOL)isSandbox { + self = [super init]; + if (self) { + _deviceToken = [deviceToken copy]; + _sandbox = isSandbox; + } + return self; +} + +- (instancetype)initWithTokenOptionsDictionary:(NSDictionary *)dictionary { + id deviceToken = dictionary[kFIRMessagingTokenOptionsAPNSKey]; + if (![deviceToken isKindOfClass:[NSData class]]) { + return nil; + } + + id isSandbox = dictionary[kFIRMessagingTokenOptionsAPNSIsSandboxKey]; + if (![isSandbox isKindOfClass:[NSNumber class]]) { + return nil; + } + self = [super init]; + if (self) { + _deviceToken = (NSData *)deviceToken; + _sandbox = ((NSNumber *)isSandbox).boolValue; + } + return self; +} + +#pragma mark - NSCopying +- (id)copyWithZone:(NSZone *)zone { + FIRMessagingAPNSInfo *clone = [[FIRMessagingAPNSInfo alloc] init]; + clone.deviceToken = [_deviceToken copy]; + clone.sandbox = _sandbox; + return clone; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + NSData *deviceToken = [aDecoder decodeObjectOfClass:[NSData class] + forKey:kFIRInstanceIDAPNSInfoTokenKey]; + if (!deviceToken) { + return nil; + } + + BOOL isSandbox = [aDecoder decodeBoolForKey:kFIRInstanceIDAPNSInfoSandboxKey]; + return [self initWithDeviceToken:(NSData *)deviceToken isSandbox:isSandbox]; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.deviceToken forKey:kFIRInstanceIDAPNSInfoTokenKey]; + [aCoder encodeBool:self.sandbox forKey:kFIRInstanceIDAPNSInfoSandboxKey]; +} + +- (BOOL)isEqualToAPNSInfo:(FIRMessagingAPNSInfo *)otherInfo { + return ([self.deviceToken isEqualToData:otherInfo.deviceToken] && + self.isSandbox == otherInfo.isSandbox); +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.h new file mode 100644 index 0000000..24e6419 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.h @@ -0,0 +1,103 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +extern NSString *__nonnull const kFIRMessagingKeychainWildcardIdentifier; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Wrapper around storing FCM auth data in iOS keychain. + */ +@interface FIRMessagingAuthKeychain : NSObject + +/** + * Designated Initializer. Init a generic `SecClassGenericPassword` keychain with `identifier` + * as the `kSecAttrGeneric`. + * + * @param identifier The generic attribute to be used by the keychain. + * + * @return A Keychain object with `kSecAttrGeneric` attribute set to identifier. + */ +- (instancetype)initWithIdentifier:(NSString *)identifier; + +/** + * Get keychain items matching the given service and account. The service and/or account + * can be a wildcard (`kFIRMessagingKeychainWildcardIdentifier`), which case the query + * will include all items matching any services and/or accounts. + * + * @param service The kSecAttrService used to save the password. Can be wildcard. + * @param account The kSecAttrAccount used to save the password. Can be wildcard. + * + * @return An array of |NSData|s matching the provided inputs. + */ +- (NSArray *)itemsMatchingService:(NSString *)service account:(NSString *)account; + +/** + * Get keychain item for a given service and account. + * + * @param service The kSecAttrService used to save the password. + * @param account The kSecAttrAccount used to save the password. + * + * @return A cached keychain item for a given account and service, or nil if it was not + * found or could not be retrieved. + */ +- (NSData *)dataForService:(NSString *)service account:(NSString *)account; + +/** + * Remove the cached items from the keychain matching the service, account and access group. + * In case the items do not exist, YES is returned but with a valid error object with code + * `errSecItemNotFound`. + * + * @param service The kSecAttrService used to save the password. + * @param account The kSecAttrAccount used to save the password. + * @param handler The callback handler which is invoked when the remove operation is complete, with + * an error if there is any. + */ +- (void)removeItemsMatchingService:(NSString *)service + account:(NSString *)account + handler:(nullable void (^)(NSError *error))handler; + +/** + * Set the data for a given service and account. + * We use `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` which + * prevents backup and restore to iCloud, and works for app extension that can + * execute right after a device is restarted (and not unlocked). + * + * @param data The data to save. + * @param service The `kSecAttrService` used to save the password. + * @param account The `kSecAttrAccount` used to save the password. + * @param handler The callback handler which is invoked when the add operation is complete, + * with an error if there is any. + * + */ +- (void)setData:(NSData *)data + forService:(NSString *)service + account:(NSString *)account + handler:(nullable void (^)(NSError *))handler; + +/* + * This method only sets the cache data of token. + * It is only used when users still use InstanceID to update token info + * After token refreshed by InstanceID, the storage is already updated but not the cache. + * use this method to update the cache. + */ +- (void)setCacheData:(NSData *)data forService:(NSString *)service account:(NSString *)account; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.m new file mode 100644 index 0000000..50957ce --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.m @@ -0,0 +1,234 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingKeychain.h" + +/** + * The error type representing why we couldn't read data from the keychain. + */ +typedef NS_ENUM(int, FIRMessagingKeychainErrorType) { + kFIRMessagingKeychainErrorBadArguments = -1301, +}; + +NSString *const kFIRMessagingKeychainWildcardIdentifier = @"*"; + +@interface FIRMessagingAuthKeychain () + +@property(nonatomic, copy) NSString *generic; +// cachedKeychainData is keyed by service and account, the value is an array of NSData. +// It is used to cache the tokens per service, per account, as well as checkin data per service, +// per account inside the keychain. +@property(nonatomic, strong) + NSMutableDictionary *> *> + *cachedKeychainData; + +@end + +@implementation FIRMessagingAuthKeychain + +- (instancetype)initWithIdentifier:(NSString *)identifier { + self = [super init]; + if (self) { + _generic = [identifier copy]; + _cachedKeychainData = [[NSMutableDictionary alloc] init]; + } + return self; +} + ++ (NSMutableDictionary *)keychainQueryForService:(NSString *)service + account:(NSString *)account + generic:(NSString *)generic { + NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword}; + + NSMutableDictionary *finalQuery = [NSMutableDictionary dictionaryWithDictionary:query]; + if ([generic length] && ![kFIRMessagingKeychainWildcardIdentifier isEqualToString:generic]) { + finalQuery[(__bridge NSString *)kSecAttrGeneric] = generic; + } + if ([account length] && ![kFIRMessagingKeychainWildcardIdentifier isEqualToString:account]) { + finalQuery[(__bridge NSString *)kSecAttrAccount] = account; + } + if ([service length] && ![kFIRMessagingKeychainWildcardIdentifier isEqualToString:service]) { + finalQuery[(__bridge NSString *)kSecAttrService] = service; + } + + if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { + // Ensures that the keychain query behaves the same across all platforms. + // See go/firebase-macos-keychain-popups for details. + finalQuery[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; + } + + return finalQuery; +} + +- (NSMutableDictionary *)keychainQueryForService:(NSString *)service account:(NSString *)account { + return [[self class] keychainQueryForService:service account:account generic:self.generic]; +} + +- (NSArray *)itemsMatchingService:(NSString *)service account:(NSString *)account { + // If query wildcard service, it asks for all the results, which always query from keychain. + if (![service isEqualToString:kFIRMessagingKeychainWildcardIdentifier] && + ![account isEqualToString:kFIRMessagingKeychainWildcardIdentifier] && + _cachedKeychainData[service][account]) { + // As long as service, account array exist, even it's empty, it means we've queried it before, + // returns the cache value. + return _cachedKeychainData[service][account]; + } + + NSMutableDictionary *keychainQuery = [self keychainQueryForService:service account:account]; + NSMutableArray *results; + keychainQuery[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue; +#if TARGET_OS_OSX || TARGET_OS_WATCH + keychainQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; + NSData *passwordInfos = + CFBridgingRelease([[FIRMessagingKeychain sharedInstance] itemWithQuery:keychainQuery]); +#else // TARGET_OS_OSX || TARGET_OS_WATCH + keychainQuery[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue; + keychainQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll; + // FIRMessagingKeychain should only take a query and return a result, will handle the query here. + NSArray *passwordInfos = + CFBridgingRelease([[FIRMessagingKeychain sharedInstance] itemWithQuery:keychainQuery]); +#endif // TARGET_OS_OSX || TARGET_OS_WATCH + + if (!passwordInfos) { + // Nothing was found, simply return from this sync block. + // Make sure to label the cache entry empty, signaling that we've queried this entry. + if ([service isEqualToString:kFIRMessagingKeychainWildcardIdentifier] || + [account isEqualToString:kFIRMessagingKeychainWildcardIdentifier]) { + // Do not update cache if it's wildcard query. + return @[]; + } else if (_cachedKeychainData[service]) { + [_cachedKeychainData[service] setObject:@[] forKey:account]; + } else { + [_cachedKeychainData setObject:[@{account : @[]} mutableCopy] forKey:service]; + } + return @[]; + } + results = [[NSMutableArray alloc] init]; +#if TARGET_OS_OSX || TARGET_OS_WATCH + [results addObject:passwordInfos]; +#else // TARGET_OS_OSX || TARGET_OS_WATCH + NSInteger numPasswords = passwordInfos.count; + for (NSUInteger i = 0; i < numPasswords; i++) { + NSDictionary *passwordInfo = [passwordInfos objectAtIndex:i]; + if (passwordInfo[(__bridge id)kSecValueData]) { + [results addObject:passwordInfo[(__bridge id)kSecValueData]]; + } + } +#endif // TARGET_OS_OSX || TARGET_OS_WATCH + // We query the keychain because it didn't exist in cache, now query is done, update the result in + // the cache. + if ([service isEqualToString:kFIRMessagingKeychainWildcardIdentifier] || + [account isEqualToString:kFIRMessagingKeychainWildcardIdentifier]) { + // Do not update cache if it's wildcard query. + return [results copy]; + } else if (_cachedKeychainData[service]) { + [_cachedKeychainData[service] setObject:[results copy] forKey:account]; + } else { + NSMutableDictionary *entry = [@{account : [results copy]} mutableCopy]; + [_cachedKeychainData setObject:entry forKey:service]; + } + return [results copy]; +} + +- (NSData *)dataForService:(NSString *)service account:(NSString *)account { + NSArray *items = [self itemsMatchingService:service account:account]; + // If items is nil or empty, nil will be returned. + return items.firstObject; +} + +- (void)removeItemsMatchingService:(NSString *)service + account:(NSString *)account + handler:(void (^)(NSError *error))handler { + if ([service isEqualToString:kFIRMessagingKeychainWildcardIdentifier]) { + // Delete all keychain items. + _cachedKeychainData = [[NSMutableDictionary alloc] init]; + } else if ([account isEqualToString:kFIRMessagingKeychainWildcardIdentifier]) { + // Delete all entries under service, + if (_cachedKeychainData[service]) { + _cachedKeychainData[service] = [[NSMutableDictionary alloc] init]; + } + } else if (_cachedKeychainData[service]) { + // We should keep the service/account entry instead of nil so we know + // it's "empty entry" instead of "not query from keychain yet". + [_cachedKeychainData[service] setObject:@[] forKey:account]; + } else { + [_cachedKeychainData setObject:[@{account : @[]} mutableCopy] forKey:service]; + } + NSMutableDictionary *keychainQuery = [self keychainQueryForService:service account:account]; + [[FIRMessagingKeychain sharedInstance] removeItemWithQuery:keychainQuery handler:handler]; +} + +- (void)setData:(NSData *)data + forService:(NSString *)service + account:(NSString *)account + handler:(void (^)(NSError *))handler { + if ([service isEqualToString:kFIRMessagingKeychainWildcardIdentifier] || + [account isEqualToString:kFIRMessagingKeychainWildcardIdentifier]) { + if (handler) { + handler([NSError errorWithDomain:kFIRMessagingKeychainErrorDomain + code:kFIRMessagingKeychainErrorBadArguments + userInfo:nil]); + } + return; + } + [self removeItemsMatchingService:service + account:account + handler:^(NSError *error) { + if (error) { + if (handler) { + handler(error); + } + return; + } + if (data.length > 0) { + NSMutableDictionary *keychainQuery = + [self keychainQueryForService:service account:account]; + keychainQuery[(__bridge id)kSecValueData] = data; + + keychainQuery[(__bridge id)kSecAttrAccessible] = + (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + [[FIRMessagingKeychain sharedInstance] addItemWithQuery:keychainQuery + handler:handler]; + } + }]; + // Set the cache value. This must happen after removeItemsMatchingService:account:handler was + // called, so the cache value was reset before setting a new value. + if (_cachedKeychainData[service]) { + if (_cachedKeychainData[service][account]) { + _cachedKeychainData[service][account] = @[ data ]; + } else { + [_cachedKeychainData[service] setObject:@[ data ] forKey:account]; + } + } else { + [_cachedKeychainData setObject:[@{account : @[ data ]} mutableCopy] forKey:service]; + } +} + +- (void)setCacheData:(NSData *)data forService:(NSString *)service account:(NSString *)account { + if (_cachedKeychainData[service]) { + if (_cachedKeychainData[service][account]) { + _cachedKeychainData[service][account] = @[ data ]; + } else { + [_cachedKeychainData[service] setObject:@[ data ] forKey:account]; + } + } else { + [_cachedKeychainData setObject:[@{account : @[ data ]} mutableCopy] forKey:service]; + } +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthService.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthService.h new file mode 100644 index 0000000..27fa191 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthService.h @@ -0,0 +1,95 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRMessagingCheckinPreferences; +/** + * @related FIRInstanceIDCheckinService + * + * The completion handler invoked once the fetch from Checkin server finishes. + * For successful fetches we returned checkin information by the checkin service + * and `nil` error, else we return the appropriate error object as reported by the + * Checkin Service. + * + * @param checkinPreferences The checkin preferences as fetched from the server. + * @param error The error object which fetching GServices data. + */ +typedef void (^FIRMessagingDeviceCheckinCompletion)( + FIRMessagingCheckinPreferences *_Nullable checkinPreferences, NSError *_Nullable error); +/** + * FIRMessagingAuthService is responsible for retrieving, caching, and supplying checkin info + * for the rest of Instance ID. A checkin can be scheduled, meaning that it will keep retrying the + * checkin request until it is successful. A checkin can also be requested directly, with a + * completion handler. + */ +@interface FIRMessagingAuthService : NSObject + +#pragma mark - Checkin Service + +- (BOOL)hasCheckinPlist; + +/** + * Checks if the current deviceID and secret are valid or not. + * + * @return YES if the checkin credentials are valid else NO. + */ +- (BOOL)hasValidCheckinInfo; + +/** + * Fetch checkin info from the server. This would usually refresh the existing + * checkin credentials for the current app. + * + * @param handler The completion handler to invoke once the checkin info has been + * refreshed. + */ +- (void)fetchCheckinInfoWithHandler:(nullable FIRMessagingDeviceCheckinCompletion)handler; + +/** + * Schedule checkin. Will hit the network only if the currently loaded checkin + * preferences are stale. + * + * @param immediately YES if we want it to be scheduled immediately else NO. + */ +- (void)scheduleCheckin:(BOOL)immediately; + +/** + * Returns the checkin preferences currently loaded in memory. The Checkin preferences + * can be either valid or invalid. + * + * @return The checkin preferences loaded in memory. + */ +- (FIRMessagingCheckinPreferences *)checkinPreferences; + +/** + * Cancels any ongoing checkin fetch, if any. + */ +- (void)stopCheckinRequest; + +/** + * Resets the checkin information. + * + * @param handler The callback handler which is invoked when checkin reset is complete, + * with an error if there is any. + */ +- (void)resetCheckinWithHandler:(void (^)(NSError *error))handler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthService.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthService.m new file mode 100644 index 0000000..d5b364b --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingAuthService.m @@ -0,0 +1,301 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingAuthService.h" + +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.h" + +// Max time interval between checkin retry in seconds. +static const int64_t kMaxCheckinRetryIntervalInSeconds = 1 << 5; + +@interface FIRMessagingAuthService () + +// Used to retrieve and cache the checkin info to disk and Keychain. +@property(nonatomic, readwrite, strong) FIRMessagingCheckinStore *checkinStore; +// Used to perform single checkin fetches. +@property(nonatomic, readwrite, strong) FIRMessagingCheckinService *checkinService; +// The current checkin info. It will be compared to what is retrieved to determine whether it is +// different than what is in the cache. +@property(nonatomic, readwrite, strong) FIRMessagingCheckinPreferences *checkinPreferences; + +// This array will track multiple handlers waiting for checkin to be performed. When a checkin +// request completes, all the handlers will be notified. +// Changes to the checkinHandlers array should happen in a thread-safe manner. +@property(nonatomic, readonly, strong) + NSMutableArray *checkinHandlers; + +// This is set to true if there is a checkin request in-flight. +@property(atomic, readwrite, assign) BOOL isCheckinInProgress; +// This timer is used a perform checkin retries. It is cancellable. +@property(atomic, readwrite, strong) NSTimer *scheduledCheckinTimer; +// The number of times checkin has been retried during a scheduled checkin. +@property(atomic, readwrite, assign) int checkinRetryCount; + +@end + +@implementation FIRMessagingAuthService + +- (instancetype)init { + self = [super init]; + if (self) { + _checkinStore = [[FIRMessagingCheckinStore alloc] init]; + _checkinPreferences = [_checkinStore cachedCheckinPreferences]; + _checkinService = [[FIRMessagingCheckinService alloc] init]; + _checkinHandlers = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)dealloc { + [_scheduledCheckinTimer invalidate]; +} + +#pragma mark - Schedule Checkin + +- (BOOL)hasCheckinPlist { + return [_checkinStore hasCheckinPlist]; +} + +- (void)scheduleCheckin:(BOOL)immediately { + // Checkin is still valid, so a remote checkin is not required. + if ([self.checkinPreferences hasValidCheckinInfo]) { + return; + } + + // Checkin is already scheduled, so this (non-immediate) request can be ignored. + if (!immediately && [self.scheduledCheckinTimer isValid]) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAuthService000, + @"Checkin sync already scheduled. Will not schedule."); + return; + } + + if (immediately) { + [self performScheduledCheckin]; + } else { + int64_t checkinRetryDuration = [self calculateNextCheckinRetryIntervalInSeconds]; + [self startCheckinTimerWithDuration:(NSTimeInterval)checkinRetryDuration]; + } +} + +- (void)startCheckinTimerWithDuration:(NSTimeInterval)timerDuration { + self.scheduledCheckinTimer = + [NSTimer scheduledTimerWithTimeInterval:timerDuration + target:self + selector:@selector(onScheduledCheckinTimerFired:) + userInfo:nil + repeats:NO]; + // Add some tolerance to the timer, to allow iOS to be more flexible with this timer + self.scheduledCheckinTimer.tolerance = 0.5; +} + +- (void)clearScheduledCheckinTimer { + [self.scheduledCheckinTimer invalidate]; + self.scheduledCheckinTimer = nil; +} + +- (void)onScheduledCheckinTimerFired:(NSTimer *)timer { + [self performScheduledCheckin]; +} + +- (void)performScheduledCheckin { + // No checkin scheduled as of now. + [self clearScheduledCheckinTimer]; + + // Checkin is still valid, so a remote checkin is not required. + if ([self.checkinPreferences hasValidCheckinInfo]) { + return; + } + + FIRMessaging_WEAKIFY(self); + [self fetchCheckinInfoWithHandler:^(FIRMessagingCheckinPreferences *_Nullable checkinPreferences, + NSError *_Nullable error) { + FIRMessaging_STRONGIFY(self); + self.checkinRetryCount++; + + if (error) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAuthService001, @"Checkin error %@.", error); + + dispatch_async(dispatch_get_main_queue(), ^{ + // Schedule another checkin + [self scheduleCheckin:NO]; + }); + + } else { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAuthService002, @"Checkin success."); + } + }]; +} + +- (int64_t)calculateNextCheckinRetryIntervalInSeconds { + // persistent failures can lead to overflow prevent that. + if (self.checkinRetryCount >= 10) { + return kMaxCheckinRetryIntervalInSeconds; + } + return MIN(1 << self.checkinRetryCount, kMaxCheckinRetryIntervalInSeconds); +} + +#pragma mark - Checkin Service + +- (BOOL)hasValidCheckinInfo { + return [self.checkinPreferences hasValidCheckinInfo]; +} + +- (void)fetchCheckinInfoWithHandler:(nullable FIRMessagingDeviceCheckinCompletion)handler { + // Perform any changes to self.checkinHandlers and _isCheckinInProgress in a thread-safe way. + @synchronized(self) { + [self.checkinHandlers addObject:[handler copy]]; + + if (_isCheckinInProgress) { + // Nothing more to do until our checkin request is done + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAuthServiceCheckinInProgress, + @"Checkin is in progress\n"); + return; + } + } + + // Checkin is still valid, so a remote checkin is not required. + if ([self.checkinPreferences hasValidCheckinInfo]) { + [self notifyCheckinHandlersWithCheckin:self.checkinPreferences error:nil]; + return; + } + + @synchronized(self) { + _isCheckinInProgress = YES; + } + [self.checkinService + checkinWithExistingCheckin:self.checkinPreferences + completion:^(FIRMessagingCheckinPreferences *checkinPreferences, + NSError *error) { + @synchronized(self) { + self->_isCheckinInProgress = NO; + } + if (error) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAuthService003, + @"Failed to checkin device %@", error); + [self notifyCheckinHandlersWithCheckin:nil error:error]; + return; + } + + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeAuthService004, + @"Successfully got checkin credentials"); + BOOL hasSameCachedPreferences = + [self cachedCheckinMatchesCheckin:checkinPreferences]; + checkinPreferences.hasPreCachedAuthCredentials = hasSameCachedPreferences; + + // Update to the most recent checkin preferences + self.checkinPreferences = checkinPreferences; + + // Save the checkin info to disk + // Keychain might not be accessible, so confirm that checkin preferences can + // be saved + [self->_checkinStore + saveCheckinPreferences:checkinPreferences + handler:^(NSError *checkinSaveError) { + if (checkinSaveError && !hasSameCachedPreferences) { + // The checkin info was new, but it couldn't be + // written to the Keychain. Delete any stuff that was + // cached in memory. This doesn't delete any + // previously persisted preferences. + FIRMessagingLoggerError( + kFIRMessagingMessageCodeService004, + @"Unable to save checkin info, resetting " + @"checkin preferences " + "in memory."); + [checkinPreferences reset]; + [self + notifyCheckinHandlersWithCheckin:nil + error: + checkinSaveError]; + } else { + // The checkin is either new, or it was the same (and + // it couldn't be saved). Either way, report that the + // checkin preferences were received successfully. + [self notifyCheckinHandlersWithCheckin: + checkinPreferences + error:nil]; + if (!hasSameCachedPreferences) { + // Checkin is new. + // Notify any listeners that might be waiting for + // checkin to be fetched, such as Firebase + // Messaging (for its MCS connection). + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] + postNotificationName: + kFIRMessagingCheckinFetchedNotification + object:nil]; + }); + } + } + }]; + }]; +} + +- (FIRMessagingCheckinPreferences *)checkinPreferences { + return _checkinPreferences; +} + +- (void)stopCheckinRequest { + [self.checkinService stopFetching]; +} + +- (void)resetCheckinWithHandler:(void (^)(NSError *error))handler { + [_checkinStore removeCheckinPreferencesWithHandler:^(NSError *error) { + if (!error) { + self.checkinPreferences = nil; + } + if (handler) { + handler(error); + } + }]; +} + +#pragma mark - Private + +/** + * Goes through the current list of checkin handlers and fires them with the same checkin and/or + * error info. The checkin handlers will get cleared after. + */ +- (void)notifyCheckinHandlersWithCheckin:(nullable FIRMessagingCheckinPreferences *)checkin + error:(nullable NSError *)error { + @synchronized(self) { + for (FIRMessagingDeviceCheckinCompletion handler in self.checkinHandlers) { + handler(checkin, error); + } + [self.checkinHandlers removeAllObjects]; + } +} + +- (void)setCheckinHandlers:(NSMutableArray *)checkinHandlers { + NSLog(@"%lu", (unsigned long)self.checkinHandlers.count); +} + +/** + * Given a |checkin|, it will compare it to the current checkinPreferences to see if the + * deviceID and secretToken are the same. + */ +- (BOOL)cachedCheckinMatchesCheckin:(FIRMessagingCheckinPreferences *)checkin { + if (self.checkinPreferences && checkin) { + return ([self.checkinPreferences.deviceID isEqualToString:checkin.deviceID] && + [self.checkinPreferences.secretToken isEqualToString:checkin.secretToken]); + } + return NO; +} +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.h new file mode 100644 index 0000000..800654b --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.h @@ -0,0 +1,81 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@interface FIRMessagingBackupExcludedPlist : NSObject + +/** + * Caches the plist contents in memory so we don't hit the disk each time we want + * to query something in the plist. This is loaded lazily i.e. if you write to the + * plist the contents you want to write will be stored here if the write was + * successful. The other case where it is loaded is if you read the plist contents + * by calling `contentAsDictionary`. + * + * In case you write to the plist and then try to read the file using + * `contentAsDictionary` we would just return the cachedPlistContents since it would + * represent the disk contents. + */ +@property(nonatomic, readonly, strong) NSDictionary *cachedPlistContents; + +/** + * Init a backup excluded plist file. + * + * @param fileName The filename for the plist file. + * @param subDirectory The subdirectory in Application Support to save the plist. + * + * @return Helper which allows to read write data to a backup excluded plist. + */ +- (instancetype)initWithPlistFile:(NSString *)fileName subDirectory:(NSString *)subDirectory; + +/** + * Write dictionary data to the backup excluded plist file. If the file does not exist + * it would be created before writing to it. + * + * @param dict The data to be written to the plist. + * @param error The error object if any while writing the data. + * + * @return YES if the write was successful else NO. + */ +- (BOOL)writeDictionary:(NSDictionary *)dict error:(NSError **)error; + +/** + * Delete the backup excluded plist created with the above filename. + * + * @param error The error object if any while deleting the file. + * + * @return YES If the delete was successful else NO. + */ +- (BOOL)deleteFile:(NSError **)error; + +/** + * The contents of the plist file. We also store the contents of the file in-memory. + * If the in-memory contents are valid we return the in-memory contents else we read + * the file from disk. + * + * @return A dictionary object that contains the contents of the plist file if the file + * exists else nil. + */ +- (NSDictionary *)contentAsDictionary; + +/** + * Check if the plist exists on the disk or not. + * + * @return YES if the file exists on the disk else NO. + */ +- (BOOL)doesFileExist; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.m new file mode 100644 index 0000000..812230b --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.m @@ -0,0 +1,117 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.h" + +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" + +@interface FIRMessagingBackupExcludedPlist () + +@property(nonatomic, readwrite, copy) NSString *fileName; +@property(nonatomic, readwrite, copy) NSString *subDirectoryName; +@property(nonatomic, readwrite, strong) NSDictionary *cachedPlistContents; + +@end + +@implementation FIRMessagingBackupExcludedPlist + +- (instancetype)initWithPlistFile:(NSString *)fileName subDirectory:(NSString *)subDirectory { + self = [super init]; + if (self) { + _fileName = [fileName copy]; + _subDirectoryName = [subDirectory copy]; + } + return self; +} + +- (BOOL)writeDictionary:(NSDictionary *)dict error:(NSError **)error { + NSString *path = [self plistPathInDirectory]; + if (![dict writeToFile:path atomically:YES]) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeBackupExcludedPlist000, + @"Failed to write to %@.plist", self.fileName); + return NO; + } + + // Successfully wrote contents -- change the in-memory contents + self.cachedPlistContents = [dict copy]; + + NSURL *URL = [NSURL fileURLWithPath:path]; + if (error) { + *error = nil; + } + + NSDictionary *preferences = [URL resourceValuesForKeys:@[ NSURLIsExcludedFromBackupKey ] + error:error]; + if ([preferences[NSURLIsExcludedFromBackupKey] boolValue]) { + return YES; + } + + BOOL success = [URL setResourceValue:@(YES) forKey:NSURLIsExcludedFromBackupKey error:error]; + if (!success) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeBackupExcludedPlist001, + @"Error excluding %@ from backup, %@", [URL lastPathComponent], + error ? *error : @""); + } + return success; +} + +- (BOOL)deleteFile:(NSError **)error { + BOOL success = YES; + NSString *path = [self plistPathInDirectory]; + if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { + success = [[NSFileManager defaultManager] removeItemAtPath:path error:error]; + } + // remove the in-memory contents + self.cachedPlistContents = nil; + return success; +} + +- (NSDictionary *)contentAsDictionary { + if (!self.cachedPlistContents) { + NSString *path = [self plistPathInDirectory]; + if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { + self.cachedPlistContents = [[NSDictionary alloc] initWithContentsOfFile:path]; + } + } + return self.cachedPlistContents; +} + +- (BOOL)doesFileExist { + NSString *path = [self plistPathInDirectory]; + return [[NSFileManager defaultManager] fileExistsAtPath:path]; +} + +#pragma mark - Private + +- (NSString *)plistPathInDirectory { + NSArray *directoryPaths; + NSString *plistNameWithExtension = [NSString stringWithFormat:@"%@.plist", self.fileName]; + directoryPaths = + NSSearchPathForDirectoriesInDomains([self supportedDirectory], NSUserDomainMask, YES); + NSArray *components = @[ directoryPaths.lastObject, _subDirectoryName, plistNameWithExtension ]; + + return [NSString pathWithComponents:components]; +} + +- (NSSearchPathDirectory)supportedDirectory { +#if TARGET_OS_TV + return NSCachesDirectory; +#else + return NSApplicationSupportDirectory; +#endif +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h new file mode 100644 index 0000000..93b5556 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h @@ -0,0 +1,110 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +FOUNDATION_EXPORT const NSTimeInterval kFIRMessagingDefaultCheckinInterval; + +/** + * The preferences InstanceID loads from checkin server. The deviceID and secret that checkin + * provides is used to authenticate all future requests to the server. Besides the deviceID + * and secret the other information that checkin provides is stored in a plist on the device. + * The deviceID and secret are persisted in the device keychain. + */ +@interface FIRMessagingCheckinPreferences : NSObject + +/** + * DeviceID and secretToken are the checkin auth credentials and are stored in the Keychain. + */ +@property(nonatomic, readonly, copy) NSString *deviceID; +@property(nonatomic, readonly, copy) NSString *secretToken; + +/** + * All the other checkin preferences other than deviceID and secret are stored in a plist. + */ +@property(nonatomic, readonly, copy) NSString *deviceDataVersion; +@property(nonatomic, readonly, copy) NSString *digest; +@property(nonatomic, readonly, copy) NSString *versionInfo; +@property(nonatomic, readonly, assign) int64_t lastCheckinTimestampMillis; + +/** + * The content retrieved from checkin server that should be persisted in a plist. This + * doesn't contain the deviceID and secret which are stored in the Keychain since they + * should be more private. + * + * @return The checkin preferences that should be persisted in a plist. + */ +- (NSDictionary *)checkinPlistContents; + +/** + * Return whether checkin info exists, valid or not. + */ +- (BOOL)hasCheckinInfo; + +/** + * Verify if checkin preferences are valid or not. + * + * @return YES if valid checkin preferences else NO. + */ +- (BOOL)hasValidCheckinInfo; + +- (BOOL)hasPreCachedAuthCredentials; +- (void)setHasPreCachedAuthCredentials:(BOOL)hasPreCachedAuthCredentials; + +/** + * Parse the checkin auth credentials saved in the Keychain to initialize checkin + * preferences. + * + * @param keychainContent The checkin auth credentials saved in the Keychain. + * + * @return A valid checkin preferences object if the checkin auth credentials in the + * keychain can be parsed successfully else nil. + */ ++ (FIRMessagingCheckinPreferences *)preferencesFromKeychainContents:(NSString *)keychainContent; + +/** + * Default initializer for InstanceID checkin preferences. + * + * @param deviceID The deviceID for the app. + * @param secretToken The secret token the app uses to authenticate with the server. + * + * @return A checkin preferences object with given deviceID and secretToken. + */ +- (instancetype)initWithDeviceID:(NSString *)deviceID secretToken:(NSString *)secretToken; + +/** + * Update checkin preferences from the preferences dict persisted as a plist. The dict contains + * all the checkin preferences retrieved from the server except the deviceID and secret which + * are stored in the Keychain. + * + * @param checkinPlistContent The checkin preferences saved in a plist on the disk. + */ +- (void)updateWithCheckinPlistContents:(NSDictionary *)checkinPlistContent; + +/** + * Reset the current checkin preferences object. + */ +- (void)reset; + +/** + * The string that contains the checkin auth credentials i.e. deviceID and secret. This + * needs to be stored in the Keychain. + * + * @return The checkin auth credential string containing the deviceID and secret. + */ +- (NSString *)checkinKeychainContent; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.m new file mode 100644 index 0000000..b929142 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.m @@ -0,0 +1,168 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h" + +#import +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.h" + +const NSTimeInterval kFIRMessagingDefaultCheckinInterval = 7 * 24 * 60 * 60; // 7 days. +static NSString *const kCheckinKeychainContentSeparatorString = @"|"; + +@interface FIRMessagingCheckinPreferences () + +@property(nonatomic, readwrite, copy) NSString *deviceID; +@property(nonatomic, readwrite, copy) NSString *secretToken; +@property(nonatomic, readwrite, copy) NSString *digest; +@property(nonatomic, readwrite, copy) NSString *versionInfo; +@property(nonatomic, readwrite, copy) NSString *deviceDataVersion; + +@property(nonatomic, readwrite, strong) NSMutableDictionary *gServicesData; +@property(nonatomic, readwrite, assign) int64_t lastCheckinTimestampMillis; + +// This flag indicates that we have already saved the above deviceID and secret +// to our keychain and hence we don't need to save again. This is helpful since +// on checkin refresh we can avoid writing to the Keychain which can sometimes +// be very buggy. For info check this https://forums.developer.apple.com/thread/4743 +@property(nonatomic, readwrite, assign) BOOL hasPreCachedAuthCredentials; + +@end + +@implementation FIRMessagingCheckinPreferences + ++ (FIRMessagingCheckinPreferences *)preferencesFromKeychainContents:(NSString *)keychainContent { + NSString *deviceID = [self checkinDeviceIDFromKeychainContent:keychainContent]; + NSString *secret = [self checkinSecretFromKeychainContent:keychainContent]; + if ([deviceID length] && [secret length]) { + return [[FIRMessagingCheckinPreferences alloc] initWithDeviceID:deviceID secretToken:secret]; + } else { + return nil; + } +} + +- (instancetype)initWithDeviceID:(NSString *)deviceID secretToken:(NSString *)secretToken { + self = [super init]; + if (self) { + self.deviceID = [deviceID copy]; + self.secretToken = [secretToken copy]; + } + return self; +} + +- (void)reset { + self.deviceID = nil; + self.secretToken = nil; + self.digest = nil; + self.versionInfo = nil; + self.gServicesData = nil; + self.deviceDataVersion = nil; + self.lastCheckinTimestampMillis = 0; +} +- (NSDictionary *)checkinPlistContents { + NSMutableDictionary *checkinPlistContents = [NSMutableDictionary dictionary]; + checkinPlistContents[kFIRMessagingDigestStringKey] = self.digest ?: @""; + checkinPlistContents[kFIRMessagingVersionInfoStringKey] = self.versionInfo ?: @""; + checkinPlistContents[kFIRMessagingDeviceDataVersionKey] = self.deviceDataVersion ?: @""; + checkinPlistContents[kFIRMessagingLastCheckinTimeKey] = @(self.lastCheckinTimestampMillis); + checkinPlistContents[kFIRMessagingGServicesDictionaryKey] = + [self.gServicesData count] ? self.gServicesData : @{}; + return checkinPlistContents; +} + +- (BOOL)hasCheckinInfo { + return (self.deviceID.length && self.secretToken.length); +} + +- (BOOL)hasValidCheckinInfo { + int64_t currentTimestampInMillis = FIRMessagingCurrentTimestampInMilliseconds(); + int64_t timeSinceLastCheckinInMillis = currentTimestampInMillis - self.lastCheckinTimestampMillis; + + BOOL hasCheckinInfo = [self hasCheckinInfo]; + NSString *lastLocale = [[GULUserDefaults standardUserDefaults] + stringForKey:kFIRMessagingInstanceIDUserDefaultsKeyLocale]; + // If it's app's first time open and checkin is already fetched and no locale information is + // stored, then checkin info is valid. We should not checkin again because locale is considered + // "changed". + if (hasCheckinInfo && !lastLocale) { + NSString *currentLocale = FIRMessagingCurrentLocale(); + [[GULUserDefaults standardUserDefaults] setObject:currentLocale + forKey:kFIRMessagingInstanceIDUserDefaultsKeyLocale]; + return YES; + } + + // If locale has changed, checkin info is no longer valid. + // Also update locale information if changed. (Only do it here not in token refresh) + if (FIRMessagingHasLocaleChanged()) { + NSString *currentLocale = FIRMessagingCurrentLocale(); + [[GULUserDefaults standardUserDefaults] setObject:currentLocale + forKey:kFIRMessagingInstanceIDUserDefaultsKeyLocale]; + return NO; + } + + return (hasCheckinInfo && + (timeSinceLastCheckinInMillis / 1000.0 < kFIRMessagingDefaultCheckinInterval)); +} + +- (void)setHasPreCachedAuthCredentials:(BOOL)hasPreCachedAuthCredentials { + _hasPreCachedAuthCredentials = hasPreCachedAuthCredentials; +} + +- (NSString *)checkinKeychainContent { + if ([self.deviceID length] && [self.secretToken length]) { + return [NSString stringWithFormat:@"%@%@%@", self.deviceID, + kCheckinKeychainContentSeparatorString, self.secretToken]; + } else { + return nil; + } +} + +- (void)updateWithCheckinPlistContents:(NSDictionary *)checkinPlistContent { + for (NSString *key in checkinPlistContent) { + if ([kFIRMessagingDigestStringKey isEqualToString:key]) { + self.digest = [checkinPlistContent[key] copy]; + } else if ([kFIRMessagingVersionInfoStringKey isEqualToString:key]) { + self.versionInfo = [checkinPlistContent[key] copy]; + } else if ([kFIRMessagingLastCheckinTimeKey isEqualToString:key]) { + self.lastCheckinTimestampMillis = [checkinPlistContent[key] longLongValue]; + } else if ([kFIRMessagingGServicesDictionaryKey isEqualToString:key]) { + self.gServicesData = [checkinPlistContent[key] mutableCopy]; + } else if ([kFIRMessagingDeviceDataVersionKey isEqualToString:key]) { + self.deviceDataVersion = [checkinPlistContent[key] copy]; + } + // Otherwise we have some keys we don't care about + } +} + ++ (NSString *)checkinDeviceIDFromKeychainContent:(NSString *)keychainContent { + return [self checkinKeychainContent:keychainContent forIndex:0]; +} + ++ (NSString *)checkinSecretFromKeychainContent:(NSString *)keychainContent { + return [self checkinKeychainContent:keychainContent forIndex:1]; +} + ++ (NSString *)checkinKeychainContent:(NSString *)keychainContent forIndex:(int)index { + NSArray *keychainComponents = + [keychainContent componentsSeparatedByString:kCheckinKeychainContentSeparatorString]; + if (index >= 0 && index < 2 && [keychainComponents count] == 2) { + return keychainComponents[index]; + } else { + return nil; + } +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.h new file mode 100644 index 0000000..f40f4b1 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.h @@ -0,0 +1,62 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" + +NS_ASSUME_NONNULL_BEGIN + +// keys in Checkin preferences +FOUNDATION_EXPORT NSString *const kFIRMessagingDeviceAuthIdKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingSecretTokenKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingDigestStringKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingLastCheckinTimeKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingVersionInfoStringKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingGServicesDictionaryKey; +FOUNDATION_EXPORT NSString *const kFIRMessagingDeviceDataVersionKey; + +@class FIRMessagingCheckinPreferences; + +/** + * Register the device with Checkin Service and get back the `authID`, `secret + * token` etc. for the client. Checkin results are cached in the + * `FIRMessagingCache` and periodically refreshed to prevent them from being stale. + * Each client needs to register with checkin before registering with InstanceID. + */ +@interface FIRMessagingCheckinService : NSObject + +/** + * Execute a device checkin request to obtain an deviceID, secret token, + * gService data. + * + * @param existingCheckin An existing checkin preference object, if available. + * @param completion Completion handler called on success or failure of device checkin. + */ +- (void)checkinWithExistingCheckin:(nullable FIRMessagingCheckinPreferences *)existingCheckin + completion: + (void (^)(FIRMessagingCheckinPreferences *_Nullable checkinPreferences, + NSError *_Nullable error))completion; + +/** + * This would stop any request that the service made to the checkin backend and also + * release any callback handlers that it holds. + */ +- (void)stopFetching; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.m new file mode 100644 index 0000000..ccb20cf --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.m @@ -0,0 +1,227 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.h" + +#import +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingAuthService.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h" + +static NSString *const kDeviceCheckinURL = @"https://device-provisioning.googleapis.com/checkin"; + +// keys in Checkin preferences +NSString *const kFIRMessagingDeviceAuthIdKey = @"GMSInstanceIDDeviceAuthIdKey"; +NSString *const kFIRMessagingSecretTokenKey = @"GMSInstanceIDSecretTokenKey"; +NSString *const kFIRMessagingDigestStringKey = @"GMSInstanceIDDigestKey"; +NSString *const kFIRMessagingLastCheckinTimeKey = @"GMSInstanceIDLastCheckinTimestampKey"; +NSString *const kFIRMessagingVersionInfoStringKey = @"GMSInstanceIDVersionInfo"; +NSString *const kFIRMessagingGServicesDictionaryKey = @"GMSInstanceIDGServicesData"; +NSString *const kFIRMessagingDeviceDataVersionKey = @"GMSInstanceIDDeviceDataVersion"; + +static NSUInteger const kCheckinType = 2; // DeviceType IOS in l/w/a/_checkin.proto +static NSUInteger const kCheckinVersion = 2; +static NSUInteger const kFragment = 0; + +@interface FIRMessagingCheckinService () + +@property(nonatomic, readwrite, strong) NSURLSession *session; + +@end + +@implementation FIRMessagingCheckinService + +- (instancetype)init { + self = [super init]; + if (self) { + // Create an URLSession once, even though checkin should happen about once a day + NSURLSessionConfiguration *config = NSURLSessionConfiguration.defaultSessionConfiguration; + config.timeoutIntervalForResource = 60.0f; // 1 minute + config.allowsCellularAccess = YES; + + self.session = [NSURLSession sessionWithConfiguration:config]; + self.session.sessionDescription = @"com.google.iid-checkin"; + } + return self; +} +- (void)dealloc { + [self.session invalidateAndCancel]; +} + +- (void)checkinWithExistingCheckin:(FIRMessagingCheckinPreferences *)existingCheckin + completion:(FIRMessagingDeviceCheckinCompletion)completion { + if (self.session == nil) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeService005, + @"Inconsistent state: NSURLSession has been invalidated"); + NSError *error = + [NSError messagingErrorWithCode:kFIRMessagingErrorCodeRegistrarFailedToCheckIn + failureReason:@"Failed to checkin. NSURLSession is invalid."]; + if (completion) { + completion(nil, error); + } + return; + } + NSURL *url = [NSURL URLWithString:kDeviceCheckinURL]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + [request setValue:@"application/json" forHTTPHeaderField:@"content-type"]; + NSDictionary *checkinParameters = [self checkinParametersWithExistingCheckin:existingCheckin]; + NSData *checkinData = [NSJSONSerialization dataWithJSONObject:checkinParameters + options:0 + error:nil]; + request.HTTPMethod = @"POST"; + request.HTTPBody = checkinData; + + void (^handler)(NSData *, NSURLResponse *, NSError *) = + ^(NSData *data, NSURLResponse *response, NSError *error) { + if (error) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeService000, + @"Device checkin HTTP fetch error. Error Code: %ld", + (long)error.code); + if (completion) { + completion(nil, error); + } + return; + } + + NSError *serializationError = nil; + NSDictionary *dataResponse = [NSJSONSerialization JSONObjectWithData:data + options:0 + error:&serializationError]; + if (serializationError) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeService001, + @"Error serializing json object. Error Code: %ld", + (long)serializationError.code); + if (completion) { + completion(nil, serializationError); + } + return; + } + + NSString *deviceAuthID = [dataResponse[@"android_id"] stringValue]; + NSString *secretToken = [dataResponse[@"security_token"] stringValue]; + if ([deviceAuthID length] == 0) { + NSError *error = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeInvalidRequest + failureReason:@"Invalid device auth ID."]; + if (completion) { + completion(nil, error); + } + return; + } + + int64_t lastCheckinTimestampMillis = [dataResponse[@"time_msec"] longLongValue]; + int64_t currentTimestampMillis = FIRMessagingCurrentTimestampInMilliseconds(); + // Somehow the server clock gets out of sync with the device clock. + // Reset the last checkin timestamp in case this happens. + if (lastCheckinTimestampMillis > currentTimestampMillis) { + FIRMessagingLoggerDebug( + kFIRMessagingMessageCodeService002, @"Invalid last checkin timestamp %@ in future.", + [NSDate dateWithTimeIntervalSince1970:lastCheckinTimestampMillis / 1000.0]); + lastCheckinTimestampMillis = currentTimestampMillis; + } + + NSString *deviceDataVersionInfo = dataResponse[@"device_data_version_info"] ?: @""; + NSString *digest = dataResponse[@"digest"] ?: @""; + + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeService003, + @"Checkin successful with authId: %@, " + @"digest: %@, " + @"lastCheckinTimestamp: %lld", + deviceAuthID, digest, lastCheckinTimestampMillis); + + NSString *versionInfo = dataResponse[@"version_info"] ?: @""; + NSMutableDictionary *gservicesData = [NSMutableDictionary dictionary]; + + // Read gServices data. + NSArray *flatSettings = dataResponse[@"setting"]; + for (NSDictionary *dict in flatSettings) { + if (dict[@"name"] && dict[@"value"]) { + gservicesData[dict[@"name"]] = dict[@"value"]; + } else { + FIRMessagingLoggerDebug(kFIRMessagingInvalidSettingResponse, + @"Invalid setting in checkin response: (%@: %@)", dict[@"name"], + dict[@"value"]); + } + } + + FIRMessagingCheckinPreferences *checkinPreferences = + [[FIRMessagingCheckinPreferences alloc] initWithDeviceID:deviceAuthID + secretToken:secretToken]; + NSDictionary *preferences = @{ + kFIRMessagingDigestStringKey : digest, + kFIRMessagingVersionInfoStringKey : versionInfo, + kFIRMessagingLastCheckinTimeKey : @(lastCheckinTimestampMillis), + kFIRMessagingGServicesDictionaryKey : gservicesData, + kFIRMessagingDeviceDataVersionKey : deviceDataVersionInfo, + }; + [checkinPreferences updateWithCheckinPlistContents:preferences]; + if (completion) { + completion(checkinPreferences, nil); + } + }; + + NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:handler]; + [task resume]; +} + +- (void)stopFetching { + [self.session invalidateAndCancel]; + // The session cannot be reused after invalidation. Dispose it to prevent accident reusing. + self.session = nil; +} + +#pragma mark - Private + +- (NSDictionary *)checkinParametersWithExistingCheckin: + (nullable FIRMessagingCheckinPreferences *)checkinPreferences { + NSString *deviceModel = [GULAppEnvironmentUtil deviceModel]; + NSString *systemVersion = [GULAppEnvironmentUtil systemVersion]; + NSString *osVersion = [NSString stringWithFormat:@"IOS_%@", systemVersion]; + + // Get locale from GCM if GCM exists else use system API. + NSString *locale = FIRMessagingCurrentLocale(); + + NSInteger userNumber = 0; // Multi Profile may change this. + NSInteger userSerialNumber = 0; // Multi Profile may change this + + NSString *timeZone = [NSTimeZone localTimeZone].name; + int64_t lastCheckingTimestampMillis = checkinPreferences.lastCheckinTimestampMillis; + + NSDictionary *checkinParameters = @{ + @"checkin" : @{ + @"iosbuild" : @{@"model" : deviceModel, @"os_version" : osVersion}, + @"type" : @(kCheckinType), + @"user_number" : @(userNumber), + @"last_checkin_msec" : @(lastCheckingTimestampMillis), + }, + @"fragment" : @(kFragment), + @"locale" : locale, + @"version" : @(kCheckinVersion), + @"digest" : checkinPreferences.digest ?: @"", + @"time_zone" : timeZone, + @"user_serial_number" : @(userSerialNumber), + @"id" : @([checkinPreferences.deviceID longLongValue]), + @"security_token" : @([checkinPreferences.secretToken longLongValue]), + }; + + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeService006, @"Checkin parameters: %@", + checkinParameters); + return checkinParameters; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.h new file mode 100644 index 0000000..994b519 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.h @@ -0,0 +1,70 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRMessagingAuthKeychain; +@class FIRMessagingBackupExcludedPlist; +@class FIRMessagingCheckinPreferences; + +// These values exposed for testing +extern NSString *const kFIRMessagingCheckinKeychainService; + +/** + * Checkin preferences backing store. + */ +@interface FIRMessagingCheckinStore : NSObject + +/** + * Checks whether the backup excluded checkin preferences are present on the disk or not. + * + * @return YES if the backup excluded checkin plist exists on the disks else NO. + */ +- (BOOL)hasCheckinPlist; + +#pragma mark - Save + +/** + * Save the checkin preferences to backing store. + * + * @param preferences Checkin preferences to save. + * @param handler The callback handler which is invoked when the operation is complete, + * with an error if there is any. + */ +- (void)saveCheckinPreferences:(FIRMessagingCheckinPreferences *)preferences + handler:(void (^)(NSError *error))handler; + +#pragma mark - Delete + +/** + * Remove the cached checkin preferences. + * + * @param handler The callback handler which is invoked when the operation is complete, + * with an error if there is any. + */ +- (void)removeCheckinPreferencesWithHandler:(void (^)(NSError *error))handler; + +#pragma mark - Get + +/** + * Get the cached device secret. If we cannot access it for some reason we + * return the appropriate error object. + * + * @return The cached checkin preferences if present else nil. + */ +- (FIRMessagingCheckinPreferences *)cachedCheckinPreferences; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.m new file mode 100644 index 0000000..a9facf8 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.m @@ -0,0 +1,186 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.h" + +#import "FirebaseMessaging/Sources/FIRMessagingCode.h" +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.h" + +// NOTE: These values should be in sync with what InstanceID saves in as. +static NSString *const kCheckinFileName = @"g-checkin"; +static NSString *const kFIRMessagingCheckinKeychainGeneric = @"com.google.iid"; +NSString *const kFIRMessagingCheckinKeychainService = @"com.google.iid.checkin"; + +@interface FIRMessagingCheckinStore () + +@property(nonatomic, readwrite, strong) FIRMessagingBackupExcludedPlist *plist; +@property(nonatomic, readwrite, strong) FIRMessagingAuthKeychain *keychain; +// Checkin will store items under +// Keychain account: , +// Keychain service: |kFIRMessagingCheckinKeychainService| +@property(nonatomic, readonly) NSString *bundleIdentifierForKeychainAccount; + +@end + +@implementation FIRMessagingCheckinStore + +- (instancetype)init { + self = [super init]; + if (self) { + _plist = [[FIRMessagingBackupExcludedPlist alloc] + initWithPlistFile:kCheckinFileName + subDirectory:kFIRMessagingInstanceIDSubDirectoryName]; + _keychain = + [[FIRMessagingAuthKeychain alloc] initWithIdentifier:kFIRMessagingCheckinKeychainGeneric]; + } + return self; +} + +- (BOOL)hasCheckinPlist { + return [self.plist doesFileExist]; +} + +- (NSString *)bundleIdentifierForKeychainAccount { + static NSString *bundleIdentifier; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + bundleIdentifier = FIRMessagingAppIdentifier(); + }); + return bundleIdentifier; +} + +- (void)saveCheckinPreferences:(FIRMessagingCheckinPreferences *)preferences + handler:(void (^)(NSError *error))handler { + NSDictionary *checkinPlistContents = [preferences checkinPlistContents]; + NSString *checkinKeychainContent = [preferences checkinKeychainContent]; + + if (![checkinKeychainContent length]) { + NSString *failureReason = @"Failed to get checkin keychain content from memory."; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeCheckinStore000, @"%@", failureReason); + if (handler) { + handler([NSError messagingErrorWithCode:kFIRMessagingErrorCodeRegistrarFailedToCheckIn + failureReason:failureReason]); + } + return; + } + if (![checkinPlistContents count]) { + NSString *failureReason = @"Failed to get checkin plist contents from memory."; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeCheckinStore001, @"%@", failureReason); + if (handler) { + handler([NSError messagingErrorWithCode:kFIRMessagingErrorCodeRegistrarFailedToCheckIn + failureReason:failureReason]); + } + return; + } + + // Save all other checkin preferences in a plist + NSError *error; + if (![self.plist writeDictionary:checkinPlistContents error:&error]) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeCheckinStore003, + @"Failed to save checkin plist contents." + @"Will delete auth credentials"); + [self.keychain removeItemsMatchingService:kFIRMessagingCheckinKeychainService + account:self.bundleIdentifierForKeychainAccount + handler:nil]; + if (handler) { + handler(error); + } + return; + } + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeCheckinStoreCheckinPlistSaved, + @"Checkin plist file is saved"); + + // Save the deviceID and secret in the Keychain + if (!preferences.hasPreCachedAuthCredentials) { + NSData *data = [checkinKeychainContent dataUsingEncoding:NSUTF8StringEncoding]; + [self.keychain setData:data + forService:kFIRMessagingCheckinKeychainService + account:self.bundleIdentifierForKeychainAccount + handler:^(NSError *error) { + if (error) { + if (handler) { + handler(error); + } + return; + } + if (handler) { + handler(nil); + } + }]; + } else { + handler(nil); + } +} + +- (void)removeCheckinPreferencesWithHandler:(void (^)(NSError *error))handler { + // Delete the checkin preferences plist first to avoid delay. + NSError *deletePlistError; + if (![self.plist deleteFile:&deletePlistError]) { + handler(deletePlistError); + return; + } + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeCheckinStoreCheckinPlistDeleted, + @"Deleted checkin plist file."); + // Remove deviceID and secret from Keychain + [self.keychain removeItemsMatchingService:kFIRMessagingCheckinKeychainService + account:self.bundleIdentifierForKeychainAccount + handler:^(NSError *error) { + handler(error); + }]; +} + +- (FIRMessagingCheckinPreferences *)cachedCheckinPreferences { + // Query the keychain for deviceID and secret + NSData *item = [self.keychain dataForService:kFIRMessagingCheckinKeychainService + account:self.bundleIdentifierForKeychainAccount]; + + // Check info found in keychain + NSString *checkinKeychainContent = [[NSString alloc] initWithData:item + encoding:NSUTF8StringEncoding]; + FIRMessagingCheckinPreferences *checkinPreferences = [FIRMessagingCheckinPreferences + preferencesFromKeychainContents:[checkinKeychainContent copy]]; + + NSDictionary *checkinPlistContents = [self.plist contentAsDictionary]; + + NSString *plistDeviceAuthID = checkinPlistContents[kFIRMessagingDeviceAuthIdKey]; + NSString *plistSecretToken = checkinPlistContents[kFIRMessagingSecretTokenKey]; + + // If deviceID and secret not found in the keychain verify that we don't have them in the + // checkin preferences plist. + if (![checkinPreferences.deviceID length] && ![checkinPreferences.secretToken length]) { + if ([plistDeviceAuthID length] && [plistSecretToken length]) { + // Couldn't find checkin credentials in keychain but found them in the plist. + checkinPreferences = + [[FIRMessagingCheckinPreferences alloc] initWithDeviceID:plistDeviceAuthID + secretToken:plistSecretToken]; + } else { + // Couldn't find checkin credentials in keychain nor plist + return nil; + } + } + + [checkinPreferences updateWithCheckinPlistContents:checkinPlistContents]; + return checkinPreferences; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingKeychain.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingKeychain.h new file mode 100644 index 0000000..73bcfbb --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingKeychain.h @@ -0,0 +1,62 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/* The Keychain error domain */ +extern NSString *const kFIRMessagingKeychainErrorDomain; + +/* + * Wrapping the keychain operations in a serialize queue. This is to avoid keychain operation + * blocking main queue. + */ +@interface FIRMessagingKeychain : NSObject + +/** + * FIRMessagingKeychain. + * + * @return A shared instance of FIRMessagingKeychain. + */ ++ (instancetype)sharedInstance; + +/** + * Get keychain items matching the given a query. + * + * @param keychainQuery The keychain query. + * + * @return An CFTypeRef result matching the provided inputs. + */ +- (CFTypeRef)itemWithQuery:(NSDictionary *)keychainQuery; + +/** + * Remove the cached items from the keychain matching the query. + * + * @param keychainQuery The keychain query. + * @param handler The callback handler which is invoked when the remove operation is + * complete, with an error if there is any. + */ +- (void)removeItemWithQuery:(NSDictionary *)keychainQuery handler:(void (^)(NSError *error))handler; + +/** + * Add the item with a given query. + * + * @param keychainQuery The keychain query. + * @param handler The callback handler which is invoked when the add operation is + * complete, with an error if there is any. + */ +- (void)addItemWithQuery:(NSDictionary *)keychainQuery handler:(void (^)(NSError *))handler; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingKeychain.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingKeychain.m new file mode 100644 index 0000000..d9527f0 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingKeychain.m @@ -0,0 +1,110 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingKeychain.h" + +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" + +NSString *const kFIRMessagingKeychainErrorDomain = @"com.google.iid"; + +@interface FIRMessagingKeychain () { + dispatch_queue_t _keychainOperationQueue; +} + +@end + +@implementation FIRMessagingKeychain + ++ (instancetype)sharedInstance { + static FIRMessagingKeychain *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRMessagingKeychain alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _keychainOperationQueue = + dispatch_queue_create("com.google.FirebaseInstanceID.Keychain", DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (CFTypeRef)itemWithQuery:(NSDictionary *)keychainQuery { + __block SecKeyRef keyRef = NULL; + dispatch_sync(_keychainOperationQueue, ^{ + OSStatus status = + SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyRef); + + if (status != noErr) { + if (keyRef) { + CFRelease(keyRef); + } + FIRMessagingLoggerDebug(kFIRMessagingKeychainReadItemError, + @"Info is not found in Keychain. OSStatus: %d. Keychain query: %@", + (int)status, keychainQuery); + } + }); + return keyRef; +} + +- (void)removeItemWithQuery:(NSDictionary *)keychainQuery + handler:(void (^)(NSError *error))handler { + dispatch_async(_keychainOperationQueue, ^{ + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)keychainQuery); + if (status != noErr) { + FIRMessagingLoggerDebug( + kFIRMessagingKeychainDeleteItemError, + @"Couldn't delete item from Keychain OSStatus: %d with the keychain query %@", + (int)status, keychainQuery); + } + + if (handler) { + NSError *error = nil; + // When item is not found, it should NOT be considered as an error. The operation should + // continue. + if (status != noErr && status != errSecItemNotFound) { + error = [NSError errorWithDomain:kFIRMessagingKeychainErrorDomain code:status userInfo:nil]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + handler(error); + }); + } + }); +} + +- (void)addItemWithQuery:(NSDictionary *)keychainQuery handler:(void (^)(NSError *))handler { + dispatch_async(_keychainOperationQueue, ^{ + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL); + + if (handler) { + NSError *error = nil; + if (status != noErr) { + FIRMessagingLoggerWarn(kFIRMessagingKeychainAddItemError, + @"Couldn't add item to Keychain OSStatus: %d", (int)status); + error = [NSError errorWithDomain:kFIRMessagingKeychainErrorDomain code:status userInfo:nil]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + handler(error); + }); + } + }); +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.h new file mode 100644 index 0000000..98b9f66 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.h @@ -0,0 +1,32 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRMessagingTokenDeleteOperation : FIRMessagingTokenOperation + +- (instancetype)initWithAuthorizedEntity:(nullable NSString *)authorizedEntity + scope:(nullable NSString *)scope + checkinPreferences:(FIRMessagingCheckinPreferences *)checkinPreferences + instanceID:(nullable NSString *)instanceID + action:(FIRMessagingTokenAction)action + heartbeatLogger:(id)heartbeatLogger; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.m new file mode 100644 index 0000000..ae0097c --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.m @@ -0,0 +1,119 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.h" + +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h" + +@implementation FIRMessagingTokenDeleteOperation + +- (instancetype)initWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + checkinPreferences:(FIRMessagingCheckinPreferences *)checkinPreferences + instanceID:(NSString *)instanceID + action:(FIRMessagingTokenAction)action + heartbeatLogger:(id)heartbeatLogger { + return [super initWithAction:action + forAuthorizedEntity:authorizedEntity + scope:scope + options:nil + checkinPreferences:checkinPreferences + instanceID:instanceID + heartbeatLogger:heartbeatLogger]; +} + +- (void)performTokenOperation { + NSMutableURLRequest *request = [self tokenRequest]; + + // Build form-encoded body + NSString *deviceAuthID = self.checkinPreferences.deviceID; + NSMutableArray *queryItems = + [FIRMessagingTokenOperation standardQueryItemsWithDeviceID:deviceAuthID scope:self.scope]; + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"delete" value:@"true"]]; + if (self.action == FIRMessagingTokenActionDeleteTokenAndIID) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"iid-operation" value:@"delete"]]; + } + if (self.authorizedEntity) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"sender" value:self.authorizedEntity]]; + } + // Typically we include our public key-signed url items, but in some cases (like deleting all FCM + // tokens), we don't. + if (self.instanceID.length > 0) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kFIRMessagingParamInstanceID + value:self.instanceID]]; + } + + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.queryItems = queryItems; + NSString *content = components.query; + request.HTTPBody = [content dataUsingEncoding:NSUTF8StringEncoding]; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenDeleteOperationFetchRequest, + @"Unregister request to %@ content: %@", + FIRMessagingTokenRegisterServer(), content); + + FIRMessaging_WEAKIFY(self); + void (^requestHandler)(NSData *, NSURLResponse *, NSError *) = + ^(NSData *data, NSURLResponse *response, NSError *error) { + FIRMessaging_STRONGIFY(self); + [self handleResponseWithData:data response:response error:error]; + }; + + NSURLSessionConfiguration *config = NSURLSessionConfiguration.ephemeralSessionConfiguration; + config.timeoutIntervalForResource = 60.0f; // 1 minute + NSURLSession *session = [NSURLSession sessionWithConfiguration:config]; + self.dataTask = [session dataTaskWithRequest:request completionHandler:requestHandler]; + [self.dataTask resume]; +} + +- (void)handleResponseWithData:(NSData *)data + response:(NSURLResponse *)response + error:(NSError *)error { + if (error) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenDeleteOperationRequestError, + @"Device unregister HTTP fetch error. Error code: %ld", + (long)error.code); + [self finishWithResult:FIRMessagingTokenOperationError token:nil error:error]; + return; + } + + NSString *dataResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if (dataResponse.length == 0) { + NSError *error = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeUnknown + failureReason:@"Empty response."]; + [self finishWithResult:FIRMessagingTokenOperationError token:nil error:error]; + return; + } + + if (![dataResponse hasPrefix:@"deleted="] && ![dataResponse hasPrefix:@"token="]) { + NSString *failureReason = + [NSString stringWithFormat:@"Invalid unregister response %@", response]; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenDeleteOperationBadResponse, @"%@", + failureReason); + NSError *error = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeUnknown + failureReason:failureReason]; + [self finishWithResult:FIRMessagingTokenOperationError token:nil error:error]; + return; + } + [self finishWithResult:FIRMessagingTokenOperationSucceeded token:nil error:nil]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.h new file mode 100644 index 0000000..646262b --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kFIRMessagingFirebaseUserAgentKey; + +FOUNDATION_EXPORT NSString *const kFIRMessagingFirebaseHeartbeatKey; + +@interface FIRMessagingTokenFetchOperation : FIRMessagingTokenOperation + +- (instancetype)initWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + options:(nullable NSDictionary *)options + checkinPreferences:(FIRMessagingCheckinPreferences *)checkinPreferences + instanceID:(NSString *)instanceID + heartbeatLogger:(id)heartbeatLogger; + +@end +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.m new file mode 100644 index 0000000..a6ecc95 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.m @@ -0,0 +1,205 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.h" + +#import "FirebaseMessaging/Sources/FIRMessagingCode.h" +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +// We can have a static int since this error should theoretically only +// happen once (for the first time). If it repeats there is something +// else that is wrong. +static int phoneRegistrationErrorRetryCount = 0; +static const int kMaxPhoneRegistrationErrorRetryCount = 10; +NSString *const kFIRMessagingFirebaseUserAgentKey = @"X-firebase-client"; +NSString *const kFIRMessagingFirebaseHeartbeatKey = @"X-firebase-client-log-type"; + +@implementation FIRMessagingTokenFetchOperation + +- (instancetype)initWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + options:(nullable NSDictionary *)options + checkinPreferences:(FIRMessagingCheckinPreferences *)checkinPreferences + instanceID:(NSString *)instanceID + heartbeatLogger:(id)heartbeatLogger { + return [super initWithAction:FIRMessagingTokenActionFetch + forAuthorizedEntity:authorizedEntity + scope:scope + options:options + checkinPreferences:checkinPreferences + instanceID:instanceID + heartbeatLogger:heartbeatLogger]; +} + +- (void)performTokenOperation { + NSMutableURLRequest *request = [self tokenRequest]; + NSString *checkinVersionInfo = self.checkinPreferences.versionInfo; + [request setValue:checkinVersionInfo forHTTPHeaderField:@"info"]; + [request setValue:[FIRApp firebaseUserAgent] + forHTTPHeaderField:kFIRMessagingFirebaseUserAgentKey]; + [request setValue:@([self.heartbeatLogger heartbeatCodeForToday]).stringValue + forHTTPHeaderField:kFIRMessagingFirebaseHeartbeatKey]; + + // Build form-encoded body + NSString *deviceAuthID = self.checkinPreferences.deviceID; + NSMutableArray *queryItems = + [[self class] standardQueryItemsWithDeviceID:deviceAuthID scope:self.scope]; + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"sender" value:self.authorizedEntity]]; + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"X-subtype" + value:self.authorizedEntity]]; + + if (self.instanceID.length > 0) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kFIRMessagingParamInstanceID + value:self.instanceID]]; + } + // Create query items from passed-in options + id apnsTokenData = self.options[kFIRMessagingTokenOptionsAPNSKey]; + id apnsSandboxValue = self.options[kFIRMessagingTokenOptionsAPNSIsSandboxKey]; + if ([apnsTokenData isKindOfClass:[NSData class]] && + [apnsSandboxValue isKindOfClass:[NSNumber class]]) { + NSString *APNSString = FIRMessagingAPNSTupleStringForTokenAndServerType( + apnsTokenData, ((NSNumber *)apnsSandboxValue).boolValue); + // The name of the query item happens to be the same as the dictionary key + NSURLQueryItem *item = [NSURLQueryItem queryItemWithName:kFIRMessagingTokenOptionsAPNSKey + value:APNSString]; + [queryItems addObject:item]; + } + id firebaseAppID = self.options[kFIRMessagingTokenOptionsFirebaseAppIDKey]; + if ([firebaseAppID isKindOfClass:[NSString class]]) { + // The name of the query item happens to be the same as the dictionary key + NSURLQueryItem *item = + [NSURLQueryItem queryItemWithName:kFIRMessagingTokenOptionsFirebaseAppIDKey + value:(NSString *)firebaseAppID]; + [queryItems addObject:item]; + } + + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.queryItems = queryItems; + NSString *content = components.query; + request.HTTPBody = [content dataUsingEncoding:NSUTF8StringEncoding]; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenFetchOperationFetchRequest, + @"Register request to %@ content: %@", FIRMessagingTokenRegisterServer(), + content); + + FIRMessaging_WEAKIFY(self); + void (^requestHandler)(NSData *, NSURLResponse *, NSError *) = + ^(NSData *data, NSURLResponse *response, NSError *error) { + FIRMessaging_STRONGIFY(self); + [self handleResponseWithData:data response:response error:error]; + }; + NSURLSessionConfiguration *config = NSURLSessionConfiguration.ephemeralSessionConfiguration; + config.timeoutIntervalForResource = 60.0f; // 1 minute + NSURLSession *session = [NSURLSession sessionWithConfiguration:config]; + self.dataTask = [session dataTaskWithRequest:request completionHandler:requestHandler]; + [self.dataTask resume]; +} + +#pragma mark - Request Handling + +- (void)handleResponseWithData:(NSData *)data + response:(NSURLResponse *)response + error:(NSError *)error { + if (error) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenFetchOperationRequestError, + @"Token fetch HTTP error. Error Code: %ld", (long)error.code); + [self finishWithResult:FIRMessagingTokenOperationError token:nil error:error]; + return; + } + NSString *dataResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + + if (dataResponse.length == 0) { + NSError *error = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeUnknown + failureReason:@"Empty response."]; + [self finishWithResult:FIRMessagingTokenOperationError token:nil error:error]; + return; + } + NSDictionary *parsedResponse = [self parseFetchTokenResponse:dataResponse]; + + if ([parsedResponse[@"token"] length]) { + [self finishWithResult:FIRMessagingTokenOperationSucceeded + token:parsedResponse[@"token"] + error:nil]; + return; + } + + NSString *errorValue = parsedResponse[@"Error"]; + NSError *responseError = nil; + if (errorValue.length) { + NSArray *errorComponents = [errorValue componentsSeparatedByString:@":"]; + // HACK (Kansas replication delay), PHONE_REGISTRATION_ERROR on App + // uninstall and reinstall. + if ([errorComponents containsObject:@"PHONE_REGISTRATION_ERROR"]) { + // Encountered issue http://b/27043795 + // Retry register until successful or another error encountered or a + // certain number of tries are over. + + if (phoneRegistrationErrorRetryCount < kMaxPhoneRegistrationErrorRetryCount) { + const int nextRetryInterval = 1 << phoneRegistrationErrorRetryCount; + FIRMessaging_WEAKIFY(self); + + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(nextRetryInterval * NSEC_PER_SEC)), + dispatch_get_main_queue(), ^{ + FIRMessaging_STRONGIFY(self); + phoneRegistrationErrorRetryCount++; + [self performTokenOperation]; + }); + return; + } + } else if ([errorComponents containsObject:kFIRMessaging_CMD_RST]) { + NSString *failureReason = @"Identity is invalid. Server request identity reset."; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeInternal001, @"%@", failureReason); + responseError = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeInvalidIdentity + failureReason:failureReason]; + } else { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenFetchOperationRequestError, + @"Token fetch got an error from server: %@", errorValue); + responseError = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeUnknown + failureReason:errorValue]; + } + } + if (!responseError) { + NSString *failureReason = @"Invalid fetch response, expected 'token' or 'Error' key"; + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenFetchOperationBadResponse, @"%@", + failureReason); + responseError = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeUnknown + failureReason:failureReason]; + } + [self finishWithResult:FIRMessagingTokenOperationError token:nil error:responseError]; +} + +// expect a response e.g. "token=\nGOOG.ttl=123" +- (NSDictionary *)parseFetchTokenResponse:(NSString *)response { + NSArray *lines = [response componentsSeparatedByString:@"\n"]; + NSMutableDictionary *parsedResponse = [NSMutableDictionary dictionary]; + for (NSString *line in lines) { + NSArray *keyAndValue = [line componentsSeparatedByString:@"="]; + if ([keyAndValue count] > 1) { + parsedResponse[keyAndValue[0]] = keyAndValue[1]; + } + } + return parsedResponse; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h new file mode 100644 index 0000000..c4714fd --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h @@ -0,0 +1,95 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Represents an Instance ID token, and all of the relevant information + * associated with it. It can read from and write to an NSDictionary object, for + * simple serialization. + */ +@interface FIRMessagingTokenInfo : NSObject + +/// The authorized entity (also known as Sender ID), associated with the token. +@property(nonatomic, readonly, copy) NSString *authorizedEntity; +/// The scope associated with the token. This is an arbitrary string, typically "*". +@property(nonatomic, readonly, copy) NSString *scope; +/// The token value itself, with which all other properties are associated. +@property(nonatomic, readonly, copy) NSString *token; + +// These properties are nullable because they might not exist for tokens fetched from +// legacy storage formats. + +/// The app version that this token represents. +@property(nonatomic, readonly, copy, nullable) NSString *appVersion; +/// The Firebase app ID (also known as GMP App ID), that this token is associated with. +@property(nonatomic, readonly, copy, nullable) NSString *firebaseAppID; + +/// Tokens may not always be associated with an APNs token, and may be associated after +/// being created. +@property(nonatomic, strong, nullable) FIRMessagingAPNSInfo *APNSInfo; +/// The time that this token info was updated. The cache time is writeable, since in +/// some cases the token info may be refreshed from the server. In those situations, +/// the cacheTime would be updated. +@property(nonatomic, copy, nullable) NSDate *cacheTime; + +/// Indicates the info was stored on the keychain by version 10.18.0 or earlier. +@property(nonatomic, readonly) BOOL needsMigration; + +/** + * Initializes a FIRMessagingTokenInfo object with the required parameters. These + * parameters represent all the relevant associated data with a token. + * + * @param authorizedEntity The authorized entity (also known as Sender ID). + * @param scope The scope of the token, typically "*" meaning + * it's a "default scope". + * @param token The token value itself. + * @param appVersion The application version that this token is associated with. + * @param firebaseAppID The Firebase app ID which this token is associated with. + * @return An instance of FIRMessagingTokenInfo. + */ +- (instancetype)initWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + token:(NSString *)token + appVersion:(nullable NSString *)appVersion + firebaseAppID:(nullable NSString *)firebaseAppID; + +/** + * Check whether the token is still fresh based on: + * 1. Last fetch token is within the 7 days. + * 2. Language setting is not changed. + * 3. App version is current. + * 4. GMP App ID is current. + * 5. token is consistent with the current IID. + * 6. APNS info has changed. + * @param IID The app identifiier that is used to check if token is prefixed with. + * @return If token is fresh. + * + */ +- (BOOL)isFreshWithIID:(NSString *)IID; + +/* + * Check whether the token is default token. + */ +- (BOOL)isDefaultToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.m new file mode 100644 index 0000000..683473c --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.m @@ -0,0 +1,223 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h" + +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" + +/** + * @enum Token Info Dictionary Key Constants + * @discussion The keys that are checked when a token info is + * created from a dictionary. The same keys are used + * when decoding/encoding an archive. + */ +/// Specifies a dictionary key whose value represents the authorized entity, or +/// Sender ID for the token. +static NSString *const kFIRInstanceIDAuthorizedEntityKey = @"authorized_entity"; +/// Specifies a dictionary key whose value represents the scope of the token, +/// typically "*". +static NSString *const kFIRInstanceIDScopeKey = @"scope"; +/// Specifies a dictionary key which represents the token value itself. +static NSString *const kFIRInstanceIDTokenKey = @"token"; +/// Specifies a dictionary key which represents the app version associated +/// with the token. +static NSString *const kFIRInstanceIDAppVersionKey = @"app_version"; +/// Specifies a dictionary key which represents the GMP App ID associated with +/// the token. +static NSString *const kFIRInstanceIDFirebaseAppIDKey = @"firebase_app_id"; +/// Specifies a dictionary key representing an archive for a +/// `FIRInstanceIDAPNSInfo` object. +static NSString *const kFIRInstanceIDAPNSInfoKey = @"apns_info"; +/// Specifies a dictionary key representing the "last cached" time for the token. +static NSString *const kFIRInstanceIDCacheTimeKey = @"cache_time"; +/// Default interval that token stays fresh. +static const NSTimeInterval kDefaultFetchTokenInterval = 7 * 24 * 60 * 60; // 7 days. + +@implementation FIRMessagingTokenInfo + +- (instancetype)initWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + token:(NSString *)token + appVersion:(NSString *)appVersion + firebaseAppID:(NSString *)firebaseAppID { + self = [super init]; + if (self) { + _authorizedEntity = [authorizedEntity copy]; + _scope = [scope copy]; + _token = [token copy]; + _appVersion = [appVersion copy]; + _firebaseAppID = [firebaseAppID copy]; + } + return self; +} + +- (BOOL)isFreshWithIID:(NSString *)IID { + // Last fetch token cache time could be null if token is from legacy storage format. Then token is + // considered not fresh and should be refreshed and overwrite with the latest storage format. + if (!IID) { + return NO; + } + if (!_cacheTime) { + return NO; + } + + // Check if it's consistent with IID + if (![self.token hasPrefix:IID]) { + return NO; + } + + if ([self hasDenylistedScope]) { + return NO; + } + + // Check if app has just been updated to a new version. + NSString *currentAppVersion = FIRMessagingCurrentAppVersion(); + if (!_appVersion || ![_appVersion isEqualToString:currentAppVersion]) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenManager004, + @"Invalidating cached token for %@ (%@) due to app version change.", + _authorizedEntity, _scope); + return NO; + } + + // Check if GMP App ID has changed + NSString *currentFirebaseAppID = FIRMessagingFirebaseAppID(); + if (!_firebaseAppID || ![_firebaseAppID isEqualToString:currentFirebaseAppID]) { + FIRMessagingLoggerDebug( + kFIRMessagingMessageCodeTokenInfoFirebaseAppIDChanged, + @"Invalidating cached token due to Firebase App IID change from %@ to %@", _firebaseAppID, + currentFirebaseAppID); + return NO; + } + + // Check whether locale has changed, if yes, token needs to be updated with server for locale + // information. + if (FIRMessagingHasLocaleChanged()) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenInfoLocaleChanged, + @"Invalidating cached token due to locale change"); + return NO; + } + + // Locale is not changed, check whether token has been fetched within 7 days. + NSTimeInterval lastFetchTokenTimestamp = [_cacheTime timeIntervalSince1970]; + NSTimeInterval currentTimestamp = FIRMessagingCurrentTimestampInSeconds(); + NSTimeInterval timeSinceLastFetchToken = currentTimestamp - lastFetchTokenTimestamp; + return (timeSinceLastFetchToken < kDefaultFetchTokenInterval); +} + +- (BOOL)hasDenylistedScope { + /// The token with fiam scope is set by old FIAM SDK(s) which will remain in keychain for ever. So + /// we need to remove these tokens to deny its usage. + if ([self.scope isEqualToString:kFIRMessagingFIAMTokenScope]) { + return YES; + } + + return NO; +} + +- (BOOL)isDefaultToken { + return [self.scope isEqualToString:kFIRMessagingDefaultTokenScope]; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder { + BOOL needsMigration = NO; + // These value cannot be nil + + NSString *authorizedEntity = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstanceIDAuthorizedEntityKey]; + if (!authorizedEntity) { + return nil; + } + + NSString *scope = [aDecoder decodeObjectOfClass:[NSString class] forKey:kFIRInstanceIDScopeKey]; + if (!scope) { + return nil; + } + + NSString *token = [aDecoder decodeObjectOfClass:[NSString class] forKey:kFIRInstanceIDTokenKey]; + if (!token) { + return nil; + } + + // These values are nullable, so don't fail on nil. + + NSString *appVersion = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstanceIDAppVersionKey]; + NSString *firebaseAppID = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstanceIDFirebaseAppIDKey]; + + NSSet *classes = [[NSSet alloc] initWithArray:@[ FIRMessagingAPNSInfo.class ]]; + FIRMessagingAPNSInfo *rawAPNSInfo = [aDecoder decodeObjectOfClasses:classes + forKey:kFIRInstanceIDAPNSInfoKey]; + if (rawAPNSInfo && ![rawAPNSInfo isKindOfClass:[FIRMessagingAPNSInfo class]]) { + // If the decoder fails to decode a FIRMessagingAPNSInfo, check if this was archived by a + // FirebaseMessaging 10.18.0 or earlier. + // TODO(#12246) This block may be replaced with `rawAPNSInfo = nil` once we're confident all + // users have upgraded to at least 10.19.0. Perhaps, after privacy manifests have been required + // for awhile? + @try { + NSKeyedUnarchiver *unarchiver = + [[NSKeyedUnarchiver alloc] initForReadingFromData:(NSData *)rawAPNSInfo error:nil]; + unarchiver.requiresSecureCoding = NO; + [unarchiver setClass:[FIRMessagingAPNSInfo class] forClassName:@"FIRInstanceIDAPNSInfo"]; + rawAPNSInfo = [unarchiver decodeObjectForKey:NSKeyedArchiveRootObjectKey]; + [unarchiver finishDecoding]; + needsMigration = YES; + } @catch (NSException *exception) { + FIRMessagingLoggerInfo(kFIRMessagingMessageCodeTokenInfoBadAPNSInfo, + @"Could not parse raw APNS Info while parsing archived token info."); + rawAPNSInfo = nil; + } @finally { + } + } + + NSDate *cacheTime = [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kFIRInstanceIDCacheTimeKey]; + + self = [super init]; + if (self) { + _authorizedEntity = [authorizedEntity copy]; + _scope = [scope copy]; + _token = [token copy]; + _appVersion = [appVersion copy]; + _firebaseAppID = [firebaseAppID copy]; + _APNSInfo = [rawAPNSInfo copy]; + _cacheTime = cacheTime; + _needsMigration = needsMigration; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.authorizedEntity forKey:kFIRInstanceIDAuthorizedEntityKey]; + [aCoder encodeObject:self.scope forKey:kFIRInstanceIDScopeKey]; + [aCoder encodeObject:self.token forKey:kFIRInstanceIDTokenKey]; + [aCoder encodeObject:self.appVersion forKey:kFIRInstanceIDAppVersionKey]; + [aCoder encodeObject:self.firebaseAppID forKey:kFIRInstanceIDFirebaseAppIDKey]; + if (self.APNSInfo) { + [aCoder encodeObject:self.APNSInfo forKey:kFIRInstanceIDAPNSInfoKey]; + } + [aCoder encodeObject:self.cacheTime forKey:kFIRInstanceIDCacheTimeKey]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.h new file mode 100644 index 0000000..f878094 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.h @@ -0,0 +1,197 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h" + +@class FIRMessagingAuthService; +@class FIRMessagingCheckinPreferences; +@class FIRMessagingTokenInfo; + +@protocol FIRHeartbeatLoggerProtocol; + +typedef NS_OPTIONS(NSUInteger, FIRMessagingInvalidTokenReason) { + FIRMessagingInvalidTokenReasonNone = 0, // 0 + FIRMessagingInvalidTokenReasonAppVersion = (1 << 0), // 0...00001 + FIRMessagingInvalidTokenReasonAPNSToken = (1 << 1), // 0...00010 +}; + +/** + * Manager for the InstanceID token requests i.e `newToken` and `deleteToken`. This + * manages the overall interaction of the `FIRMessagingTokenStore`, the token register + * service and the callbacks associated with `GCMInstanceID`. + */ +@interface FIRMessagingTokenManager : NSObject + +@property(nonatomic, readonly, copy) NSString *deviceAuthID; +@property(nonatomic, readonly, copy) NSString *secretToken; +@property(nonatomic, readonly, copy) NSString *versionInfo; +@property(nonatomic, readonly, copy) NSString *defaultFCMToken; +@property(nonatomic, readwrite, copy) NSString *fcmSenderID; +@property(nonatomic, readwrite, copy) NSString *firebaseAppID; + +/// Expose the auth service, so it can be used by others +@property(nonatomic, readonly, strong) FIRMessagingAuthService *authService; + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Designated initializer. + * + * @param heartbeatLogger The heartbeat logger that is injected into token operations. + */ +- (instancetype)initWithHeartbeatLogger:(id)heartbeatLogger + NS_DESIGNATED_INITIALIZER; + +/** + * Fetch new token for the given authorizedEntity and scope. This makes an + * asynchronous request to the InstanceID backend to create a new token for + * the service and returns it. This will replace any old token for the given + * authorizedEntity and scope that has been cached before. + * + * @param authorizedEntity The authorized entity for the token, should not be nil. + * @param scope The scope for the token, should not be nil. + * @param instanceID The unique string identifying the app instance. + * @param options The options to be added to the fetch request. + * @param handler The handler to be invoked once we have the token or the + * fetch request to InstanceID backend results in an error. Also + * since it's a public handler it should always be called + * asynchronously. This should be non-nil. + */ +- (void)fetchNewTokenWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + instanceID:(NSString *)instanceID + options:(NSDictionary *)options + handler:(FIRMessagingFCMTokenFetchCompletion)handler; + +- (void)tokenWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + options:(NSDictionary *)options + handler:(FIRMessagingFCMTokenFetchCompletion)handler; + +/** + * Return the cached token info, if one exists, for the given authorizedEntity and scope. + * + * @param authorizedEntity The authorized entity for the token. + * @param scope The scope for the token. + * + * @return The cached token info, if available, matching the parameters. + */ +- (FIRMessagingTokenInfo *)cachedTokenInfoWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope; + +/** + * Delete the token for the given authorizedEntity and scope. If the token has + * been cached, it will be deleted from the store. It will also make an + * asynchronous request to the InstanceID backend to invalidate the token. + * + * @param authorizedEntity The authorized entity for the token, should not be nil. + * @param scope The scope for the token, should not be nil. + * @param instanceID The unique string identifying the app instance. + * @param handler The handler to be invoked once the delete request to + * InstanceID backend has returned. If the request was + * successful we invoke the handler with a nil error; + * otherwise we call it with an appropriate error. Also since + * it's a public handler it should always be called + * asynchronously. This should be non-nil. + */ +- (void)deleteTokenWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + instanceID:(NSString *)instanceID + handler:(FIRMessagingDeleteFCMTokenCompletion)handler; + +/** + * Deletes all cached tokens from the persistent store. This method should only be triggered + * when InstanceID is deleted + * + * @param handler The handler to be invoked once the delete request to InstanceID backend + * has returned. If the request was successful we invoke the handler with + * a nil error; else we pass in an appropriate error. This should be non-nil + * and be called asynchronously. + */ +- (void)deleteAllTokensWithHandler:(FIRMessagingDeleteFCMTokenCompletion)handler; + +/** + * Deletes all cached tokens from the persistent store. + * @param handler The callback handler which is invoked when tokens deletion is complete, + * with an error if there is any. + * + */ + +- (void)deleteWithHandler:(void (^)(NSError *))handler; + +/** + * Stop any ongoing token operations. + */ +- (void)stopAllTokenOperations; + +/** + * Invalidate any cached tokens, if the app version has changed since last launch or if the token + * is cached for more than 7 days. + * @param IID The cached instanceID, check if token is prefixed by such IID. + * + * @return Whether we should fetch default token from server. + * + * @discussion This should safely be called prior to any tokens being retrieved from + * the cache or being fetched from the network. + */ +- (BOOL)checkTokenRefreshPolicyWithIID:(NSString *)IID; + +/** + * Upon being provided with different APNs or sandbox, any locally cached tokens + * should be deleted, and the new APNs token should be cached. + * + * @discussion It is possible for this method to be called while token operations are + * in-progress or queued. In this case, the in-flight token operations will have stale + * APNs information. The default token is checked for being out-of-date by Instance ID, + * and re-fetched. Custom tokens are not currently checked. + * + * @param deviceToken The APNS device token, provided by the operating system. + * @param isSandbox YES if the device token is for the sandbox environment, NO otherwise. + * + * @return The array of FIRMessagingTokenInfo objects which were invalidated. + */ +- (NSArray *)updateTokensToAPNSDeviceToken:(NSData *)deviceToken + isSandbox:(BOOL)isSandbox; + +/* + * Sets APNS token + */ +- (void)setAPNSToken:(NSData *)APNSToken withUserInfo:(NSDictionary *)userInfo; + +- (BOOL)hasValidCheckinInfo; + +/* + * Gets the current default token, if not exist, request a new one from server. + */ +- (NSString *)tokenAndRequestIfNotExist; + +/* + * Saves the default token to the keychain. + */ +- (void)saveDefaultTokenInfoInKeychain:(NSString *)defaultFcmToken; + +/* + * Posts a token refresh notification when a default FCM token is generated. + * + */ +- (void)postTokenRefreshNotificationWithDefaultFCMToken:(NSString *)defaultFCMToken; + +/* + * Checks if two tokens have changed. + */ +- (BOOL)hasTokenChangedFromOldToken:(NSString *)oldToken toNewToken:(NSString *)newToken; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.m new file mode 100644 index 0000000..d446ea6 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.m @@ -0,0 +1,768 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.h" + +#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h" +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingDefines.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingAuthService.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.h" + +@interface FIRMessagingTokenManager () { + FIRMessagingTokenStore *_tokenStore; + NSString *_defaultFCMToken; +} + +@property(nonatomic, readwrite, strong) FIRMessagingCheckinStore *checkinStore; +@property(nonatomic, readwrite, strong) FIRMessagingAuthService *authService; +@property(nonatomic, readonly, strong) NSOperationQueue *tokenOperations; + +@property(nonatomic, readwrite, strong) FIRMessagingAPNSInfo *currentAPNSInfo; +@property(nonatomic, readwrite) FIRInstallations *installations; + +@property(readonly) id heartbeatLogger; + +@end + +@implementation FIRMessagingTokenManager + +- (instancetype)initWithHeartbeatLogger:(id)heartbeatLogger { + self = [super init]; + if (self) { + _tokenStore = [[FIRMessagingTokenStore alloc] init]; + _authService = [[FIRMessagingAuthService alloc] init]; + [self resetCredentialsIfNeeded]; + [self configureTokenOperations]; + _installations = [FIRInstallations installations]; + _heartbeatLogger = heartbeatLogger; + } + return self; +} + +- (void)dealloc { + [self stopAllTokenOperations]; +} + +- (NSString *)tokenAndRequestIfNotExist { + if (!self.fcmSenderID.length) { + return nil; + } + + if (_defaultFCMToken.length) { + return _defaultFCMToken; + } + + FIRMessagingTokenInfo *cachedTokenInfo = + [self cachedTokenInfoWithAuthorizedEntity:self.fcmSenderID + scope:kFIRMessagingDefaultTokenScope]; + NSString *cachedToken = cachedTokenInfo.token; + + if (cachedToken) { + return cachedToken; + } else { + [self tokenWithAuthorizedEntity:self.fcmSenderID + scope:kFIRMessagingDefaultTokenScope + options:[self tokenOptions] + handler:^(NSString *_Nullable FCMToken, NSError *_Nullable error){ + + }]; + return nil; + } +} + +- (NSString *)defaultFCMToken { + return _defaultFCMToken; +} + +- (void)postTokenRefreshNotificationWithDefaultFCMToken:(NSString *)defaultFCMToken { + // Should always trigger the token refresh notification when the delegate method is called + // No need to check if the token has changed, it's handled in the notification receiver. + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center postNotificationName:kFIRMessagingRegistrationTokenRefreshNotification + object:defaultFCMToken]; +} + +- (void)saveDefaultTokenInfoInKeychain:(NSString *)defaultFcmToken { + if ([self hasTokenChangedFromOldToken:_defaultFCMToken toNewToken:defaultFcmToken]) { + _defaultFCMToken = [defaultFcmToken copy]; + FIRMessagingTokenInfo *tokenInfo = + [[FIRMessagingTokenInfo alloc] initWithAuthorizedEntity:_fcmSenderID + scope:kFIRMessagingDefaultTokenScope + token:defaultFcmToken + appVersion:FIRMessagingCurrentAppVersion() + firebaseAppID:_firebaseAppID]; + tokenInfo.APNSInfo = + [[FIRMessagingAPNSInfo alloc] initWithTokenOptionsDictionary:[self tokenOptions]]; + + [self->_tokenStore saveTokenInfoInCache:tokenInfo]; + } +} + +- (BOOL)hasTokenChangedFromOldToken:(NSString *)oldToken toNewToken:(NSString *)newToken { + return oldToken.length != newToken.length || + (oldToken.length && newToken.length && ![oldToken isEqualToString:newToken]); +} + +- (NSDictionary *)tokenOptions { + NSDictionary *instanceIDOptions = @{}; + NSData *apnsTokenData = self.currentAPNSInfo.deviceToken; + if (apnsTokenData) { + instanceIDOptions = @{ + kFIRMessagingTokenOptionsAPNSKey : apnsTokenData, + kFIRMessagingTokenOptionsAPNSIsSandboxKey : @(self.currentAPNSInfo.isSandbox), + }; + } + + return instanceIDOptions; +} + +- (NSString *)deviceAuthID { + return [_authService checkinPreferences].deviceID; +} + +- (NSString *)secretToken { + return [_authService checkinPreferences].secretToken; +} + +- (NSString *)versionInfo { + return [_authService checkinPreferences].versionInfo; +} + +- (void)configureTokenOperations { + _tokenOperations = [[NSOperationQueue alloc] init]; + _tokenOperations.name = @"com.google.iid-token-operations"; + // For now, restrict the operations to be serial, because in some cases (like if the + // authorized entity and scope are the same), order matters. + // If we have to deal with several different token requests simultaneously, it would be a good + // idea to add some better intelligence around this (performing unrelated token operations + // simultaneously, etc.). + _tokenOperations.maxConcurrentOperationCount = 1; + if ([_tokenOperations respondsToSelector:@selector(qualityOfService)]) { + _tokenOperations.qualityOfService = NSOperationQualityOfServiceUtility; + } +} + +- (void)tokenWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + options:(NSDictionary *)options + handler:(FIRMessagingFCMTokenFetchCompletion)handler { + if (!handler) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeInstanceID000, @"Invalid nil handler"); + return; + } + + // Add internal options + NSMutableDictionary *tokenOptions = [NSMutableDictionary dictionary]; + if (options.count) { + [tokenOptions addEntriesFromDictionary:options]; + } + + // ensure we have an APNS Token + if (tokenOptions[kFIRMessagingTokenOptionsAPNSKey] == nil) { + // we don't have an APNS token. Don't fetch or return a FCM Token + FIRMessagingLoggerWarn(kFIRMessagingMessageCodeAPNSTokenNotAvailableDuringTokenFetch, + @"Declining request for FCM Token since no APNS Token specified"); + dispatch_async(dispatch_get_main_queue(), ^{ + NSError *missingAPNSTokenError = + [NSError messagingErrorWithCode:kFIRMessagingErrorCodeMissingDeviceToken + failureReason:@"No APNS token specified before fetching FCM Token"]; + handler(nil, missingAPNSTokenError); + }); + return; + } + +#if TARGET_OS_SIMULATOR + if (tokenOptions[kFIRMessagingTokenOptionsAPNSKey] != nil) { + // If APNS token is available on iOS Simulator, we must use the sandbox profile + // https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes + tokenOptions[kFIRMessagingTokenOptionsAPNSIsSandboxKey] = @(YES); + } +#endif // TARGET_OS_SIMULATOR + + if (tokenOptions[kFIRMessagingTokenOptionsAPNSKey] != nil && + tokenOptions[kFIRMessagingTokenOptionsAPNSIsSandboxKey] == nil) { + // APNS key was given, but server type is missing. Supply the server type with automatic + // checking. This can happen when the token is requested from FCM, which does not include a + // server type during its request. + tokenOptions[kFIRMessagingTokenOptionsAPNSIsSandboxKey] = @(FIRMessagingIsSandboxApp()); + } + if (self.firebaseAppID) { + tokenOptions[kFIRMessagingTokenOptionsFirebaseAppIDKey] = self.firebaseAppID; + } + + // comparing enums to ints directly throws a warning + FIRMessagingErrorCode noError = INT_MAX; + FIRMessagingErrorCode errorCode = noError; + if (![authorizedEntity length]) { + errorCode = kFIRMessagingErrorCodeMissingAuthorizedEntity; + } else if (![scope length]) { + errorCode = kFIRMessagingErrorCodeMissingScope; + } else if (!self.installations) { + errorCode = kFIRMessagingErrorCodeMissingFid; + } + + FIRMessagingFCMTokenFetchCompletion newHandler = ^(NSString *token, NSError *error) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(token, error); + }); + }; + + if (errorCode != noError) { + newHandler( + nil, + [NSError messagingErrorWithCode:errorCode + failureReason:@"Failed to send token request, missing critical info."]); + return; + } + + FIRMessaging_WEAKIFY(self); + [_authService fetchCheckinInfoWithHandler:^(FIRMessagingCheckinPreferences *preferences, + NSError *error) { + FIRMessaging_STRONGIFY(self); + if (error) { + newHandler(nil, error); + return; + } + + if (!self) { + NSError *derefErr = + [NSError messagingErrorWithCode:kFIRMessagingErrorCodeInternal + failureReason:@"Unable to fetch token. Lost Reference to TokenManager"]; + handler(nil, derefErr); + return; + } + + FIRMessaging_WEAKIFY(self); + [self->_installations + installationIDWithCompletion:^(NSString *_Nullable identifier, NSError *_Nullable error) { + FIRMessaging_STRONGIFY(self); + + if (error) { + newHandler(nil, error); + } else { + FIRMessagingTokenInfo *cachedTokenInfo = + [self cachedTokenInfoWithAuthorizedEntity:authorizedEntity scope:scope]; + FIRMessagingAPNSInfo *optionsAPNSInfo = + [[FIRMessagingAPNSInfo alloc] initWithTokenOptionsDictionary:tokenOptions]; + // Check if APNS Info is changed + if ((!cachedTokenInfo.APNSInfo && !optionsAPNSInfo) || + [cachedTokenInfo.APNSInfo isEqualToAPNSInfo:optionsAPNSInfo]) { + // check if token is fresh + if ([cachedTokenInfo isFreshWithIID:identifier]) { + newHandler(cachedTokenInfo.token, nil); + return; + } + } + [self fetchNewTokenWithAuthorizedEntity:[authorizedEntity copy] + scope:[scope copy] + instanceID:identifier + options:tokenOptions + handler:newHandler]; + } + }]; + }]; +} + +- (void)fetchNewTokenWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + instanceID:(NSString *)instanceID + options:(NSDictionary *)options + handler:(FIRMessagingFCMTokenFetchCompletion)handler { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenManager000, + @"Fetch new token for authorizedEntity: %@, scope: %@", authorizedEntity, + scope); + FIRMessagingTokenFetchOperation *operation = + [self createFetchOperationWithAuthorizedEntity:authorizedEntity + scope:scope + options:options + instanceID:instanceID]; + FIRMessaging_WEAKIFY(self); + FIRMessagingTokenOperationCompletion completion = ^(FIRMessagingTokenOperationResult result, + NSString *_Nullable token, + NSError *_Nullable error) { + FIRMessaging_STRONGIFY(self); + if (error) { + handler(nil, error); + return; + } + + if (!self) { + NSError *lostRefError = [NSError messagingErrorWithCode:kFIRMessagingErrorCodeInternal + failureReason:@"Lost Reference to TokenManager"]; + handler(nil, lostRefError); + return; + } + + if ([self isDefaultTokenWithAuthorizedEntity:authorizedEntity scope:scope]) { + [self postTokenRefreshNotificationWithDefaultFCMToken:token]; + } + NSString *firebaseAppID = options[kFIRMessagingTokenOptionsFirebaseAppIDKey]; + FIRMessagingTokenInfo *tokenInfo = + [[FIRMessagingTokenInfo alloc] initWithAuthorizedEntity:authorizedEntity + scope:scope + token:token + appVersion:FIRMessagingCurrentAppVersion() + firebaseAppID:firebaseAppID]; + tokenInfo.APNSInfo = [[FIRMessagingAPNSInfo alloc] initWithTokenOptionsDictionary:options]; + + [self->_tokenStore + saveTokenInfo:tokenInfo + handler:^(NSError *error) { + if (!error) { + // Do not send the token back in case the save was unsuccessful. Since with + // the new asynchronous fetch mechanism this can lead to infinite loops, for + // example, we will return a valid token even though we weren't able to store + // it in our cache. The first token will lead to a onTokenRefresh callback + // wherein the user again calls `getToken` but since we weren't able to save + // it we won't hit the cache but hit the server again leading to an infinite + // loop. + FIRMessagingLoggerDebug( + kFIRMessagingMessageCodeTokenManager001, + @"Token fetch successful, token: %@, authorizedEntity: %@, scope:%@", token, + authorizedEntity, scope); + + if (handler) { + handler(token, nil); + } + } else { + if (handler) { + handler(nil, error); + } + } + }]; + }; + // Add completion handler, and ensure it's called on the main queue + [operation addCompletionHandler:^(FIRMessagingTokenOperationResult result, + NSString *_Nullable token, NSError *_Nullable error) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(result, token, error); + }); + }]; + [self.tokenOperations addOperation:operation]; +} + +- (FIRMessagingTokenInfo *)cachedTokenInfoWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope { + FIRMessagingTokenInfo *tokenInfo = [_tokenStore tokenInfoWithAuthorizedEntity:authorizedEntity + scope:scope]; + return tokenInfo; +} + +- (BOOL)isDefaultTokenWithAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope { + if (_fcmSenderID.length != authorizedEntity.length) { + return NO; + } + if (![_fcmSenderID isEqualToString:authorizedEntity]) { + return NO; + } + return [scope isEqualToString:kFIRMessagingDefaultTokenScope]; +} + +- (void)deleteTokenWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + instanceID:(NSString *)instanceID + handler:(FIRMessagingDeleteFCMTokenCompletion)handler { + if ([_tokenStore tokenInfoWithAuthorizedEntity:authorizedEntity scope:scope]) { + [_tokenStore removeTokenWithAuthorizedEntity:authorizedEntity scope:scope]; + } + // Does not matter if we cannot find it in the cache. Still make an effort to unregister + // from the server. + FIRMessagingCheckinPreferences *checkinPreferences = self.authService.checkinPreferences; + FIRMessagingTokenDeleteOperation *operation = + [self createDeleteOperationWithAuthorizedEntity:authorizedEntity + scope:scope + checkinPreferences:checkinPreferences + instanceID:instanceID + action:FIRMessagingTokenActionDeleteToken]; + + if (handler) { + [operation addCompletionHandler:^(FIRMessagingTokenOperationResult result, + NSString *_Nullable token, NSError *_Nullable error) { + if ([self isDefaultTokenWithAuthorizedEntity:authorizedEntity scope:scope]) { + [self postTokenRefreshNotificationWithDefaultFCMToken:nil]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + handler(error); + }); + }]; + } + [self.tokenOperations addOperation:operation]; +} + +- (void)deleteAllTokensWithHandler:(void (^)(NSError *))handler { + FIRMessaging_WEAKIFY(self); + + [self.installations + installationIDWithCompletion:^(NSString *_Nullable identifier, NSError *_Nullable error) { + FIRMessaging_STRONGIFY(self); + if (error) { + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(error); + }); + } + return; + } + // delete all tokens + FIRMessagingCheckinPreferences *checkinPreferences = self.authService.checkinPreferences; + if (!checkinPreferences) { + // The checkin is already deleted. No need to trigger the token delete operation as client + // no longer has the checkin information for server to delete. + dispatch_async(dispatch_get_main_queue(), ^{ + handler(nil); + }); + return; + } + FIRMessagingTokenDeleteOperation *operation = [self + createDeleteOperationWithAuthorizedEntity:kFIRMessagingKeychainWildcardIdentifier + scope:kFIRMessagingKeychainWildcardIdentifier + checkinPreferences:checkinPreferences + instanceID:identifier + action:FIRMessagingTokenActionDeleteTokenAndIID]; + if (handler) { + [operation addCompletionHandler:^(FIRMessagingTokenOperationResult result, + NSString *_Nullable token, NSError *_Nullable error) { + self->_defaultFCMToken = nil; + dispatch_async(dispatch_get_main_queue(), ^{ + handler(error); + }); + }]; + } + [self.tokenOperations addOperation:operation]; + }]; +} + +- (void)deleteAllTokensLocallyWithHandler:(void (^)(NSError *error))handler { + [_tokenStore removeAllTokensWithHandler:handler]; +} + +- (void)stopAllTokenOperations { + [self.authService stopCheckinRequest]; + [self.tokenOperations cancelAllOperations]; +} + +- (void)deleteWithHandler:(void (^)(NSError *))handler { + FIRMessaging_WEAKIFY(self); + [self deleteAllTokensWithHandler:^(NSError *_Nullable error) { + FIRMessaging_STRONGIFY(self); + if (error) { + handler(error); + return; + } + + if (!self) { + NSError *lostRefError = + [NSError messagingErrorWithCode:kFIRMessagingErrorCodeInternal + failureReason:@"Cannot delete token. Lost reference to TokenManager"]; + handler(lostRefError); + return; + } + + [self deleteAllTokensLocallyWithHandler:^(NSError *localError) { + [self postTokenRefreshNotificationWithDefaultFCMToken:nil]; + self->_defaultFCMToken = nil; + if (localError) { + handler(localError); + return; + } + [self.authService resetCheckinWithHandler:^(NSError *_Nonnull authError) { + handler(authError); + }]; + }]; + }]; +} + +#pragma mark - CheckinStore + +/** + * Reset the keychain preferences if the app had been deleted earlier and then reinstalled. + * Keychain preferences are not cleared in the above scenario so explicitly clear them. + * + * In case of an iCloud backup and restore the Keychain preferences should already be empty + * since the Keychain items are marked with `*BackupThisDeviceOnly`. + */ +- (void)resetCredentialsIfNeeded { + BOOL checkinPlistExists = [_authService hasCheckinPlist]; + // Checkin info existed in backup excluded plist. Should not be a fresh install. + if (checkinPlistExists) { + return; + } + // Keychain can still exist even if app is uninstalled. + FIRMessagingCheckinPreferences *oldCheckinPreferences = _authService.checkinPreferences; + + if (!oldCheckinPreferences) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeStore009, + @"App reset detected but no valid checkin auth preferences found." + @" Will not delete server token registrations."); + return; + } + [_authService resetCheckinWithHandler:^(NSError *_Nonnull error) { + if (!error) { + FIRMessagingLoggerDebug( + kFIRMessagingMessageCodeStore002, + @"Removed cached checkin preferences from Keychain because this is a fresh install."); + } else { + FIRMessagingLoggerError( + kFIRMessagingMessageCodeStore003, + @"Couldn't remove cached checkin preferences for a fresh install. Error: %@", error); + } + + if (oldCheckinPreferences.deviceID.length && oldCheckinPreferences.secretToken.length) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeStore006, + @"Resetting old checkin and deleting server token registrations."); + // We don't really need to delete old FCM tokens created via IID auth tokens since + // those tokens are already hashed by APNS token as the has so creating a new + // token should automatically delete the old-token. + [self didDeleteFCMScopedTokensForCheckin:oldCheckinPreferences]; + } + }]; +} + +- (void)didDeleteFCMScopedTokensForCheckin:(FIRMessagingCheckinPreferences *)checkin { + // Make a best effort try to delete the old client related state on the FCM server. This is + // required to delete old pubusb registrations which weren't cleared when the app was deleted. + // + // This is only a one time effort. If this call fails the client would still receive duplicate + // pubsub notifications if he is again subscribed to the same topic. + // + // The client state should be cleared on the server for the provided checkin preferences. + FIRMessagingTokenDeleteOperation *operation = + [self createDeleteOperationWithAuthorizedEntity:nil + scope:nil + checkinPreferences:checkin + instanceID:nil + action:FIRMessagingTokenActionDeleteToken]; + [operation addCompletionHandler:^(FIRMessagingTokenOperationResult result, + NSString *_Nullable token, NSError *_Nullable error) { + if (error) { + FIRMessagingMessageCode code = + kFIRMessagingMessageCodeTokenManagerErrorDeletingFCMTokensOnAppReset; + FIRMessagingLoggerDebug(code, @"Failed to delete GCM server registrations on app reset."); + } else { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenManagerDeletedFCMTokensOnAppReset, + @"Successfully deleted GCM server registrations on app reset"); + } + }]; + + [self.tokenOperations addOperation:operation]; +} + +#pragma mark - Unit Testing Stub Helpers +// We really have this method so that we can more easily stub it out for unit testing +- (FIRMessagingTokenFetchOperation *) + createFetchOperationWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + options:(NSDictionary *)options + instanceID:(NSString *)instanceID { + FIRMessagingCheckinPreferences *checkinPreferences = self.authService.checkinPreferences; + FIRMessagingTokenFetchOperation *operation = + [[FIRMessagingTokenFetchOperation alloc] initWithAuthorizedEntity:authorizedEntity + scope:scope + options:options + checkinPreferences:checkinPreferences + instanceID:instanceID + heartbeatLogger:self.heartbeatLogger]; + return operation; +} + +// We really have this method so that we can more easily stub it out for unit testing +- (FIRMessagingTokenDeleteOperation *) + createDeleteOperationWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + checkinPreferences:(FIRMessagingCheckinPreferences *)checkinPreferences + instanceID:(NSString *)instanceID + action:(FIRMessagingTokenAction)action { + FIRMessagingTokenDeleteOperation *operation = + [[FIRMessagingTokenDeleteOperation alloc] initWithAuthorizedEntity:authorizedEntity + scope:scope + checkinPreferences:checkinPreferences + instanceID:instanceID + action:action + heartbeatLogger:self.heartbeatLogger]; + return operation; +} + +#pragma mark - Invalidating Cached Tokens +- (BOOL)checkTokenRefreshPolicyWithIID:(NSString *)IID { + // We know at least one cached token exists. + BOOL shouldFetchDefaultToken = NO; + NSArray *tokenInfos = [_tokenStore cachedTokenInfos]; + + NSMutableArray *tokenInfosToDelete = + [NSMutableArray arrayWithCapacity:tokenInfos.count]; + for (FIRMessagingTokenInfo *tokenInfo in tokenInfos) { + if ([tokenInfo isFreshWithIID:IID]) { + // Token is fresh and in right format, do nothing + continue; + } + if ([tokenInfo isDefaultToken]) { + // Default token is expired, do not mark for deletion. Fetch directly from server to + // replace the current one. + shouldFetchDefaultToken = YES; + } else { + // Non-default token is expired, mark for deletion. + [tokenInfosToDelete addObject:tokenInfo]; + } + FIRMessagingLoggerDebug( + kFIRMessagingMessageCodeTokenManagerInvalidateStaleToken, + @"Invalidating cached token for %@ (%@) due to token is no longer fresh.", + tokenInfo.authorizedEntity, tokenInfo.scope); + } + for (FIRMessagingTokenInfo *tokenInfoToDelete in tokenInfosToDelete) { + [_tokenStore removeTokenWithAuthorizedEntity:tokenInfoToDelete.authorizedEntity + scope:tokenInfoToDelete.scope]; + } + return shouldFetchDefaultToken; +} + +- (NSArray *)updateTokensToAPNSDeviceToken:(NSData *)deviceToken + isSandbox:(BOOL)isSandbox { + // Each cached IID token that is missing an APNSInfo, or has an APNSInfo associated should be + // checked and invalidated if needed. + FIRMessagingAPNSInfo *APNSInfo = [[FIRMessagingAPNSInfo alloc] initWithDeviceToken:deviceToken + isSandbox:isSandbox]; + if ([self.currentAPNSInfo isEqualToAPNSInfo:APNSInfo]) { + return @[]; + } + self.currentAPNSInfo = APNSInfo; + + NSArray *tokenInfos = [_tokenStore cachedTokenInfos]; + NSMutableArray *tokenInfosToDelete = + [NSMutableArray arrayWithCapacity:tokenInfos.count]; + for (FIRMessagingTokenInfo *cachedTokenInfo in tokenInfos) { + // Check if the cached APNSInfo is nil, or if it is an old APNSInfo. + if (!cachedTokenInfo.APNSInfo || + ![cachedTokenInfo.APNSInfo isEqualToAPNSInfo:self.currentAPNSInfo]) { + // Mark for invalidation. + [tokenInfosToDelete addObject:cachedTokenInfo]; + } + } + for (FIRMessagingTokenInfo *tokenInfoToDelete in tokenInfosToDelete) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenManagerAPNSChangedTokenInvalidated, + @"Invalidating cached token for %@ (%@) due to APNs token change.", + tokenInfoToDelete.authorizedEntity, tokenInfoToDelete.scope); + [_tokenStore removeTokenWithAuthorizedEntity:tokenInfoToDelete.authorizedEntity + scope:tokenInfoToDelete.scope]; + } + return tokenInfosToDelete; +} + +#pragma mark - APNS Token +- (void)setAPNSToken:(NSData *)APNSToken withUserInfo:(NSDictionary *)userInfo { + if (!APNSToken || ![APNSToken isKindOfClass:[NSData class]]) { + if ([APNSToken class]) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeInternal002, @"Invalid APNS token type %@", + NSStringFromClass([APNSToken class])); + } else { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeInternal002, @"Empty APNS token type"); + } + return; + } + + // The APNS token is being added, or has changed (rare) + if ([self.currentAPNSInfo.deviceToken isEqualToData:APNSToken]) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeInstanceID011, + @"Trying to reset APNS token to the same value. Will return"); + return; + } + // Use this token type for when we have to automatically fetch tokens in the future +#if TARGET_OS_SIMULATOR + // If APNS token is available on iOS Simulator, we must use the sandbox profile + // https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes + BOOL isSandboxApp = YES; +#else // TARGET_OS_SIMULATOR + NSInteger type = [userInfo[kFIRMessagingAPNSTokenType] integerValue]; + BOOL isSandboxApp = (type == FIRMessagingAPNSTokenTypeSandbox); + if (type == FIRMessagingAPNSTokenTypeUnknown) { + isSandboxApp = FIRMessagingIsSandboxApp(); + } +#endif // TARGET_OS_SIMULATOR + + // Pro-actively invalidate the default token, if the APNs change makes it + // invalid. Previously, we invalidated just before fetching the token. + NSArray *invalidatedTokens = + [self updateTokensToAPNSDeviceToken:APNSToken isSandbox:isSandboxApp]; + + self.currentAPNSInfo = [[FIRMessagingAPNSInfo alloc] initWithDeviceToken:[APNSToken copy] + isSandbox:isSandboxApp]; + + // Re-fetch any invalidated tokens automatically, this time with the current APNs token, so that + // they are up-to-date. Or this is a fresh install and no apns token stored yet. + if (invalidatedTokens.count > 0 || [_tokenStore cachedTokenInfos].count == 0) { + FIRMessaging_WEAKIFY(self); + + [self.installations installationIDWithCompletion:^(NSString *_Nullable identifier, + NSError *_Nullable error) { + FIRMessaging_STRONGIFY(self); + if (self == nil) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeInstanceID017, + @"Instance ID shut down during token reset. Aborting"); + return; + } + if (self.currentAPNSInfo == nil) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeInstanceID018, + @"apnsTokenData was set to nil during token reset. Aborting"); + return; + } + + NSMutableDictionary *tokenOptions = [@{ + kFIRMessagingTokenOptionsAPNSKey : self.currentAPNSInfo.deviceToken, + kFIRMessagingTokenOptionsAPNSIsSandboxKey : @(isSandboxApp) + } mutableCopy]; + if (self.firebaseAppID) { + tokenOptions[kFIRMessagingTokenOptionsFirebaseAppIDKey] = self.firebaseAppID; + } + + for (FIRMessagingTokenInfo *tokenInfo in invalidatedTokens) { + [self fetchNewTokenWithAuthorizedEntity:tokenInfo.authorizedEntity + scope:tokenInfo.scope + instanceID:identifier + options:tokenOptions + handler:^(NSString *_Nullable token, + NSError *_Nullable error){ + // Do nothing as callback is not needed and the + // sub-function already handle errors. + }]; + } + if ([self->_tokenStore cachedTokenInfos].count == 0) { + [self tokenWithAuthorizedEntity:self.fcmSenderID + scope:kFIRMessagingDefaultTokenScope + options:tokenOptions + handler:^(NSString *_Nullable FCMToken, NSError *_Nullable error){ + // Do nothing as callback is not needed and the sub-function + // already handle errors. + }]; + } + }]; + } +} + +#pragma mark - checkin +- (BOOL)hasValidCheckinInfo { + return self.authService.checkinPreferences.hasValidCheckinInfo; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h new file mode 100644 index 0000000..b65e718 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h @@ -0,0 +1,96 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRMessagingCheckinPreferences; + +@protocol FIRHeartbeatLoggerProtocol; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Represents the action taken on an FCM token. + */ +typedef NS_ENUM(NSInteger, FIRMessagingTokenAction) { + FIRMessagingTokenActionFetch, + FIRMessagingTokenActionDeleteToken, + FIRMessagingTokenActionDeleteTokenAndIID, +}; + +/** + * Represents the possible results of a token operation. + */ +typedef NS_ENUM(NSInteger, FIRMessagingTokenOperationResult) { + FIRMessagingTokenOperationSucceeded, + FIRMessagingTokenOperationError, + FIRMessagingTokenOperationCancelled, +}; + +/** + * Callback to invoke once the HTTP call to FIRMessaging backend for updating + * subscription finishes. + * + * @param result The result of the operation. + * @param token If the action for fetching a token and the request was successful, this will hold + * the value of the token. Otherwise nil. + * @param error The error which occurred while performing the token operation. This will be nil + * in case the operation was successful, or if the operation was cancelled. + */ +typedef void (^FIRMessagingTokenOperationCompletion)(FIRMessagingTokenOperationResult result, + NSString *_Nullable token, + NSError *_Nullable error); + +@interface FIRMessagingTokenOperation : NSOperation + +@property(nonatomic, readonly) FIRMessagingTokenAction action; +@property(nonatomic, readonly, nullable) NSString *authorizedEntity; +@property(nonatomic, readonly, nullable) NSString *scope; +@property(nonatomic, readonly, nullable) NSDictionary *options; +@property(nonatomic, readonly, strong) FIRMessagingCheckinPreferences *checkinPreferences; +@property(nonatomic, readonly, strong) NSString *instanceID; + +@property(nonatomic, readonly) FIRMessagingTokenOperationResult result; + +@property(atomic, strong, nullable) NSURLSessionDataTask *dataTask; + +@property(readonly) id heartbeatLogger; + +#pragma mark - Request Construction ++ (NSMutableArray *)standardQueryItemsWithDeviceID:(NSString *)deviceID + scope:(NSString *)scope; +- (NSMutableURLRequest *)tokenRequest; +- (instancetype)init NS_UNAVAILABLE; + +#pragma mark - Initialization +- (instancetype)initWithAction:(FIRMessagingTokenAction)action + forAuthorizedEntity:(nullable NSString *)authorizedEntity + scope:(NSString *)scope + options:(nullable NSDictionary *)options + checkinPreferences:(FIRMessagingCheckinPreferences *)checkinPreferences + instanceID:(NSString *)instanceID + heartbeatLogger:(id)heartbeatLogger + NS_DESIGNATED_INITIALIZER; + +- (void)addCompletionHandler:(FIRMessagingTokenOperationCompletion)handler; + +#pragma mark - Result +- (void)finishWithResult:(FIRMessagingTokenOperationResult)result + token:(nullable NSString *)token + error:(nullable NSError *)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.m new file mode 100644 index 0000000..563479e --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.m @@ -0,0 +1,230 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h" + +#import +#import "FirebaseCore/Extension/FIRHeartbeatLogger.h" +#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/FIRMessaging_Private.h" +#import "FirebaseMessaging/Sources/NSError+FIRMessaging.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h" + +static const NSInteger kFIRMessagingPlatformVersionIOS = 2; + +// Scope parameter that defines the service using the token +static NSString *const kFIRMessagingParamScope = @"X-scope"; +// Defines the SDK version +static NSString *const kFIRMessagingParamFCMLibVersion = @"X-cliv"; + +@interface FIRMessagingTokenOperation () { + BOOL _isFinished; + BOOL _isExecuting; + NSMutableArray *_completionHandlers; + FIRMessagingCheckinPreferences *_checkinPreferences; +} + +@property(nonatomic, readwrite, strong) NSString *instanceID; + +@property(atomic, strong, nullable) NSString *FISAuthToken; + +@end + +@implementation FIRMessagingTokenOperation + +- (instancetype)initWithAction:(FIRMessagingTokenAction)action + forAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope + options:(NSDictionary *)options + checkinPreferences:(FIRMessagingCheckinPreferences *)checkinPreferences + instanceID:(NSString *)instanceID + heartbeatLogger:(id)heartbeatLogger { + self = [super init]; + if (self) { + _action = action; + _authorizedEntity = [authorizedEntity copy]; + _scope = [scope copy]; + _options = [options copy]; + _checkinPreferences = checkinPreferences; + _instanceID = instanceID; + _completionHandlers = [[NSMutableArray alloc] init]; + _heartbeatLogger = heartbeatLogger; + + _isExecuting = NO; + _isFinished = NO; + } + return self; +} + +- (void)dealloc { + [_completionHandlers removeAllObjects]; +} + +- (void)addCompletionHandler:(FIRMessagingTokenOperationCompletion)handler { + [_completionHandlers addObject:[handler copy]]; +} + +- (BOOL)isAsynchronous { + return YES; +} + +- (BOOL)isExecuting { + return _isExecuting; +} + +- (void)setExecuting:(BOOL)executing { + [self willChangeValueForKey:@"isExecuting"]; + _isExecuting = executing; + [self didChangeValueForKey:@"isExecuting"]; +} + +- (BOOL)isFinished { + return _isFinished; +} + +- (void)setFinished:(BOOL)finished { + [self willChangeValueForKey:@"isFinished"]; + _isFinished = finished; + [self didChangeValueForKey:@"isFinished"]; +} + +- (void)start { + if (self.isCancelled) { + [self finishWithResult:FIRMessagingTokenOperationCancelled token:nil error:nil]; + return; + } + + // Quickly validate whether or not the operation has all it needs to begin + BOOL checkinfoAvailable = [self.checkinPreferences hasCheckinInfo]; + if (!checkinfoAvailable) { + FIRMessagingErrorCode errorCode = kFIRMessagingErrorCodeRegistrarFailedToCheckIn; + [self finishWithResult:FIRMessagingTokenOperationError + token:nil + error:[NSError messagingErrorWithCode:errorCode + failureReason: + @"Failed to checkin before token registration."]]; + return; + } + + [self setExecuting:YES]; + + [[FIRInstallations installations] + authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error) { + if (tokenResult.authToken.length > 0) { + self.FISAuthToken = tokenResult.authToken; + [self performTokenOperation]; + } else { + [self finishWithResult:FIRMessagingTokenOperationError token:nil error:error]; + } + }]; +} + +- (void)finishWithResult:(FIRMessagingTokenOperationResult)result + token:(nullable NSString *)token + error:(nullable NSError *)error { + // Add a check to prevent this finish from being called more than once. + if (self.isFinished) { + return; + } + self.dataTask = nil; + _result = result; + for (FIRMessagingTokenOperationCompletion completionHandler in _completionHandlers) { + completionHandler(result, token, error); + } + + [self setExecuting:NO]; + [self setFinished:YES]; +} + +- (void)cancel { + [super cancel]; + [self.dataTask cancel]; + [self finishWithResult:FIRMessagingTokenOperationCancelled token:nil error:nil]; +} + +- (void)performTokenOperation { +} + +- (NSMutableURLRequest *)tokenRequest { + NSString *authHeader = + [FIRMessagingTokenOperation HTTPAuthHeaderFromCheckin:self.checkinPreferences]; + return [[self class] requestWithAuthHeader:authHeader FISAuthToken:self.FISAuthToken]; +} + +#pragma mark - Request Construction + ++ (NSMutableURLRequest *)requestWithAuthHeader:(NSString *)authHeaderString + FISAuthToken:(NSString *)FISAuthToken { + NSURL *url = [NSURL URLWithString:FIRMessagingTokenRegisterServer()]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + + // Add HTTP headers + [request setValue:authHeaderString forHTTPHeaderField:@"Authorization"]; + [request setValue:FIRMessagingAppIdentifier() forHTTPHeaderField:@"app"]; + if (FISAuthToken) { + [request setValue:FISAuthToken forHTTPHeaderField:@"x-goog-firebase-installations-auth"]; + } + request.HTTPMethod = @"POST"; + return request; +} + ++ (NSMutableArray *)standardQueryItemsWithDeviceID:(NSString *)deviceID + scope:(NSString *)scope { + NSMutableArray *queryItems = [NSMutableArray arrayWithCapacity:8]; + + // E.g. X-osv=10.2.1 + NSString *systemVersion = [GULAppEnvironmentUtil systemVersion]; + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"X-osv" value:systemVersion]]; + // E.g. device= + if (deviceID) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"device" value:deviceID]]; + } + // E.g. X-scope=fcm + if (scope) { + [queryItems addObject:[NSURLQueryItem queryItemWithName:kFIRMessagingParamScope value:scope]]; + } + // E.g. plat=2 + NSString *platform = [NSString stringWithFormat:@"%ld", (long)kFIRMessagingPlatformVersionIOS]; + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"plat" value:platform]]; + // E.g. app=com.myapp.foo + NSString *appIdentifier = FIRMessagingAppIdentifier(); + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"app" value:appIdentifier]]; + // E.g. app_ver=1.5 + NSString *appVersion = FIRMessagingCurrentAppVersion(); + [queryItems addObject:[NSURLQueryItem queryItemWithName:@"app_ver" value:appVersion]]; + // E.g. X-cliv=fiid-1.2.3 + NSString *fcmLibraryVersion = + [NSString stringWithFormat:@"fiid-%@", [FIRMessaging FIRMessagingSDKVersion]]; + if (fcmLibraryVersion.length) { + NSURLQueryItem *gcmLibVersion = + [NSURLQueryItem queryItemWithName:kFIRMessagingParamFCMLibVersion value:fcmLibraryVersion]; + [queryItems addObject:gcmLibVersion]; + } + + return queryItems; +} + +#pragma mark - Header + ++ (NSString *)HTTPAuthHeaderFromCheckin:(FIRMessagingCheckinPreferences *)checkin { + NSString *deviceID = checkin.deviceID; + NSString *secret = checkin.secretToken; + return [NSString stringWithFormat:@"AidLogin %@:%@", deviceID, secret]; +} +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.h b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.h new file mode 100644 index 0000000..1a42ab0 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.h @@ -0,0 +1,97 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRMessagingAPNSInfo; +@class FIRMessagingAuthKeychain; +@class FIRMessagingTokenInfo; + +/** + * This class is responsible for retrieving and saving `FIRMessagingTokenInfo` objects from the + * keychain. The keychain keys that are used are: + * Account:
(e.g. com.mycompany.myapp) + * Service: : (e.g. 1234567890:*) + */ +@interface FIRMessagingTokenStore : NSObject + +NS_ASSUME_NONNULL_BEGIN + +- (instancetype)init; + +#pragma mark - Get + +/** + * Get the cached token from the Keychain. + * + * @param authorizedEntity The authorized entity for the token. + * @param scope The scope for the token. + * + * @return The cached token info if any for the given authorizedEntity and scope else + * nil. + */ +- (nullable FIRMessagingTokenInfo *)tokenInfoWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope; + +/** + * Return all cached token infos from the Keychain. + * + * @return The cached token infos, if any, that are stored in the Keychain. + */ +- (NSArray *)cachedTokenInfos; + +#pragma mark - Save + +/** + * Save the instanceID token info to the persistent store. + * + * @param tokenInfo The token info to store. + * @param handler The callback handler which is invoked when token saving is complete, + * with an error if there is any. + */ +- (void)saveTokenInfo:(FIRMessagingTokenInfo *)tokenInfo + handler:(nullable void (^)(NSError *))handler; + +#pragma mark - Delete + +/** + * Remove the cached token from Keychain. + * + * @param authorizedEntity The authorized entity for the token. + * @param scope The scope for the token. + * + */ +- (void)removeTokenWithAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope; + +/** + * Remove all the cached tokens from the Keychain. + * @param handler The callback handler which is invoked when tokens deletion is complete, + * with an error if there is any. + * + */ +- (void)removeAllTokensWithHandler:(nullable void (^)(NSError *))handler; + +/* + * Only save to local cache but not keychain. This is used when old + * InstanceID SDK updates the token in the keychain, Messaging + * should update its cache without writing to keychain again. + * @param tokenInfo The token info need to be updated in the cache. + */ +- (void)saveTokenInfoInCache:(FIRMessagingTokenInfo *)tokenInfo; + +NS_ASSUME_NONNULL_END + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.m b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.m new file mode 100644 index 0000000..2e18e14 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.m @@ -0,0 +1,180 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.h" + +#import "FirebaseMessaging/Sources/FIRMessagingConstants.h" +#import "FirebaseMessaging/Sources/FIRMessagingLogger.h" +#import "FirebaseMessaging/Sources/FIRMessagingUtilities.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.h" +#import "FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h" + +static NSString *const kFIRMessagingTokenKeychainId = @"com.google.iid-tokens"; + +@interface FIRMessagingTokenStore () + +@property(nonatomic, readwrite, strong) FIRMessagingAuthKeychain *keychain; + +@end + +@implementation FIRMessagingTokenStore + +- (instancetype)init { + self = [super init]; + if (self) { + _keychain = [[FIRMessagingAuthKeychain alloc] initWithIdentifier:kFIRMessagingTokenKeychainId]; + } + return self; +} + +#pragma mark - Get + ++ (NSString *)serviceKeyForAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope { + return [NSString stringWithFormat:@"%@:%@", authorizedEntity, scope]; +} + +- (nullable FIRMessagingTokenInfo *)tokenInfoWithAuthorizedEntity:(NSString *)authorizedEntity + scope:(NSString *)scope { + // TODO(chliangGoogle): If we don't have the token plist we should delete all the tokens from + // the keychain. This is because not having the plist signifies a backup and restore operation. + // In case the keychain has any tokens these would now be stale and therefore should be + // deleted. + if (![authorizedEntity length] || ![scope length]) { + return nil; + } + NSString *account = FIRMessagingAppIdentifier(); + NSString *service = [[self class] serviceKeyForAuthorizedEntity:authorizedEntity scope:scope]; + NSData *item = [self.keychain dataForService:service account:account]; + if (!item) { + return nil; + } + // Token infos created from legacy storage don't have appVersion, firebaseAppID, or APNSInfo. + FIRMessagingTokenInfo *tokenInfo = [[self class] tokenInfoFromKeychainItem:item]; + if ([tokenInfo needsMigration]) { + [self + saveTokenInfo:tokenInfo + handler:^(NSError *error) { + if (error) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenManager001, + @"Failed to migrate token: %@ account: %@ service %@", + tokenInfo, account, service); + } else { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenManager001, + @"Successful token migration: %@ account: %@ service %@", + tokenInfo, account, service); + } + }]; + } + return tokenInfo; +} + +- (NSArray *)cachedTokenInfos { + NSString *account = FIRMessagingAppIdentifier(); + NSArray *items = + [self.keychain itemsMatchingService:kFIRMessagingKeychainWildcardIdentifier account:account]; + NSMutableArray *tokenInfos = + [NSMutableArray arrayWithCapacity:items.count]; + for (NSData *item in items) { + FIRMessagingTokenInfo *tokenInfo = [[self class] tokenInfoFromKeychainItem:item]; + if (tokenInfo) { + [tokenInfos addObject:tokenInfo]; + } + } + return tokenInfos; +} + ++ (nullable FIRMessagingTokenInfo *)tokenInfoFromKeychainItem:(NSData *)item { + // Check if it is saved as an archived FIRMessagingTokenInfo, otherwise return nil. + FIRMessagingTokenInfo *tokenInfo = nil; + if (item) { + @try { + NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:item + error:nil]; + unarchiver.requiresSecureCoding = NO; + [unarchiver setClass:[FIRMessagingTokenInfo class] forClassName:@"FIRInstanceIDTokenInfo"]; + tokenInfo = [unarchiver decodeObjectForKey:NSKeyedArchiveRootObjectKey]; + [unarchiver finishDecoding]; + } @catch (NSException *exception) { + FIRMessagingLoggerDebug(kFIRMessagingMessageCodeTokenStoreExceptionUnarchivingTokenInfo, + @"Unable to parse token info from Keychain item; item was in an " + @"invalid format"); + tokenInfo = nil; + } @finally { + } + } + return tokenInfo; +} + +#pragma mark - Save +// Token Infos will be saved under these Keychain keys: +// Account:
(e.g. com.mycompany.myapp) +// Service: : (e.g. 1234567890:*) +- (void)saveTokenInfo:(FIRMessagingTokenInfo *)tokenInfo + handler:(void (^)(NSError *))handler { // Keep the cachetime up-to-date. + tokenInfo.cacheTime = [NSDate date]; + // Always write to the Keychain, so that the cacheTime is up-to-date. + NSData *tokenInfoData; + // TODO(chliangGoogle: Use the new API and secureCoding protocol. + [NSKeyedArchiver setClassName:@"FIRInstanceIDTokenInfo" forClass:[FIRMessagingTokenInfo class]]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + tokenInfoData = [NSKeyedArchiver archivedDataWithRootObject:tokenInfo]; +#pragma clang diagnostic pop + NSString *account = FIRMessagingAppIdentifier(); + NSString *service = [[self class] serviceKeyForAuthorizedEntity:tokenInfo.authorizedEntity + scope:tokenInfo.scope]; + [self.keychain setData:tokenInfoData forService:service account:account handler:handler]; +} + +- (void)saveTokenInfoInCache:(FIRMessagingTokenInfo *)tokenInfo { + tokenInfo.cacheTime = [NSDate date]; + // TODO(chliangGoogle): Use the new API and secureCoding protocol. + // Always write to the Keychain, so that the cacheTime is up-to-date. + NSData *tokenInfoData; + [NSKeyedArchiver setClassName:@"FIRInstanceIDTokenInfo" forClass:[FIRMessagingTokenInfo class]]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + tokenInfoData = [NSKeyedArchiver archivedDataWithRootObject:tokenInfo]; +#pragma clang diagnostic pop + NSString *account = FIRMessagingAppIdentifier(); + NSString *service = [[self class] serviceKeyForAuthorizedEntity:tokenInfo.authorizedEntity + scope:tokenInfo.scope]; + [self.keychain setCacheData:tokenInfoData forService:service account:account]; +} + +#pragma mark - Delete + +- (void)removeTokenWithAuthorizedEntity:(nonnull NSString *)authorizedEntity + scope:(nonnull NSString *)scope { + if (![authorizedEntity length] || ![scope length]) { + FIRMessagingLoggerError(kFIRMessagingMessageCodeStore012, + @"Will not delete token with invalid entity: %@, scope: %@", + authorizedEntity, scope); + return; + } + NSString *account = FIRMessagingAppIdentifier(); + NSString *service = [[self class] serviceKeyForAuthorizedEntity:authorizedEntity scope:scope]; + [self.keychain removeItemsMatchingService:service account:account handler:nil]; +} + +- (void)removeAllTokensWithHandler:(void (^)(NSError *error))handler { + NSString *account = FIRMessagingAppIdentifier(); + [self.keychain removeItemsMatchingService:kFIRMessagingKeychainWildcardIdentifier + account:account + handler:handler]; +} + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRAnalyticsInterop.h b/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRAnalyticsInterop.h new file mode 100644 index 0000000..3b49733 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRAnalyticsInterop.h @@ -0,0 +1,68 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@protocol FIRAnalyticsInteropListener; + +NS_ASSUME_NONNULL_BEGIN + +/// Block typedef callback parameter to `getUserProperties(with:)`. +typedef void (^FIRAInteropUserPropertiesCallback)(NSDictionary *userProperties) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Connector for bridging communication between Firebase SDKs and FirebaseAnalytics APIs. +@protocol FIRAnalyticsInterop + +/// Sets user property when trigger event is logged. This API is only available in the SDK. +- (void)setConditionalUserProperty:(NSDictionary *)conditionalUserProperty; + +/// Clears user property if set. +- (void)clearConditionalUserProperty:(NSString *)userPropertyName + forOrigin:(NSString *)origin + clearEventName:(NSString *)clearEventName + clearEventParameters:(NSDictionary *)clearEventParameters; + +/// Returns currently set user properties. +- (NSArray *> *)conditionalUserProperties:(NSString *)origin + propertyNamePrefix: + (NSString *)propertyNamePrefix; + +/// Returns the maximum number of user properties. +- (NSInteger)maxUserProperties:(NSString *)origin; + +/// Returns the user properties to a callback function. +- (void)getUserPropertiesWithCallback: + (void (^)(NSDictionary *userProperties))callback; + +/// Logs events. +- (void)logEventWithOrigin:(NSString *)origin + name:(NSString *)name + parameters:(nullable NSDictionary *)parameters; + +/// Sets user property. +- (void)setUserPropertyWithOrigin:(NSString *)origin name:(NSString *)name value:(id)value; + +/// Registers an Analytics listener for the given origin. +- (void)registerAnalyticsListener:(id)listener + withOrigin:(NSString *)origin; + +/// Unregisters an Analytics listener for the given origin. +- (void)unregisterAnalyticsListenerWithOrigin:(NSString *)origin; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRAnalyticsInteropListener.h b/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRAnalyticsInteropListener.h new file mode 100644 index 0000000..327aefd --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRAnalyticsInteropListener.h @@ -0,0 +1,24 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// Handles events and messages from Analytics. +@protocol FIRAnalyticsInteropListener + +/// Triggers when an Analytics event happens for the registered origin with +/// FirebaseAnalyticsInterop`s `registerAnalyticsListener(_:withOrigin:)`. +- (void)messageTriggered:(NSString *)name parameters:(NSDictionary *)parameters; + +@end diff --git a/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRInteropEventNames.h b/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRInteropEventNames.h new file mode 100644 index 0000000..efc54ab --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRInteropEventNames.h @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// @file FIRInteropEventNames.h + +#import + +/// Notification open event name. +static NSString *const kFIRIEventNotificationOpen = @"_no"; + +/// Notification foreground event name. +static NSString *const kFIRIEventNotificationForeground = @"_nf"; + +/// Campaign event name. +static NSString *const kFIRIEventFirebaseCampaign = @"_cmp"; diff --git a/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRInteropParameterNames.h b/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRInteropParameterNames.h new file mode 100644 index 0000000..f640702 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/Interop/Analytics/Public/FIRInteropParameterNames.h @@ -0,0 +1,73 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/// @file FIRInteropParameterNames.h +/// +/// Predefined event parameter names used by Firebase. This file is a subset of the +/// FirebaseAnalytics FIRParameterNames.h public header. +/// +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       kFIRParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       kFIRParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       kFIRParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Message identifier. +static NSString *const kFIRIParameterMessageIdentifier = @"_nmid"; + +/// Message name. +static NSString *const kFIRIParameterMessageName = @"_nmn"; + +/// Message send time. +static NSString *const kFIRIParameterMessageTime = @"_nmt"; + +/// Message device time. +static NSString *const kFIRIParameterMessageDeviceTime = @"_ndt"; + +/// Topic message. +static NSString *const kFIRIParameterTopic = @"_nt"; + +/// Stores the message_id of the last notification opened by the app. +static NSString *const kFIRIUserPropertyLastNotification = @"_ln"; diff --git a/frontend/ios/Pods/FirebaseMessaging/LICENSE b/frontend/ios/Pods/FirebaseMessaging/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/ios/Pods/FirebaseMessaging/README.md b/frontend/ios/Pods/FirebaseMessaging/README.md new file mode 100644 index 0000000..8c98212 --- /dev/null +++ b/frontend/ios/Pods/FirebaseMessaging/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 16.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](docs/AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@20 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m new file mode 100644 index 0000000..11d849e --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m @@ -0,0 +1,95 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h" + +#import + +@implementation GDTCCTCompressionHelper + ++ (nullable NSData *)gzippedData:(NSData *)data { +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (data.length > UINT_MAX) { + return nil; + } +#endif + + enum { kChunkSize = 1024 }; + + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + + int level = Z_DEFAULT_COMPRESSION; + if (!bytes || !length) { + return nil; + } + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int memLevel = 8; // Default. + int windowBits = 15 + 16; // Enable gzip header instead of zlib header. + + int retCode; + if (deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel, Z_DEFAULT_STRATEGY) != Z_OK) { + return nil; + } + + // Hint the size at 1/4 the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length / 4)]; + unsigned char output[kChunkSize]; + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + // Collect the data. + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + deflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // If the loop exits, it used all input and the stream ended. + NSAssert(strm.avail_in == 0, + @"Should have finished deflating without using all input, %u bytes left", strm.avail_in); + NSAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + deflateEnd(&strm); + + return result; +} + ++ (BOOL)isGzipped:(NSData *)data { + const UInt8 *bytes = (const UInt8 *)data.bytes; + return (data.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b); +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m new file mode 100644 index 0000000..450fda8 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m @@ -0,0 +1,322 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h" + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#elif TARGET_OS_OSX +#import +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import +#import +#import + +#import "GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h" + +#pragma mark - General purpose encoders + +pb_bytes_array_t *GDTCCTEncodeString(NSString *string) { + NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding]; + return GDTCCTEncodeData(stringBytes); +} + +pb_bytes_array_t *GDTCCTEncodeData(NSData *data) { + pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + if (pbBytesArray != NULL) { + [data getBytes:pbBytesArray->bytes length:data.length]; + pbBytesArray->size = (pb_size_t)data.length; + } + return pbBytesArray; +} + +#pragma mark - CCT object constructors + +NSData *_Nullable GDTCCTEncodeBatchedLogRequest(gdt_cct_BatchedLogRequest *batchedLogRequest) { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) { + GDTCORLogError(GDTCORMCEGeneralError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&sizestream)); + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) { + GDTCORLogError(GDTCORMCEGeneralError, @"Error in nanopb encoding for bytes: %s", + PB_GET_ERROR(&ostream)); + } + + return CFBridgingRelease(dataRef); +} + +gdt_cct_BatchedLogRequest GDTCCTConstructBatchedLogRequest( + NSDictionary *> *logMappingIDToLogSet) { + gdt_cct_BatchedLogRequest batchedLogRequest = gdt_cct_BatchedLogRequest_init_default; + NSUInteger numberOfLogRequests = logMappingIDToLogSet.count; + gdt_cct_LogRequest *logRequests = calloc(numberOfLogRequests, sizeof(gdt_cct_LogRequest)); + if (logRequests == NULL) { + return batchedLogRequest; + } + + __block int i = 0; + [logMappingIDToLogSet enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull logMappingID, + NSSet *_Nonnull logSet, + BOOL *_Nonnull stop) { + int32_t logSource = [logMappingID intValue]; + gdt_cct_LogRequest logRequest = GDTCCTConstructLogRequest(logSource, logSet); + logRequests[i] = logRequest; + i++; + }]; + + batchedLogRequest.log_request = logRequests; + batchedLogRequest.log_request_count = (pb_size_t)numberOfLogRequests; + return batchedLogRequest; +} + +gdt_cct_LogRequest GDTCCTConstructLogRequest(int32_t logSource, + NSSet *_Nonnull logSet) { + if (logSet.count == 0) { + GDTCORLogError(GDTCORMCEGeneralError, @"%@", + @"An empty event set can't be serialized to proto."); + gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default; + return logRequest; + } + gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default; + logRequest.log_source = logSource; + logRequest.has_log_source = 1; + logRequest.client_info = GDTCCTConstructClientInfo(); + logRequest.has_client_info = 1; + logRequest.log_event = calloc(logSet.count, sizeof(gdt_cct_LogEvent)); + if (logRequest.log_event == NULL) { + return logRequest; + } + int i = 0; + for (GDTCOREvent *log in logSet) { + gdt_cct_LogEvent logEvent = GDTCCTConstructLogEvent(log); + logRequest.log_event[i] = logEvent; + i++; + } + logRequest.log_event_count = (pb_size_t)logSet.count; + + GDTCORClock *currentTime = [GDTCORClock snapshot]; + logRequest.request_time_ms = currentTime.timeMillis; + logRequest.has_request_time_ms = 1; + logRequest.request_uptime_ms = [currentTime uptimeMilliseconds]; + logRequest.has_request_uptime_ms = 1; + + return logRequest; +} + +gdt_cct_LogEvent GDTCCTConstructLogEvent(GDTCOREvent *event) { + gdt_cct_LogEvent logEvent = gdt_cct_LogEvent_init_default; + logEvent.event_time_ms = event.clockSnapshot.timeMillis; + logEvent.has_event_time_ms = 1; + logEvent.event_uptime_ms = [event.clockSnapshot uptimeMilliseconds]; + logEvent.has_event_uptime_ms = 1; + logEvent.timezone_offset_seconds = event.clockSnapshot.timezoneOffsetSeconds; + logEvent.has_timezone_offset_seconds = 1; + if (event.customBytes) { + NSData *networkConnectionInfoData = event.networkConnectionInfoData; + if (networkConnectionInfoData) { + [networkConnectionInfoData getBytes:&logEvent.network_connection_info + length:networkConnectionInfoData.length]; + logEvent.has_network_connection_info = 1; + } + NSNumber *eventCode = event.eventCode; + if (eventCode != nil) { + logEvent.has_event_code = 1; + logEvent.event_code = [eventCode intValue]; + } + } + NSError *error; + NSData *extensionBytes; + extensionBytes = event.serializedDataObjectBytes; + if (error) { + GDTCORLogWarning(GDTCORMCWFileReadError, + @"There was an error reading extension bytes from disk: %@", error); + return logEvent; + } + logEvent.source_extension = GDTCCTEncodeData(extensionBytes); // read bytes from the file. + if (event.productData) { + logEvent.compliance_data = GDTCCTConstructComplianceData(event.productData); + logEvent.has_compliance_data = 1; + } + return logEvent; +} + +gdt_cct_ComplianceData GDTCCTConstructComplianceData(GDTCORProductData *productData) { + privacy_context_external_ExternalPRequestContext prequest = + privacy_context_external_ExternalPRequestContext_init_default; + prequest.origin_associated_product_id = productData.productID; + prequest.has_origin_associated_product_id = 1; + + privacy_context_external_ExternalPrivacyContext privacy_context = + privacy_context_external_ExternalPrivacyContext_init_default; + privacy_context.prequest = prequest; + privacy_context.has_prequest = 1; + + gdt_cct_ComplianceData complianceData = gdt_cct_ComplianceData_init_default; + complianceData.privacy_context = privacy_context; + complianceData.has_privacy_context = 1; + complianceData.product_id_origin = gdt_cct_ComplianceData_ProductIdOrigin_EVENT_OVERRIDE; + complianceData.has_product_id_origin = 1; + return complianceData; +} + +gdt_cct_ClientInfo GDTCCTConstructClientInfo(void) { + gdt_cct_ClientInfo clientInfo = gdt_cct_ClientInfo_init_default; + clientInfo.client_type = gdt_cct_ClientInfo_ClientType_IOS_FIREBASE; + clientInfo.has_client_type = 1; +#if TARGET_OS_IOS || TARGET_OS_TV + clientInfo.ios_client_info = GDTCCTConstructiOSClientInfo(); + clientInfo.has_ios_client_info = 1; +#elif TARGET_OS_OSX + clientInfo.mac_client_info = GDTCCTConstructMacClientInfo(); + clientInfo.has_mac_client_info = 1; +#endif + return clientInfo; +} + +gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo(void) { + gdt_cct_IosClientInfo iOSClientInfo = gdt_cct_IosClientInfo_init_default; +#if TARGET_OS_IOS || TARGET_OS_TV + UIDevice *device = [UIDevice currentDevice]; + NSBundle *bundle = [NSBundle mainBundle]; + NSLocale *locale = [NSLocale currentLocale]; + iOSClientInfo.os_full_version = GDTCCTEncodeString(device.systemVersion); + NSArray *versionComponents = [device.systemVersion componentsSeparatedByString:@"."]; + iOSClientInfo.os_major_version = GDTCCTEncodeString(versionComponents[0]); + NSString *version = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; + if (version) { + iOSClientInfo.application_build = GDTCCTEncodeString(version); + } + NSString *countryCode = [locale objectForKey:NSLocaleCountryCode]; + if (countryCode) { + iOSClientInfo.country = GDTCCTEncodeString([locale objectForKey:NSLocaleCountryCode]); + } + iOSClientInfo.model = GDTCCTEncodeString(GDTCORDeviceModel()); + NSString *languageCode = bundle.preferredLocalizations.firstObject; + iOSClientInfo.language_code = + languageCode ? GDTCCTEncodeString(languageCode) : GDTCCTEncodeString(@"en"); + iOSClientInfo.application_bundle_id = GDTCCTEncodeString(bundle.bundleIdentifier); +#endif + return iOSClientInfo; +} + +gdt_cct_MacClientInfo GDTCCTConstructMacClientInfo(void) { + gdt_cct_MacClientInfo macOSClientInfo = gdt_cct_MacClientInfo_init_default; + + NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; + NSString *majorVersion = [@(osVersion.majorVersion) stringValue]; + NSString *minorVersion = [@(osVersion.minorVersion) stringValue]; + NSString *majorAndMinorString = [NSString stringWithFormat:@"%@.%@", majorVersion, minorVersion]; + macOSClientInfo.os_major_version = GDTCCTEncodeString(majorAndMinorString); + + NSString *patchVersion = [@(osVersion.patchVersion) stringValue]; + NSString *majorMinorPatchString = + [NSString stringWithFormat:@"%@.%@", majorAndMinorString, patchVersion]; + macOSClientInfo.os_full_version = GDTCCTEncodeString(majorMinorPatchString); + + NSBundle *bundle = [NSBundle mainBundle]; + NSString *version = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; + if (version) { + macOSClientInfo.application_build = GDTCCTEncodeString(version); + } + + NSString *bundleID = bundle.bundleIdentifier; + if (bundleID) { + macOSClientInfo.application_bundle_id = GDTCCTEncodeString(bundleID); + } + + return macOSClientInfo; +} + +NSData *GDTCCTConstructNetworkConnectionInfoData(void) { + gdt_cct_NetworkConnectionInfo networkConnectionInfo = gdt_cct_NetworkConnectionInfo_init_default; + NSInteger currentNetworkType = GDTCORNetworkTypeMessage(); + if (currentNetworkType) { + networkConnectionInfo.has_network_type = 1; + if (currentNetworkType == GDTCORNetworkTypeMobile) { + networkConnectionInfo.network_type = gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE; + networkConnectionInfo.mobile_subtype = GDTCCTNetworkConnectionInfoNetworkMobileSubtype(); + if (networkConnectionInfo.mobile_subtype != + gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE) { + networkConnectionInfo.has_mobile_subtype = 1; + } + } else { + networkConnectionInfo.network_type = gdt_cct_NetworkConnectionInfo_NetworkType_WIFI; + } + } + NSData *networkConnectionInfoData = [NSData dataWithBytes:&networkConnectionInfo + length:sizeof(networkConnectionInfo)]; + return networkConnectionInfoData; +} + +gdt_cct_NetworkConnectionInfo_MobileSubtype GDTCCTNetworkConnectionInfoNetworkMobileSubtype(void) { + NSNumber *networkMobileSubtypeMessage = @(GDTCORNetworkMobileSubTypeMessage()); + if (!networkMobileSubtypeMessage.intValue) { + return gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE; + } + static NSDictionary *MessageToNetworkSubTypeMessage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + MessageToNetworkSubTypeMessage = @{ + @(GDTCORNetworkMobileSubtypeGPRS) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_GPRS), + @(GDTCORNetworkMobileSubtypeEdge) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EDGE), + @(GDTCORNetworkMobileSubtypeWCDMA) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE), + @(GDTCORNetworkMobileSubtypeHSDPA) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_HSDPA), + @(GDTCORNetworkMobileSubtypeHSUPA) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_HSUPA), + @(GDTCORNetworkMobileSubtypeCDMA1x) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_CDMA), + @(GDTCORNetworkMobileSubtypeCDMAEVDORev0) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_0), + @(GDTCORNetworkMobileSubtypeCDMAEVDORevA) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_A), + @(GDTCORNetworkMobileSubtypeCDMAEVDORevB) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_B), + @(GDTCORNetworkMobileSubtypeHRPD) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EHRPD), + @(GDTCORNetworkMobileSubtypeLTE) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE), + }; + }); + NSNumber *networkMobileSubtype = MessageToNetworkSubTypeMessage[networkMobileSubtypeMessage]; + return networkMobileSubtype.intValue; +} + +#pragma mark - CCT Object decoders + +gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error) { + gdt_cct_LogResponse response = gdt_cct_LogResponse_init_default; + pb_istream_t istream = pb_istream_from_buffer([data bytes], [data length]); + if (!pb_decode(&istream, gdt_cct_LogResponse_fields, &response)) { + NSString *nanopb_error = [NSString stringWithFormat:@"%s", PB_GET_ERROR(&istream)]; + NSDictionary *userInfo = @{@"nanopb error:" : nanopb_error}; + if (error != NULL) { + *error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:userInfo]; + } + response = (gdt_cct_LogResponse)gdt_cct_LogResponse_init_default; + } + return response; +} diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTURLSessionDataResponse.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTURLSessionDataResponse.m new file mode 100644 index 0000000..669e93f --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTURLSessionDataResponse.m @@ -0,0 +1,28 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h" + +@implementation GDTCCTURLSessionDataResponse + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(NSData *)body { + self = [super init]; + if (self) { + _HTTPResponse = response; + _HTTPBody = body; + } + return self; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m new file mode 100644 index 0000000..354d14c --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m @@ -0,0 +1,668 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import +#import +#import + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h" +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h" +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h" +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h" + +NS_ASSUME_NONNULL_BEGIN + +#ifdef GDTCOR_VERSION +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x +static NSString *const kGDTCCTSupportSDKVersion = @STR(GDTCOR_VERSION); +#else +static NSString *const kGDTCCTSupportSDKVersion = @"UNKNOWN"; +#endif // GDTCOR_VERSION + +typedef void (^GDTCCTUploaderURLTaskCompletion)(NSNumber *batchID, + NSSet *_Nullable events, + NSData *_Nullable data, + NSURLResponse *_Nullable response, + NSError *_Nullable error); + +typedef void (^GDTCCTUploaderEventBatchBlock)(NSNumber *_Nullable batchID, + NSSet *_Nullable events); + +@interface GDTCCTUploadOperation () + +/// The properties to store parameters passed in the initializer. See the initialized docs for +/// details. +@property(nonatomic, readonly) GDTCORTarget target; +@property(nonatomic, readonly) GDTCORUploadConditions conditions; +@property(nonatomic, readonly) NSURL *uploadURL; +@property(nonatomic, readonly) id storage; +@property(nonatomic, readonly) id metadataProvider; +@property(nonatomic, readonly, nullable) id metricsController; + +/** The URL session that will attempt upload. */ +@property(nonatomic, nullable) NSURLSession *uploaderSession; + +/// The metrics being uploaded by the operation. These metrics are fetched and included as an event +/// in the upload batch as part of the upload process. +/// +/// Metrics being uploaded are retained so they can be re-stored if upload is not successful. +@property(nonatomic, nullable) GDTCORMetrics *currentMetrics; + +/// NSOperation state properties implementation. +@property(nonatomic, readwrite, getter=isExecuting) BOOL executing; +@property(nonatomic, readwrite, getter=isFinished) BOOL finished; + +@property(nonatomic, readwrite) BOOL uploadAttempted; + +@end + +@implementation GDTCCTUploadOperation + +- (instancetype)initWithTarget:(GDTCORTarget)target + conditions:(GDTCORUploadConditions)conditions + uploadURL:(NSURL *)uploadURL + queue:(dispatch_queue_t)queue + storage:(id)storage + metadataProvider:(id)metadataProvider + metricsController:(nullable id)metricsController { + self = [super init]; + if (self) { + _uploaderQueue = queue; + _target = target; + _conditions = conditions; + _uploadURL = uploadURL; + _storage = storage; + _metadataProvider = metadataProvider; + _metricsController = metricsController; + } + return self; +} + +- (NSURLSession *)uploaderSessionCreateIfNeeded { + if (_uploaderSession == nil) { + NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; + _uploaderSession = [NSURLSession sessionWithConfiguration:config + delegate:self + delegateQueue:nil]; + } + return _uploaderSession; +} + +- (void)uploadTarget:(GDTCORTarget)target withConditions:(GDTCORUploadConditions)conditions { + __block GDTCORBackgroundIdentifier backgroundTaskID = GDTCORBackgroundIdentifierInvalid; + + dispatch_block_t backgroundTaskCompletion = ^{ + // End the background task if there was one. + if (backgroundTaskID != GDTCORBackgroundIdentifierInvalid) { + [[GDTCORApplication sharedApplication] endBackgroundTask:backgroundTaskID]; + backgroundTaskID = GDTCORBackgroundIdentifierInvalid; + } + }; + + backgroundTaskID = [[GDTCORApplication sharedApplication] + beginBackgroundTaskWithName:@"GDTCCTUploader-upload" + expirationHandler:^{ + if (backgroundTaskID != GDTCORBackgroundIdentifierInvalid) { + // Cancel the upload and complete delivery. + [self.currentTask cancel]; + + // End the background task. + backgroundTaskCompletion(); + } else { + GDTCORLog(GDTCORMCDDebugLog, GDTCORLoggingLevelWarnings, + @"Attempted to cancel invalid background task in " + "GDTCCTUploadOperation."); + } + }]; + + id storage = self.storage; + + // 1. Check if the conditions for the target are suitable. + [self isReadyToUploadTarget:target conditions:conditions] + .validateOn(self.uploaderQueue, + ^BOOL(NSNull *__unused _) { + // 2. Stop the operation if it has been cancelled. + return !self.isCancelled; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(NSNull *result) { + // 3. Remove previously attempted batches. + return [storage removeAllBatchesForTarget:target deleteEvents:NO]; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(NSNull *__unused _) { + // There may be a big amount of events stored, so creating a batch may be an + // expensive operation. + + // 4. Do a lightweight check if there are any events for the target first to + // finish early if there are none. + return [storage hasEventsForTarget:target]; + }) + .validateOn(self.uploaderQueue, + ^BOOL(NSNumber *hasEvents) { + // 5. Stop operation if there are no events to upload. + return hasEvents.boolValue; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(NSNumber *__unused _) { + // 6. Fetch events to upload. + GDTCORStorageEventSelector *eventSelector = [self eventSelectorTarget:target + withConditions:conditions]; + return [storage batchWithEventSelector:eventSelector + batchExpiration:[NSDate dateWithTimeIntervalSinceNow:600]]; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(GDTCORUploadBatch *batch) { + // 7. Add metrics to the batch if the target has a + // corresponding metrics controller. + if (!self.metricsController) { + return [FBLPromise resolvedWith:batch]; + } + + return [self batchByAddingMetricsEventToBatch:batch forTarget:target]; + }) + .validateOn(self.uploaderQueue, + ^BOOL(GDTCORUploadBatch *__unused _) { + // 8. Stop the operation if it has been cancelled. + return !self.isCancelled; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(GDTCORUploadBatch *batch) { + // A non-empty batch has been created, consider it as an upload attempt. + self.uploadAttempted = YES; + + // 9. Perform upload. + return [self uploadBatch:batch toTarget:target storage:storage]; + }) + .catchOn(self.uploaderQueue, + ^(NSError *error){ + // TODO: Consider reporting the error to the client. + }) + .alwaysOn(self.uploaderQueue, ^{ + // 10. Finish operation. + [self finishOperation]; + backgroundTaskCompletion(); + }); +} + +#pragma mark - Upload implementation details + +/** Uploads a given batch from storage to a target. */ +- (FBLPromise *)uploadBatch:(GDTCORUploadBatch *)batch + toTarget:(GDTCORTarget)target + storage:(id)storage { + // 1. Send URL request. + return [self sendURLRequestWithBatch:batch target:target] + .thenOn(self.uploaderQueue, + ^FBLPromise *(GDTCCTURLSessionDataResponse *response) { + // 2. Update the next upload time and process response. + [self updateNextUploadTimeWithResponse:response forTarget:target]; + + return [self processResponse:response forBatch:batch storage:storage]; + }) + .recoverOn(self.uploaderQueue, ^id(NSError *error) { + // If a network error occurred, move the events back to the main + // storage so they can attempt to be uploaded in the next attempt. + // Additionally, if metrics were added to the batch, place them back + // in storage. + if (self.currentMetrics) { + [self.metricsController offerMetrics:self.currentMetrics]; + } + return [storage removeBatchWithID:batch.batchID deleteEvents:NO]; + }); +} + +/** Processes a URL session response for a given batch from storage. */ +- (FBLPromise *)processResponse:(GDTCCTURLSessionDataResponse *)response + forBatch:(GDTCORUploadBatch *)batch + storage:(id)storage { + // Cleanup batch based on the response's status code. + NSInteger statusCode = response.HTTPResponse.statusCode; + BOOL isSuccess = statusCode >= 200 && statusCode < 300; + // Transient errors include "too many requests" (429) and server errors (5xx). + BOOL isTransientError = + statusCode == 429 || statusCode == 404 || (statusCode >= 500 && statusCode < 600); + + BOOL shouldDeleteEvents = isSuccess || !isTransientError; + + // If the batch included metrics and the upload failed, place metrics back + // in storage. + GDTCORMetrics *uploadedMetrics = [self currentMetrics]; + if (uploadedMetrics && !isSuccess) { + [self.metricsController offerMetrics:uploadedMetrics]; + } + + if (isSuccess) { + GDTCORLogDebug(@"CCT: batch %@ uploaded. Batch will be deleted.", batch.batchID); + + } else if (isTransientError) { + GDTCORLogDebug(@"CCT: batch %@ upload failed. Batch will attempt to be uploaded later.", + batch.batchID); + + } else { + GDTCORLogDebug(@"CCT: batch %@ upload failed. Batch will be deleted.", batch.batchID); + + if (/* isInvalidPayloadError */ statusCode == 400) { + // Log events that will be dropped due to the upload error. + [self.metricsController logEventsDroppedForReason:GDTCOREventDropReasonInvalidPayload + events:batch.events]; + } + } + + return [storage removeBatchWithID:batch.batchID deleteEvents:shouldDeleteEvents]; +} + +/** Composes and sends URL request. */ +- (FBLPromise *)sendURLRequestWithBatch:(GDTCORUploadBatch *)batch + target:(GDTCORTarget)target { + return [FBLPromise + onQueue:self.uploaderQueue + do:^NSURLRequest * { + // 1. Prepare URL request. + NSData *requestProtoData = [self constructRequestProtoWithEvents:batch.events]; + NSData *gzippedData = [GDTCCTCompressionHelper gzippedData:requestProtoData]; + BOOL usingGzipData = + gzippedData != nil && gzippedData.length < requestProtoData.length; + NSData *dataToSend = usingGzipData ? gzippedData : requestProtoData; + NSURLRequest *request = [self constructRequestWithURL:self.uploadURL + forTarget:target + data:dataToSend]; + GDTCORLogDebug(@"CTT: request containing %lu events for batch: %@ for target: " + @"%ld created: %@", + (unsigned long)batch.events.count, batch.batchID, (long)target, + request); + return request; + }] + .thenOn(self.uploaderQueue, + ^FBLPromise *(NSURLRequest *request) { + // 2. Send URL request. + NSURLSession *session = [self uploaderSessionCreateIfNeeded]; + return [FBLPromise wrapObjectOrErrorCompletion:^( + FBLPromiseObjectOrErrorCompletion _Nonnull handler) { + [[session dataTaskWithRequest:request + completionHandler:^(NSData *_Nullable data, + NSURLResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + handler(nil, error); + } else { + handler([[GDTCCTURLSessionDataResponse alloc] + initWithResponse:(NSHTTPURLResponse *)response + HTTPBody:data], + nil); + } + }] resume]; + }]; + }) + .thenOn(self.uploaderQueue, + ^GDTCCTURLSessionDataResponse *(GDTCCTURLSessionDataResponse *response) { + // Invalidate session to release the delegate (which is `self`) to break the retain + // cycle. + [self.uploaderSession finishTasksAndInvalidate]; + return response; + }) + .recoverOn(self.uploaderQueue, ^id(NSError *error) { + // Invalidate session to release the delegate (which is `self`) to break the retain cycle. + [self.uploaderSession finishTasksAndInvalidate]; + // Re-throw the error. + return error; + }); +} + +/** Parses server response and update next upload time for the specified target based on it. */ +- (void)updateNextUploadTimeWithResponse:(GDTCCTURLSessionDataResponse *)response + forTarget:(GDTCORTarget)target { + GDTCORClock *futureUploadTime; + if (response.HTTPBody) { + NSError *decodingError; + gdt_cct_LogResponse logResponse = GDTCCTDecodeLogResponse(response.HTTPBody, &decodingError); + if (!decodingError && logResponse.has_next_request_wait_millis) { + GDTCORLogDebug(@"CCT: The backend responded asking to not upload for %lld millis from now.", + logResponse.next_request_wait_millis); + futureUploadTime = + [GDTCORClock clockSnapshotInTheFuture:logResponse.next_request_wait_millis]; + } else if (decodingError) { + GDTCORLogDebug(@"There was a response decoding error: %@", decodingError); + } + pb_release(gdt_cct_LogResponse_fields, &logResponse); + } + + // If no futureUploadTime was parsed from the response body, then check + // [Retry-After](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header. + if (!futureUploadTime) { + NSString *retryAfterHeader = response.HTTPResponse.allHeaderFields[@"Retry-After"]; + if (retryAfterHeader.length > 0) { + NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + NSNumber *retryAfterSeconds = [formatter numberFromString:retryAfterHeader]; + if (retryAfterSeconds != nil) { + uint64_t retryAfterMillis = retryAfterSeconds.unsignedIntegerValue * 1000u; + futureUploadTime = [GDTCORClock clockSnapshotInTheFuture:retryAfterMillis]; + } + } + } + + if (!futureUploadTime) { + GDTCORLogDebug(@"%@", @"CCT: The backend response failed to parse, so the next request " + @"won't occur until 15 minutes from now"); + // 15 minutes from now. + futureUploadTime = [GDTCORClock clockSnapshotInTheFuture:15 * 60 * 1000]; + } + + [self.metadataProvider setNextUploadTime:futureUploadTime forTarget:target]; +} + +#pragma mark - Private helper methods + +/** @return A resolved promise if is ready and a rejected promise if not. */ +- (FBLPromise *)isReadyToUploadTarget:(GDTCORTarget)target + conditions:(GDTCORUploadConditions)conditions { + FBLPromise *promise = [FBLPromise pendingPromise]; + if ([self readyToUploadTarget:target conditions:conditions]) { + [promise fulfill:[NSNull null]]; + } else { + NSString *reason = + [NSString stringWithFormat:@"Target %ld is not ready to upload with condition: %ld", + (long)target, (long)conditions]; + [promise reject:[self genericRejectedPromiseErrorWithReason:reason]]; + } + return promise; +} + +// TODO: Move to a separate class/extension/file when needed in other files. +/** Returns an error object with the specified failure reason. */ +- (NSError *)genericRejectedPromiseErrorWithReason:(NSString *)reason { + return [NSError errorWithDomain:@"GDTCCTUploader" + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : reason}]; +} + +/** Returns if the specified target is ready to be uploaded based on the specified conditions. */ +- (BOOL)readyToUploadTarget:(GDTCORTarget)target conditions:(GDTCORUploadConditions)conditions { + // Not ready to upload with no network connection. + // TODO: Reconsider using reachability to prevent an upload attempt. + // See https://developer.apple.com/videos/play/wwdc2019/712/ (49:40) for more details. + if (conditions & GDTCORUploadConditionNoNetwork) { + GDTCORLogDebug(@"%@", @"CCT: Not ready to upload without a network connection."); + return NO; + } + + // Upload events with no additional conditions if high priority. + if ((conditions & GDTCORUploadConditionHighPriority) == GDTCORUploadConditionHighPriority) { + GDTCORLogDebug(@"%@", @"CCT: a high priority event is allowing an upload"); + return YES; + } + + // Check next upload time for the target. + BOOL isAfterNextUploadTime = YES; + GDTCORClock *nextUploadTime = [self.metadataProvider nextUploadTimeForTarget:target]; + if (nextUploadTime) { + isAfterNextUploadTime = [[GDTCORClock snapshot] isAfter:nextUploadTime]; + } + + if (isAfterNextUploadTime) { + GDTCORLogDebug(@"CCT: can upload to target %ld because the request wait time has transpired", + (long)target); + } else { + GDTCORLogDebug(@"CCT: can't upload to target %ld because the backend asked to wait", + (long)target); + } + + return isAfterNextUploadTime; +} + +/** Constructs data given an upload package. + * + * @param events The events used to construct the request proto bytes. + * @return Proto bytes representing a gdt_cct_LogRequest object. + */ +- (nonnull NSData *)constructRequestProtoWithEvents:(NSSet *)events { + // Segment the log events by log type. + NSMutableDictionary *> *logMappingIDToLogSet = + [[NSMutableDictionary alloc] init]; + [events enumerateObjectsUsingBlock:^(GDTCOREvent *_Nonnull event, BOOL *_Nonnull stop) { + NSMutableSet *logSet = logMappingIDToLogSet[event.mappingID]; + logSet = logSet ? logSet : [[NSMutableSet alloc] init]; + [logSet addObject:event]; + logMappingIDToLogSet[event.mappingID] = logSet; + }]; + + gdt_cct_BatchedLogRequest batchedLogRequest = + GDTCCTConstructBatchedLogRequest(logMappingIDToLogSet); + + NSData *data = GDTCCTEncodeBatchedLogRequest(&batchedLogRequest); + pb_release(gdt_cct_BatchedLogRequest_fields, &batchedLogRequest); + return data ? data : [[NSData alloc] init]; +} + +/** Constructs a request to the given URL and target with the specified request body data. + * + * @param target The target backend to send the request to. + * @param data The request body data. + * @return A new NSURLRequest ready to be sent to FLL. + */ +- (nullable NSURLRequest *)constructRequestWithURL:(NSURL *)URL + forTarget:(GDTCORTarget)target + data:(NSData *)data { + if (data == nil || data.length == 0) { + GDTCORLogDebug(@"There was no data to construct a request for target %ld.", (long)target); + return nil; + } + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + NSString *targetString; + switch (target) { + case kGDTCORTargetCCT: + targetString = @"cct"; + break; + + case kGDTCORTargetFLL: + targetString = @"fll"; + break; + + case kGDTCORTargetCSH: + targetString = @"csh"; + break; + case kGDTCORTargetINT: + targetString = @"int"; + break; + + default: + targetString = @"unknown"; + break; + } + NSString *userAgent = + [NSString stringWithFormat:@"datatransport/%@ %@support/%@ apple/", kGDTCORVersion, + targetString, kGDTCCTSupportSDKVersion]; + + [request setValue:[self.metadataProvider APIKeyForTarget:target] + forHTTPHeaderField:@"X-Goog-Api-Key"]; + + if ([GDTCCTCompressionHelper isGzipped:data]) { + [request setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"]; + } + [request setValue:@"application/x-protobuf" forHTTPHeaderField:@"Content-Type"]; + [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; + [request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + request.HTTPMethod = @"POST"; + [request setHTTPBody:data]; + return request; +} + +/** Creates and returns a storage event selector for the specified target and conditions. */ +- (GDTCORStorageEventSelector *)eventSelectorTarget:(GDTCORTarget)target + withConditions:(GDTCORUploadConditions)conditions { + if ((conditions & GDTCORUploadConditionHighPriority) == GDTCORUploadConditionHighPriority) { + return [GDTCORStorageEventSelector eventSelectorForTarget:target]; + } + NSMutableSet *qosTiers = [[NSMutableSet alloc] init]; + if (conditions & GDTCORUploadConditionWifiData) { + [qosTiers addObjectsFromArray:@[ + @(GDTCOREventQoSFast), @(GDTCOREventQoSWifiOnly), @(GDTCOREventQosDefault), + @(GDTCOREventQoSTelemetry), @(GDTCOREventQoSUnknown) + ]]; + } + if (conditions & GDTCORUploadConditionMobileData) { + [qosTiers addObjectsFromArray:@[ @(GDTCOREventQoSFast), @(GDTCOREventQosDefault) ]]; + } + + return [[GDTCORStorageEventSelector alloc] initWithTarget:target + eventIDs:nil + mappingIDs:nil + qosTiers:qosTiers]; +} + +- (FBLPromise *)batchByAddingMetricsEventToBatch:(GDTCORUploadBatch *)batch + forTarget:(GDTCORTarget)target { + return [self.metricsController getAndResetMetrics] + .thenOn(self.uploaderQueue, + ^GDTCORUploadBatch *(GDTCORMetrics *metrics) { + // Save the metrics so they can be re-stored if upload fails. + [self setCurrentMetrics:metrics]; + + GDTCOREvent *metricsEvent = [GDTCOREvent eventWithMetrics:metrics forTarget:target]; + GDTCORUploadBatch *batchWithMetricEvent = [[GDTCORUploadBatch alloc] + initWithBatchID:batch.batchID + events:[batch.events setByAddingObject:metricsEvent]]; + + return batchWithMetricEvent; + }) + .recoverOn(self.uploaderQueue, ^GDTCORUploadBatch *(NSError *error) { + // Return given batch if an error occurs (i.e. no metrics were fetched). + return batch; + }); +} + +#pragma mark - NSURLSessionDelegate + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *_Nullable))completionHandler { + if (!completionHandler) { + return; + } + if (response.statusCode == 302 || response.statusCode == 301) { + NSURLRequest *newRequest = [self constructRequestWithURL:request.URL + forTarget:kGDTCORTargetCCT + data:task.originalRequest.HTTPBody]; + completionHandler(newRequest); + } else { + completionHandler(request); + } +} + +#pragma mark - NSOperation methods + +@synthesize executing = _executing; +@synthesize finished = _finished; + +- (BOOL)isFinished { + @synchronized(self) { + return _finished; + } +} + +- (BOOL)isExecuting { + @synchronized(self) { + return _executing; + } +} + +- (BOOL)isAsynchronous { + return YES; +} + +- (void)startOperation { + @synchronized(self) { + [self willChangeValueForKey:@"isExecuting"]; + [self willChangeValueForKey:@"isFinished"]; + self->_executing = YES; + self->_finished = NO; + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; + } +} + +- (void)finishOperation { + @synchronized(self) { + [self willChangeValueForKey:@"isExecuting"]; + [self willChangeValueForKey:@"isFinished"]; + self->_executing = NO; + self->_finished = YES; + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; + } +} + +- (void)start { + [self startOperation]; + + GDTCORLogDebug(@"Upload operation started: %@", self); + [self uploadTarget:self.target withConditions:self.conditions]; +} + +- (void)cancel { + @synchronized(self) { + [super cancel]; + + // If the operation hasn't been started we can set `isFinished = YES` straight away. + if (!_executing) { + _executing = NO; + _finished = YES; + } + } +} + +#pragma mark - Force Category Linking + +extern void GDTCCTInclude_GDTCOREvent_GDTCCTSupport_Category(void); +extern void GDTCCTInclude_GDTCOREvent_GDTMetricsSupport_Category(void); +extern void GDTCCTInclude_GDTCORLogSourceMetrics_Internal_Category(void); + +/// Does nothing when called, and not meant to be called. +/// +/// This method forces the linker to include categories even if +/// users do not include the '-ObjC' linker flag in their project. ++ (void)noop { + GDTCCTInclude_GDTCOREvent_GDTCCTSupport_Category(); + GDTCCTInclude_GDTCOREvent_GDTMetricsSupport_Category(); + GDTCCTInclude_GDTCORLogSourceMetrics_Internal_Category(); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m new file mode 100644 index 0000000..c436ed3 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m @@ -0,0 +1,215 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCCTUploader () + +@property(nonatomic, readonly) NSOperationQueue *uploadOperationQueue; +@property(nonatomic, readonly) dispatch_queue_t uploadQueue; + +@property(nonatomic, readonly) + NSMutableDictionary *nextUploadTimeByTarget; + +@end + +@implementation GDTCCTUploader + +static NSURL *_testServerURL = nil; + ++ (void)load { + GDTCCTUploader *uploader = [GDTCCTUploader sharedInstance]; +#if GDT_TEST + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetTest]; +#endif // GDT_TEST + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetCCT]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetFLL]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetCSH]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetINT]; +} + ++ (instancetype)sharedInstance { + static GDTCCTUploader *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCCTUploader alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _uploadQueue = dispatch_queue_create("com.google.GDTCCTUploader", DISPATCH_QUEUE_SERIAL); + _uploadOperationQueue = [[NSOperationQueue alloc] init]; + _uploadOperationQueue.maxConcurrentOperationCount = 1; + _nextUploadTimeByTarget = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)uploadTarget:(GDTCORTarget)target withConditions:(GDTCORUploadConditions)conditions { + // Current GDTCCTUploader expected behaviour: + // 1. Accept multiple upload request + // 2. Verify if there are events eligible for upload and start upload for the first suitable + // target + // 3. Ignore other requests while an upload is in-progress. + + // TODO: Revisit expected behaviour. + // Potentially better option: + // 1. Accept and enqueue all upload requests + // 2. Notify the client of upload stages + // 3. Allow the client cancelling upload requests as needed. + + id storage = GDTCORStoragePromiseInstanceForTarget(target); + if (storage == nil) { + GDTCORLogError(GDTCORMCEGeneralError, + @"Failed to upload target: %ld - could not find corresponding storage instance.", + (long)target); + return; + } + + id metricsController = + GDTCORMetricsControllerInstanceForTarget(target); + + GDTCCTUploadOperation *uploadOperation = + [[GDTCCTUploadOperation alloc] initWithTarget:target + conditions:conditions + uploadURL:[[self class] serverURLForTarget:target] + queue:self.uploadQueue + storage:storage + metadataProvider:self + metricsController:metricsController]; + + GDTCORLogDebug(@"Upload operation created: %@, target: %@", uploadOperation, @(target)); + + __weak __auto_type weakSelf = self; + __weak GDTCCTUploadOperation *weakOperation = uploadOperation; + uploadOperation.completionBlock = ^{ + __auto_type strongSelf = weakSelf; + GDTCCTUploadOperation *strongOperation = weakOperation; + if (strongSelf == nil || strongOperation == nil) { + GDTCORLogDebug(@"Internal inconsistency: GDTCCTUploader was deallocated during upload.", nil); + return; + } + + GDTCORLogDebug(@"Upload operation finished: %@, uploadAttempted: %@", strongOperation, + @(strongOperation.uploadAttempted)); + + if (strongOperation.uploadAttempted) { + // Ignore all upload requests received when the upload was in progress. + [strongSelf.uploadOperationQueue cancelAllOperations]; + } + }; + + [self.uploadOperationQueue addOperation:uploadOperation]; + GDTCORLogDebug(@"Upload operation scheduled: %@, operation count: %@", uploadOperation, + @(self.uploadOperationQueue.operationCount)); +} + +#pragma mark - URLs + ++ (void)setTestServerURL:(NSURL *_Nullable)serverURL { + _testServerURL = serverURL; +} + ++ (NSURL *_Nullable)testServerURL { + return _testServerURL; +} + ++ (nullable NSURL *)serverURLForTarget:(GDTCORTarget)target { +#if GDT_TEST + if (_testServerURL) { + return _testServerURL; + } +#endif // GDT_TEST + + return [GDTCOREndpoints uploadURLForTarget:target]; +} + +- (NSString *)FLLAndCSHAndINTAPIKey { + static NSString *defaultServerKey; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // These strings should be interleaved to construct the real key. + const char *p1 = "AzSBG0honD6A-PxV5nBc"; + const char *p2 = "Iay44Iwtu2vV0AOrz1C"; + const char defaultKey[40] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], + p1[4], p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], + p1[8], p2[8], p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], + p1[12], p2[12], p1[13], p2[13], p1[14], p2[14], p1[15], p2[15], + p1[16], p2[16], p1[17], p2[17], p1[18], p2[18], p1[19], '\0'}; + defaultServerKey = [NSString stringWithUTF8String:defaultKey]; + }); + return defaultServerKey; +} + +#pragma mark - GDTCCTUploadMetadataProvider + +- (nullable GDTCORClock *)nextUploadTimeForTarget:(GDTCORTarget)target { + @synchronized(self.nextUploadTimeByTarget) { + return self.nextUploadTimeByTarget[@(target)]; + } +} + +- (void)setNextUploadTime:(nullable GDTCORClock *)time forTarget:(GDTCORTarget)target { + @synchronized(self.nextUploadTimeByTarget) { + self.nextUploadTimeByTarget[@(target)] = time; + } +} + +- (nullable NSString *)APIKeyForTarget:(GDTCORTarget)target { + if (target == kGDTCORTargetFLL || target == kGDTCORTargetCSH) { + return [self FLLAndCSHAndINTAPIKey]; + } + + if (target == kGDTCORTargetINT) { + return [self FLLAndCSHAndINTAPIKey]; + } + + return nil; +} + +#if GDT_TEST +- (BOOL)waitForUploadFinishedWithTimeout:(NSTimeInterval)timeout { + NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:timeout]; + while ([expirationDate compare:[NSDate date]] == NSOrderedDescending) { + if (self.uploadOperationQueue.operationCount == 0) { + return YES; + } else { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + } + } + + GDTCORLogDebug(@"Uploader wait for finish timeout exceeded. Operations still in queue: %@", + self.uploadOperationQueue.operations); + return NO; +} +#endif // GDT_TEST + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m new file mode 100644 index 0000000..f102c81 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m @@ -0,0 +1,244 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +NSString *const GDTCCTNeedsNetworkConnectionInfo = @"needs_network_connection_info"; + +NSString *const GDTCCTNetworkConnectionInfo = @"network_connection_info"; + +NSString *const GDTCCTEventCodeInfo = @"event_code_info"; + +@implementation GDTCOREvent (GDTCCTSupport) + +- (void)setNeedsNetworkConnectionInfoPopulated:(BOOL)needsNetworkConnectionInfoPopulated { + if (!needsNetworkConnectionInfoPopulated) { + if (!self.customBytes) { + return; + } + + // Make sure we don't destroy the eventCode data, if any is present. + @try { + NSError *error; + NSMutableDictionary *bytesDict = + [[NSJSONSerialization JSONObjectWithData:self.customBytes options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + NSNumber *eventCode = bytesDict[GDTCCTEventCodeInfo]; + if (eventCode != nil) { + self.customBytes = + [NSJSONSerialization dataWithJSONObject:@{GDTCCTEventCodeInfo : eventCode} + options:0 + error:&error]; + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when setting the event for needs_network_connection_info: %@", + exception); + } + } else { + @try { + NSError *error; + NSMutableDictionary *bytesDict; + if (self.customBytes) { + bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an even'ts event_code: %@", error); + return; + } + } else { + bytesDict = [[NSMutableDictionary alloc] init]; + } + [bytesDict setObject:@YES forKey:GDTCCTNeedsNetworkConnectionInfo]; + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when setting the event for needs_network_connection_info: %@", + exception); + } + } +} + +- (BOOL)needsNetworkConnectionInfoPopulated { + if (self.customBytes) { + @try { + NSError *error; + NSDictionary *bytesDict = [NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error]; + return bytesDict && !error && [bytesDict[GDTCCTNeedsNetworkConnectionInfo] boolValue]; + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when checking the event for needs_network_connection_info: %@", + exception); + } + } + return NO; +} + +- (void)setNetworkConnectionInfoData:(NSData *)networkConnectionInfoData { + @try { + NSError *error; + NSString *dataString = [networkConnectionInfoData base64EncodedStringWithOptions:0]; + if (dataString != nil) { + NSMutableDictionary *bytesDict; + if (self.customBytes) { + bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an even'ts event_code: %@", error); + return; + } + } else { + bytesDict = [[NSMutableDictionary alloc] init]; + } + [bytesDict setObject:dataString forKey:GDTCCTNetworkConnectionInfo]; + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + if (error) { + self.customBytes = nil; + GDTCORLogDebug(@"Error when setting an event's network_connection_info: %@", error); + } + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when setting an event's network_connection_info: %@", exception); + } +} + +- (nullable NSData *)networkConnectionInfoData { + if (self.customBytes) { + @try { + NSError *error; + NSDictionary *bytesDict = [NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error]; + NSString *base64Data = bytesDict[GDTCCTNetworkConnectionInfo]; + if (base64Data == nil) { + return nil; + } + + NSData *networkConnectionInfoData = [[NSData alloc] initWithBase64EncodedString:base64Data + options:0]; + if (error) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", error); + return nil; + } else { + return networkConnectionInfoData; + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", exception); + } + } + return nil; +} + +- (NSNumber *)eventCode { + if (self.customBytes) { + @try { + NSError *error; + NSDictionary *bytesDict = [NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error]; + NSString *eventCodeString = bytesDict[GDTCCTEventCodeInfo]; + + if (!eventCodeString) { + return nil; + } + + NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + NSNumber *eventCode = [formatter numberFromString:eventCodeString]; + + if (error) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", error); + return nil; + } else { + return eventCode; + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when getting an event's event_code: %@", exception); + } + } + return nil; +} + +- (void)setEventCode:(NSNumber *)eventCode { + if (eventCode == nil) { + if (!self.customBytes) { + return; + } + + NSError *error; + NSMutableDictionary *bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + + [bytesDict removeObjectForKey:GDTCCTEventCodeInfo]; + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + if (error) { + self.customBytes = nil; + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + return; + } + + @try { + NSMutableDictionary *bytesDict; + NSError *error; + if (self.customBytes) { + bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + } else { + bytesDict = [[NSMutableDictionary alloc] init]; + } + + NSString *eventCodeString = [eventCode stringValue]; + if (eventCodeString == nil) { + return; + } + + [bytesDict setObject:eventCodeString forKey:GDTCCTEventCodeInfo]; + + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + if (error) { + self.customBytes = nil; + GDTCORLogDebug(@"Error when setting an event's network_connection_info: %@", error); + return; + } + + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", exception); + } +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void GDTCCTInclude_GDTCOREvent_GDTCCTSupport_Category(void) { +} diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTMetricsSupport.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTMetricsSupport.m new file mode 100644 index 0000000..6386835 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTMetricsSupport.m @@ -0,0 +1,37 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" + +/// The mapping ID that represents the `LogSource` for GDT metrics. +static NSString *const kMetricEventMappingID = @"1710"; + +@implementation GDTCOREvent (GDTMetricsSupport) + ++ (GDTCOREvent *)eventWithMetrics:(GDTCORMetrics *)metrics forTarget:(GDTCORTarget)target { + GDTCOREvent *metricsEvent = [[GDTCOREvent alloc] initWithMappingID:kMetricEventMappingID + target:target]; + metricsEvent.dataObject = metrics; + + return metricsEvent; +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void GDTCCTInclude_GDTCOREvent_GDTMetricsSupport_Category(void) { +} diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCORMetrics+GDTCCTSupport.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCORMetrics+GDTCCTSupport.m new file mode 100644 index 0000000..044b85a --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCORMetrics+GDTCCTSupport.m @@ -0,0 +1,211 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h" + +#import +#import +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h" + +typedef NSDictionary GDTCORDroppedEventCounter; + +@interface GDTCORLogSourceMetrics (Internal) + +/// A dictionary of log sources that map to counters that reflect the number of events dropped for a +/// given set of reasons (``GDTCOREventDropReason``). +@property(nonatomic, readonly) + NSDictionary *droppedEventCounterByLogSource; + +@end + +@implementation GDTCORMetrics (GDTCCTSupport) + +- (NSData *)transportBytes { + // Create and populate proto. + gdt_client_metrics_ClientMetrics clientMetricsProto = + gdt_client_metrics_ClientMetrics_init_default; + + clientMetricsProto.window = + GDTCCTConstructTimeWindow(self.collectionStartDate, self.collectionEndDate); + + clientMetricsProto.log_source_metrics = GDTCCTConstructLogSourceMetrics(self.logSourceMetrics); + clientMetricsProto.log_source_metrics_count = + GDTCCTGetLogSourceMetricsCount(self.logSourceMetrics); + + clientMetricsProto.global_metrics = + GDTCCTConstructGlobalMetrics(self.currentCacheSize, self.maxCacheSize); + + clientMetricsProto.app_namespace = GDTCCTEncodeString(self.bundleID); + + // Encode proto into a data buffer. + pb_ostream_t sizeStream = PB_OSTREAM_SIZING; + + // - Encode 1 time to determine the expected size of the buffer. + if (!pb_encode(&sizeStream, gdt_client_metrics_ClientMetrics_fields, &clientMetricsProto)) { + GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&sizeStream)); + } + + // - Encode a 2nd time to actually copy the proto's bytes into the buffer. + size_t bufferSize = sizeStream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, gdt_client_metrics_ClientMetrics_fields, &clientMetricsProto)) { + GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&ostream)); + } + CFDataSetLength(dataRef, ostream.bytes_written); + + // Release the allocated proto. + pb_release(gdt_client_metrics_ClientMetrics_fields, &clientMetricsProto); + + return CFBridgingRelease(dataRef); +} + +/// Constructs and returns a ``gdt_client_metrics_LogSourceMetrics`` from the given log source +/// metrics. +/// @param logSourceMetrics The given log source metrics. +gdt_client_metrics_LogSourceMetrics *GDTCCTConstructLogSourceMetrics( + GDTCORLogSourceMetrics *logSourceMetrics) { + // The metrics proto is a repeating field where each element represents the + // dropped event data for a log source (mapping ID). + NSUInteger logMetricsCount = logSourceMetrics.droppedEventCounterByLogSource.count; + gdt_client_metrics_LogSourceMetrics *repeatedLogSourceMetrics = + calloc(logMetricsCount, sizeof(gdt_client_metrics_LogSourceMetrics)); + + // Each log source (mapping ID) has a corresponding dropped event counter. + // Enumerate over the dictionary of log source and, for each log source, + // (mapping ID) create a proto representation of the number of events dropped + // for each given reason. + __block NSUInteger logSourceIndex = 0; + [logSourceMetrics.droppedEventCounterByLogSource + enumerateKeysAndObjectsUsingBlock:^(NSString *logSource, + GDTCORDroppedEventCounter *eventCounterForLogSource, + BOOL *__unused _) { + // Create the log source proto for the given mapping ID. It contains a + // repeating field to encapsulate the number of events dropped for each + // given drop reason. + __block gdt_client_metrics_LogSourceMetrics logSourceMetrics = + gdt_client_metrics_LogSourceMetrics_init_zero; + logSourceMetrics.log_source = GDTCCTEncodeString(logSource); + logSourceMetrics.log_event_dropped_count = (pb_size_t)eventCounterForLogSource.count; + logSourceMetrics.log_event_dropped = + calloc(eventCounterForLogSource.count, sizeof(gdt_client_metrics_LogEventDropped)); + + // Each dropped event counter counts the number of events dropped for + // each drop reason. Enumerate over all of these counters to populate + // the log source proto's repeating field of event drop data. + __block NSUInteger eventCounterIndex = 0; + [eventCounterForLogSource + enumerateKeysAndObjectsUsingBlock:^(NSNumber *eventDropReason, + NSNumber *droppedEventCount, BOOL *__unused _) { + gdt_client_metrics_LogEventDropped droppedEvents = + gdt_client_metrics_LogEventDropped_init_zero; + droppedEvents.events_dropped_count = droppedEventCount.integerValue; + droppedEvents.reason = + GDTCCTConvertEventDropReasonToProtoReason(eventDropReason.integerValue); + + // Append the dropped events proto to the repeated field and + // increment the index used for appending. + logSourceMetrics.log_event_dropped[eventCounterIndex] = droppedEvents; + eventCounterIndex += 1; + }]; + + // Append the metrics for the given log source (mappingID) to the + // repeated field and increment the index used for appending. + repeatedLogSourceMetrics[logSourceIndex] = logSourceMetrics; + logSourceIndex += 1; + }]; + + return repeatedLogSourceMetrics; +} + +/// Returns the count of log sources that have event drop metrics. +/// @param logSourceMetrics The given log source metrics. +pb_size_t GDTCCTGetLogSourceMetricsCount(GDTCORLogSourceMetrics *logSourceMetrics) { + return (pb_size_t)logSourceMetrics.droppedEventCounterByLogSource.count; +} + +/// Constructs and returns a ``gdt_client_metrics_TimeWindow`` proto from the given parameters. +/// @param collectionStartDate The start of the time window. +/// @param collectionEndDate The end of the time window. +gdt_client_metrics_TimeWindow GDTCCTConstructTimeWindow(NSDate *collectionStartDate, + NSDate *collectionEndDate) { + gdt_client_metrics_TimeWindow timeWindow = gdt_client_metrics_TimeWindow_init_zero; + // `- [NSDate timeIntervalSince1970]` returns a time interval in seconds so + // multiply by 1000 to convert to milliseconds. + timeWindow.start_ms = (int64_t)collectionStartDate.timeIntervalSince1970 * 1000; + timeWindow.end_ms = (int64_t)collectionEndDate.timeIntervalSince1970 * 1000; + return timeWindow; +} + +/// Constructs and returns a ``gdt_client_metrics_GlobalMetrics`` proto from the given parameters. +/// @param currentCacheSize The current cache size. +/// @param maxCacheSize The max cache size. +gdt_client_metrics_GlobalMetrics GDTCCTConstructGlobalMetrics(uint64_t currentCacheSize, + uint64_t maxCacheSize) { + gdt_client_metrics_StorageMetrics storageMetrics = gdt_client_metrics_StorageMetrics_init_zero; + storageMetrics.current_cache_size_bytes = currentCacheSize; + storageMetrics.max_cache_size_bytes = maxCacheSize; + + gdt_client_metrics_GlobalMetrics globalMetrics = gdt_client_metrics_GlobalMetrics_init_zero; + globalMetrics.storage_metrics = storageMetrics; + + return globalMetrics; +} + +/// Returns the corresponding ``gdt_client_metrics_LogEventDropped_Reason`` for the given +/// ``GDTCOREventDropReason``. +/// +/// To represent ``GDTCOREventDropReason`` in a proto, the reason must be mapped to a +/// ``gdt_client_metrics_LogEventDropped_Reason``. +/// +/// @param reason The ``GDTCOREventDropReason`` to represent in a proto. +gdt_client_metrics_LogEventDropped_Reason GDTCCTConvertEventDropReasonToProtoReason( + GDTCOREventDropReason reason) { + switch (reason) { + case GDTCOREventDropReasonUnknown: + return gdt_client_metrics_LogEventDropped_Reason_REASON_UNKNOWN; + case GDTCOREventDropReasonMessageTooOld: + return gdt_client_metrics_LogEventDropped_Reason_MESSAGE_TOO_OLD; + case GDTCOREventDropReasonStorageFull: + return gdt_client_metrics_LogEventDropped_Reason_CACHE_FULL; + case GDTCOREventDropReasonPayloadTooBig: + return gdt_client_metrics_LogEventDropped_Reason_PAYLOAD_TOO_BIG; + case GDTCOREventDropReasonMaxRetriesReached: + return gdt_client_metrics_LogEventDropped_Reason_MAX_RETRIES_REACHED; + case GDTCOREventDropReasonInvalidPayload: + // The below typo (`PAYLOD`) is currently checked in to g3. + return gdt_client_metrics_LogEventDropped_Reason_INVALID_PAYLOD; + case GDTCOREventDropReasonServerError: + return gdt_client_metrics_LogEventDropped_Reason_SERVER_ERROR; + } +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void GDTCCTInclude_GDTCORLogSourceMetrics_Internal_Category(void) { +} diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h new file mode 100644 index 0000000..b53dd5f --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** A class with methods to help with gzipped data. */ +@interface GDTCCTCompressionHelper : NSObject + +/** Compresses the given data and returns a new data object. + * + * @note Reduced version from GULNSData+zlib.m of GoogleUtilities. + * @return Compressed data, or nil if there was an error. + */ ++ (nullable NSData *)gzippedData:(NSData *)data; + +/** Returns YES if the data looks like it was gzip compressed by checking for the gzip magic number. + * + * @note: From https://en.wikipedia.org/wiki/Gzip, gzip's magic number is 1f 8b. + * @return YES if the data appears gzipped, NO otherwise. + */ ++ (BOOL)isGzipped:(NSData *)data; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h new file mode 100644 index 0000000..2f0ccd0 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h @@ -0,0 +1,144 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h" +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h" + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - General purpose encoders + +/** Converts an NSString* to a pb_bytes_array_t*. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * + * @param string The string to convert. + * @return A newly allocated array of bytes representing the UTF8 encoding of the string. + */ +pb_bytes_array_t *GDTCCTEncodeString(NSString *string); + +/** Converts an NSData to a pb_bytes_array_t*. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * + * @param data The data to convert. + * @return A newly allocated array of bytes with [data bytes] copied into it. + */ +pb_bytes_array_t *GDTCCTEncodeData(NSData *data); + +#pragma mark - CCT object constructors + +/** Encodes a batched log request. + * + * @note Ensure that pb_release is called on the batchedLogRequest param. + * + * @param batchedLogRequest A pointer to the log batch to encode to bytes. + * @return An NSData object representing the bytes of the log request batch. + */ +FOUNDATION_EXPORT +NSData *GDTCCTEncodeBatchedLogRequest(gdt_cct_BatchedLogRequest *batchedLogRequest); + +/** Constructs a gdt_cct_BatchedLogRequest given sets of events segemented by mapping ID. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * + * @param logMappingIDToLogSet A map of mapping IDs to sets of events to convert into a batch. + * @return A newly created gdt_cct_BatchedLogRequest. + */ +FOUNDATION_EXPORT +gdt_cct_BatchedLogRequest GDTCCTConstructBatchedLogRequest( + NSDictionary *> *logMappingIDToLogSet); + +/** Constructs a log request given a log source and a set of events. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * @param logSource The CCT log source to put into the log request. + * @param logSet The set of events to send in this log request. + */ +FOUNDATION_EXPORT +gdt_cct_LogRequest GDTCCTConstructLogRequest(int32_t logSource, NSSet *logSet); + +/** Constructs a gdt_cct_LogEvent given a GDTCOREvent*. + * + * @param event The GDTCOREvent to convert. + * @return The new gdt_cct_LogEvent object. + */ +FOUNDATION_EXPORT +gdt_cct_LogEvent GDTCCTConstructLogEvent(GDTCOREvent *event); + +/** Constructs a `gdt_cct_ComplianceData` given a `GDTCORProductData` instance. + * + * @param productData The product data to convert to compliance data. + */ +FOUNDATION_EXPORT +gdt_cct_ComplianceData GDTCCTConstructComplianceData(GDTCORProductData *productData); + +/** Constructs a gdt_cct_ClientInfo representing the client device. + * + * @return The new gdt_cct_ClientInfo object. + */ +FOUNDATION_EXPORT +gdt_cct_ClientInfo GDTCCTConstructClientInfo(void); + +/** Constructs a gdt_cct_IosClientInfo representing the client device. + * + * @return The new gdt_cct_IosClientInfo object. + */ +FOUNDATION_EXPORT +gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo(void); + +/** Constructs a gdt_cct_MacClientInfo representing the client device. + * + * @return The new gdt_cct_MacClientInfo object. + */ +FOUNDATION_EXPORT +gdt_cct_MacClientInfo GDTCCTConstructMacClientInfo(void); + +/** Constructs the data of a gdt_cct_NetworkConnectionInfo representing the client nework connection + * information. + * + * @return The data of a gdt_cct_NetworkConnectionInfo object. + */ +FOUNDATION_EXPORT +NSData *GDTCCTConstructNetworkConnectionInfoData(void); + +/** Return a gdt_cct_NetworkConnectionInfo_MobileSubtype representing the client + * + * @return The gdt_cct_NetworkConnectionInfo_MobileSubtype. + */ +FOUNDATION_EXPORT +gdt_cct_NetworkConnectionInfo_MobileSubtype GDTCCTNetworkConnectionInfoNetworkMobileSubtype(void); + +#pragma mark - CCT object decoders + +/** Decodes a gdt_cct_LogResponse given proto bytes. + * + * @note calloc is called in this method. Ensure that pb_release is called on the return value. + * + * @param data The proto bytes of the gdt_cct_LogResponse. + * @param error An error that will be populated if something went wrong during decoding. + * @return A newly allocated gdt_cct_LogResponse from the data, if the bytes decoded properly. + */ +FOUNDATION_EXPORT +gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error); + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h new file mode 100644 index 0000000..30ec203 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h @@ -0,0 +1,29 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** The class represents HTTP response received from `NSURLSession`. */ +@interface GDTCCTURLSessionDataResponse : NSObject + +@property(nonatomic, readonly) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic, nullable, readonly) NSData *HTTPBody; + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(nullable NSData *)body; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h new file mode 100644 index 0000000..cfc2c48 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h @@ -0,0 +1,78 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h" + +@protocol GDTCORStoragePromiseProtocol; +@protocol GDTCORMetricsControllerProtocol; + +NS_ASSUME_NONNULL_BEGIN + +/// The protocol defines methods to retrieve/update data shared between different upload operations. +@protocol GDTCCTUploadMetadataProvider + +/** Returns a GDTCORClock object representing time after which a next upload attempt is allowed for + * the specified target. Upload is allowed now if `nil`. */ +- (nullable GDTCORClock *)nextUploadTimeForTarget:(GDTCORTarget)target; + +/** Stores or resets time after which a next upload attempt is allowed for the specified target. */ +- (void)setNextUploadTime:(nullable GDTCORClock *)time forTarget:(GDTCORTarget)target; + +/** Returns an API key for the specified target. */ +- (nullable NSString *)APIKeyForTarget:(GDTCORTarget)target; + +@end + +/** Class capable of uploading events to the CCT backend. */ +@interface GDTCCTUploadOperation : NSOperation + +- (instancetype)init NS_UNAVAILABLE; + +/// Designated initializer. +/// @param target The events target to upload. +/// @param conditions A set of upload conditions. The conditions affect the set of events to be +/// uploaded, e.g. events with some QoS are not uploaded on a cellular network, etc. +/// @param uploadURL The backend URL to upload the events. +/// @param queue A queue to dispatch async upload steps. +/// @param storage A storage object to fetch events for upload. +/// @param metadataProvider An object to retrieve/update data shared between upload operations. +/// @param metricsController The metrics controller corresponding to the given target. If the given +/// target does not support metrics controller, `nil` should be passed. +/// @return An individual operation that can be added to an operation queue. +- (instancetype)initWithTarget:(GDTCORTarget)target + conditions:(GDTCORUploadConditions)conditions + uploadURL:(NSURL *)uploadURL + queue:(dispatch_queue_t)queue + storage:(id)storage + metadataProvider:(id)metadataProvider + metricsController:(nullable id)metricsController + NS_DESIGNATED_INITIALIZER; + +/** YES if a batch upload attempt was performed. NO otherwise. If NO for the finished operation, + * then there were no events suitable for upload. */ +@property(nonatomic, readonly) BOOL uploadAttempted; + +/** The queue on which all CCT uploading will occur. */ +@property(nonatomic, readonly) dispatch_queue_t uploaderQueue; + +/** The current upload task. */ +@property(nullable, nonatomic, readonly) NSURLSessionUploadTask *currentTask; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h new file mode 100644 index 0000000..36934c6 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h @@ -0,0 +1,45 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Class capable of uploading events to the CCT backend. */ +@interface GDTCCTUploader : NSObject + +/** Creates and/or returns the singleton instance of this class. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +#if GDT_TEST +/** An upload URL used across all targets. For testing only. */ +@property(class, nullable, nonatomic) NSURL *testServerURL; + +/** Spins runloop until upload finishes or timeout. + * @return YES if upload finishes, NO in the case of timeout. + */ +- (BOOL)waitForUploadFinishedWithTimeout:(NSTimeInterval)timeout; + +#endif // GDT_TEST + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h new file mode 100644 index 0000000..84d36ae --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h @@ -0,0 +1,34 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +@class GDTCORMetrics; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCOREvent (GDTMetricsSupport) + +/// Creates and returns an event for the given target with the given metrics. +/// @param metrics The metrics to set at the event's data. +/// @param target The backend target that the event corresponds to. ++ (GDTCOREvent *)eventWithMetrics:(GDTCORMetrics *)metrics forTarget:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h new file mode 100644 index 0000000..8d1e696 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h @@ -0,0 +1,25 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORMetrics (GDTCCTSupport) + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c new file mode 100644 index 0000000..8e5412e --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c @@ -0,0 +1,138 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +const gdt_cct_NetworkConnectionInfo_NetworkType gdt_cct_NetworkConnectionInfo_network_type_default = gdt_cct_NetworkConnectionInfo_NetworkType_NONE; +const gdt_cct_NetworkConnectionInfo_MobileSubtype gdt_cct_NetworkConnectionInfo_mobile_subtype_default = gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE; +const gdt_cct_QosTierConfiguration_QosTier gdt_cct_LogRequest_qos_tier_default = gdt_cct_QosTierConfiguration_QosTier_DEFAULT; +const int32_t gdt_cct_QosTierConfiguration_log_source_default = 0; + + +const pb_field_t gdt_cct_LogEvent_fields[8] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, gdt_cct_LogEvent, event_time_ms, event_time_ms, 0), + PB_FIELD( 6, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_LogEvent, source_extension, event_time_ms, 0), + PB_FIELD( 11, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, event_code, source_extension, 0), + PB_FIELD( 15, SINT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, timezone_offset_seconds, event_code, 0), + PB_FIELD( 17, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, event_uptime_ms, timezone_offset_seconds, 0), + PB_FIELD( 23, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, network_connection_info, event_uptime_ms, &gdt_cct_NetworkConnectionInfo_fields), + PB_FIELD( 33, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, compliance_data, network_connection_info, &gdt_cct_ComplianceData_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_NetworkConnectionInfo_fields[3] = { + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, gdt_cct_NetworkConnectionInfo, network_type, network_type, &gdt_cct_NetworkConnectionInfo_network_type_default), + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_NetworkConnectionInfo, mobile_subtype, network_type, &gdt_cct_NetworkConnectionInfo_mobile_subtype_default), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_MacClientInfo_fields[5] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, gdt_cct_MacClientInfo, os_major_version, os_major_version, 0), + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_MacClientInfo, os_full_version, os_major_version, 0), + PB_FIELD( 3, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_MacClientInfo, application_build, os_full_version, 0), + PB_FIELD( 7, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_MacClientInfo, application_bundle_id, application_build, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_IosClientInfo_fields[8] = { + PB_FIELD( 3, BYTES , OPTIONAL, POINTER , FIRST, gdt_cct_IosClientInfo, os_major_version, os_major_version, 0), + PB_FIELD( 4, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, os_full_version, os_major_version, 0), + PB_FIELD( 5, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, application_build, os_full_version, 0), + PB_FIELD( 6, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, country, application_build, 0), + PB_FIELD( 7, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, model, country, 0), + PB_FIELD( 8, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, language_code, model, 0), + PB_FIELD( 11, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, application_bundle_id, language_code, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_ClientInfo_fields[4] = { + PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, gdt_cct_ClientInfo, client_type, client_type, 0), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_ClientInfo, ios_client_info, client_type, &gdt_cct_IosClientInfo_fields), + PB_FIELD( 13, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_ClientInfo, mac_client_info, ios_client_info, &gdt_cct_MacClientInfo_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_BatchedLogRequest_fields[2] = { + PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, gdt_cct_BatchedLogRequest, log_request, log_request, &gdt_cct_LogRequest_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_LogRequest_fields[7] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, gdt_cct_LogRequest, client_info, client_info, &gdt_cct_ClientInfo_fields), + PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, log_source, client_info, 0), + PB_FIELD( 3, MESSAGE , REPEATED, POINTER , OTHER, gdt_cct_LogRequest, log_event, log_source, &gdt_cct_LogEvent_fields), + PB_FIELD( 4, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, request_time_ms, log_event, 0), + PB_FIELD( 8, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, request_uptime_ms, request_time_ms, 0), + PB_FIELD( 9, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, qos_tier, request_uptime_ms, &gdt_cct_LogRequest_qos_tier_default), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_QosTierConfiguration_fields[3] = { + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , FIRST, gdt_cct_QosTierConfiguration, qos_tier, qos_tier, 0), + PB_FIELD( 3, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_QosTierConfiguration, log_source, qos_tier, &gdt_cct_QosTierConfiguration_log_source_default), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_QosTiersOverride_fields[3] = { + PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, gdt_cct_QosTiersOverride, qos_tier_configuration, qos_tier_configuration, &gdt_cct_QosTierConfiguration_fields), + PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_QosTiersOverride, qos_tier_fingerprint, qos_tier_configuration, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_LogResponse_fields[3] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, gdt_cct_LogResponse, next_request_wait_millis, next_request_wait_millis, 0), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogResponse, qos_tier, next_request_wait_millis, &gdt_cct_QosTiersOverride_fields), + PB_LAST_FIELD +}; + + + + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_LogEvent, network_connection_info) < 65536 && pb_membersize(gdt_cct_LogEvent, compliance_data) < 65536 && pb_membersize(gdt_cct_ClientInfo, ios_client_info) < 65536 && pb_membersize(gdt_cct_ClientInfo, mac_client_info) < 65536 && pb_membersize(gdt_cct_LogRequest, client_info) < 65536 && pb_membersize(gdt_cct_LogResponse, qos_tier) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_gdt_cct_LogEvent_gdt_cct_NetworkConnectionInfo_gdt_cct_MacClientInfo_gdt_cct_IosClientInfo_gdt_cct_ClientInfo_gdt_cct_BatchedLogRequest_gdt_cct_LogRequest_gdt_cct_QosTierConfiguration_gdt_cct_QosTiersOverride_gdt_cct_LogResponse) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_LogEvent, network_connection_info) < 256 && pb_membersize(gdt_cct_LogEvent, compliance_data) < 256 && pb_membersize(gdt_cct_ClientInfo, ios_client_info) < 256 && pb_membersize(gdt_cct_ClientInfo, mac_client_info) < 256 && pb_membersize(gdt_cct_LogRequest, client_info) < 256 && pb_membersize(gdt_cct_LogResponse, qos_tier) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_gdt_cct_LogEvent_gdt_cct_NetworkConnectionInfo_gdt_cct_MacClientInfo_gdt_cct_IosClientInfo_gdt_cct_ClientInfo_gdt_cct_BatchedLogRequest_gdt_cct_LogRequest_gdt_cct_QosTierConfiguration_gdt_cct_QosTiersOverride_gdt_cct_LogResponse) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h new file mode 100644 index 0000000..a13a16c --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h @@ -0,0 +1,305 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_GDT_CCT_CCT_NANOPB_H_INCLUDED +#define PB_GDT_CCT_CCT_NANOPB_H_INCLUDED +#include + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _gdt_cct_NetworkConnectionInfo_NetworkType { + gdt_cct_NetworkConnectionInfo_NetworkType_NONE = -1, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE = 0, + gdt_cct_NetworkConnectionInfo_NetworkType_WIFI = 1, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_MMS = 2, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_SUPL = 3, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_DUN = 4, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_HIPRI = 5, + gdt_cct_NetworkConnectionInfo_NetworkType_WIMAX = 6, + gdt_cct_NetworkConnectionInfo_NetworkType_BLUETOOTH = 7, + gdt_cct_NetworkConnectionInfo_NetworkType_DUMMY = 8, + gdt_cct_NetworkConnectionInfo_NetworkType_ETHERNET = 9, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_FOTA = 10, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IMS = 11, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_CBS = 12, + gdt_cct_NetworkConnectionInfo_NetworkType_WIFI_P2P = 13, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IA = 14, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_EMERGENCY = 15, + gdt_cct_NetworkConnectionInfo_NetworkType_PROXY = 16, + gdt_cct_NetworkConnectionInfo_NetworkType_VPN = 17 +} gdt_cct_NetworkConnectionInfo_NetworkType; +#define _gdt_cct_NetworkConnectionInfo_NetworkType_MIN gdt_cct_NetworkConnectionInfo_NetworkType_NONE +#define _gdt_cct_NetworkConnectionInfo_NetworkType_MAX gdt_cct_NetworkConnectionInfo_NetworkType_VPN +#define _gdt_cct_NetworkConnectionInfo_NetworkType_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_NetworkType)(gdt_cct_NetworkConnectionInfo_NetworkType_VPN+1)) + +typedef enum _gdt_cct_NetworkConnectionInfo_MobileSubtype { + gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE = 0, + gdt_cct_NetworkConnectionInfo_MobileSubtype_GPRS = 1, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EDGE = 2, + gdt_cct_NetworkConnectionInfo_MobileSubtype_UMTS = 3, + gdt_cct_NetworkConnectionInfo_MobileSubtype_CDMA = 4, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_0 = 5, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_A = 6, + gdt_cct_NetworkConnectionInfo_MobileSubtype_RTT = 7, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSDPA = 8, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSUPA = 9, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPA = 10, + gdt_cct_NetworkConnectionInfo_MobileSubtype_IDEN = 11, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_B = 12, + gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE = 13, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EHRPD = 14, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPAP = 15, + gdt_cct_NetworkConnectionInfo_MobileSubtype_GSM = 16, + gdt_cct_NetworkConnectionInfo_MobileSubtype_TD_SCDMA = 17, + gdt_cct_NetworkConnectionInfo_MobileSubtype_IWLAN = 18, + gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE_CA = 19, + gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED = 100 +} gdt_cct_NetworkConnectionInfo_MobileSubtype; +#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE +#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MAX gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED +#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_MobileSubtype)(gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED+1)) + +typedef enum _gdt_cct_ClientInfo_ClientType { + gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN = 0, + gdt_cct_ClientInfo_ClientType_IOS_FIREBASE = 15 +} gdt_cct_ClientInfo_ClientType; +#define _gdt_cct_ClientInfo_ClientType_MIN gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN +#define _gdt_cct_ClientInfo_ClientType_MAX gdt_cct_ClientInfo_ClientType_IOS_FIREBASE +#define _gdt_cct_ClientInfo_ClientType_ARRAYSIZE ((gdt_cct_ClientInfo_ClientType)(gdt_cct_ClientInfo_ClientType_IOS_FIREBASE+1)) + +typedef enum _gdt_cct_QosTierConfiguration_QosTier { + gdt_cct_QosTierConfiguration_QosTier_DEFAULT = 0, + gdt_cct_QosTierConfiguration_QosTier_UNMETERED_ONLY = 1, + gdt_cct_QosTierConfiguration_QosTier_UNMETERED_OR_DAILY = 2, + gdt_cct_QosTierConfiguration_QosTier_FAST_IF_RADIO_AWAKE = 3, + gdt_cct_QosTierConfiguration_QosTier_NEVER = 4 +} gdt_cct_QosTierConfiguration_QosTier; +#define _gdt_cct_QosTierConfiguration_QosTier_MIN gdt_cct_QosTierConfiguration_QosTier_DEFAULT +#define _gdt_cct_QosTierConfiguration_QosTier_MAX gdt_cct_QosTierConfiguration_QosTier_NEVER +#define _gdt_cct_QosTierConfiguration_QosTier_ARRAYSIZE ((gdt_cct_QosTierConfiguration_QosTier)(gdt_cct_QosTierConfiguration_QosTier_NEVER+1)) + +/* Struct definitions */ +typedef struct _gdt_cct_BatchedLogRequest { + pb_size_t log_request_count; + struct _gdt_cct_LogRequest *log_request; +/* @@protoc_insertion_point(struct:gdt_cct_BatchedLogRequest) */ +} gdt_cct_BatchedLogRequest; + +typedef struct _gdt_cct_IosClientInfo { + pb_bytes_array_t *os_major_version; + pb_bytes_array_t *os_full_version; + pb_bytes_array_t *application_build; + pb_bytes_array_t *country; + pb_bytes_array_t *model; + pb_bytes_array_t *language_code; + pb_bytes_array_t *application_bundle_id; +/* @@protoc_insertion_point(struct:gdt_cct_IosClientInfo) */ +} gdt_cct_IosClientInfo; + +typedef struct _gdt_cct_MacClientInfo { + pb_bytes_array_t *os_major_version; + pb_bytes_array_t *os_full_version; + pb_bytes_array_t *application_build; + pb_bytes_array_t *application_bundle_id; +/* @@protoc_insertion_point(struct:gdt_cct_MacClientInfo) */ +} gdt_cct_MacClientInfo; + +typedef struct _gdt_cct_ClientInfo { + bool has_client_type; + gdt_cct_ClientInfo_ClientType client_type; + bool has_ios_client_info; + gdt_cct_IosClientInfo ios_client_info; + bool has_mac_client_info; + gdt_cct_MacClientInfo mac_client_info; +/* @@protoc_insertion_point(struct:gdt_cct_ClientInfo) */ +} gdt_cct_ClientInfo; + +typedef struct _gdt_cct_NetworkConnectionInfo { + bool has_network_type; + gdt_cct_NetworkConnectionInfo_NetworkType network_type; + bool has_mobile_subtype; + gdt_cct_NetworkConnectionInfo_MobileSubtype mobile_subtype; +/* @@protoc_insertion_point(struct:gdt_cct_NetworkConnectionInfo) */ +} gdt_cct_NetworkConnectionInfo; + +typedef struct _gdt_cct_QosTierConfiguration { + bool has_qos_tier; + gdt_cct_QosTierConfiguration_QosTier qos_tier; + bool has_log_source; + int32_t log_source; +/* @@protoc_insertion_point(struct:gdt_cct_QosTierConfiguration) */ +} gdt_cct_QosTierConfiguration; + +typedef struct _gdt_cct_QosTiersOverride { + pb_size_t qos_tier_configuration_count; + struct _gdt_cct_QosTierConfiguration *qos_tier_configuration; + bool has_qos_tier_fingerprint; + int64_t qos_tier_fingerprint; +/* @@protoc_insertion_point(struct:gdt_cct_QosTiersOverride) */ +} gdt_cct_QosTiersOverride; + +typedef struct _gdt_cct_LogEvent { + bool has_event_time_ms; + int64_t event_time_ms; + pb_bytes_array_t *source_extension; + bool has_event_code; + int32_t event_code; + bool has_timezone_offset_seconds; + int64_t timezone_offset_seconds; + bool has_event_uptime_ms; + int64_t event_uptime_ms; + bool has_network_connection_info; + gdt_cct_NetworkConnectionInfo network_connection_info; + bool has_compliance_data; + gdt_cct_ComplianceData compliance_data; +/* @@protoc_insertion_point(struct:gdt_cct_LogEvent) */ +} gdt_cct_LogEvent; + +typedef struct _gdt_cct_LogRequest { + bool has_client_info; + gdt_cct_ClientInfo client_info; + bool has_log_source; + int32_t log_source; + pb_size_t log_event_count; + struct _gdt_cct_LogEvent *log_event; + bool has_request_time_ms; + int64_t request_time_ms; + bool has_request_uptime_ms; + int64_t request_uptime_ms; + bool has_qos_tier; + gdt_cct_QosTierConfiguration_QosTier qos_tier; +/* @@protoc_insertion_point(struct:gdt_cct_LogRequest) */ +} gdt_cct_LogRequest; + +typedef struct _gdt_cct_LogResponse { + bool has_next_request_wait_millis; + int64_t next_request_wait_millis; + bool has_qos_tier; + gdt_cct_QosTiersOverride qos_tier; +/* @@protoc_insertion_point(struct:gdt_cct_LogResponse) */ +} gdt_cct_LogResponse; + +/* Default values for struct fields */ +extern const gdt_cct_NetworkConnectionInfo_NetworkType gdt_cct_NetworkConnectionInfo_network_type_default; +extern const gdt_cct_NetworkConnectionInfo_MobileSubtype gdt_cct_NetworkConnectionInfo_mobile_subtype_default; +extern const gdt_cct_QosTierConfiguration_QosTier gdt_cct_LogRequest_qos_tier_default; +extern const int32_t gdt_cct_QosTierConfiguration_log_source_default; + +/* Initializer values for message structs */ +#define gdt_cct_LogEvent_init_default {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_default, false, gdt_cct_ComplianceData_init_default} +#define gdt_cct_NetworkConnectionInfo_init_default {false, gdt_cct_NetworkConnectionInfo_NetworkType_NONE, false, gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE} +#define gdt_cct_MacClientInfo_init_default {NULL, NULL, NULL, NULL} +#define gdt_cct_IosClientInfo_init_default {NULL, NULL, NULL, NULL, NULL, NULL, NULL} +#define gdt_cct_ClientInfo_init_default {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_default, false, gdt_cct_MacClientInfo_init_default} +#define gdt_cct_BatchedLogRequest_init_default {0, NULL} +#define gdt_cct_LogRequest_init_default {false, gdt_cct_ClientInfo_init_default, false, 0, 0, NULL, false, 0, false, 0, false, gdt_cct_QosTierConfiguration_QosTier_DEFAULT} +#define gdt_cct_QosTierConfiguration_init_default {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0} +#define gdt_cct_QosTiersOverride_init_default {0, NULL, false, 0} +#define gdt_cct_LogResponse_init_default {false, 0, false, gdt_cct_QosTiersOverride_init_default} +#define gdt_cct_LogEvent_init_zero {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_zero, false, gdt_cct_ComplianceData_init_zero} +#define gdt_cct_NetworkConnectionInfo_init_zero {false, _gdt_cct_NetworkConnectionInfo_NetworkType_MIN, false, _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN} +#define gdt_cct_MacClientInfo_init_zero {NULL, NULL, NULL, NULL} +#define gdt_cct_IosClientInfo_init_zero {NULL, NULL, NULL, NULL, NULL, NULL, NULL} +#define gdt_cct_ClientInfo_init_zero {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_zero, false, gdt_cct_MacClientInfo_init_zero} +#define gdt_cct_BatchedLogRequest_init_zero {0, NULL} +#define gdt_cct_LogRequest_init_zero {false, gdt_cct_ClientInfo_init_zero, false, 0, 0, NULL, false, 0, false, 0, false, _gdt_cct_QosTierConfiguration_QosTier_MIN} +#define gdt_cct_QosTierConfiguration_init_zero {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0} +#define gdt_cct_QosTiersOverride_init_zero {0, NULL, false, 0} +#define gdt_cct_LogResponse_init_zero {false, 0, false, gdt_cct_QosTiersOverride_init_zero} + +/* Field tags (for use in manual encoding/decoding) */ +#define gdt_cct_BatchedLogRequest_log_request_tag 1 +#define gdt_cct_IosClientInfo_os_major_version_tag 3 +#define gdt_cct_IosClientInfo_os_full_version_tag 4 +#define gdt_cct_IosClientInfo_application_build_tag 5 +#define gdt_cct_IosClientInfo_country_tag 6 +#define gdt_cct_IosClientInfo_model_tag 7 +#define gdt_cct_IosClientInfo_language_code_tag 8 +#define gdt_cct_IosClientInfo_application_bundle_id_tag 11 +#define gdt_cct_MacClientInfo_os_major_version_tag 1 +#define gdt_cct_MacClientInfo_os_full_version_tag 2 +#define gdt_cct_MacClientInfo_application_build_tag 3 +#define gdt_cct_MacClientInfo_application_bundle_id_tag 7 +#define gdt_cct_ClientInfo_client_type_tag 1 +#define gdt_cct_ClientInfo_ios_client_info_tag 4 +#define gdt_cct_ClientInfo_mac_client_info_tag 13 +#define gdt_cct_NetworkConnectionInfo_network_type_tag 1 +#define gdt_cct_NetworkConnectionInfo_mobile_subtype_tag 2 +#define gdt_cct_QosTierConfiguration_qos_tier_tag 2 +#define gdt_cct_QosTierConfiguration_log_source_tag 3 +#define gdt_cct_QosTiersOverride_qos_tier_configuration_tag 1 +#define gdt_cct_QosTiersOverride_qos_tier_fingerprint_tag 2 +#define gdt_cct_LogEvent_event_time_ms_tag 1 +#define gdt_cct_LogEvent_event_code_tag 11 +#define gdt_cct_LogEvent_event_uptime_ms_tag 17 +#define gdt_cct_LogEvent_source_extension_tag 6 +#define gdt_cct_LogEvent_timezone_offset_seconds_tag 15 +#define gdt_cct_LogEvent_network_connection_info_tag 23 +#define gdt_cct_LogEvent_compliance_data_tag 33 +#define gdt_cct_LogRequest_request_time_ms_tag 4 +#define gdt_cct_LogRequest_request_uptime_ms_tag 8 +#define gdt_cct_LogRequest_client_info_tag 1 +#define gdt_cct_LogRequest_log_source_tag 2 +#define gdt_cct_LogRequest_log_event_tag 3 +#define gdt_cct_LogRequest_qos_tier_tag 9 +#define gdt_cct_LogResponse_next_request_wait_millis_tag 1 +#define gdt_cct_LogResponse_qos_tier_tag 3 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t gdt_cct_LogEvent_fields[8]; +extern const pb_field_t gdt_cct_NetworkConnectionInfo_fields[3]; +extern const pb_field_t gdt_cct_MacClientInfo_fields[5]; +extern const pb_field_t gdt_cct_IosClientInfo_fields[8]; +extern const pb_field_t gdt_cct_ClientInfo_fields[4]; +extern const pb_field_t gdt_cct_BatchedLogRequest_fields[2]; +extern const pb_field_t gdt_cct_LogRequest_fields[7]; +extern const pb_field_t gdt_cct_QosTierConfiguration_fields[3]; +extern const pb_field_t gdt_cct_QosTiersOverride_fields[3]; +extern const pb_field_t gdt_cct_LogResponse_fields[3]; + +/* Maximum encoded size of messages (where known) */ +/* gdt_cct_LogEvent_size depends on runtime parameters */ +#define gdt_cct_NetworkConnectionInfo_size 13 +/* gdt_cct_MacClientInfo_size depends on runtime parameters */ +/* gdt_cct_IosClientInfo_size depends on runtime parameters */ +/* gdt_cct_ClientInfo_size depends on runtime parameters */ +/* gdt_cct_BatchedLogRequest_size depends on runtime parameters */ +/* gdt_cct_LogRequest_size depends on runtime parameters */ +#define gdt_cct_QosTierConfiguration_size 13 +/* gdt_cct_QosTiersOverride_size depends on runtime parameters */ +/* gdt_cct_LogResponse_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define CCT_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.c b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.c new file mode 100644 index 0000000..1e95954 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.c @@ -0,0 +1,92 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t gdt_client_metrics_ClientMetrics_fields[5] = { + PB_FIELD( 1, MESSAGE , SINGULAR, STATIC , FIRST, gdt_client_metrics_ClientMetrics, window, window, &gdt_client_metrics_TimeWindow_fields), + PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, gdt_client_metrics_ClientMetrics, log_source_metrics, window, &gdt_client_metrics_LogSourceMetrics_fields), + PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, gdt_client_metrics_ClientMetrics, global_metrics, log_source_metrics, &gdt_client_metrics_GlobalMetrics_fields), + PB_FIELD( 4, BYTES , SINGULAR, POINTER , OTHER, gdt_client_metrics_ClientMetrics, app_namespace, global_metrics, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_TimeWindow_fields[3] = { + PB_FIELD( 1, INT64 , SINGULAR, STATIC , FIRST, gdt_client_metrics_TimeWindow, start_ms, start_ms, 0), + PB_FIELD( 2, INT64 , SINGULAR, STATIC , OTHER, gdt_client_metrics_TimeWindow, end_ms, start_ms, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_GlobalMetrics_fields[2] = { + PB_FIELD( 1, MESSAGE , SINGULAR, STATIC , FIRST, gdt_client_metrics_GlobalMetrics, storage_metrics, storage_metrics, &gdt_client_metrics_StorageMetrics_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_StorageMetrics_fields[3] = { + PB_FIELD( 1, INT64 , SINGULAR, STATIC , FIRST, gdt_client_metrics_StorageMetrics, current_cache_size_bytes, current_cache_size_bytes, 0), + PB_FIELD( 2, INT64 , SINGULAR, STATIC , OTHER, gdt_client_metrics_StorageMetrics, max_cache_size_bytes, current_cache_size_bytes, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_LogSourceMetrics_fields[3] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, gdt_client_metrics_LogSourceMetrics, log_source, log_source, 0), + PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, gdt_client_metrics_LogSourceMetrics, log_event_dropped, log_source, &gdt_client_metrics_LogEventDropped_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_LogEventDropped_fields[3] = { + PB_FIELD( 1, INT64 , SINGULAR, STATIC , FIRST, gdt_client_metrics_LogEventDropped, events_dropped_count, events_dropped_count, 0), + PB_FIELD( 3, UENUM , SINGULAR, STATIC , OTHER, gdt_client_metrics_LogEventDropped, reason, events_dropped_count, 0), + PB_LAST_FIELD +}; + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_client_metrics_ClientMetrics, window) < 65536 && pb_membersize(gdt_client_metrics_ClientMetrics, global_metrics) < 65536 && pb_membersize(gdt_client_metrics_GlobalMetrics, storage_metrics) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_gdt_client_metrics_ClientMetrics_gdt_client_metrics_TimeWindow_gdt_client_metrics_GlobalMetrics_gdt_client_metrics_StorageMetrics_gdt_client_metrics_LogSourceMetrics_gdt_client_metrics_LogEventDropped) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_client_metrics_ClientMetrics, window) < 256 && pb_membersize(gdt_client_metrics_ClientMetrics, global_metrics) < 256 && pb_membersize(gdt_client_metrics_GlobalMetrics, storage_metrics) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_gdt_client_metrics_ClientMetrics_gdt_client_metrics_TimeWindow_gdt_client_metrics_GlobalMetrics_gdt_client_metrics_StorageMetrics_gdt_client_metrics_LogSourceMetrics_gdt_client_metrics_LogEventDropped) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h new file mode 100644 index 0000000..c4d7686 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h @@ -0,0 +1,141 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_GDT_CLIENT_METRICS_CLIENT_METRICS_NANOPB_H_INCLUDED +#define PB_GDT_CLIENT_METRICS_CLIENT_METRICS_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _gdt_client_metrics_LogEventDropped_Reason { + gdt_client_metrics_LogEventDropped_Reason_REASON_UNKNOWN = 0, + gdt_client_metrics_LogEventDropped_Reason_MESSAGE_TOO_OLD = 1, + gdt_client_metrics_LogEventDropped_Reason_CACHE_FULL = 2, + gdt_client_metrics_LogEventDropped_Reason_PAYLOAD_TOO_BIG = 3, + gdt_client_metrics_LogEventDropped_Reason_MAX_RETRIES_REACHED = 4, + gdt_client_metrics_LogEventDropped_Reason_INVALID_PAYLOD = 5, + gdt_client_metrics_LogEventDropped_Reason_SERVER_ERROR = 6 +} gdt_client_metrics_LogEventDropped_Reason; +#define _gdt_client_metrics_LogEventDropped_Reason_MIN gdt_client_metrics_LogEventDropped_Reason_REASON_UNKNOWN +#define _gdt_client_metrics_LogEventDropped_Reason_MAX gdt_client_metrics_LogEventDropped_Reason_SERVER_ERROR +#define _gdt_client_metrics_LogEventDropped_Reason_ARRAYSIZE ((gdt_client_metrics_LogEventDropped_Reason)(gdt_client_metrics_LogEventDropped_Reason_SERVER_ERROR+1)) + +/* Struct definitions */ +typedef struct _gdt_client_metrics_LogSourceMetrics { + pb_bytes_array_t *log_source; + pb_size_t log_event_dropped_count; + struct _gdt_client_metrics_LogEventDropped *log_event_dropped; +/* @@protoc_insertion_point(struct:gdt_client_metrics_LogSourceMetrics) */ +} gdt_client_metrics_LogSourceMetrics; + +typedef struct _gdt_client_metrics_LogEventDropped { + int64_t events_dropped_count; + gdt_client_metrics_LogEventDropped_Reason reason; +/* @@protoc_insertion_point(struct:gdt_client_metrics_LogEventDropped) */ +} gdt_client_metrics_LogEventDropped; + +typedef struct _gdt_client_metrics_StorageMetrics { + int64_t current_cache_size_bytes; + int64_t max_cache_size_bytes; +/* @@protoc_insertion_point(struct:gdt_client_metrics_StorageMetrics) */ +} gdt_client_metrics_StorageMetrics; + +typedef struct _gdt_client_metrics_TimeWindow { + int64_t start_ms; + int64_t end_ms; +/* @@protoc_insertion_point(struct:gdt_client_metrics_TimeWindow) */ +} gdt_client_metrics_TimeWindow; + +typedef struct _gdt_client_metrics_GlobalMetrics { + gdt_client_metrics_StorageMetrics storage_metrics; +/* @@protoc_insertion_point(struct:gdt_client_metrics_GlobalMetrics) */ +} gdt_client_metrics_GlobalMetrics; + +typedef struct _gdt_client_metrics_ClientMetrics { + gdt_client_metrics_TimeWindow window; + pb_size_t log_source_metrics_count; + struct _gdt_client_metrics_LogSourceMetrics *log_source_metrics; + gdt_client_metrics_GlobalMetrics global_metrics; + pb_bytes_array_t *app_namespace; +/* @@protoc_insertion_point(struct:gdt_client_metrics_ClientMetrics) */ +} gdt_client_metrics_ClientMetrics; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define gdt_client_metrics_ClientMetrics_init_default {gdt_client_metrics_TimeWindow_init_default, 0, NULL, gdt_client_metrics_GlobalMetrics_init_default, NULL} +#define gdt_client_metrics_TimeWindow_init_default {0, 0} +#define gdt_client_metrics_GlobalMetrics_init_default {gdt_client_metrics_StorageMetrics_init_default} +#define gdt_client_metrics_StorageMetrics_init_default {0, 0} +#define gdt_client_metrics_LogSourceMetrics_init_default {NULL, 0, NULL} +#define gdt_client_metrics_LogEventDropped_init_default {0, _gdt_client_metrics_LogEventDropped_Reason_MIN} +#define gdt_client_metrics_ClientMetrics_init_zero {gdt_client_metrics_TimeWindow_init_zero, 0, NULL, gdt_client_metrics_GlobalMetrics_init_zero, NULL} +#define gdt_client_metrics_TimeWindow_init_zero {0, 0} +#define gdt_client_metrics_GlobalMetrics_init_zero {gdt_client_metrics_StorageMetrics_init_zero} +#define gdt_client_metrics_StorageMetrics_init_zero {0, 0} +#define gdt_client_metrics_LogSourceMetrics_init_zero {NULL, 0, NULL} +#define gdt_client_metrics_LogEventDropped_init_zero {0, _gdt_client_metrics_LogEventDropped_Reason_MIN} + +/* Field tags (for use in manual encoding/decoding) */ +#define gdt_client_metrics_LogSourceMetrics_log_source_tag 1 +#define gdt_client_metrics_LogSourceMetrics_log_event_dropped_tag 2 +#define gdt_client_metrics_LogEventDropped_events_dropped_count_tag 1 +#define gdt_client_metrics_LogEventDropped_reason_tag 3 +#define gdt_client_metrics_StorageMetrics_current_cache_size_bytes_tag 1 +#define gdt_client_metrics_StorageMetrics_max_cache_size_bytes_tag 2 +#define gdt_client_metrics_TimeWindow_start_ms_tag 1 +#define gdt_client_metrics_TimeWindow_end_ms_tag 2 +#define gdt_client_metrics_GlobalMetrics_storage_metrics_tag 1 +#define gdt_client_metrics_ClientMetrics_window_tag 1 +#define gdt_client_metrics_ClientMetrics_log_source_metrics_tag 2 +#define gdt_client_metrics_ClientMetrics_global_metrics_tag 3 +#define gdt_client_metrics_ClientMetrics_app_namespace_tag 4 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t gdt_client_metrics_ClientMetrics_fields[5]; +extern const pb_field_t gdt_client_metrics_TimeWindow_fields[3]; +extern const pb_field_t gdt_client_metrics_GlobalMetrics_fields[2]; +extern const pb_field_t gdt_client_metrics_StorageMetrics_fields[3]; +extern const pb_field_t gdt_client_metrics_LogSourceMetrics_fields[3]; +extern const pb_field_t gdt_client_metrics_LogEventDropped_fields[3]; + +/* Maximum encoded size of messages (where known) */ +/* gdt_client_metrics_ClientMetrics_size depends on runtime parameters */ +#define gdt_client_metrics_TimeWindow_size 22 +#define gdt_client_metrics_GlobalMetrics_size 24 +#define gdt_client_metrics_StorageMetrics_size 22 +/* gdt_client_metrics_LogSourceMetrics_size depends on runtime parameters */ +#define gdt_client_metrics_LogEventDropped_size 13 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define CLIENT_METRICS_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.c b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.c new file mode 100644 index 0000000..f3552f7 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.c @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +const gdt_cct_ComplianceData_ProductIdOrigin gdt_cct_ComplianceData_product_id_origin_default = gdt_cct_ComplianceData_ProductIdOrigin_NOT_SET; + + +const pb_field_t gdt_cct_ComplianceData_fields[3] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, gdt_cct_ComplianceData, privacy_context, privacy_context, &privacy_context_external_ExternalPrivacyContext_fields), + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_ComplianceData, product_id_origin, privacy_context, &gdt_cct_ComplianceData_product_id_origin_default), + PB_LAST_FIELD +}; + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_ComplianceData, privacy_context) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_gdt_cct_ComplianceData) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_ComplianceData, privacy_context) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_gdt_cct_ComplianceData) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h new file mode 100644 index 0000000..a143c76 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h @@ -0,0 +1,77 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_GDT_CCT_COMPLIANCE_NANOPB_H_INCLUDED +#define PB_GDT_CCT_COMPLIANCE_NANOPB_H_INCLUDED +#include + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _gdt_cct_ComplianceData_ProductIdOrigin { + gdt_cct_ComplianceData_ProductIdOrigin_NOT_SET = 0, + gdt_cct_ComplianceData_ProductIdOrigin_EVENT_OVERRIDE = 5 +} gdt_cct_ComplianceData_ProductIdOrigin; +#define _gdt_cct_ComplianceData_ProductIdOrigin_MIN gdt_cct_ComplianceData_ProductIdOrigin_NOT_SET +#define _gdt_cct_ComplianceData_ProductIdOrigin_MAX gdt_cct_ComplianceData_ProductIdOrigin_EVENT_OVERRIDE +#define _gdt_cct_ComplianceData_ProductIdOrigin_ARRAYSIZE ((gdt_cct_ComplianceData_ProductIdOrigin)(gdt_cct_ComplianceData_ProductIdOrigin_EVENT_OVERRIDE+1)) + +/* Struct definitions */ +typedef struct _gdt_cct_ComplianceData { + bool has_privacy_context; + privacy_context_external_ExternalPrivacyContext privacy_context; + bool has_product_id_origin; + gdt_cct_ComplianceData_ProductIdOrigin product_id_origin; +/* @@protoc_insertion_point(struct:gdt_cct_ComplianceData) */ +} gdt_cct_ComplianceData; + +/* Default values for struct fields */ +extern const gdt_cct_ComplianceData_ProductIdOrigin gdt_cct_ComplianceData_product_id_origin_default; + +/* Initializer values for message structs */ +#define gdt_cct_ComplianceData_init_default {false, privacy_context_external_ExternalPrivacyContext_init_default, false, gdt_cct_ComplianceData_ProductIdOrigin_NOT_SET} +#define gdt_cct_ComplianceData_init_zero {false, privacy_context_external_ExternalPrivacyContext_init_zero, false, _gdt_cct_ComplianceData_ProductIdOrigin_MIN} + +/* Field tags (for use in manual encoding/decoding) */ +#define gdt_cct_ComplianceData_privacy_context_tag 1 +#define gdt_cct_ComplianceData_product_id_origin_tag 2 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t gdt_cct_ComplianceData_fields[3]; + +/* Maximum encoded size of messages (where known) */ +#define gdt_cct_ComplianceData_size (14 + privacy_context_external_ExternalPRequestContext_size) + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define COMPLIANCE_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.c b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.c new file mode 100644 index 0000000..9eb1d16 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.c @@ -0,0 +1,35 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t privacy_context_external_ExternalPRequestContext_fields[2] = { + PB_FIELD( 13, INT32 , OPTIONAL, STATIC , FIRST, privacy_context_external_ExternalPRequestContext, origin_associated_product_id, origin_associated_product_id, 0), + PB_LAST_FIELD +}; + + +/* @@protoc_insertion_point(eof) */ diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h new file mode 100644 index 0000000..03f0f12 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_PRIVACY_CONTEXT_EXTERNAL_EXTERNAL_PREQUEST_CONTEXT_NANOPB_H_INCLUDED +#define PB_PRIVACY_CONTEXT_EXTERNAL_EXTERNAL_PREQUEST_CONTEXT_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Struct definitions */ +typedef struct _privacy_context_external_ExternalPRequestContext { + bool has_origin_associated_product_id; + int32_t origin_associated_product_id; +/* @@protoc_insertion_point(struct:privacy_context_external_ExternalPRequestContext) */ +} privacy_context_external_ExternalPRequestContext; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define privacy_context_external_ExternalPRequestContext_init_default {false, 0} +#define privacy_context_external_ExternalPRequestContext_init_zero {false, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define privacy_context_external_ExternalPRequestContext_origin_associated_product_id_tag 13 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t privacy_context_external_ExternalPRequestContext_fields[2]; + +/* Maximum encoded size of messages (where known) */ +#define privacy_context_external_ExternalPRequestContext_size 11 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define EXTERNAL_PREQUEST_CONTEXT_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.c b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.c new file mode 100644 index 0000000..8b81605 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.c @@ -0,0 +1,59 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t privacy_context_external_ExternalPrivacyContext_fields[2] = { + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , FIRST, privacy_context_external_ExternalPrivacyContext, prequest, prequest, &privacy_context_external_ExternalPRequestContext_fields), + PB_LAST_FIELD +}; + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(privacy_context_external_ExternalPrivacyContext, prequest) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_privacy_context_external_ExternalPrivacyContext) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(privacy_context_external_ExternalPrivacyContext, prequest) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_privacy_context_external_ExternalPrivacyContext) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h new file mode 100644 index 0000000..dc6981a --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h @@ -0,0 +1,64 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_PRIVACY_CONTEXT_EXTERNAL_EXTERNAL_PRIVACY_CONTEXT_NANOPB_H_INCLUDED +#define PB_PRIVACY_CONTEXT_EXTERNAL_EXTERNAL_PRIVACY_CONTEXT_NANOPB_H_INCLUDED +#include + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Struct definitions */ +typedef struct _privacy_context_external_ExternalPrivacyContext { + bool has_prequest; + privacy_context_external_ExternalPRequestContext prequest; +/* @@protoc_insertion_point(struct:privacy_context_external_ExternalPrivacyContext) */ +} privacy_context_external_ExternalPrivacyContext; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define privacy_context_external_ExternalPrivacyContext_init_default {false, privacy_context_external_ExternalPRequestContext_init_default} +#define privacy_context_external_ExternalPrivacyContext_init_zero {false, privacy_context_external_ExternalPRequestContext_init_zero} + +/* Field tags (for use in manual encoding/decoding) */ +#define privacy_context_external_ExternalPrivacyContext_prequest_tag 2 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t privacy_context_external_ExternalPrivacyContext_fields[2]; + +/* Maximum encoded size of messages (where known) */ +#define privacy_context_external_ExternalPrivacyContext_size 13 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define EXTERNAL_PRIVACY_CONTEXT_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h new file mode 100644 index 0000000..295e6f8 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h @@ -0,0 +1,51 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A string sets in customBytes as a key paired to @YES if current event needs to + * populate network connection info data, @NO otherwise. + */ +FOUNDATION_EXPORT NSString *const GDTCCTNeedsNetworkConnectionInfo; + +/** A string sets in customBytes as a key paired to the network connection info data + * of current event. + */ +FOUNDATION_EXPORT NSString *const GDTCCTNetworkConnectionInfo; + +/** A category that uses the customBytes property of a GDTCOREvent to store network connection info. + */ +@interface GDTCOREvent (GDTCCTSupport) + +/** If YES, needs the network connection info field set during prioritization. + * @note Uses the GDTCOREvent customBytes property. + */ +@property(nonatomic) BOOL needsNetworkConnectionInfoPopulated; + +/** The network connection info as collected at the time of the event. + * @note Uses the GDTCOREvent customBytes property. + */ +@property(nullable, nonatomic) NSData *networkConnectionInfoData; + +/** Code that identifies the event to be sent to the CCT backend. + */ +@property(nullable, nonatomic) NSNumber *eventCode; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m new file mode 100644 index 0000000..14462ae --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m @@ -0,0 +1,36 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" + +GDTCORAssertionBlock GDTCORAssertionBlockToRunInstead(void) { + // This class is only compiled in by unit tests, and this should fail quickly in optimized builds. + Class GDTCORAssertClass = NSClassFromString(@"GDTCORAssertHelper"); + if (__builtin_expect(!!GDTCORAssertClass, 0)) { + SEL assertionBlockSEL = NSSelectorFromString(@"assertionBlock"); + if (assertionBlockSEL) { + IMP assertionBlockIMP = [GDTCORAssertClass methodForSelector:assertionBlockSEL]; + if (assertionBlockIMP) { + GDTCORAssertionBlock assertionBlock = ((GDTCORAssertionBlock(*)(id, SEL))assertionBlockIMP)( + GDTCORAssertClass, assertionBlockSEL); + if (assertionBlock) { + return assertionBlock; + } + } + } + } + return NULL; +} diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m new file mode 100644 index 0000000..97f96fa --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m @@ -0,0 +1,174 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" + +#import + +// Using a monotonic clock is necessary because CFAbsoluteTimeGetCurrent(), NSDate, and related all +// are subject to drift. That it to say, multiple consecutive calls do not always result in a +// time that is in the future. Clocks may be adjusted by the user, NTP, or any number of external +// factors. This class attempts to determine the wall-clock time at the time of the event by +// capturing the kernel start and time since boot to determine a wallclock time in UTC. +// +// Timezone offsets at the time of a snapshot are also captured in order to provide local-time +// details. Other classes in this library depend on comparing times at some time in the future to +// a time captured in the past, and this class needs to provide a mechanism to do that. +// +// TL;DR: This class attempts to accomplish two things: 1. Provide accurate event times. 2. Provide +// a monotonic clock mechanism to accurately check if some clock snapshot was before or after +// by using a shared reference point (kernel boot time). +// +// Note: Much of the mach time stuff doesn't work properly in the simulator. So this class can be +// difficult to unit test. + +/** Returns the kernel boottime property from sysctl. + * + * @return The KERN_BOOTTIME property from sysctl, in nanoseconds. + */ +static int64_t KernelBootTimeInNanoseconds(void) { + // Caching the result is not possible because clock drift would not be accounted for. + struct timeval boottime; + int mib[2] = {CTL_KERN, KERN_BOOTTIME}; + size_t size = sizeof(boottime); + int rc = sysctl(mib, 2, &boottime, &size, NULL, 0); + if (rc != 0) { + return 0; + } + return (int64_t)boottime.tv_sec * NSEC_PER_SEC + (int64_t)boottime.tv_usec * NSEC_PER_USEC; +} + +/** Returns value of gettimeofday, in nanoseconds. + * + * @return The value of gettimeofday, in nanoseconds. + */ +static int64_t UptimeInNanoseconds(void) { + int64_t before_now_nsec; + int64_t after_now_nsec; + struct timeval now; + + before_now_nsec = KernelBootTimeInNanoseconds(); + // Addresses a race condition in which the system time has updated, but the boottime has not. + do { + gettimeofday(&now, NULL); + after_now_nsec = KernelBootTimeInNanoseconds(); + } while (after_now_nsec != before_now_nsec); + return (int64_t)now.tv_sec * NSEC_PER_SEC + (int64_t)now.tv_usec * NSEC_PER_USEC - + before_now_nsec; +} + +// TODO: Consider adding a 'trustedTime' property that can be populated by the response from a BE. +@implementation GDTCORClock + +- (instancetype)init { + self = [super init]; + if (self) { + _kernelBootTimeNanoseconds = KernelBootTimeInNanoseconds(); + _uptimeNanoseconds = UptimeInNanoseconds(); + _timeMillis = + (int64_t)((CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) * NSEC_PER_USEC); + _timezoneOffsetSeconds = [[NSTimeZone systemTimeZone] secondsFromGMT]; + } + return self; +} + ++ (GDTCORClock *)snapshot { + return [[GDTCORClock alloc] init]; +} + ++ (instancetype)clockSnapshotInTheFuture:(uint64_t)millisInTheFuture { + GDTCORClock *snapshot = [self snapshot]; + snapshot->_timeMillis += millisInTheFuture; + return snapshot; +} + +- (BOOL)isAfter:(GDTCORClock *)otherClock { + // These clocks are trivially comparable when they share a kernel boot time. + if (_kernelBootTimeNanoseconds == otherClock->_kernelBootTimeNanoseconds) { + int64_t timeDiff = (_timeMillis + _timezoneOffsetSeconds) - + (otherClock->_timeMillis + otherClock->_timezoneOffsetSeconds); + return timeDiff > 0; + } else { + int64_t kernelBootTimeDiff = + otherClock->_kernelBootTimeNanoseconds - _kernelBootTimeNanoseconds; + // This isn't a great solution, but essentially, if the other clock's boot time is 'later', NO + // is returned. This can be altered by changing the system time and rebooting. + return kernelBootTimeDiff < 0 ? YES : NO; + } +} + +- (int64_t)uptimeMilliseconds { + return self.uptimeNanoseconds / NSEC_PER_MSEC; +} + +- (NSUInteger)hash { + return [@(_kernelBootTimeNanoseconds) hash] ^ [@(_uptimeNanoseconds) hash] ^ + [@(_timeMillis) hash] ^ [@(_timezoneOffsetSeconds) hash]; +} + +- (BOOL)isEqual:(id)object { + return [self hash] == [object hash]; +} + +#pragma mark - NSSecureCoding + +/** NSKeyedCoder key for timeMillis property. */ +static NSString *const kGDTCORClockTimeMillisKey = @"GDTCORClockTimeMillis"; + +/** NSKeyedCoder key for timezoneOffsetMillis property. */ +static NSString *const kGDTCORClockTimezoneOffsetSeconds = @"GDTCORClockTimezoneOffsetSeconds"; + +/** NSKeyedCoder key for _kernelBootTime ivar. */ +static NSString *const kGDTCORClockKernelBootTime = @"GDTCORClockKernelBootTime"; + +/** NSKeyedCoder key for _uptimeNanoseconds ivar. */ +static NSString *const kGDTCORClockUptime = @"GDTCORClockUptime"; + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [super init]; + if (self) { + // TODO: If the kernelBootTimeNanoseconds is more recent, we need to change the kernel boot time + // and uptimeMillis ivars + _timeMillis = [aDecoder decodeInt64ForKey:kGDTCORClockTimeMillisKey]; + _timezoneOffsetSeconds = [aDecoder decodeInt64ForKey:kGDTCORClockTimezoneOffsetSeconds]; + _kernelBootTimeNanoseconds = [aDecoder decodeInt64ForKey:kGDTCORClockKernelBootTime]; + _uptimeNanoseconds = [aDecoder decodeInt64ForKey:kGDTCORClockUptime]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeInt64:_timeMillis forKey:kGDTCORClockTimeMillisKey]; + [aCoder encodeInt64:_timezoneOffsetSeconds forKey:kGDTCORClockTimezoneOffsetSeconds]; + [aCoder encodeInt64:_kernelBootTimeNanoseconds forKey:kGDTCORClockKernelBootTime]; + [aCoder encodeInt64:_uptimeNanoseconds forKey:kGDTCORClockUptime]; +} + +#pragma mark - Deprecated properties + +- (int64_t)kernelBootTime { + return self.kernelBootTimeNanoseconds; +} + +- (int64_t)uptime { + return self.uptimeNanoseconds; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m new file mode 100644 index 0000000..5eaee92 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +volatile NSInteger GDTCORConsoleLoggerLoggingLevel = GDTCORLoggingLevelErrors; + +/** The console logger prefix. */ +static NSString *kGDTCORConsoleLogger = @"[GoogleDataTransport]"; + +NSString *GDTCORMessageCodeEnumToString(GDTCORMessageCode code) { + return [[NSString alloc] initWithFormat:@"I-GDTCOR%06ld", (long)code]; +} + +void GDTCORLog(GDTCORMessageCode code, GDTCORLoggingLevel logLevel, NSString *format, ...) { +// Don't log anything in not debug builds. +#if !NDEBUG + if (logLevel >= GDTCORConsoleLoggerLoggingLevel) { + NSString *logFormat = [NSString stringWithFormat:@"%@[%@] %@", kGDTCORConsoleLogger, + GDTCORMessageCodeEnumToString(code), format]; + va_list args; + va_start(args, format); + NSLogv(logFormat, args); + va_end(args); + } +#endif // !NDEBUG +} + +void GDTCORLogAssert( + BOOL wasFatal, NSString *_Nonnull file, NSInteger line, NSString *_Nullable format, ...) { +// Don't log anything in not debug builds. +#if !NDEBUG + GDTCORMessageCode code = wasFatal ? GDTCORMCEFatalAssertion : GDTCORMCEGeneralError; + NSString *logFormat = + [NSString stringWithFormat:@"%@[%@] (%@:%ld) : %@", kGDTCORConsoleLogger, + GDTCORMessageCodeEnumToString(code), file, (long)line, format]; + va_list args; + va_start(args, format); + NSLogv(logFormat, args); + va_end(args); +#endif // !NDEBUG +} diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m new file mode 100644 index 0000000..0bc8515 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m @@ -0,0 +1,101 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h" + +@interface GDTCORDirectorySizeTracker () + +/** The observed directory path. */ +@property(nonatomic, readonly) NSString *directoryPath; + +/** The cached content size of the observed directory. */ +@property(nonatomic, nullable) NSNumber *cachedSizeBytes; + +@end + +@implementation GDTCORDirectorySizeTracker + +- (instancetype)initWithDirectoryPath:(NSString *)path { + self = [super init]; + if (self) { + _directoryPath = path; + } + return self; +} + +- (GDTCORStorageSizeBytes)directoryContentSize { + if (self.cachedSizeBytes == nil) { + self.cachedSizeBytes = @([self calculateDirectoryContentSize]); + } + + return self.cachedSizeBytes.unsignedLongLongValue; +} + +- (void)fileWasAddedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize { + if (![path hasPrefix:self.directoryPath]) { + // Ignore because the file is not inside the directory. + return; + } + + self.cachedSizeBytes = @([self directoryContentSize] + fileSize); +} + +- (void)fileWasRemovedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize { + if (![path hasPrefix:self.directoryPath]) { + // Ignore because the file is not inside the directory. + return; + } + + self.cachedSizeBytes = @([self directoryContentSize] - fileSize); +} + +- (void)resetCachedSize { + self.cachedSizeBytes = nil; +} + +- (GDTCORStorageSizeBytes)calculateDirectoryContentSize { + NSArray *prefetchedProperties = @[ NSURLIsRegularFileKey, NSURLFileSizeKey ]; + uint64_t totalBytes = 0; + NSURL *directoryURL = [NSURL fileURLWithPath:self.directoryPath]; + + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] + enumeratorAtURL:directoryURL + includingPropertiesForKeys:prefetchedProperties + options:NSDirectoryEnumerationSkipsHiddenFiles + errorHandler:^BOOL(NSURL *_Nonnull url, NSError *_Nonnull error) { + return YES; + }]; + + for (NSURL *fileURL in enumerator) { + @autoreleasepool { + NSNumber *isRegularFile; + [fileURL getResourceValue:&isRegularFile forKey:NSURLIsRegularFileKey error:nil]; + if (isRegularFile.boolValue) { + totalBytes += [self fileSizeAtURL:fileURL]; + } + } + } + + return totalBytes; +} + +- (GDTCORStorageSizeBytes)fileSizeAtURL:(NSURL *)fileURL { + NSNumber *fileSize; + [fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:nil]; + return fileSize.unsignedLongLongValue; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m new file mode 100644 index 0000000..f16db13 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m @@ -0,0 +1,92 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h" + +static NSString *const kINTServerURL = + @"https://dummyapiverylong-dummy.google.com/dummy/api/very/long"; + +@implementation GDTCOREndpoints + ++ (NSDictionary *)uploadURLs { + // These strings should be interleaved to construct the real URL. This is just to (hopefully) + // fool github URL scanning bots. + static NSURL *CCTServerURL; + static dispatch_once_t CCTOnceToken; + dispatch_once(&CCTOnceToken, ^{ + const char *p1 = "hts/frbslgiggolai.o/0clgbth"; + const char *p2 = "tp:/ieaeogn.ogepscmvc/o/ac"; + const char URL[54] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], + p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], + p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13], + p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17], + p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22], + p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], '\0'}; + CCTServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]]; + }); + + static NSURL *FLLServerURL; + static dispatch_once_t FLLOnceToken; + dispatch_once(&FLLOnceToken, ^{ + const char *p1 = "hts/frbslgigp.ogepscmv/ieo/eaybtho"; + const char *p2 = "tp:/ieaeogn-agolai.o/1frlglgc/aclg"; + const char URL[69] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], + p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], + p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13], + p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17], + p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22], + p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], p2[26], + p1[27], p2[27], p1[28], p2[28], p1[29], p2[29], p1[30], p2[30], p1[31], + p2[31], p1[32], p2[32], p1[33], p2[33], '\0'}; + FLLServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]]; + }); + + static NSURL *CSHServerURL; + static dispatch_once_t CSHOnceToken; + dispatch_once(&CSHOnceToken, ^{ + // These strings should be interleaved to construct the real URL. This is just to (hopefully) + // fool github URL scanning bots. + const char *p1 = "hts/cahyiseot-agolai.o/1frlglgc/aclg"; + const char *p2 = "tp:/rsltcrprsp.ogepscmv/ieo/eaybtho"; + const char URL[72] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], + p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], + p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13], + p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17], + p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22], + p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], p2[26], + p1[27], p2[27], p1[28], p2[28], p1[29], p2[29], p1[30], p2[30], p1[31], + p2[31], p1[32], p2[32], p1[33], p2[33], p1[34], p2[34], p1[35], '\0'}; + CSHServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]]; + }); + static NSDictionary *uploadURLs; + static dispatch_once_t URLOnceToken; + dispatch_once(&URLOnceToken, ^{ + uploadURLs = @{ + @(kGDTCORTargetCCT) : CCTServerURL, + @(kGDTCORTargetFLL) : FLLServerURL, + @(kGDTCORTargetCSH) : CSHServerURL, + @(kGDTCORTargetINT) : [NSURL URLWithString:kINTServerURL] + }; + }); + return uploadURLs; +} + ++ (nullable NSURL *)uploadURLForTarget:(GDTCORTarget)target { + NSDictionary *URLs = [self uploadURLs]; + return [URLs objectForKey:@(target)]; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m new file mode 100644 index 0000000..98db41a --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m @@ -0,0 +1,170 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h" + +@implementation GDTCOREvent + ++ (NSString *)nextEventID { + // Replace special non-alphanumeric characters to avoid potential conflicts with storage logic. + return [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""]; +} + +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + productData:(nullable GDTCORProductData *)productData + target:(GDTCORTarget)target { + GDTCORAssert(mappingID.length > 0, @"Please give a valid mapping ID"); + GDTCORAssert(target > 0, @"A target cannot be negative or 0"); + if (mappingID.length == 0 || target <= 0) { + return nil; + } + self = [super init]; + if (self) { + _eventID = [GDTCOREvent nextEventID]; + _mappingID = mappingID; + _productData = productData; + _target = target; + _qosTier = GDTCOREventQosDefault; + _expirationDate = [NSDate dateWithTimeIntervalSinceNow:604800]; // 7 days. + + GDTCORLogDebug(@"Event %@ created. ID:%@ mappingID: %@ target:%ld", self, _eventID, mappingID, + (long)target); + } + + return self; +} + +- (nullable instancetype)initWithMappingID:(NSString *)mappingID target:(GDTCORTarget)target { + return [self initWithMappingID:mappingID productData:nil target:target]; +} + +- (instancetype)copy { + GDTCOREvent *copy = [[GDTCOREvent alloc] initWithMappingID:_mappingID + productData:_productData + target:_target]; + copy->_eventID = _eventID; + copy.dataObject = _dataObject; + copy.qosTier = _qosTier; + copy.clockSnapshot = _clockSnapshot; + copy.customBytes = _customBytes; + GDTCORLogDebug(@"Copying event %@ to event %@", self, copy); + return copy; +} + +- (NSUInteger)hash { + // This loses some precision, but it's probably fine. + NSUInteger eventIDHash = [_eventID hash]; + NSUInteger mappingIDHash = [_mappingID hash]; + NSUInteger productDataHash = [_productData hash]; + NSUInteger timeHash = [_clockSnapshot hash]; + NSInteger serializedBytesHash = [_serializedDataObjectBytes hash]; + + return eventIDHash ^ mappingIDHash ^ productDataHash ^ _target ^ _qosTier ^ timeHash ^ + serializedBytesHash; +} + +- (BOOL)isEqual:(id)object { + return [self hash] == [object hash]; +} + +#pragma mark - Property overrides + +- (void)setDataObject:(id)dataObject { + // If you're looking here because of a performance issue in -transportBytes slowing the assignment + // of -dataObject, one way to address this is to add a queue to this class, + // dispatch_(barrier_ if concurrent)async here, and implement the getter with a dispatch_sync. + if (dataObject != _dataObject) { + _dataObject = dataObject; + } + self->_serializedDataObjectBytes = [dataObject transportBytes]; +} + +#pragma mark - NSSecureCoding and NSCoding Protocols + +/** NSCoding key for eventID property. */ +static NSString *kEventIDKey = @"GDTCOREventEventIDKey"; + +/** NSCoding key for mappingID property. */ +static NSString *kMappingIDKey = @"GDTCOREventMappingIDKey"; + +/** NSCoding key for target property. */ +static NSString *kTargetKey = @"GDTCOREventTargetKey"; + +/** NSCoding key for qosTier property. */ +static NSString *kQoSTierKey = @"GDTCOREventQoSTierKey"; + +/** NSCoding key for clockSnapshot property. */ +static NSString *kClockSnapshotKey = @"GDTCOREventClockSnapshotKey"; + +/** NSCoding key for expirationDate property. */ +static NSString *kExpirationDateKey = @"GDTCOREventExpirationDateKey"; + +/** NSCoding key for serializedDataObjectBytes property. */ +static NSString *kSerializedDataObjectBytes = @"GDTCOREventSerializedDataObjectBytesKey"; + +/** NSCoding key for customData property. */ +static NSString *kCustomDataKey = @"GDTCOREventCustomDataKey"; + +/** NSCoding key for productData property. */ +static NSString *kProductDataKey = @"GDTCOREventProductDataKey"; + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (self) { + _mappingID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kMappingIDKey]; + _productData = [aDecoder decodeObjectOfClass:[GDTCORProductData class] forKey:kProductDataKey]; + _target = [aDecoder decodeIntegerForKey:kTargetKey]; + _eventID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kEventIDKey] + ?: [GDTCOREvent nextEventID]; + _qosTier = [aDecoder decodeIntegerForKey:kQoSTierKey]; + _clockSnapshot = [aDecoder decodeObjectOfClass:[GDTCORClock class] forKey:kClockSnapshotKey]; + _customBytes = [aDecoder decodeObjectOfClass:[NSData class] forKey:kCustomDataKey]; + _expirationDate = [aDecoder decodeObjectOfClass:[NSDate class] forKey:kExpirationDateKey]; + _serializedDataObjectBytes = [aDecoder decodeObjectOfClass:[NSData class] + forKey:kSerializedDataObjectBytes]; + if (!_serializedDataObjectBytes) { + return nil; + } + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_eventID forKey:kEventIDKey]; + [aCoder encodeObject:_mappingID forKey:kMappingIDKey]; + [aCoder encodeObject:_productData forKey:kProductDataKey]; + [aCoder encodeInteger:_target forKey:kTargetKey]; + [aCoder encodeInteger:_qosTier forKey:kQoSTierKey]; + [aCoder encodeObject:_clockSnapshot forKey:kClockSnapshotKey]; + [aCoder encodeObject:_customBytes forKey:kCustomDataKey]; + [aCoder encodeObject:_expirationDate forKey:kExpirationDateKey]; + [aCoder encodeObject:self.serializedDataObjectBytes forKey:kSerializedDataObjectBytes]; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m new file mode 100644 index 0000000..4ff937c --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m @@ -0,0 +1,161 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h" + +@implementation GDTCORFlatFileStorage (Promises) + +- (FBLPromise *> *)batchIDsForTarget:(GDTCORTarget)target { + return [FBLPromise onQueue:self.storageQueue + wrapObjectCompletion:^(FBLPromiseObjectCompletion _Nonnull handler) { + [self batchIDsForTarget:target onComplete:handler]; + }]; +} + +- (FBLPromise *)removeBatchWithID:(NSNumber *)batchID deleteEvents:(BOOL)deleteEvents { + return [FBLPromise onQueue:self.storageQueue + wrapCompletion:^(FBLPromiseCompletion _Nonnull handler) { + [self removeBatchWithID:batchID deleteEvents:deleteEvents onComplete:handler]; + }]; +} + +- (FBLPromise *)removeBatchesWithIDs:(NSSet *)batchIDs + deleteEvents:(BOOL)deleteEvents { + NSMutableArray *removeBatchPromises = + [NSMutableArray arrayWithCapacity:batchIDs.count]; + for (NSNumber *batchID in batchIDs) { + [removeBatchPromises addObject:[self removeBatchWithID:batchID deleteEvents:deleteEvents]]; + } + + return [FBLPromise onQueue:self.storageQueue all:[removeBatchPromises copy]].thenOn( + self.storageQueue, ^id(id result) { + return [FBLPromise resolvedWith:[NSNull null]]; + }); +} + +- (FBLPromise *)removeAllBatchesForTarget:(GDTCORTarget)target + deleteEvents:(BOOL)deleteEvents { + return + [self batchIDsForTarget:target].thenOn(self.storageQueue, ^id(NSSet *batchIDs) { + if (batchIDs.count == 0) { + return [FBLPromise resolvedWith:[NSNull null]]; + } else { + return [self removeBatchesWithIDs:batchIDs deleteEvents:NO]; + } + }); +} + +- (FBLPromise *)hasEventsForTarget:(GDTCORTarget)target { + return [FBLPromise onQueue:self.storageQueue + wrapBoolCompletion:^(FBLPromiseBoolCompletion _Nonnull handler) { + [self hasEventsForTarget:target onComplete:handler]; + }]; +} + +- (FBLPromise *)batchWithEventSelector: + (GDTCORStorageEventSelector *)eventSelector + batchExpiration:(NSDate *)expiration { + return [FBLPromise + onQueue:self.storageQueue + async:^(FBLPromiseFulfillBlock _Nonnull fulfill, FBLPromiseRejectBlock _Nonnull reject) { + [self batchWithEventSelector:eventSelector + batchExpiration:expiration + onComplete:^(NSNumber *_Nullable newBatchID, + NSSet *_Nullable batchEvents) { + if (newBatchID == nil || batchEvents == nil) { + reject([self genericRejectedPromiseErrorWithReason: + @"There are no events for the selector."]); + } else { + fulfill([[GDTCORUploadBatch alloc] initWithBatchID:newBatchID + events:batchEvents]); + } + }]; + }]; +} + +- (FBLPromise *)fetchAndUpdateMetricsWithHandler: + (GDTCORMetricsMetadata * (^)(GDTCORMetricsMetadata *_Nullable fetchedMetadata, + NSError *_Nullable fetchError))handler { + return FBLPromise.doOn(self.storageQueue, ^id { + // Fetch the stored metrics metadata. + NSError *decodeError; + NSString *metricsMetadataPath = + [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:@"metrics_metadata"]; + GDTCORMetricsMetadata *decodedMetadata = (GDTCORMetricsMetadata *)GDTCORDecodeArchiveAtPath( + GDTCORMetricsMetadata.class, metricsMetadataPath, &decodeError); + + // Update the metadata using the retrieved metadata. + GDTCORMetricsMetadata *updatedMetadata = handler(decodedMetadata, decodeError); + if (updatedMetadata == nil) { + // `nil` metadata is not expected and will be a no-op. + return nil; + } + + if (![updatedMetadata isEqual:decodedMetadata]) { + // The metadata was updated so it needs to be saved. + // - Encode the updated metadata. + NSError *encodeError; + NSData *encodedMetadata = GDTCOREncodeArchive(updatedMetadata, nil, &encodeError); + if (encodeError) { + return encodeError; + } + + // - Write the encoded metadata to disk. + NSError *writeError; + BOOL writeResult = GDTCORWriteDataToFile(encodedMetadata, metricsMetadataPath, &writeError); + if (writeResult == NO || writeError) { + return writeError; + } + } + + return nil; + }); +} + +- (FBLPromise *)fetchStorageMetadata { + return FBLPromise.asyncOn(self.storageQueue, ^(FBLPromiseFulfillBlock _Nonnull fulfill, + FBLPromiseRejectBlock _Nonnull reject) { + [self storageSizeWithCallback:^(GDTCORStorageSizeBytes storageSize) { + fulfill([GDTCORStorageMetadata metadataWithCurrentCacheSize:storageSize + maxCacheSize:kGDTCORFlatFileStorageSizeLimit]); + }]; + }); +} + +// TODO: Move to a separate class/extension when needed in more places. +- (NSError *)genericRejectedPromiseErrorWithReason:(NSString *)reason { + return [NSError errorWithDomain:@"GDTCORFlatFileStorage" + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : reason}]; +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void GDTCORInclude_GDTCORLogSourceMetrics_Internal_Category(void) { +} diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m new file mode 100644 index 0000000..fe36a19 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m @@ -0,0 +1,849 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A library data key this class uses to track batchIDs. */ +static NSString *const gBatchIDCounterKey = @"GDTCORFlatFileStorageBatchIDCounter"; + +/** The separator used between metadata elements in filenames. */ +static NSString *const kMetadataSeparator = @"-"; + +NSString *const kGDTCOREventComponentsEventIDKey = @"GDTCOREventComponentsEventIDKey"; + +NSString *const kGDTCOREventComponentsQoSTierKey = @"GDTCOREventComponentsQoSTierKey"; + +NSString *const kGDTCOREventComponentsMappingIDKey = @"GDTCOREventComponentsMappingIDKey"; + +NSString *const kGDTCOREventComponentsExpirationKey = @"GDTCOREventComponentsExpirationKey"; + +NSString *const kGDTCORBatchComponentsTargetKey = @"GDTCORBatchComponentsTargetKey"; + +NSString *const kGDTCORBatchComponentsBatchIDKey = @"GDTCORBatchComponentsBatchIDKey"; + +NSString *const kGDTCORBatchComponentsExpirationKey = @"GDTCORBatchComponentsExpirationKey"; + +NSString *const GDTCORFlatFileStorageErrorDomain = @"GDTCORFlatFileStorage"; + +const uint64_t kGDTCORFlatFileStorageSizeLimit = 20 * 1000 * 1000; // 20 MB. + +@interface GDTCORFlatFileStorage () + +/** An instance of the size tracker to keep track of the disk space consumed by the storage. */ +@property(nonatomic, readonly) GDTCORDirectorySizeTracker *sizeTracker; + +@end + +@implementation GDTCORFlatFileStorage + +@synthesize sizeTracker = _sizeTracker; +@synthesize delegate = _delegate; + ++ (void)load { +#if !NDEBUG + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetTest]; +#endif // !NDEBUG + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetCCT]; + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetFLL]; + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetCSH]; + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetINT]; +} + ++ (instancetype)sharedInstance { + static GDTCORFlatFileStorage *sharedStorage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedStorage = [[GDTCORFlatFileStorage alloc] init]; + }); + return sharedStorage; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _storageQueue = + dispatch_queue_create("com.google.GDTCORFlatFileStorage", DISPATCH_QUEUE_SERIAL); + _uploadCoordinator = [GDTCORUploadCoordinator sharedInstance]; + } + return self; +} + +- (GDTCORDirectorySizeTracker *)sizeTracker { + if (_sizeTracker == nil) { + _sizeTracker = + [[GDTCORDirectorySizeTracker alloc] initWithDirectoryPath:GDTCORRootDirectory().path]; + } + return _sizeTracker; +} + +#pragma mark - GDTCORStorageProtocol + +- (void)storeEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + GDTCORLogDebug(@"Saving event: %@", event); + if (event == nil || event.serializedDataObjectBytes == nil) { + GDTCORLogDebug(@"%@", @"The event was nil, so it was not saved."); + if (completion) { + completion(NO, [NSError errorWithDomain:NSInternalInconsistencyException + code:-1 + userInfo:nil]); + } + return; + } + if (!completion) { + completion = ^(BOOL wasWritten, NSError *_Nullable error) { + GDTCORLogDebug(@"event %@ stored. success:%@ error:%@", event, wasWritten ? @"YES" : @"NO", + error); + }; + } + + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; + bgID = [[GDTCORApplication sharedApplication] + beginBackgroundTaskWithName:@"GDTStorage" + expirationHandler:^{ + // End the background task if it's still valid. + [[GDTCORApplication sharedApplication] endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }]; + + dispatch_async(_storageQueue, ^{ + // Check that a backend implementation is available for this target. + GDTCORTarget target = event.target; + NSString *filePath = [GDTCORFlatFileStorage pathForTarget:target + eventID:event.eventID + qosTier:@(event.qosTier) + expirationDate:event.expirationDate + mappingID:event.mappingID]; + NSError *error; + NSData *encodedEvent = GDTCOREncodeArchive(event, nil, &error); + if (error) { + completion(NO, error); + return; + } + + // Check storage size limit before storing the event. + uint64_t resultingStorageSize = self.sizeTracker.directoryContentSize + encodedEvent.length; + if (resultingStorageSize > kGDTCORFlatFileStorageSizeLimit) { + NSError *error = [NSError + errorWithDomain:GDTCORFlatFileStorageErrorDomain + code:GDTCORFlatFileStorageErrorSizeLimitReached + userInfo:@{ + NSLocalizedFailureReasonErrorKey : @"Storage size limit has been reached." + }]; + if (self.delegate != nil) { + GDTCORLogDebug(@"Delegate notified that event with mapping ID %@ was dropped.", + event.mappingID); + [self.delegate storage:self didDropEvent:event]; + } + completion(NO, error); + return; + } + + // Write the encoded event to the file. + BOOL writeResult = GDTCORWriteDataToFile(encodedEvent, filePath, &error); + if (writeResult == NO || error) { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@ error:%@", filePath, error); + completion(NO, error); + return; + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + completion(YES, nil); + } + + // Notify size tracker. + [self.sizeTracker fileWasAddedAtPath:filePath withSize:encodedEvent.length]; + + // Check the QoS, if it's high priority, notify the target that it has a high priority event. + if (event.qosTier == GDTCOREventQoSFast) { + // TODO: Remove a direct dependency on the upload coordinator. + [self.uploadCoordinator forceUploadForTarget:target]; + } + + // Cancel or end the associated background task if it's still valid. + [[GDTCORApplication sharedApplication] endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }); +} + +- (void)batchWithEventSelector:(nonnull GDTCORStorageEventSelector *)eventSelector + batchExpiration:(nonnull NSDate *)expiration + onComplete: + (nonnull void (^)(NSNumber *_Nullable batchID, + NSSet *_Nullable events))onComplete { + dispatch_queue_t queue = _storageQueue; + void (^onPathsForTargetComplete)(NSNumber *, NSSet *_Nonnull) = ^( + NSNumber *batchID, NSSet *_Nonnull paths) { + dispatch_async(queue, ^{ + NSMutableSet *events = [[NSMutableSet alloc] init]; + for (NSString *eventPath in paths) { + NSError *error; + GDTCOREvent *event = + (GDTCOREvent *)GDTCORDecodeArchiveAtPath([GDTCOREvent class], eventPath, &error); + if (event == nil || error) { + GDTCORLogDebug(@"Error deserializing event: %@", error); + [[NSFileManager defaultManager] removeItemAtPath:eventPath error:nil]; + continue; + } else { + NSString *fileName = [eventPath lastPathComponent]; + NSString *batchPath = + [GDTCORFlatFileStorage batchPathForTarget:eventSelector.selectedTarget + batchID:batchID + expirationDate:expiration]; + [[NSFileManager defaultManager] createDirectoryAtPath:batchPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSString *destinationPath = [batchPath stringByAppendingPathComponent:fileName]; + error = nil; + [[NSFileManager defaultManager] moveItemAtPath:eventPath + toPath:destinationPath + error:&error]; + if (error) { + GDTCORLogDebug(@"An event file wasn't moveable into the batch directory: %@", error); + } + [events addObject:event]; + } + } + if (onComplete) { + if (events.count == 0) { + onComplete(nil, nil); + } else { + onComplete(batchID, events); + } + } + }); + }; + + void (^onBatchIDFetchComplete)(NSNumber *) = ^(NSNumber *batchID) { + dispatch_async(queue, ^{ + if (batchID == nil) { + if (onComplete) { + onComplete(nil, nil); + return; + } + } + [self pathsForTarget:eventSelector.selectedTarget + eventIDs:eventSelector.selectedEventIDs + qosTiers:eventSelector.selectedQosTiers + mappingIDs:eventSelector.selectedMappingIDs + onComplete:^(NSSet *_Nonnull paths) { + onPathsForTargetComplete(batchID, paths); + }]; + }); + }; + + [self nextBatchID:^(NSNumber *_Nullable batchID) { + if (batchID == nil) { + if (onComplete) { + onComplete(nil, nil); + } + } else { + onBatchIDFetchComplete(batchID); + } + }]; +} + +- (void)removeBatchWithID:(nonnull NSNumber *)batchID + deleteEvents:(BOOL)deleteEvents + onComplete:(void (^_Nullable)(void))onComplete { + dispatch_async(_storageQueue, ^{ + [self syncThreadUnsafeRemoveBatchWithID:batchID deleteEvents:deleteEvents]; + + if (onComplete) { + onComplete(); + } + }); +} + +- (void)batchIDsForTarget:(GDTCORTarget)target + onComplete:(nonnull void (^)(NSSet *_Nullable))onComplete { + dispatch_async(_storageQueue, ^{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error; + NSArray *batchPaths = + [fileManager contentsOfDirectoryAtPath:[GDTCORFlatFileStorage batchDataStoragePath] + error:&error]; + if (error || batchPaths.count == 0) { + if (onComplete) { + onComplete(nil); + } + return; + } + NSMutableSet *batchIDs = [[NSMutableSet alloc] init]; + for (NSString *path in batchPaths) { + NSDictionary *components = [self batchComponentsFromFilename:path]; + NSNumber *targetNumber = components[kGDTCORBatchComponentsTargetKey]; + NSNumber *batchID = components[kGDTCORBatchComponentsBatchIDKey]; + if (batchID != nil && targetNumber.intValue == target) { + [batchIDs addObject:batchID]; + } + } + if (onComplete) { + onComplete(batchIDs); + } + }); +} + +- (void)libraryDataForKey:(nonnull NSString *)key + onFetchComplete:(nonnull void (^)(NSData *_Nullable, NSError *_Nullable))onFetchComplete + setNewValue:(NSData *_Nullable (^_Nullable)(void))setValueBlock { + dispatch_async(_storageQueue, ^{ + NSString *dataPath = [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:key]; + NSError *error; + NSData *data = [NSData dataWithContentsOfFile:dataPath options:0 error:&error]; + if (onFetchComplete) { + onFetchComplete(data, error); + } + if (setValueBlock) { + NSData *newValue = setValueBlock(); + // The -isKindOfClass check is necessary because without an explicit 'return nil' in the block + // the implicit return value will be the block itself. The compiler doesn't detect this. + if (newValue != nil && [newValue isKindOfClass:[NSData class]] && newValue.length) { + NSError *newValueError; + if ([newValue writeToFile:dataPath options:NSDataWritingAtomic error:&newValueError]) { + // Update storage size. + [self.sizeTracker fileWasRemovedAtPath:dataPath withSize:data.length]; + [self.sizeTracker fileWasAddedAtPath:dataPath withSize:newValue.length]; + } else { + GDTCORLogDebug(@"Error writing new value in libraryDataForKey: %@", newValueError); + } + } + } + }); +} + +- (void)storeLibraryData:(NSData *)data + forKey:(nonnull NSString *)key + onComplete:(nullable void (^)(NSError *_Nullable error))onComplete { + if (!data || data.length <= 0) { + if (onComplete) { + onComplete([NSError errorWithDomain:NSInternalInconsistencyException code:-1 userInfo:nil]); + } + return; + } + dispatch_async(_storageQueue, ^{ + NSError *error; + NSString *dataPath = [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:key]; + if ([data writeToFile:dataPath options:NSDataWritingAtomic error:&error]) { + [self.sizeTracker fileWasAddedAtPath:dataPath withSize:data.length]; + } + if (onComplete) { + onComplete(error); + } + }); +} + +- (void)removeLibraryDataForKey:(nonnull NSString *)key + onComplete:(nonnull void (^)(NSError *_Nullable error))onComplete { + dispatch_async(_storageQueue, ^{ + NSError *error; + NSString *dataPath = [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:key]; + GDTCORStorageSizeBytes fileSize = + [self.sizeTracker fileSizeAtURL:[NSURL fileURLWithPath:dataPath]]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) { + if ([[NSFileManager defaultManager] removeItemAtPath:dataPath error:&error]) { + [self.sizeTracker fileWasRemovedAtPath:dataPath withSize:fileSize]; + } + if (onComplete) { + onComplete(error); + } + } + }); +} + +- (void)hasEventsForTarget:(GDTCORTarget)target onComplete:(void (^)(BOOL hasEvents))onComplete { + dispatch_async(_storageQueue, ^{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *targetPath = [NSString + stringWithFormat:@"%@/%ld", [GDTCORFlatFileStorage eventDataStoragePath], (long)target]; + [fileManager createDirectoryAtPath:targetPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:targetPath]; + BOOL hasEventAtLeastOneEvent = [enumerator nextObject] != nil; + if (onComplete) { + onComplete(hasEventAtLeastOneEvent); + } + }); +} + +- (void)checkForExpirations { + dispatch_async(_storageQueue, ^{ + GDTCORLogDebug(@"%@", @"Checking for expired events and batches"); + NSTimeInterval now = [NSDate date].timeIntervalSince1970; + NSFileManager *fileManager = [NSFileManager defaultManager]; + + // TODO: Storage may not have enough context to remove batches because a batch may be being + // uploaded but the storage has not context of it. + + // Find expired batches and move their events back to the main storage. + // If a batch contains expired events they are expected to be removed further in the method + // together with other expired events in the main storage. + NSString *batchDataPath = [GDTCORFlatFileStorage batchDataStoragePath]; + NSArray *batchDataPaths = [fileManager contentsOfDirectoryAtPath:batchDataPath + error:nil]; + for (NSString *path in batchDataPaths) { + @autoreleasepool { + NSString *fileName = [path lastPathComponent]; + NSDictionary *batchComponents = [self batchComponentsFromFilename:fileName]; + NSDate *expirationDate = batchComponents[kGDTCORBatchComponentsExpirationKey]; + NSNumber *batchID = batchComponents[kGDTCORBatchComponentsBatchIDKey]; + if (expirationDate != nil && expirationDate.timeIntervalSince1970 < now && batchID != nil) { + NSNumber *batchID = batchComponents[kGDTCORBatchComponentsBatchIDKey]; + // Move all events from the expired batch back to the main storage. + [self syncThreadUnsafeRemoveBatchWithID:batchID deleteEvents:NO]; + } + } + } + + // Find expired events and remove them from the storage. + NSMutableSet *expiredEvents = [NSMutableSet set]; + NSString *eventDataPath = [GDTCORFlatFileStorage eventDataStoragePath]; + NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:eventDataPath]; + NSString *path; + + while (YES) { + @autoreleasepool { + // Call `[enumerator nextObject]` under autorelease pool to make sure all autoreleased + // objects created under the hood are released on each iteration end to avoid unnecessary + // memory growth. + path = [enumerator nextObject]; + if (path == nil) { + break; + } + + NSString *fileName = [path lastPathComponent]; + NSDictionary *eventComponents = [self eventComponentsFromFilename:fileName]; + NSDate *expirationDate = eventComponents[kGDTCOREventComponentsExpirationKey]; + if (expirationDate != nil && expirationDate.timeIntervalSince1970 < now) { + NSString *pathToDelete = [eventDataPath stringByAppendingPathComponent:path]; + + // Decode the expired event from the path to be deleted. + NSError *decodeError; + GDTCOREvent *event = (GDTCOREvent *)GDTCORDecodeArchiveAtPath([GDTCOREvent class], + pathToDelete, &decodeError); + if (event == nil || decodeError) { + GDTCORLogDebug(@"Error deserializing event while checking for expired events: %@", + decodeError); + event = nil; + } + + // Remove the path to be deleted, adding the decoded event to the + // event set if the removal was successful. + NSError *removeError; + [fileManager removeItemAtPath:pathToDelete error:&removeError]; + if (removeError != nil) { + GDTCORLogDebug(@"There was an error deleting an expired item: %@", removeError); + } else { + GDTCORLogDebug(@"Item deleted because it expired: %@", pathToDelete); + if (event) { + [expiredEvents addObject:event]; + } + } + } + } + } + + if (self.delegate != nil && [expiredEvents count] > 0) { + GDTCORLogDebug(@"Delegate notified that %@ events were dropped.", @(expiredEvents.count)); + [self.delegate storage:self didRemoveExpiredEvents:[expiredEvents copy]]; + } + + [self.sizeTracker resetCachedSize]; + }); +} + +- (void)storageSizeWithCallback:(void (^)(uint64_t storageSize))onComplete { + if (!onComplete) { + return; + } + + dispatch_async(_storageQueue, ^{ + onComplete([self.sizeTracker directoryContentSize]); + }); +} + +#pragma mark - Private not thread safe methods +/** Looks for directory paths containing events for a batch with the specified ID. + * @param batchID A batch ID. + * @param outError A pointer to `NSError *` to assign as possible error to. + * @return An array of an array of paths to directories for event batches with a specified batch ID + * or `nil` in the case of an error. Usually returns a single path but potentially return more in + * cases when the app is terminated while uploading a batch. + */ +- (nullable NSArray *)batchDirPathsForBatchID:(NSNumber *)batchID + error:(NSError **_Nonnull)outError { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error; + NSArray *batches = + [fileManager contentsOfDirectoryAtPath:[GDTCORFlatFileStorage batchDataStoragePath] + error:&error]; + if (batches == nil) { + *outError = error; + GDTCORLogDebug(@"Failed to find event file paths for batchID: %@, error: %@", batchID, error); + return nil; + } + + NSMutableArray *batchDirPaths = [NSMutableArray array]; + for (NSString *path in batches) { + NSDictionary *components = [self batchComponentsFromFilename:path]; + NSNumber *pathBatchID = components[kGDTCORBatchComponentsBatchIDKey]; + if ([pathBatchID isEqual:batchID]) { + NSString *batchDirPath = + [[GDTCORFlatFileStorage batchDataStoragePath] stringByAppendingPathComponent:path]; + [batchDirPaths addObject:batchDirPath]; + } + } + + return [batchDirPaths copy]; +} + +/** Makes a copy of the contents of a directory to a directory at the specified path.*/ +- (BOOL)moveContentsOfDirectoryAtPath:(NSString *)sourcePath + to:(NSString *)destinationPath + error:(NSError **_Nonnull)outError { + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSError *error; + NSArray *contentsPaths = [fileManager contentsOfDirectoryAtPath:sourcePath + error:&error]; + if (contentsPaths == nil) { + *outError = error; + return NO; + } + + NSMutableArray *errors = [NSMutableArray array]; + for (NSString *path in contentsPaths) { + NSString *contentDestinationPath = [destinationPath stringByAppendingPathComponent:path]; + NSString *contentSourcePath = [sourcePath stringByAppendingPathComponent:path]; + + NSError *moveError; + if (![fileManager moveItemAtPath:contentSourcePath + toPath:contentDestinationPath + error:&moveError] && + moveError) { + [errors addObject:moveError]; + } + } + + if (errors.count == 0) { + return YES; + } else { + NSError *combinedError = [NSError errorWithDomain:@"GDTCORFlatFileStorage" + code:-1 + userInfo:@{NSUnderlyingErrorKey : errors}]; + *outError = combinedError; + return NO; + } +} + +- (void)syncThreadUnsafeRemoveBatchWithID:(nonnull NSNumber *)batchID + deleteEvents:(BOOL)deleteEvents { + NSError *error; + NSArray *batchDirPaths = [self batchDirPathsForBatchID:batchID error:&error]; + + if (batchDirPaths == nil) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + + void (^removeBatchDir)(NSString *batchDirPath) = ^(NSString *batchDirPath) { + NSError *error; + if ([fileManager removeItemAtPath:batchDirPath error:&error]) { + GDTCORLogDebug(@"Batch removed at path: %@", batchDirPath); + } else { + GDTCORLogDebug(@"Failed to remove batch at path: %@", batchDirPath); + } + }; + + for (NSString *batchDirPath in batchDirPaths) { + @autoreleasepool { + if (deleteEvents) { + removeBatchDir(batchDirPath); + } else { + NSString *batchDirName = [batchDirPath lastPathComponent]; + NSDictionary *components = [self batchComponentsFromFilename:batchDirName]; + NSString *targetValue = [components[kGDTCORBatchComponentsTargetKey] stringValue]; + NSString *destinationPath; + if (targetValue) { + destinationPath = [[GDTCORFlatFileStorage eventDataStoragePath] + stringByAppendingPathComponent:targetValue]; + } + + // `- [NSFileManager moveItemAtPath:toPath:error:]` method fails if an item by the + // destination path already exists (which usually is the case for the current method). Move + // the events one by one instead. + if (destinationPath && [self moveContentsOfDirectoryAtPath:batchDirPath + to:destinationPath + error:&error]) { + GDTCORLogDebug(@"Batched events at path: %@ moved back to the storage: %@", batchDirPath, + destinationPath); + } else { + GDTCORLogDebug(@"Error encountered whilst moving events back: %@", error); + } + + // Even if not all events where moved back to the storage, there is not much can be done at + // this point, so cleanup batch directory now to avoid cluttering. + removeBatchDir(batchDirPath); + } + } + } + + [self.sizeTracker resetCachedSize]; +} + +#pragma mark - Private helper methods + ++ (NSString *)eventDataStoragePath { + static NSString *eventDataPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + eventDataPath = [NSString stringWithFormat:@"%@/%@/gdt_event_data", GDTCORRootDirectory().path, + NSStringFromClass([self class])]; + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:eventDataPath + withIntermediateDirectories:YES + attributes:0 + error:&error]; + GDTCORAssert(error == nil, @"Creating the library data path failed: %@", error); + return eventDataPath; +} + ++ (NSString *)batchDataStoragePath { + static NSString *batchDataPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + batchDataPath = [NSString stringWithFormat:@"%@/%@/gdt_batch_data", GDTCORRootDirectory().path, + NSStringFromClass([self class])]; + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:batchDataPath + withIntermediateDirectories:YES + attributes:0 + error:&error]; + GDTCORAssert(error == nil, @"Creating the batch data path failed: %@", error); + return batchDataPath; +} + ++ (NSString *)libraryDataStoragePath { + static NSString *libraryDataPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + libraryDataPath = + [NSString stringWithFormat:@"%@/%@/gdt_library_data", GDTCORRootDirectory().path, + NSStringFromClass([self class])]; + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:libraryDataPath + withIntermediateDirectories:YES + attributes:0 + error:&error]; + GDTCORAssert(error == nil, @"Creating the library data path failed: %@", error); + return libraryDataPath; +} + ++ (NSString *)batchPathForTarget:(GDTCORTarget)target + batchID:(NSNumber *)batchID + expirationDate:(NSDate *)expirationDate { + return + [NSString stringWithFormat:@"%@/%ld%@%@%@%llu", [GDTCORFlatFileStorage batchDataStoragePath], + (long)target, kMetadataSeparator, batchID, kMetadataSeparator, + ((uint64_t)expirationDate.timeIntervalSince1970)]; +} + ++ (NSString *)pathForTarget:(GDTCORTarget)target + eventID:(NSString *)eventID + qosTier:(NSNumber *)qosTier + expirationDate:(NSDate *)expirationDate + mappingID:(NSString *)mappingID { + NSMutableCharacterSet *allowedChars = [[NSCharacterSet alphanumericCharacterSet] mutableCopy]; + [allowedChars addCharactersInString:kMetadataSeparator]; + mappingID = [mappingID stringByAddingPercentEncodingWithAllowedCharacters:allowedChars]; + return [NSString stringWithFormat:@"%@/%ld/%@%@%@%@%llu%@%@", + [GDTCORFlatFileStorage eventDataStoragePath], (long)target, + eventID, kMetadataSeparator, qosTier, kMetadataSeparator, + ((uint64_t)expirationDate.timeIntervalSince1970), + kMetadataSeparator, mappingID]; +} + +- (void)pathsForTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + qosTiers:(nullable NSSet *)qosTiers + mappingIDs:(nullable NSSet *)mappingIDs + onComplete:(void (^)(NSSet *paths))onComplete { + void (^completion)(NSSet *) = onComplete == nil ? ^(NSSet *paths){} : onComplete; + dispatch_async(_storageQueue, ^{ + NSMutableSet *paths = [[NSMutableSet alloc] init]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *targetPath = [NSString + stringWithFormat:@"%@/%ld", [GDTCORFlatFileStorage eventDataStoragePath], (long)target]; + [fileManager createDirectoryAtPath:targetPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSError *error; + NSArray *dirPaths = [fileManager contentsOfDirectoryAtPath:targetPath error:&error]; + if (error) { + GDTCORLogDebug(@"There was an error reading the contents of the target path: %@", error); + completion(paths); + return; + } + BOOL checkingIDs = eventIDs.count > 0; + BOOL checkingQosTiers = qosTiers.count > 0; + BOOL checkingMappingIDs = mappingIDs.count > 0; + BOOL checkingAnything = checkingIDs == NO && checkingQosTiers == NO && checkingMappingIDs == NO; + for (NSString *path in dirPaths) { + // Skip hidden files that are created as part of atomic file creation. + if ([path hasPrefix:@"."]) { + continue; + } + NSString *filePath = [targetPath stringByAppendingPathComponent:path]; + if (checkingAnything) { + [paths addObject:filePath]; + continue; + } + NSString *filename = [path lastPathComponent]; + NSDictionary *eventComponents = [self eventComponentsFromFilename:filename]; + if (!eventComponents) { + GDTCORLogDebug(@"There was an error reading the filename components: %@", eventComponents); + continue; + } + NSString *eventID = eventComponents[kGDTCOREventComponentsEventIDKey]; + NSNumber *qosTier = eventComponents[kGDTCOREventComponentsQoSTierKey]; + NSString *mappingID = eventComponents[kGDTCOREventComponentsMappingIDKey]; + + NSNumber *eventIDMatch = checkingIDs ? @([eventIDs containsObject:eventID]) : nil; + NSNumber *qosTierMatch = checkingQosTiers ? @([qosTiers containsObject:qosTier]) : nil; + NSNumber *mappingIDMatch = + checkingMappingIDs + ? @([mappingIDs containsObject:[mappingID stringByRemovingPercentEncoding]]) + : nil; + if ((eventIDMatch == nil || eventIDMatch.boolValue) && + (qosTierMatch == nil || qosTierMatch.boolValue) && + (mappingIDMatch == nil || mappingIDMatch.boolValue)) { + [paths addObject:filePath]; + } + } + completion(paths); + }); +} + +- (void)nextBatchID:(void (^)(NSNumber *_Nullable batchID))nextBatchID { + __block int32_t lastBatchID = -1; + [self libraryDataForKey:gBatchIDCounterKey + onFetchComplete:^(NSData *_Nullable data, NSError *_Nullable getValueError) { + if (!getValueError) { + [data getBytes:(void *)&lastBatchID length:sizeof(int32_t)]; + } + if (data == nil) { + lastBatchID = 0; + } + if (nextBatchID) { + nextBatchID(@(lastBatchID)); + } + } + setNewValue:^NSData *_Nullable(void) { + if (lastBatchID != -1) { + int32_t incrementedValue = lastBatchID + 1; + return [NSData dataWithBytes:&incrementedValue length:sizeof(int32_t)]; + } + return nil; + }]; +} + +- (nullable NSDictionary *)eventComponentsFromFilename:(NSString *)fileName { + NSArray *components = [fileName componentsSeparatedByString:kMetadataSeparator]; + if (components.count >= 4) { + NSString *eventID = components[0]; + NSNumber *qosTier = @(components[1].integerValue); + NSDate *expirationDate = [NSDate dateWithTimeIntervalSince1970:components[2].longLongValue]; + NSString *mappingID = [[components subarrayWithRange:NSMakeRange(3, components.count - 3)] + componentsJoinedByString:kMetadataSeparator]; + if (eventID == nil || qosTier == nil || mappingID == nil || expirationDate == nil) { + GDTCORLogDebug(@"There was an error parsing the event filename components: %@", components); + return nil; + } + return @{ + kGDTCOREventComponentsEventIDKey : eventID, + kGDTCOREventComponentsQoSTierKey : qosTier, + kGDTCOREventComponentsExpirationKey : expirationDate, + kGDTCOREventComponentsMappingIDKey : mappingID + }; + } + GDTCORLogDebug(@"The event filename could not be split: %@", fileName); + return nil; +} + +- (nullable NSDictionary *)batchComponentsFromFilename:(NSString *)fileName { + NSArray *components = [fileName componentsSeparatedByString:kMetadataSeparator]; + if (components.count == 3) { + NSNumber *target = @(components[0].integerValue); + NSNumber *batchID = @(components[1].integerValue); + NSDate *expirationDate = [NSDate dateWithTimeIntervalSince1970:components[2].doubleValue]; + if (target == nil || batchID == nil || expirationDate == nil) { + GDTCORLogDebug(@"There was an error parsing the batch filename components: %@", components); + return nil; + } + return @{ + kGDTCORBatchComponentsTargetKey : target, + kGDTCORBatchComponentsBatchIDKey : batchID, + kGDTCORBatchComponentsExpirationKey : expirationDate + }; + } + GDTCORLogDebug(@"The batch filename could not be split: %@", fileName); + return nil; +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillBackground:(GDTCORApplication *)app { + dispatch_async(_storageQueue, ^{ + // Immediately request a background task to run until the end of the current queue of work, + // and cancel it once the work is done. + __block GDTCORBackgroundIdentifier bgID = + [app beginBackgroundTaskWithName:@"GDTStorage" + expirationHandler:^{ + [app endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }]; + // End the background task if it's still valid. + [app endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m new file mode 100644 index 0000000..7e53456 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m @@ -0,0 +1,118 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h" + +@implementation GDTCORLifecycle + ++ (void)load { + [self sharedInstance]; +} + +/** Creates/returns the singleton instance of this class. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance { + static GDTCORLifecycle *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCORLifecycle alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(applicationDidEnterBackgroundNotification:) + name:kGDTCORApplicationDidEnterBackgroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(applicationWillEnterForegroundNotification:) + name:kGDTCORApplicationWillEnterForegroundNotification + object:nil]; + + [notificationCenter addObserver:self + selector:@selector(applicationWillTerminateNotification:) + name:kGDTCORApplicationWillTerminateNotification + object:nil]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)applicationDidEnterBackgroundNotification:(NSNotification *)notification { + GDTCORApplication *application = [GDTCORApplication sharedApplication]; + if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillBackground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORTransformer that the app is backgrounding."); + [[GDTCORTransformer sharedInstance] appWillBackground:application]; + } + if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillBackground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORUploadCoordinator that the app is backgrounding."); + [[GDTCORUploadCoordinator sharedInstance] appWillBackground:application]; + } + if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillBackground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORRegistrar that the app is backgrounding."); + [[GDTCORRegistrar sharedInstance] appWillBackground:application]; + } +} + +- (void)applicationWillEnterForegroundNotification:(NSNotification *)notification { + GDTCORApplication *application = [GDTCORApplication sharedApplication]; + if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillForeground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORTransformer that the app is foregrounding."); + [[GDTCORTransformer sharedInstance] appWillForeground:application]; + } + if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillForeground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORUploadCoordinator that the app is foregrounding."); + [[GDTCORUploadCoordinator sharedInstance] appWillForeground:application]; + } + if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillForeground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORRegistrar that the app is foregrounding."); + [[GDTCORRegistrar sharedInstance] appWillForeground:application]; + } +} + +- (void)applicationWillTerminateNotification:(NSNotification *)notification { + GDTCORApplication *application = [GDTCORApplication sharedApplication]; + if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORTransformer that the app is terminating."); + [[GDTCORTransformer sharedInstance] appWillTerminate:application]; + } + if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORUploadCoordinator that the app is terminating."); + [[GDTCORUploadCoordinator sharedInstance] appWillTerminate:application]; + } + if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORRegistrar that the app is terminating."); + [[GDTCORRegistrar sharedInstance] appWillTerminate:application]; + } +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLogSourceMetrics.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLogSourceMetrics.m new file mode 100644 index 0000000..9da40db --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLogSourceMetrics.m @@ -0,0 +1,184 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +static NSString *const kDroppedEventCounterByLogSource = @"droppedEventCounterByLogSource"; + +typedef NSDictionary GDTCORDroppedEventCounter; + +@interface GDTCORLogSourceMetrics () + +/// A dictionary of log sources that map to counters that reflect the number of events dropped for a +/// given set of reasons (``GDTCOREventDropReason``). +@property(nonatomic, readonly) + NSDictionary *droppedEventCounterByLogSource; + +@end + +@implementation GDTCORLogSourceMetrics + ++ (instancetype)metrics { + return [[self alloc] initWithDroppedEventCounterByLogSource:@{}]; +} + ++ (instancetype)metricsWithEvents:(NSArray *)events + droppedForReason:(GDTCOREventDropReason)reason { + NSMutableDictionary *eventCounterByLogSource = + [NSMutableDictionary dictionary]; + + for (GDTCOREvent *event in [events copy]) { + // Dropped events with a `nil` or empty mapping ID (log source) are not recorded. + if (event.mappingID.length == 0) { + continue; + } + + // Get the dropped event counter for the event's mapping ID (log source). + // If the dropped event counter for this event's mapping ID is `nil`, + // an empty mutable counter is returned. + NSMutableDictionary *eventCounter = [NSMutableDictionary + dictionaryWithDictionary:eventCounterByLogSource[event.mappingID] ?: @{}]; + + // Increment the log source metrics for the given reason. + NSInteger currentEventCountForReason = [eventCounter[@(reason)] integerValue]; + NSInteger updatedEventCountForReason = currentEventCountForReason + 1; + + eventCounter[@(reason)] = @(updatedEventCountForReason); + + // Update the mapping ID's (log source's) event counter with an immutable + // copy of the updated counter. + eventCounterByLogSource[event.mappingID] = [eventCounter copy]; + } + + return [[self alloc] initWithDroppedEventCounterByLogSource:[eventCounterByLogSource copy]]; +} + +- (instancetype)initWithDroppedEventCounterByLogSource: + (NSDictionary *)droppedEventCounterByLogSource { + self = [super init]; + if (self) { + _droppedEventCounterByLogSource = [droppedEventCounterByLogSource copy]; + } + return self; +} + +- (GDTCORLogSourceMetrics *)logSourceMetricsByMergingWithLogSourceMetrics: + (GDTCORLogSourceMetrics *)metrics { + // Create new log source metrics by merging the current metrics with the given metrics. + NSDictionary *mergedEventCounterByLogSource = [[self + class] dictionaryByMergingDictionary:self.droppedEventCounterByLogSource + withOtherDictionary:metrics.droppedEventCounterByLogSource + uniquingKeysWithBlock:^NSDictionary *(NSDictionary *eventCounter1, + NSDictionary *eventCounter2) { + return [[self class] + dictionaryByMergingDictionary:eventCounter1 + withOtherDictionary:eventCounter2 + uniquingKeysWithBlock:^NSNumber *(NSNumber *eventCount1, + NSNumber *eventCount2) { + return @(eventCount1.integerValue + eventCount2.integerValue); + }]; + }]; + + return + [[[self class] alloc] initWithDroppedEventCounterByLogSource:mergedEventCounterByLogSource]; +} + +/// Creates a new dictionary by merging together two given dictionaries. +/// @param dictionary A dictionary for merging. +/// @param otherDictionary Another dictionary for merging. +/// @param block A block that is called with the values for any duplicate keys that are encountered. +/// The block returns the desired value for the merged dictionary. ++ (NSDictionary *)dictionaryByMergingDictionary:(NSDictionary *)dictionary + withOtherDictionary:(NSDictionary *)otherDictionary + uniquingKeysWithBlock:(id (^)(id value1, id value2))block { + NSMutableDictionary *mergedDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary]; + + [otherDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if (mergedDictionary[key] != nil) { + // The key exists in both given dictionaries so combine the corresponding values with the + // given block. + id newValue = block(mergedDictionary[key], obj); + mergedDictionary[key] = newValue; + } else { + mergedDictionary[key] = obj; + } + }]; + + return [mergedDictionary copy]; +} + +#pragma mark - Equality + +- (BOOL)isEqualToLogSourceMetrics:(GDTCORLogSourceMetrics *)otherMetrics { + return [_droppedEventCounterByLogSource + isEqualToDictionary:otherMetrics.droppedEventCounterByLogSource]; +} + +- (BOOL)isEqual:(nullable id)object { + if (object == nil) { + return NO; + } + + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[self class]]) { + return NO; + } + + return [self isEqualToLogSourceMetrics:(GDTCORLogSourceMetrics *)object]; +} + +- (NSUInteger)hash { + return [_droppedEventCounterByLogSource hash]; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + NSDictionary *droppedEventCounterByLogSource = + [coder decodeObjectOfClasses: + [NSSet setWithArray:@[ NSDictionary.class, NSString.class, NSNumber.class ]] + forKey:kDroppedEventCounterByLogSource]; + + if (!droppedEventCounterByLogSource || + ![droppedEventCounterByLogSource isKindOfClass:[NSDictionary class]]) { + // If any of the fields are corrupted, the initializer should fail. + return nil; + } + + return [self initWithDroppedEventCounterByLogSource:droppedEventCounterByLogSource]; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { + [coder encodeObject:self.droppedEventCounterByLogSource forKey:kDroppedEventCounterByLogSource]; +} + +#pragma mark - Description + +- (NSString *)description { + return [NSString + stringWithFormat:@"%@ %@", [super description], self.droppedEventCounterByLogSource]; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetrics.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetrics.m new file mode 100644 index 0000000..ffbf0e1 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetrics.m @@ -0,0 +1,100 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h" + +@implementation GDTCORMetrics + +- (instancetype)initWithCollectionStartDate:(NSDate *)collectionStartDate + collectionEndDate:(NSDate *)collectionEndDate + logSourceMetrics:(GDTCORLogSourceMetrics *)logSourceMetrics + currentCacheSize:(GDTCORStorageSizeBytes)currentCacheSize + maxCacheSize:(GDTCORStorageSizeBytes)maxCacheSize + bundleID:(NSString *)bundleID { + self = [super init]; + if (self) { + _collectionStartDate = [collectionStartDate copy]; + _collectionEndDate = [collectionEndDate copy]; + _logSourceMetrics = logSourceMetrics; + _currentCacheSize = currentCacheSize; + _maxCacheSize = maxCacheSize; + _bundleID = [bundleID copy]; + } + return self; +} + ++ (instancetype)metricsWithMetricsMetadata:(GDTCORMetricsMetadata *)metricsMetadata + storageMetadata:(GDTCORStorageMetadata *)storageMetadata { + // The window of collection ends at the time of creating the metrics object. + NSDate *collectionEndDate = [NSDate date]; + // The main bundle ID is associated with the created metrics. + NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier] ?: @""; + + return [[GDTCORMetrics alloc] initWithCollectionStartDate:metricsMetadata.collectionStartDate + collectionEndDate:collectionEndDate + logSourceMetrics:metricsMetadata.logSourceMetrics + currentCacheSize:storageMetadata.currentCacheSize + maxCacheSize:storageMetadata.maxCacheSize + bundleID:bundleID]; +} + +#pragma mark - Equality + +- (BOOL)isEqualToMetrics:(GDTCORMetrics *)otherMetrics { + return [self.collectionStartDate isEqualToDate:otherMetrics.collectionStartDate] && + [self.collectionEndDate isEqualToDate:otherMetrics.collectionEndDate] && + [self.logSourceMetrics isEqualToLogSourceMetrics:otherMetrics.logSourceMetrics] && + [self.bundleID isEqualToString:otherMetrics.bundleID] && + self.currentCacheSize == otherMetrics.currentCacheSize && + self.maxCacheSize == otherMetrics.maxCacheSize; +} + +- (BOOL)isEqual:(nullable id)object { + if (object == nil) { + return NO; + } + + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[self class]]) { + return NO; + } + + return [self isEqualToMetrics:(GDTCORMetrics *)object]; +} + +- (NSUInteger)hash { + return [self.collectionStartDate hash] ^ [self.collectionEndDate hash] ^ + [self.logSourceMetrics hash] ^ [self.bundleID hash] ^ [@(self.currentCacheSize) hash] ^ + [@(self.maxCacheSize) hash]; +} + +#pragma mark - Description + +- (NSString *)description { + return [NSString + stringWithFormat: + @"%@ {\n\tcollectionStartDate: %@,\n\tcollectionEndDate: %@,\n\tcurrentCacheSize: " + @"%llu,\n\tmaxCacheSize: %llu,\n\tbundleID: %@,\n\tlogSourceMetrics: %@}\n", + [super description], self.collectionStartDate, self.collectionEndDate, + self.currentCacheSize, self.maxCacheSize, self.bundleID, self.logSourceMetrics]; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsController.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsController.m new file mode 100644 index 0000000..2978da7 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsController.m @@ -0,0 +1,201 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsController.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h" + +@interface GDTCORMetricsController () +/// The underlying storage object where metrics are stored. +@property(nonatomic) id storage; + +@end + +@implementation GDTCORMetricsController + ++ (void)load { +#if GDT_TEST + [[GDTCORRegistrar sharedInstance] registerMetricsController:[self sharedInstance] + target:kGDTCORTargetTest]; +#endif // GDT_TEST + // Only the Firelog backend supports metrics collection. + [[GDTCORRegistrar sharedInstance] registerMetricsController:[self sharedInstance] + target:kGDTCORTargetCSH]; + [[GDTCORRegistrar sharedInstance] registerMetricsController:[self sharedInstance] + target:kGDTCORTargetFLL]; +} + ++ (instancetype)sharedInstance { + static id sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] initWithStorage:[GDTCORFlatFileStorage sharedInstance]]; + }); + return sharedInstance; +} + +- (instancetype)initWithStorage:(id)storage { + self = [super init]; + if (self) { + _storage = storage; + } + return self; +} + +- (nonnull FBLPromise *)logEventsDroppedForReason:(GDTCOREventDropReason)reason + events:(nonnull NSSet *)events { + // No-op if there are no events to log. + if ([events count] == 0) { + return [FBLPromise resolvedWith:nil]; + } + + __auto_type handler = ^GDTCORMetricsMetadata *(GDTCORMetricsMetadata *_Nullable metricsMetadata, + NSError *_Nullable fetchError) { + GDTCORLogSourceMetrics *logSourceMetrics = + [GDTCORLogSourceMetrics metricsWithEvents:[events allObjects] droppedForReason:reason]; + + if (metricsMetadata) { + GDTCORLogSourceMetrics *updatedLogSourceMetrics = [metricsMetadata.logSourceMetrics + logSourceMetricsByMergingWithLogSourceMetrics:logSourceMetrics]; + + return [GDTCORMetricsMetadata + metadataWithCollectionStartDate:[metricsMetadata collectionStartDate] + logSourceMetrics:updatedLogSourceMetrics]; + } else { + // There was an error (e.g. empty storage); `metricsMetadata` is nil. + GDTCORLogDebug(@"Error fetching metrics metadata: %@", fetchError); + return [GDTCORMetricsMetadata metadataWithCollectionStartDate:[NSDate date] + logSourceMetrics:logSourceMetrics]; + } + }; + + return [_storage fetchAndUpdateMetricsWithHandler:handler]; +} + +- (nonnull FBLPromise *)getAndResetMetrics { + __block GDTCORMetricsMetadata *_Nullable snapshottedMetricsMetadata = nil; + + __auto_type handler = ^GDTCORMetricsMetadata *(GDTCORMetricsMetadata *_Nullable metricsMetadata, + NSError *_Nullable fetchError) { + if (metricsMetadata) { + snapshottedMetricsMetadata = metricsMetadata; + } else { + GDTCORLogDebug(@"Error fetching metrics metadata: %@", fetchError); + } + return [GDTCORMetricsMetadata metadataWithCollectionStartDate:[NSDate date] + logSourceMetrics:[GDTCORLogSourceMetrics metrics]]; + }; + + return [_storage fetchAndUpdateMetricsWithHandler:handler] + .validate(^BOOL(NSNull *__unused _) { + // Break and reject the promise chain when storage contains no metrics + // metadata. + return snapshottedMetricsMetadata != nil; + }) + .then(^FBLPromise *(NSNull *__unused _) { + // Fetch and return storage metadata (needed for metrics). + return [self.storage fetchStorageMetadata]; + }) + .then(^GDTCORMetrics *(GDTCORStorageMetadata *storageMetadata) { + // Use the fetched metrics & storage metadata to create and return a + // complete metrics object. + return [GDTCORMetrics metricsWithMetricsMetadata:snapshottedMetricsMetadata + storageMetadata:storageMetadata]; + }); +} + +- (nonnull FBLPromise *)offerMetrics:(nonnull GDTCORMetrics *)metrics { + // No-op if there are no metrics to offer. + if (metrics == nil) { + return [FBLPromise resolvedWith:nil]; + } + + __auto_type handler = ^GDTCORMetricsMetadata *(GDTCORMetricsMetadata *_Nullable metricsMetadata, + NSError *_Nullable fetchError) { + if (metricsMetadata) { + if (metrics.collectionStartDate.timeIntervalSince1970 <= + metricsMetadata.collectionStartDate.timeIntervalSince1970) { + // If the metrics to append are older than the metrics represented by + // the currently stored metrics, then return a new metadata object that + // incorporates the data from the given metrics. + return [GDTCORMetricsMetadata + metadataWithCollectionStartDate:[metrics collectionStartDate] + logSourceMetrics:[metricsMetadata.logSourceMetrics + logSourceMetricsByMergingWithLogSourceMetrics: + metrics.logSourceMetrics]]; + } else { + // This catches an edge case where the given metrics to append are + // newer than metrics represented by the currently stored metrics + // metadata. In this case, return the existing metadata object as the + // given metrics are assumed to already be accounted for by the + // currently stored metadata. + return metricsMetadata; + } + } else { + // There was an error (e.g. empty storage); `metricsMetadata` is nil. + GDTCORLogDebug(@"Error fetching metrics metadata: %@", fetchError); + + NSDate *now = [NSDate date]; + if (metrics.collectionStartDate.timeIntervalSince1970 <= now.timeIntervalSince1970) { + // The given metrics are were recorded up until now. They wouldn't + // be offered if they were successfully uploaded so their + // corresponding metadata can be safely placed back in storage. + return [GDTCORMetricsMetadata metadataWithCollectionStartDate:metrics.collectionStartDate + logSourceMetrics:metrics.logSourceMetrics]; + } else { + // This catches an edge case where the given metrics are from the + // future. If this occurs, ignore them and store an empty metadata + // object intended to track metrics metadata from this time forward. + return [GDTCORMetricsMetadata + metadataWithCollectionStartDate:[NSDate date] + logSourceMetrics:[GDTCORLogSourceMetrics metrics]]; + } + } + }; + + return [_storage fetchAndUpdateMetricsWithHandler:handler]; +} + +#pragma mark - GDTCORStorageDelegate + +- (void)storage:(id)storage + didRemoveExpiredEvents:(nonnull NSSet *)events { + [self logEventsDroppedForReason:GDTCOREventDropReasonMessageTooOld events:events]; +} + +- (void)storage:(nonnull id)storage + didDropEvent:(nonnull GDTCOREvent *)event { + [self logEventsDroppedForReason:GDTCOREventDropReasonStorageFull + events:[NSSet setWithObject:event]]; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsMetadata.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsMetadata.m new file mode 100644 index 0000000..624c8c5 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsMetadata.m @@ -0,0 +1,96 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" + +static NSString *const kCollectionStartDate = @"collectionStartDate"; +static NSString *const kLogSourceMetrics = @"logSourceMetrics"; + +@implementation GDTCORMetricsMetadata + ++ (instancetype)metadataWithCollectionStartDate:(NSDate *)collectedSinceDate + logSourceMetrics:(GDTCORLogSourceMetrics *)logSourceMetrics { + return [[self alloc] initWithCollectionStartDate:collectedSinceDate + logSourceMetrics:logSourceMetrics]; +} + +- (instancetype)initWithCollectionStartDate:(NSDate *)collectionStartDate + logSourceMetrics:(GDTCORLogSourceMetrics *)logSourceMetrics { + self = [super init]; + if (self) { + _collectionStartDate = [collectionStartDate copy]; + _logSourceMetrics = logSourceMetrics; + } + return self; +} + +#pragma mark - Equality + +- (BOOL)isEqualToMetricsMetadata:(GDTCORMetricsMetadata *)otherMetricsMetadata { + return [self.collectionStartDate isEqualToDate:otherMetricsMetadata.collectionStartDate] && + [self.logSourceMetrics isEqualToLogSourceMetrics:otherMetricsMetadata.logSourceMetrics]; +} + +- (BOOL)isEqual:(nullable id)object { + if (object == nil) { + return NO; + } + + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[self class]]) { + return NO; + } + + return [self isEqualToMetricsMetadata:(GDTCORMetricsMetadata *)object]; +} + +- (NSUInteger)hash { + return [self.collectionStartDate hash] ^ [self.logSourceMetrics hash]; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + NSDate *collectionStartDate = [coder decodeObjectOfClass:[NSDate class] + forKey:kCollectionStartDate]; + GDTCORLogSourceMetrics *logSourceMetrics = + [coder decodeObjectOfClass:[GDTCORLogSourceMetrics class] forKey:kLogSourceMetrics]; + + if (!collectionStartDate || !logSourceMetrics || + ![collectionStartDate isKindOfClass:[NSDate class]] || + ![logSourceMetrics isKindOfClass:[GDTCORLogSourceMetrics class]]) { + // If any of the fields are corrupted, the initializer should fail. + return nil; + } + + return [self initWithCollectionStartDate:collectionStartDate logSourceMetrics:logSourceMetrics]; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { + [coder encodeObject:self.collectionStartDate forKey:kCollectionStartDate]; + [coder encodeObject:self.logSourceMetrics forKey:kLogSourceMetrics]; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m new file mode 100644 index 0000000..0729bde --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m @@ -0,0 +1,566 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +#ifdef GDTCOR_VERSION +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x +NSString *const kGDTCORVersion = @STR(GDTCOR_VERSION); +#else +NSString *const kGDTCORVersion = @"Unknown"; +#endif // GDTCOR_VERSION + +const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid = 0; + +NSString *const kGDTCORApplicationDidEnterBackgroundNotification = + @"GDTCORApplicationDidEnterBackgroundNotification"; + +NSString *const kGDTCORApplicationWillEnterForegroundNotification = + @"GDTCORApplicationWillEnterForegroundNotification"; + +NSString *const kGDTCORApplicationWillTerminateNotification = + @"GDTCORApplicationWillTerminateNotification"; + +NSURL *GDTCORRootDirectory(void) { + static NSURL *GDTPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *cachePath = + NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; + GDTPath = + [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/google-sdks-events", cachePath]]; + GDTCORLogDebug(@"GDT's state will be saved to: %@", GDTPath); + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:GDTPath.path + withIntermediateDirectories:YES + attributes:nil + error:&error]; + GDTCORAssert(error == nil, @"There was an error creating GDT's path"); + return GDTPath; +} + +BOOL GDTCORReachabilityFlagsReachable(GDTCORNetworkReachabilityFlags flags) { +#if !TARGET_OS_WATCH + BOOL reachable = + (flags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable; + BOOL connectionRequired = (flags & kSCNetworkReachabilityFlagsConnectionRequired) == + kSCNetworkReachabilityFlagsConnectionRequired; + return reachable && !connectionRequired; +#else + return (flags & kGDTCORNetworkReachabilityFlagsReachable) == + kGDTCORNetworkReachabilityFlagsReachable; +#endif +} + +BOOL GDTCORReachabilityFlagsContainWWAN(GDTCORNetworkReachabilityFlags flags) { +#if TARGET_OS_IOS + return (flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN; +#else + // Assume network connection not WWAN on macOS, tvOS, watchOS. + return NO; +#endif // TARGET_OS_IOS +} + +GDTCORNetworkType GDTCORNetworkTypeMessage(void) { +#if !TARGET_OS_WATCH + SCNetworkReachabilityFlags reachabilityFlags = [GDTCORReachability currentFlags]; + if ((reachabilityFlags & kSCNetworkReachabilityFlagsReachable) == + kSCNetworkReachabilityFlagsReachable) { + if (GDTCORReachabilityFlagsContainWWAN(reachabilityFlags)) { + return GDTCORNetworkTypeMobile; + } else { + return GDTCORNetworkTypeWIFI; + } + } +#endif + return GDTCORNetworkTypeUNKNOWN; +} + +GDTCORNetworkMobileSubtype GDTCORNetworkMobileSubTypeMessage(void) { +// TODO(Xcode 15): When Xcode 15 is the minimum supported Xcode version, +// it will be unnecessary to check if `TARGET_OS_VISION` is defined. +#if TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION) + static NSDictionary *CTRadioAccessTechnologyToNetworkSubTypeMessage; + static CTTelephonyNetworkInfo *networkInfo; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + CTRadioAccessTechnologyToNetworkSubTypeMessage = @{ + CTRadioAccessTechnologyGPRS : @(GDTCORNetworkMobileSubtypeGPRS), + CTRadioAccessTechnologyEdge : @(GDTCORNetworkMobileSubtypeEdge), + CTRadioAccessTechnologyWCDMA : @(GDTCORNetworkMobileSubtypeWCDMA), + CTRadioAccessTechnologyHSDPA : @(GDTCORNetworkMobileSubtypeHSDPA), + CTRadioAccessTechnologyHSUPA : @(GDTCORNetworkMobileSubtypeHSUPA), + CTRadioAccessTechnologyCDMA1x : @(GDTCORNetworkMobileSubtypeCDMA1x), + CTRadioAccessTechnologyCDMAEVDORev0 : @(GDTCORNetworkMobileSubtypeCDMAEVDORev0), + CTRadioAccessTechnologyCDMAEVDORevA : @(GDTCORNetworkMobileSubtypeCDMAEVDORevA), + CTRadioAccessTechnologyCDMAEVDORevB : @(GDTCORNetworkMobileSubtypeCDMAEVDORevB), + CTRadioAccessTechnologyeHRPD : @(GDTCORNetworkMobileSubtypeHRPD), + CTRadioAccessTechnologyLTE : @(GDTCORNetworkMobileSubtypeLTE), + }; + networkInfo = [[CTTelephonyNetworkInfo alloc] init]; + }); + NSString *networkCurrentRadioAccessTechnology; +#if TARGET_OS_MACCATALYST + NSDictionary *networkCurrentRadioAccessTechnologyDict = + networkInfo.serviceCurrentRadioAccessTechnology; + if (networkCurrentRadioAccessTechnologyDict.count) { + networkCurrentRadioAccessTechnology = networkCurrentRadioAccessTechnologyDict.allValues[0]; + } +#else // TARGET_OS_MACCATALYST + NSDictionary *networkCurrentRadioAccessTechnologyDict = + networkInfo.serviceCurrentRadioAccessTechnology; + if (networkCurrentRadioAccessTechnologyDict.count) { + // In iOS 12, multiple radio technologies can be captured. We prefer not particular radio + // tech to another, so we'll just return the first value in the dictionary. + networkCurrentRadioAccessTechnology = networkCurrentRadioAccessTechnologyDict.allValues[0]; + } +#endif // TARGET_OS_MACCATALYST + if (networkCurrentRadioAccessTechnology) { + NSNumber *networkMobileSubtype = + CTRadioAccessTechnologyToNetworkSubTypeMessage[networkCurrentRadioAccessTechnology]; + return networkMobileSubtype.intValue; + } else { + return GDTCORNetworkMobileSubtypeUNKNOWN; + } +#else // TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION) + return GDTCORNetworkMobileSubtypeUNKNOWN; +#endif // TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION) +} + +NSString *_Nonnull GDTCORDeviceModel(void) { + static NSString *deviceModel = @"Unknown"; + +#if TARGET_OS_IOS || TARGET_OS_TV + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + size_t size; + char *keyToExtract = "hw.machine"; + sysctlbyname(keyToExtract, NULL, &size, NULL, 0); + if (size > 0) { + char *machine = calloc(1, size); + sysctlbyname(keyToExtract, machine, &size, NULL, 0); + deviceModel = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding]; + free(machine); + } else { + deviceModel = [UIDevice currentDevice].model; + } + }); +#endif + + return deviceModel; +} + +NSData *_Nullable GDTCOREncodeArchive(id obj, + NSString *filePath, + NSError *_Nullable *error) { + BOOL result = NO; + if (filePath.length > 0) { + // TODO(ncooke3): For future cleanupโ€“ this API shouldn't touch the file + // system unless it successfully encoded the given object. + result = [[NSFileManager defaultManager] + createDirectoryAtPath:[filePath stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:error]; + if (result == NO || *error) { + GDTCORLogDebug(@"Attempt to create directory failed: path:%@ error:%@", filePath, *error); + return nil; + } + } + NSData *resultData; + resultData = [NSKeyedArchiver archivedDataWithRootObject:obj + requiringSecureCoding:YES + error:error]; + if (resultData == nil || (error != NULL && *error != nil)) { + GDTCORLogDebug(@"Encoding an object failed: %@", *error); + return nil; + } + if (filePath.length > 0) { + result = [resultData writeToFile:filePath options:NSDataWritingAtomic error:error]; + if (result == NO || (error != NULL && *error != nil)) { + if (error != NULL && *error != nil) { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@ error:%@", filePath, *error); + } else { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@", filePath); + } + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + } + } + return resultData; +} + +id _Nullable GDTCORDecodeArchiveAtPath(Class archiveClass, + NSString *_Nonnull archivePath, + NSError **_Nonnull error) { + NSData *data = [NSData dataWithContentsOfFile:archivePath options:0 error:error]; + if (data == nil) { + // Reading the file failed and `error` will be populated. + return nil; + } + + return GDTCORDecodeArchive(archiveClass, data, error); +} + +id _Nullable GDTCORDecodeArchive(Class archiveClass, + NSData *_Nonnull archiveData, + NSError **_Nonnull error) { + return [NSKeyedUnarchiver unarchivedObjectOfClass:archiveClass fromData:archiveData error:error]; +} + +BOOL GDTCORWriteDataToFile(NSData *data, NSString *filePath, NSError *_Nullable *outError) { + BOOL result = NO; + if (filePath.length > 0) { + result = [[NSFileManager defaultManager] + createDirectoryAtPath:[filePath stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:outError]; + if (result == NO || *outError) { + GDTCORLogDebug(@"Attempt to create directory failed: path:%@ error:%@", filePath, *outError); + return result; + } + } + + if (filePath.length > 0) { + result = [data writeToFile:filePath options:NSDataWritingAtomic error:outError]; + if (result == NO || *outError) { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@ error:%@", filePath, *outError); + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + } + } + + return result; +} + +@interface GDTCORApplication () +/** + Private flag to match the existing `readonly` public flag. This will be accurate for all platforms, + since we handle each platform's lifecycle notifications separately. + */ +@property(atomic, readwrite) BOOL isRunningInBackground; + +@end + +@implementation GDTCORApplication + +#if TARGET_OS_WATCH +/** A dispatch queue on which all task semaphores will populate and remove from + * gBackgroundIdentifierToSemaphoreMap. + */ +static dispatch_queue_t gSemaphoreQueue; + +/** For mapping backgroundIdentifier to task semaphore. */ +static NSMutableDictionary *gBackgroundIdentifierToSemaphoreMap; +#endif + ++ (void)load { + GDTCORLogDebug( + @"%@", @"GDT is initializing. Please note that if you quit the app via the " + "debugger and not through a lifecycle event, event data will remain on disk but " + "storage won't have a reference to them since the singleton wasn't saved to disk."); +#if TARGET_OS_IOS || TARGET_OS_TV + // If this asserts, please file a bug at https://github.com/firebase/firebase-ios-sdk/issues. + GDTCORFatalAssert( + GDTCORBackgroundIdentifierInvalid == UIBackgroundTaskInvalid, + @"GDTCORBackgroundIdentifierInvalid and UIBackgroundTaskInvalid should be the same."); +#endif + [self sharedApplication]; +} + ++ (void)initialize { +#if TARGET_OS_WATCH + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSemaphoreQueue = dispatch_queue_create("com.google.GDTCORApplication", DISPATCH_QUEUE_SERIAL); + GDTCORLogDebug( + @"%@", + @"GDTCORApplication is initializing on watchOS, gSemaphoreQueue has been initialized."); + gBackgroundIdentifierToSemaphoreMap = [[NSMutableDictionary alloc] init]; + GDTCORLogDebug(@"%@", @"GDTCORApplication is initializing on watchOS, " + @"gBackgroundIdentifierToSemaphoreMap has been initialized."); + }); +#endif +} + ++ (nullable GDTCORApplication *)sharedApplication { + static GDTCORApplication *application; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + application = [[GDTCORApplication alloc] init]; + }); + return application; +} + +- (instancetype)init { + self = [super init]; + if (self) { + // This class will be instantiated in the foreground. + _isRunningInBackground = NO; + +#if TARGET_OS_IOS || TARGET_OS_TV + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + + NSString *name = UIApplicationWillTerminateNotification; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillTerminate:) + name:name + object:nil]; + +#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 + if (@available(iOS 13, tvOS 13.0, *)) { + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:UISceneWillEnterForegroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:UISceneWillDeactivateNotification + object:nil]; + } +#endif // defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 + +#elif TARGET_OS_OSX + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(macOSApplicationWillTerminate:) + name:NSApplicationWillTerminateNotification + object:nil]; + +#elif TARGET_OS_WATCH + // TODO: Notification on watchOS platform is currently posted by strings which are frangible. + // TODO: Needs improvements here. + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:@"UIApplicationDidEnterBackgroundNotification" + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:@"UIApplicationWillEnterForegroundNotification" + object:nil]; + + // Adds observers for app extension on watchOS platform + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:NSExtensionHostDidEnterBackgroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:NSExtensionHostWillEnterForegroundNotification + object:nil]; +#endif + } + return self; +} + +#if TARGET_OS_WATCH +/** Generates and maps a unique background identifier to the given semaphore. + * + * @param semaphore The semaphore to map. + * @return A unique GDTCORBackgroundIdentifier mapped to the given semaphore. + */ ++ (GDTCORBackgroundIdentifier)createAndMapBackgroundIdentifierToSemaphore: + (dispatch_semaphore_t)semaphore { + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; + dispatch_queue_t queue = gSemaphoreQueue; + NSMutableDictionary *map = gBackgroundIdentifierToSemaphoreMap; + if (queue && map) { + dispatch_sync(queue, ^{ + bgID = arc4random(); + NSNumber *bgIDNumber = @(bgID); + while (bgID == GDTCORBackgroundIdentifierInvalid || map[bgIDNumber]) { + bgID = arc4random(); + bgIDNumber = @(bgID); + } + map[bgIDNumber] = semaphore; + }); + } + return bgID; +} + +/** Returns the semaphore mapped to given bgID and removes the value from the map. + * + * @param bgID The unique NSUInteger as GDTCORBackgroundIdentifier. + * @return The semaphore mapped by given bgID. + */ ++ (dispatch_semaphore_t)semaphoreForBackgroundIdentifier:(GDTCORBackgroundIdentifier)bgID { + __block dispatch_semaphore_t semaphore; + dispatch_queue_t queue = gSemaphoreQueue; + NSMutableDictionary *map = gBackgroundIdentifierToSemaphoreMap; + NSNumber *bgIDNumber = @(bgID); + if (queue && map) { + dispatch_sync(queue, ^{ + semaphore = map[bgIDNumber]; + [map removeObjectForKey:bgIDNumber]; + }); + } + return semaphore; +} +#endif + +- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name + expirationHandler:(void (^)(void))handler { + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; +#if !TARGET_OS_WATCH + bgID = [[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithName:name + expirationHandler:handler]; +#if !NDEBUG + if (bgID != GDTCORBackgroundIdentifierInvalid) { + GDTCORLogDebug(@"Creating background task with name:%@ bgID:%ld", name, (long)bgID); + } +#endif // !NDEBUG +#elif TARGET_OS_WATCH + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + bgID = [GDTCORApplication createAndMapBackgroundIdentifierToSemaphore:semaphore]; + if (bgID != GDTCORBackgroundIdentifierInvalid) { + GDTCORLogDebug(@"Creating activity with name:%@ bgID:%ld on watchOS.", name, (long)bgID); + } + [[self sharedNSProcessInfoForBackgroundTask] + performExpiringActivityWithReason:name + usingBlock:^(BOOL expired) { + if (expired) { + if (handler) { + handler(); + } + dispatch_semaphore_signal(semaphore); + GDTCORLogDebug( + @"Activity with name:%@ bgID:%ld on watchOS is expiring.", + name, (long)bgID); + } else { + dispatch_semaphore_wait( + semaphore, + dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC)); + } + }]; +#endif + return bgID; +} + +- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID { +#if !TARGET_OS_WATCH + if (bgID != GDTCORBackgroundIdentifierInvalid) { + GDTCORLogDebug(@"Ending background task with ID:%ld was successful", (long)bgID); + [[self sharedApplicationForBackgroundTask] endBackgroundTask:bgID]; + return; + } +#elif TARGET_OS_WATCH + if (bgID != GDTCORBackgroundIdentifierInvalid) { + dispatch_semaphore_t semaphore = [GDTCORApplication semaphoreForBackgroundIdentifier:bgID]; + GDTCORLogDebug(@"Ending activity with bgID:%ld on watchOS.", (long)bgID); + if (semaphore) { + dispatch_semaphore_signal(semaphore); + GDTCORLogDebug(@"Signaling semaphore with bgID:%ld on watchOS.", (long)bgID); + } else { + GDTCORLogDebug(@"Semaphore with bgID:%ld is nil on watchOS.", (long)bgID); + } + } +#endif // !TARGET_OS_WATCH +} + +#pragma mark - App environment helpers + +- (BOOL)isAppExtension { + BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + return appExtension; +} + +/** Returns a UIApplication or NSProcessInfo instance if on the appropriate platform. + * + * @return The shared UIApplication or NSProcessInfo if on the appropriate platform. + */ +#if TARGET_OS_IOS || TARGET_OS_TV +- (nullable UIApplication *)sharedApplicationForBackgroundTask { +#elif TARGET_OS_WATCH +- (nullable NSProcessInfo *)sharedNSProcessInfoForBackgroundTask { +#else +- (nullable id)sharedApplicationForBackgroundTask { +#endif + id sharedInstance = nil; +#if TARGET_OS_IOS || TARGET_OS_TV + if (![self isAppExtension]) { + Class uiApplicationClass = NSClassFromString(@"UIApplication"); + if (uiApplicationClass && + [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) { + sharedInstance = [uiApplicationClass sharedApplication]; + } + } +#elif TARGET_OS_WATCH + sharedInstance = [NSProcessInfo processInfo]; +#endif + return sharedInstance; +} + +#pragma mark - UIApplicationDelegate and WKExtensionDelegate + +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH +- (void)iOSApplicationDidEnterBackground:(NSNotification *)notif { + _isRunningInBackground = YES; + + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is backgrounding."); + [notifCenter postNotificationName:kGDTCORApplicationDidEnterBackgroundNotification object:nil]; +} + +- (void)iOSApplicationWillEnterForeground:(NSNotification *)notif { + _isRunningInBackground = NO; + + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is foregrounding."); + [notifCenter postNotificationName:kGDTCORApplicationWillEnterForegroundNotification object:nil]; +} +#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + +#pragma mark - UIApplicationDelegate + +#if TARGET_OS_IOS || TARGET_OS_TV +- (void)iOSApplicationWillTerminate:(NSNotification *)notif { + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is terminating."); + [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil]; +} +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#pragma mark - NSApplicationDelegate + +#if TARGET_OS_OSX +- (void)macOSApplicationWillTerminate:(NSNotification *)notif { + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is terminating."); + [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil]; +} +#endif // TARGET_OS_OSX + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORProductData.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORProductData.m new file mode 100644 index 0000000..5e15e8f --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORProductData.m @@ -0,0 +1,77 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h" + +@implementation GDTCORProductData + +- (instancetype)initWithProductID:(int32_t)productID { + self = [super init]; + if (self) { + _productID = productID; + } + return self; +} + +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + return [[[self class] alloc] initWithProductID:self.productID]; +} + +#pragma mark - Equality + +- (BOOL)isEqualToProductData:(GDTCORProductData *)otherProductData { + return self.productID == otherProductData.productID; +} + +- (BOOL)isEqual:(nullable id)object { + if (object == nil) { + return NO; + } + + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[self class]]) { + return NO; + } + + return [self isEqualToProductData:(GDTCORProductData *)object]; +} + +- (NSUInteger)hash { + return self.productID; +} + +#pragma mark - NSSecureCoding + +/// NSCoding key for `productID` property. +static NSString *kProductIDKey = @"GDTCORProductDataProductIDKey"; + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + int32_t productID = [coder decodeInt32ForKey:kProductIDKey]; + return [self initWithProductID:productID]; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { + [coder encodeInt32:self.productID forKey:kProductIDKey]; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m new file mode 100644 index 0000000..43811e6 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m @@ -0,0 +1,125 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import + +/** Sets the _callbackFlag ivar whenever the network changes. + * + * @param reachability The reachability object calling back. + * @param flags The new flag values. + * @param info Any data that might be passed in by the callback. + */ +static void GDTCORReachabilityCallback(GDTCORNetworkReachabilityRef reachability, + GDTCORNetworkReachabilityFlags flags, + void *info); + +@implementation GDTCORReachability { + /** The reachability object. */ + GDTCORNetworkReachabilityRef _reachabilityRef; + + /** The queue on which callbacks and all work will occur. */ + dispatch_queue_t _reachabilityQueue; + + /** Flags specified by reachability callbacks. */ + GDTCORNetworkReachabilityFlags _callbackFlags; +} + ++ (void)initialize { + [self sharedInstance]; +} + ++ (instancetype)sharedInstance { + static GDTCORReachability *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCORReachability alloc] init]; + }); + return sharedInstance; +} + ++ (GDTCORNetworkReachabilityFlags)currentFlags { + __block GDTCORNetworkReachabilityFlags currentFlags; +#if !TARGET_OS_WATCH + dispatch_sync([GDTCORReachability sharedInstance] -> _reachabilityQueue, ^{ + GDTCORReachability *reachability = [GDTCORReachability sharedInstance]; + currentFlags = + reachability->_callbackFlags ? reachability->_callbackFlags : reachability->_flags; + GDTCORLogDebug(@"Initial reachability flags determined: %d", currentFlags); + }); +#else + currentFlags = kGDTCORNetworkReachabilityFlagsReachable; +#endif + return currentFlags; +} + +- (instancetype)init { + self = [super init]; +#if !TARGET_OS_WATCH + if (self) { + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + _reachabilityQueue = + dispatch_queue_create("com.google.GDTCORReachability", DISPATCH_QUEUE_SERIAL); + _reachabilityRef = SCNetworkReachabilityCreateWithAddress( + kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress); + Boolean success = SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _reachabilityQueue); + if (!success) { + GDTCORLogWarning(GDTCORMCWReachabilityFailed, @"%@", @"The reachability queue wasn't set."); + } + success = SCNetworkReachabilitySetCallback(_reachabilityRef, GDTCORReachabilityCallback, NULL); + if (!success) { + GDTCORLogWarning(GDTCORMCWReachabilityFailed, @"%@", + @"The reachability callback wasn't set."); + } + + // Get the initial set of flags. + dispatch_async(_reachabilityQueue, ^{ + Boolean valid = SCNetworkReachabilityGetFlags(self->_reachabilityRef, &self->_flags); + if (!valid) { + GDTCORLogDebug(@"%@", @"Determining reachability failed."); + self->_flags = 0; + } + }); + } +#endif + return self; +} + +- (void)setCallbackFlags:(GDTCORNetworkReachabilityFlags)flags { + if (_callbackFlags != flags) { + self->_callbackFlags = flags; + } +} + +@end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +static void GDTCORReachabilityCallback(GDTCORNetworkReachabilityRef reachability, + GDTCORNetworkReachabilityFlags flags, + void *info) { +#pragma clang diagnostic pop + GDTCORLogDebug(@"Reachability changed, new flags: %d", flags); + [[GDTCORReachability sharedInstance] setCallbackFlags:flags]; +} diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m new file mode 100644 index 0000000..5aefd6c --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m @@ -0,0 +1,194 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +id _Nullable GDTCORStorageInstanceForTarget(GDTCORTarget target) { + return [GDTCORRegistrar sharedInstance].targetToStorage[@(target)]; +} + +id _Nullable GDTCORStoragePromiseInstanceForTarget( + GDTCORTarget target) { + id storage = [GDTCORRegistrar sharedInstance].targetToStorage[@(target)]; + if ([storage conformsToProtocol:@protocol(GDTCORStoragePromiseProtocol)]) { + return storage; + } else { + return nil; + } +} + +id _Nullable GDTCORMetricsControllerInstanceForTarget( + GDTCORTarget target) { + return [GDTCORRegistrar sharedInstance].targetToMetricsController[@(target)]; +} + +@implementation GDTCORRegistrar + +// Manaully synthesize properties declared in `GDTCORRegistrar_Private.h` category. +@synthesize targetToUploader = _targetToUploader; +@synthesize targetToStorage = _targetToStorage; +@synthesize targetToMetricsController = _targetToMetricsController; + ++ (instancetype)sharedInstance { + static GDTCORRegistrar *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCORRegistrar alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _registrarQueue = dispatch_queue_create("com.google.GDTCORRegistrar", DISPATCH_QUEUE_SERIAL); + _targetToUploader = [NSMutableDictionary dictionary]; + _targetToStorage = [NSMutableDictionary dictionary]; + _targetToMetricsController = [NSMutableDictionary dictionary]; + } + return self; +} + +- (void)registerUploader:(id)backend target:(GDTCORTarget)target { + __weak GDTCORRegistrar *weakSelf = self; + dispatch_async(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + GDTCORLogDebug(@"Registered an uploader: %@ for target:%ld", backend, (long)target); + strongSelf->_targetToUploader[@(target)] = backend; + } + }); +} + +- (void)registerStorage:(id)storage target:(GDTCORTarget)target { + __weak GDTCORRegistrar *weakSelf = self; + dispatch_async(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + GDTCORLogDebug(@"Registered storage: %@ for target:%ld", storage, (long)target); + strongSelf->_targetToStorage[@(target)] = storage; + [self setMetricsControllerAsStorageDelegateForTarget:target]; + } + }); +} + +- (void)registerMetricsController:(id)metricsController + target:(GDTCORTarget)target { + __weak GDTCORRegistrar *weakSelf = self; + dispatch_async(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + GDTCORLogDebug(@"Registered metrics controller: %@ for target:%ld", metricsController, + (long)target); + strongSelf->_targetToMetricsController[@(target)] = metricsController; + [self setMetricsControllerAsStorageDelegateForTarget:target]; + } + }); +} + +- (NSMutableDictionary> *)targetToUploader { + __block NSMutableDictionary> *targetToUploader; + __weak GDTCORRegistrar *weakSelf = self; + dispatch_sync(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + targetToUploader = strongSelf->_targetToUploader; + } + }); + return targetToUploader; +} + +- (NSMutableDictionary> *)targetToStorage { + __block NSMutableDictionary> *targetToStorage; + __weak GDTCORRegistrar *weakSelf = self; + dispatch_sync(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + targetToStorage = strongSelf->_targetToStorage; + } + }); + return targetToStorage; +} + +- (NSMutableDictionary> *) + targetToMetricsController { + __block NSMutableDictionary> + *targetToMetricsController; + __weak GDTCORRegistrar *weakSelf = self; + dispatch_sync(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + targetToMetricsController = strongSelf->_targetToMetricsController; + } + }); + return targetToMetricsController; +} + +- (void)setMetricsControllerAsStorageDelegateForTarget:(GDTCORTarget)target { + _targetToStorage[@(target)].delegate = _targetToMetricsController[@(target)]; +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillBackground:(nonnull GDTCORApplication *)app { + NSArray> *uploaders = [self.targetToUploader allValues]; + for (id uploader in uploaders) { + if ([uploader respondsToSelector:@selector(appWillBackground:)]) { + [uploader appWillBackground:app]; + } + } + NSArray> *storages = [self.targetToStorage allValues]; + for (id storage in storages) { + if ([storage respondsToSelector:@selector(appWillBackground:)]) { + [storage appWillBackground:app]; + } + } +} + +- (void)appWillForeground:(nonnull GDTCORApplication *)app { + NSArray> *uploaders = [self.targetToUploader allValues]; + for (id uploader in uploaders) { + if ([uploader respondsToSelector:@selector(appWillForeground:)]) { + [uploader appWillForeground:app]; + } + } + NSArray> *storages = [self.targetToStorage allValues]; + for (id storage in storages) { + if ([storage respondsToSelector:@selector(appWillForeground:)]) { + [storage appWillForeground:app]; + } + } +} + +- (void)appWillTerminate:(nonnull GDTCORApplication *)app { + NSArray> *uploaders = [self.targetToUploader allValues]; + for (id uploader in uploaders) { + if ([uploader respondsToSelector:@selector(appWillTerminate:)]) { + [uploader appWillTerminate:app]; + } + } + NSArray> *storages = [self.targetToStorage allValues]; + for (id storage in storages) { + if ([storage respondsToSelector:@selector(appWillTerminate:)]) { + [storage appWillTerminate:app]; + } + } +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m new file mode 100644 index 0000000..30915da --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" + +@implementation GDTCORStorageEventSelector + ++ (instancetype)eventSelectorForTarget:(GDTCORTarget)target { + return [[self alloc] initWithTarget:target eventIDs:nil mappingIDs:nil qosTiers:nil]; +} + +- (instancetype)initWithTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + mappingIDs:(nullable NSSet *)mappingIDs + qosTiers:(nullable NSSet *)qosTiers { + self = [super init]; + if (self) { + _selectedTarget = target; + _selectedEventIDs = eventIDs; + _selectedMappingIDs = mappingIDs; + _selectedQosTiers = qosTiers; + } + return self; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageMetadata.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageMetadata.m new file mode 100644 index 0000000..de3b466 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageMetadata.m @@ -0,0 +1,36 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h" + +@implementation GDTCORStorageMetadata + +- (instancetype)initWithCurrentCacheSize:(GDTCORStorageSizeBytes)currentCacheSize + maxCacheSize:(GDTCORStorageSizeBytes)maxCacheSize { + self = [super init]; + if (self) { + _currentCacheSize = currentCacheSize; + _maxCacheSize = maxCacheSize; + } + return self; +} + ++ (instancetype)metadataWithCurrentCacheSize:(GDTCORStorageSizeBytes)currentCacheSize + maxCacheSize:(GDTCORStorageSizeBytes)maxCacheSize { + return [[self alloc] initWithCurrentCacheSize:currentCacheSize maxCacheSize:maxCacheSize]; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m new file mode 100644 index 0000000..ece9368 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m @@ -0,0 +1,108 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +@implementation GDTCORTransformer + ++ (instancetype)sharedInstance { + static GDTCORTransformer *eventTransformer; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + eventTransformer = [[self alloc] init]; + }); + return eventTransformer; +} + +- (instancetype)init { + return [self initWithApplication:[GDTCORApplication sharedApplication]]; +} + +- (instancetype)initWithApplication:(id)application { + self = [super init]; + if (self) { + _eventWritingQueue = + dispatch_queue_create("com.google.GDTCORTransformer", DISPATCH_QUEUE_SERIAL); + _application = application; + } + return self; +} + +- (void)transformEvent:(GDTCOREvent *)event + withTransformers:(NSArray> *)transformers + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + GDTCORAssert(event, @"You can't write a nil event"); + + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; + __auto_type __weak weakApplication = self.application; + bgID = [self.application beginBackgroundTaskWithName:@"GDTTransformer" + expirationHandler:^{ + [weakApplication endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }]; + + __auto_type completionWrapper = ^(BOOL wasWritten, NSError *_Nullable error) { + if (completion) { + completion(wasWritten, error); + } + + if (bgID != GDTCORBackgroundIdentifierInvalid) { + // The work is done, cancel the background task if it's valid. + [weakApplication endBackgroundTask:bgID]; + } else { + GDTCORLog(GDTCORMCDDebugLog, GDTCORLoggingLevelWarnings, + @"Attempted to cancel invalid background task in GDTCORTransformer."); + } + bgID = GDTCORBackgroundIdentifierInvalid; + }; + + dispatch_async(_eventWritingQueue, ^{ + GDTCOREvent *transformedEvent = event; + for (id transformer in transformers) { + if ([transformer respondsToSelector:@selector(transformGDTEvent:)]) { + GDTCORLogDebug(@"Applying a transformer to event %@", event); + transformedEvent = [transformer transformGDTEvent:event]; + if (!transformedEvent) { + completionWrapper(NO, nil); + return; + } + } else { + GDTCORLogError(GDTCORMCETransformerDoesntImplementTransform, + @"Transformer doesn't implement transformGDTEvent: %@", transformer); + completionWrapper(NO, nil); + return; + } + } + + id storage = + [GDTCORRegistrar sharedInstance].targetToStorage[@(event.target)]; + + [storage storeEvent:transformedEvent onComplete:completionWrapper]; + }); +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m new file mode 100644 index 0000000..870ad71 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m @@ -0,0 +1,108 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h" + +@implementation GDTCORTransport + +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + transformers: + (nullable NSArray> *)transformers + target:(GDTCORTarget)target { + GDTCORAssert(mappingID.length > 0, @"A mapping ID cannot be nil or empty"); + GDTCORAssert(target > 0, @"A target cannot be negative or 0"); + if (mappingID == nil || mappingID.length == 0 || target <= 0) { + return nil; + } + self = [super init]; + if (self) { + _mappingID = mappingID; + _transformers = transformers; + _target = target; + _transformerInstance = [GDTCORTransformer sharedInstance]; + } + GDTCORLogDebug(@"Transport object created. mappingID:%@ transformers:%@ target:%ld", mappingID, + transformers, (long)target); + return self; +} + +- (void)sendTelemetryEvent:(GDTCOREvent *)event + onComplete: + (void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + event.qosTier = GDTCOREventQoSTelemetry; + [self sendEvent:event onComplete:completion]; +} + +- (void)sendDataEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + GDTCORAssert(event.qosTier != GDTCOREventQoSTelemetry, @"Use -sendTelemetryEvent, please."); + [self sendEvent:event onComplete:completion]; +} + +- (void)sendTelemetryEvent:(GDTCOREvent *)event { + [self sendTelemetryEvent:event onComplete:nil]; +} + +- (void)sendDataEvent:(GDTCOREvent *)event { + [self sendDataEvent:event onComplete:nil]; +} + +- (GDTCOREvent *)eventForTransport { + return [[GDTCOREvent alloc] initWithMappingID:_mappingID target:_target]; +} + +- (GDTCOREvent *)eventForTransportWithProductData:(GDTCORProductData *)productData { + return [[GDTCOREvent alloc] initWithMappingID:_mappingID productData:productData target:_target]; +} + +#pragma mark - Private helper methods + +/** Sends the given event through the transport pipeline. + * + * @param event The event to send. + * @param completion A block that will be called when the event has been written or dropped. + */ +- (void)sendEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + // TODO: Determine if sending an event before registration is allowed. + GDTCORAssert(event, @"You can't send a nil event"); + GDTCOREvent *copiedEvent = [event copy]; + copiedEvent.clockSnapshot = [GDTCORClock snapshot]; + [self.transformerInstance transformEvent:copiedEvent + withTransformers:_transformers + onComplete:completion]; +} + +#pragma mark - Force Category Linking + +extern void GDTCORInclude_GDTCORLogSourceMetrics_Internal_Category(void); + +/// Does nothing when called, and not meant to be called. +/// +/// This method forces the linker to include categories even if +/// users do not include the '-ObjC' linker flag in their project. ++ (void)noop { + GDTCORInclude_GDTCORLogSourceMetrics_Internal_Category(); +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m new file mode 100644 index 0000000..7d2abe2 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m @@ -0,0 +1,30 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h" + +@implementation GDTCORUploadBatch + +- (instancetype)initWithBatchID:(NSNumber *)batchID events:(NSSet *)events { + self = [super init]; + if (self) { + _batchID = batchID; + _events = events; + } + return self; +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m new file mode 100644 index 0000000..cdc108a --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m @@ -0,0 +1,176 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +@implementation GDTCORUploadCoordinator + ++ (instancetype)sharedInstance { + static GDTCORUploadCoordinator *sharedUploader; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedUploader = [[GDTCORUploadCoordinator alloc] init]; + [sharedUploader startTimer]; + }); + return sharedUploader; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _coordinationQueue = + dispatch_queue_create("com.google.GDTCORUploadCoordinator", DISPATCH_QUEUE_SERIAL); + _registrar = [GDTCORRegistrar sharedInstance]; + _timerInterval = 30 * NSEC_PER_SEC; + _timerLeeway = 5 * NSEC_PER_SEC; + } + return self; +} + +- (void)forceUploadForTarget:(GDTCORTarget)target { + dispatch_async(_coordinationQueue, ^{ + GDTCORLogDebug(@"Forcing an upload of target %ld", (long)target); + GDTCORUploadConditions conditions = [self uploadConditions]; + conditions |= GDTCORUploadConditionHighPriority; + [self uploadTargets:@[ @(target) ] conditions:conditions]; + }); +} + +#pragma mark - Private helper methods + +/** Starts a timer that checks whether or not events can be uploaded at regular intervals. It will + * check the next-upload clocks of all targets to determine if an upload attempt can be made. + */ +- (void)startTimer { + dispatch_async(_coordinationQueue, ^{ + if (self->_timer) { + // The timer has been already started. + return; + } + + // Delay the timer slightly so it doesn't run while +load calls are still running. + dispatch_time_t deadline = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC / 2); + + self->_timer = + dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self->_coordinationQueue); + dispatch_source_set_timer(self->_timer, deadline, self->_timerInterval, self->_timerLeeway); + + dispatch_source_set_event_handler(self->_timer, ^{ + if (![[GDTCORApplication sharedApplication] isRunningInBackground]) { + GDTCORUploadConditions conditions = [self uploadConditions]; + GDTCORLogDebug(@"%@", @"Upload timer fired"); + [self uploadTargets:[self.registrar.targetToUploader allKeys] conditions:conditions]; + } + }); + GDTCORLogDebug(@"%@", @"Upload timer started"); + dispatch_resume(self->_timer); + }); +} + +/** Stops the currently running timer. */ +- (void)stopTimer { + if (_timer) { + dispatch_source_cancel(_timer); + _timer = nil; + } +} + +/** Triggers the uploader implementations for the given targets to upload. + * + * @param targets An array of targets to trigger. + * @param conditions The set of upload conditions. + */ +- (void)uploadTargets:(NSArray *)targets conditions:(GDTCORUploadConditions)conditions { + dispatch_async(_coordinationQueue, ^{ + // TODO: The reachability signal may be not reliable enough to prevent an upload attempt. + // See https://developer.apple.com/videos/play/wwdc2019/712/ (49:40) for more details. + if ((conditions & GDTCORUploadConditionNoNetwork) == GDTCORUploadConditionNoNetwork) { + return; + } + for (NSNumber *target in targets) { + id uploader = self->_registrar.targetToUploader[target]; + [uploader uploadTarget:target.intValue withConditions:conditions]; + } + }); +} + +- (void)signalToStoragesToCheckExpirations { + // The same storage may be associated with several targets. Make sure to check for expirations + // only once per storage. + NSSet> *storages = + [NSSet setWithArray:[_registrar.targetToStorage allValues]]; + for (id storage in storages) { + [storage checkForExpirations]; + } +} + +/** Returns the registered storage for the given NSNumber wrapped GDTCORTarget. + * + * @param target The NSNumber wrapping of a GDTCORTarget to find the storage instance of. + * @return The storage instance for the given target. + */ +- (nullable id)storageForTarget:(NSNumber *)target { + id storage = [GDTCORRegistrar sharedInstance].targetToStorage[target]; + GDTCORAssert(storage, @"A storage must be registered for target %@", target); + return storage; +} + +/** Returns the current upload conditions after making determinations about the network connection. + * + * @return The current upload conditions. + */ +- (GDTCORUploadConditions)uploadConditions { + GDTCORNetworkReachabilityFlags currentFlags = [GDTCORReachability currentFlags]; + BOOL networkConnected = GDTCORReachabilityFlagsReachable(currentFlags); + if (!networkConnected) { + return GDTCORUploadConditionNoNetwork; + } + BOOL isWWAN = GDTCORReachabilityFlagsContainWWAN(currentFlags); + if (isWWAN) { + return GDTCORUploadConditionMobileData; + } else { + return GDTCORUploadConditionWifiData; + } +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillForeground:(GDTCORApplication *)app { + // -startTimer is thread-safe. + [self startTimer]; + [self signalToStoragesToCheckExpirations]; +} + +- (void)appWillBackground:(GDTCORApplication *)app { + dispatch_async(_coordinationQueue, ^{ + [self stopTimer]; + }); +} + +- (void)appWillTerminate:(GDTCORApplication *)application { + dispatch_async(_coordinationQueue, ^{ + [self stopTimer]; + }); +} + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h new file mode 100644 index 0000000..e158a5a --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h @@ -0,0 +1,95 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A block type that could be run instead of normal assertion logging. No return type, no params. + */ +typedef void (^GDTCORAssertionBlock)(void); + +/** Returns the result of executing a soft-linked method present in unit tests that allows a block + * to be run instead of normal assertion logging. This helps ameliorate issues with catching + * exceptions that occur on a dispatch_queue. + * + * @return A block that can be run instead of normal assert printing. + */ +FOUNDATION_EXPORT GDTCORAssertionBlock _Nullable GDTCORAssertionBlockToRunInstead(void); + +#if defined(NS_BLOCK_ASSERTIONS) + +#define GDTCORAssert(condition, ...) \ + do { \ + } while (0); + +#define GDTCORFatalAssert(condition, ...) \ + do { \ + } while (0); + +#else // defined(NS_BLOCK_ASSERTIONS) + +/** Asserts using a console log, unless a block was specified to be run instead. + * + * @param condition The condition you'd expect to be YES. + */ +#define GDTCORAssert(condition, format, ...) \ + do { \ + __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ + if (__builtin_expect(!(condition), 0)) { \ + GDTCORAssertionBlock assertionBlock = GDTCORAssertionBlockToRunInstead(); \ + if (assertionBlock) { \ + assertionBlock(); \ + } else { \ + NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \ + __assert_file__ = __assert_file__ ? __assert_file__ : @""; \ + GDTCORLogAssert(NO, __assert_file__, __LINE__, format, ##__VA_ARGS__); \ + __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ + } \ + } \ + } while (0); + +/** Asserts by logging to the console and throwing an exception if NS_BLOCK_ASSERTIONS is not + * defined. + * + * @param condition The condition you'd expect to be YES. + */ +#define GDTCORFatalAssert(condition, format, ...) \ + do { \ + __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ + if (__builtin_expect(!(condition), 0)) { \ + GDTCORAssertionBlock assertionBlock = GDTCORAssertionBlockToRunInstead(); \ + if (assertionBlock) { \ + assertionBlock(); \ + } else { \ + NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \ + __assert_file__ = __assert_file__ ? __assert_file__ : @""; \ + GDTCORLogAssert(YES, __assert_file__, __LINE__, format, ##__VA_ARGS__); \ + [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \ + object:self \ + file:__assert_file__ \ + lineNumber:__LINE__ \ + description:format, ##__VA_ARGS__]; \ + __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ + } \ + } \ + } while (0); + +#endif // defined(NS_BLOCK_ASSERTIONS) + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h new file mode 100644 index 0000000..a6fa8a3 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h @@ -0,0 +1,66 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The class calculates and caches the specified directory content size and uses add/remove signals + * from client the client to keep the size up to date without accessing file system. + * This is an internal class designed to be used by `GDTCORFlatFileStorage`. + * NOTE: The class is not thread-safe. The client must take care of synchronization. + */ +@interface GDTCORDirectorySizeTracker : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes the object with a directory path. + * @param path The directory path to track content size. + */ +- (instancetype)initWithDirectoryPath:(NSString *)path; + +/** Returns a cached or calculates (if there is no cached) directory content size. + * @return The directory content size in bytes calculated based on `NSURLFileSizeKey`. + */ +- (GDTCORStorageSizeBytes)directoryContentSize; + +/** The client must call this method or `resetCachedSize` method each time a file or directory is + * added to the tracked directory. + * @param path The path to the added file. If the path is outside the tracked directory then the + * @param fileSize The size of the added file. + * method is no-op. + */ +- (void)fileWasAddedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize; + +/** The client must call this method or `resetCachedSize` method each time a file or directory is + * removed from the tracked directory. + * @param path The path to the removed file. If the path is outside the tracked directory then the + * @param fileSize The size of the removed file. + * method is no-op. + */ +- (void)fileWasRemovedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize; + +/** Invalidates cached directory size. */ +- (void)resetCachedSize; + +/** Returns URL resource value for `NSURLFileSizeKey` key for the specified URL. */ +- (GDTCORStorageSizeBytes)fileSizeAtURL:(NSURL *)fileURL; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h new file mode 100644 index 0000000..791678b --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h @@ -0,0 +1,27 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/// The reason the event was "dropped". An event is considered "dropped" when it is no longer +/// tracked by the SDK (i.e. deleted). +typedef NS_ENUM(NSInteger, GDTCOREventDropReason) { + GDTCOREventDropReasonUnknown = 0, + GDTCOREventDropReasonMessageTooOld, + GDTCOREventDropReasonStorageFull, + GDTCOREventDropReasonPayloadTooBig, + GDTCOREventDropReasonMaxRetriesReached, + GDTCOREventDropReasonInvalidPayload, + GDTCOREventDropReasonServerError +}; diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h new file mode 100644 index 0000000..9316e5c --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h @@ -0,0 +1,63 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/** A protocol defining the lifecycle events objects in the library must respond to immediately. */ +@protocol GDTCORLifecycleProtocol + +@optional + +/** Indicates an imminent app termination in the rare occurrence when -applicationWillTerminate: has + * been called. + * + * @param app The GDTCORApplication instance. + */ +- (void)appWillTerminate:(GDTCORApplication *)app; + +/** Indicates that the app is moving to background and eventual suspension or the current UIScene is + * deactivating. + * + * @param app The GDTCORApplication instance. + */ +- (void)appWillBackground:(GDTCORApplication *)app; + +/** Indicates that the app is resuming operation or a UIScene is activating. + * + * @param app The GDTCORApplication instance. + */ +- (void)appWillForeground:(GDTCORApplication *)app; + +@end + +/** This class manages the library's response to app lifecycle events. + * + * When backgrounding, the library doesn't stop processing events, it's just that several background + * tasks will end up being created for every event that's sent, and the stateful objects of the + * library (GDTCORStorage and GDTCORUploadCoordinator instances) will deserialize themselves from + * and to disk before and after every operation, respectively. + */ +@interface GDTCORLifecycle : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h new file mode 100644 index 0000000..b4a9f86 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h @@ -0,0 +1,57 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +@class FBLPromise; +@class GDTCOREvent; +@class GDTCORMetrics; + +NS_ASSUME_NONNULL_BEGIN + +/// A storage delegate that can perform metrics related tasks. +@protocol GDTCORMetricsControllerProtocol + +/// Updates the corresponding log source metricss for the given events dropped for a given +/// reason. +/// @param reason The reason why the events are being dropped. +/// @param events The events that being dropped. +- (FBLPromise *)logEventsDroppedForReason:(GDTCOREventDropReason)reason + events:(NSSet *)events; + +/// Gets and resets the currently stored metrics. +/// @return A promise resolving with the metrics retrieved before the reset. +- (FBLPromise *)getAndResetMetrics; + +/// Offers metrics for re-storing in storage. +/// @note If the metrics are determined to be from the future, they will be ignored. +/// @param metrics The metrics to offer for storage. +- (FBLPromise *)offerMetrics:(GDTCORMetrics *)metrics; + +@end + +/// Returns a metrics controller instance for the given target. +/// @param target The target to retrieve a corresponding metrics controller from. +/// @return The given target's corresponding metrics controller instance, or `nil` if it does not +/// have one. +FOUNDATION_EXPORT +id _Nullable GDTCORMetricsControllerInstanceForTarget( + GDTCORTarget target); + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h new file mode 100644 index 0000000..89df0bc --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h @@ -0,0 +1,232 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if !TARGET_OS_WATCH +#import +#endif + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#elif TARGET_OS_OSX +#import +#elif TARGET_OS_WATCH +#import +#endif // TARGET_OS_IOS || TARGET_OS_TV + +// TODO(Xcode 15): When Xcode 15 is the minimum supported Xcode version, +// it will be unnecessary to check if `TARGET_OS_VISION` is defined. +#if TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION) +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** The GoogleDataTransport library version. */ +FOUNDATION_EXPORT NSString *const kGDTCORVersion; + +/** A notification sent out if the app is backgrounding. */ +FOUNDATION_EXPORT NSString *const kGDTCORApplicationDidEnterBackgroundNotification; + +/** A notification sent out if the app is foregrounding. */ +FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillEnterForegroundNotification; + +/** A notification sent out if the app is terminating. */ +FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillTerminateNotification; + +/** The different possible network connection type. */ +typedef NS_ENUM(NSInteger, GDTCORNetworkType) { + GDTCORNetworkTypeUNKNOWN = 0, + GDTCORNetworkTypeWIFI = 1, + GDTCORNetworkTypeMobile = 2, +}; + +/** The different possible network connection mobile subtype. */ +typedef NS_ENUM(NSInteger, GDTCORNetworkMobileSubtype) { + GDTCORNetworkMobileSubtypeUNKNOWN = 0, + GDTCORNetworkMobileSubtypeGPRS = 1, + GDTCORNetworkMobileSubtypeEdge = 2, + GDTCORNetworkMobileSubtypeWCDMA = 3, + GDTCORNetworkMobileSubtypeHSDPA = 4, + GDTCORNetworkMobileSubtypeHSUPA = 5, + GDTCORNetworkMobileSubtypeCDMA1x = 6, + GDTCORNetworkMobileSubtypeCDMAEVDORev0 = 7, + GDTCORNetworkMobileSubtypeCDMAEVDORevA = 8, + GDTCORNetworkMobileSubtypeCDMAEVDORevB = 9, + GDTCORNetworkMobileSubtypeHRPD = 10, + GDTCORNetworkMobileSubtypeLTE = 11, +}; + +#if !TARGET_OS_WATCH +/** Define SCNetworkReachabilityFlags as GDTCORNetworkReachabilityFlags on non-watchOS. */ +typedef SCNetworkReachabilityFlags GDTCORNetworkReachabilityFlags; + +/** Define SCNetworkReachabilityRef as GDTCORNetworkReachabilityRef on non-watchOS. */ +typedef SCNetworkReachabilityRef GDTCORNetworkReachabilityRef; + +#else +/** The different possible reachabilityFlags option on watchOS. */ +typedef NS_OPTIONS(uint32_t, GDTCORNetworkReachabilityFlags) { + kGDTCORNetworkReachabilityFlagsReachable = 1 << 1, + // TODO(doudounan): Add more options on watchOS if watchOS network connection information relative + // APIs available in the future. +}; + +/** Define a struct as GDTCORNetworkReachabilityRef on watchOS to store network connection + * information. */ +typedef struct { + // TODO(doudounan): Store network connection information on watchOS if watchOS network connection + // information relative APIs available in the future. +} GDTCORNetworkReachabilityRef; +#endif + +/** Returns a URL to the root directory under which all GDT-associated data must be saved. + * + * @return A URL to the root directory under which all GDT-associated data must be saved. + */ +NSURL *GDTCORRootDirectory(void); + +/** Compares flags with the reachable flag (on non-watchos with both reachable and + * connectionRequired flags), if available, and returns YES if network reachable. + * + * @param flags The set of reachability flags. + * @return YES if the network is reachable, NO otherwise. + */ +BOOL GDTCORReachabilityFlagsReachable(GDTCORNetworkReachabilityFlags flags); + +/** Compares flags with the WWAN reachability flag, if available, and returns YES if present. + * + * @param flags The set of reachability flags. + * @return YES if the WWAN flag is set, NO otherwise. + */ +BOOL GDTCORReachabilityFlagsContainWWAN(GDTCORNetworkReachabilityFlags flags); + +/** Generates an enum message GDTCORNetworkType representing network connection type. + * + * @return A GDTCORNetworkType representing network connection type. + */ +GDTCORNetworkType GDTCORNetworkTypeMessage(void); + +/** Generates an enum message GDTCORNetworkMobileSubtype representing network connection mobile + * subtype. + * + * @return A GDTCORNetworkMobileSubtype representing network connection mobile subtype. + */ +GDTCORNetworkMobileSubtype GDTCORNetworkMobileSubTypeMessage(void); + +/** Identifies the model of the device on which the library is currently working on. + * + * @return A NSString representing the device model. + */ +NSString *_Nonnull GDTCORDeviceModel(void); + +/** Writes the given object to the given fileURL and populates the given error if it fails. + * + * @param obj The object to encode. + * @param filePath The path to write the object to. Can be nil if you just need the data. + * @param error The error to populate if something goes wrong. + * @return The data of the archive. If error is nil, it's been written to disk. + */ +NSData *_Nullable GDTCOREncodeArchive(id obj, + NSString *_Nullable filePath, + NSError *_Nullable *error); + +/// Decodes an object of the given class from the given archive path and populates the given error +/// if it fails. +/// @param archiveClass The class of the archive's root object. +/// @param archivePath The path to the archived data. +/// @param error The error to populate if something goes wrong. +id _Nullable GDTCORDecodeArchiveAtPath(Class archiveClass, + NSString *_Nonnull archivePath, + NSError **_Nonnull error); + +/// Decodes an object of the given class from the given data and populates the given error if it +/// fails. +/// @param archiveClass The class of the archive's root object. +/// @param archiveData The data to decode. +/// @param error The error to populate if something goes wrong. +id _Nullable GDTCORDecodeArchive(Class archiveClass, + NSData *_Nonnull archiveData, + NSError **_Nonnull error); + +/** Writes the provided data to a file at the provided path. Intermediate directories will be + * created as needed. + * @param data The file content. + * @param filePath The path to the file to write the provided data. + * @param outError The error to populate if something goes wrong. + * @return `YES` in the case of success, `NO` otherwise. + */ +BOOL GDTCORWriteDataToFile(NSData *data, NSString *filePath, NSError *_Nullable *outError); + +/** A typedef identify background identifiers. */ +typedef volatile NSUInteger GDTCORBackgroundIdentifier; + +/** A background task's invalid sentinel value. */ +FOUNDATION_EXPORT const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid; + +#if TARGET_OS_IOS || TARGET_OS_TV +/** A protocol that wraps UIApplicationDelegate, WKExtensionDelegate or NSObject protocol, depending + * on the platform. + */ +@protocol GDTCORApplicationDelegate +#elif TARGET_OS_OSX +@protocol GDTCORApplicationDelegate +#elif TARGET_OS_WATCH +@protocol GDTCORApplicationDelegate +#else +@protocol GDTCORApplicationDelegate +#endif // TARGET_OS_IOS || TARGET_OS_TV + +@end + +@protocol GDTCORApplicationProtocol + +@required + +/** Flag to determine if the application is running in the background. */ +@property(atomic, readonly) BOOL isRunningInBackground; + +/** Creates a background task with the returned identifier if on a suitable platform. + * + * @name name The name of the task, useful for debugging which background tasks are running. + * @param handler The handler block that is called if the background task expires. + * @return An identifier for the background task, or GDTCORBackgroundIdentifierInvalid if one + * couldn't be created. + */ +- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name + expirationHandler:(void (^__nullable)(void))handler; + +/** Ends the background task if the identifier is valid. + * + * @param bgID The background task to end. + */ +- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID; + +@end + +/** A cross-platform application class. */ +@interface GDTCORApplication : NSObject + +/** Creates and/or returns the shared application instance. + * + * @return The shared application instance. + */ ++ (nullable GDTCORApplication *)sharedApplication; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h new file mode 100644 index 0000000..eb89832 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h @@ -0,0 +1,31 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class helps determine upload conditions by determining connectivity. */ +@interface GDTCORReachability : NSObject + +/** The current set flags indicating network conditions */ ++ (GDTCORNetworkReachabilityFlags)currentFlags; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h new file mode 100644 index 0000000..d5e50bb --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h @@ -0,0 +1,59 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Manages the registration of targets with the transport SDK. */ +@interface GDTCORRegistrar : NSObject + +/** Creates and/or returns the singleton instance. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +/** Registers a backend implementation with the GoogleDataTransport infrastructure. + * + * @param backend The backend object to register with the given target. + * @param target The target this backend object will be responsible for. + */ +- (void)registerUploader:(id)backend target:(GDTCORTarget)target; + +/** Registers a storage implementation with the GoogleDataTransport infrastructure. + * + * @param storage The storage object to register with the given target. + * @param target The target this storage object will be responsible for. + */ +- (void)registerStorage:(id)storage target:(GDTCORTarget)target; + +/** Registers a metrics controller implementation with the GoogleDataTransport infrastructure. + * + * @param metricsController The metrics controller object to register with the given target. + * @param target The target this metrics controller object will be responsible for. + */ +- (void)registerMetricsController:(id)metricsController + target:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h new file mode 100644 index 0000000..7662d8b --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h @@ -0,0 +1,61 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class enables the finding of events by matching events with the properties of this class. + */ +@interface GDTCORStorageEventSelector : NSObject + +/** The target to find events for. Required. */ +@property(readonly, nonatomic) GDTCORTarget selectedTarget; + +/** Finds a specific event. */ +@property(nullable, readonly, nonatomic) NSSet *selectedEventIDs; + +/** Finds all events of a mappingID. */ +@property(nullable, readonly, nonatomic) NSSet *selectedMappingIDs; + +/** Finds all events matching the qosTiers in this list. */ +@property(nullable, readonly, nonatomic) NSSet *selectedQosTiers; + +/** Initializes an event selector that will find all events for the given target. + * + * @param target The selected target. + * @return An immutable event selector instance. + */ ++ (instancetype)eventSelectorForTarget:(GDTCORTarget)target; + +/** Instantiates an event selector. + * + * @param target The selected target. + * @param eventIDs Optional param to find an event matching this eventID. + * @param mappingIDs Optional param to find events matching this mappingID. + * @param qosTiers Optional param to find events matching the given QoS tiers. + * @return An immutable event selector instance. + */ +- (instancetype)initWithTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + mappingIDs:(nullable NSSet *)mappingIDs + qosTiers:(nullable NSSet *)qosTiers; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h new file mode 100644 index 0000000..2a3ae0e --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h @@ -0,0 +1,210 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +@class GDTCOREvent; +@class GDTCORClock; +@class GDTCORUploadBatch; + +@class FBLPromise; + +@protocol GDTCORStorageDelegate; + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^GDTCORStorageBatchBlock)(NSNumber *_Nullable newBatchID, + NSSet *_Nullable batchEvents); + +#pragma mark - GDTCORStorageProtocol + +/** Defines the interface a storage subsystem is expected to implement. */ +@protocol GDTCORStorageProtocol + +/// The object that acts as the delegate of the storage instance. +@property(nonatomic, weak, nullable) id delegate; + +@required + +/** Stores an event and calls onComplete with a non-nil error if anything went wrong. + * + * @param event The event to store + * @param completion The completion block to call after an attempt to store the event has been made. + */ +- (void)storeEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +/** Returns YES if some events have been stored for the given target, NO otherwise. + * + * @param onComplete The completion block to invoke when determining if there are events is done. + */ +- (void)hasEventsForTarget:(GDTCORTarget)target onComplete:(void (^)(BOOL hasEvents))onComplete; + +/** Constructs an event batch with the given event selector. Events in this batch will not be + * returned in any queries or other batches until the batch is removed. + * + * @param eventSelector The event selector used to find the events. + * @param expiration The expiration time of the batch. If removeBatchWithID:deleteEvents:onComplete: + * is not called within this time frame, the batch will be removed with its events deleted. + * @param onComplete The completion handler to be called when the events have been fetched. + */ +- (void)batchWithEventSelector:(nonnull GDTCORStorageEventSelector *)eventSelector + batchExpiration:(nonnull NSDate *)expiration + onComplete:(nonnull GDTCORStorageBatchBlock)onComplete; + +/** Removes the event batch. + * + * @param batchID The batchID to remove. + * @param deleteEvents If YES, the events in this batch are deleted. + * @param onComplete The completion handler to call when the batch removal process has completed. + */ +- (void)removeBatchWithID:(NSNumber *)batchID + deleteEvents:(BOOL)deleteEvents + onComplete:(void (^_Nullable)(void))onComplete; + +/** Finds the batchIDs for the given target and calls the callback block. + * + * @param target The target. + * @param onComplete The block to invoke with the set of current batchIDs. + */ +- (void)batchIDsForTarget:(GDTCORTarget)target + onComplete:(void (^)(NSSet *_Nullable batchIDs))onComplete; + +/** Checks the storage for expired events and batches, deletes them if they're expired. */ +- (void)checkForExpirations; + +/** Persists the given data with the given key. + * + * @param data The data to store. + * @param key The unique key to store it to. + * @param onComplete An block to be run when storage of the data is complete. + */ +- (void)storeLibraryData:(NSData *)data + forKey:(NSString *)key + onComplete:(nullable void (^)(NSError *_Nullable error))onComplete; + +/** Retrieves the stored data for the given key and optionally sets a new value. + * + * @param key The key corresponding to the desired data. + * @param onFetchComplete The callback to invoke with the data once it's retrieved. + * @param setValueBlock This optional block can provide a new value to set. + */ +- (void)libraryDataForKey:(nonnull NSString *)key + onFetchComplete:(nonnull void (^)(NSData *_Nullable data, + NSError *_Nullable error))onFetchComplete + setNewValue:(NSData *_Nullable (^_Nullable)(void))setValueBlock; + +/** Removes data from storage and calls the callback when complete. + * + * @param key The key of the data to remove. + * @param onComplete The callback that will be invoked when removing the data is complete. + */ +- (void)removeLibraryDataForKey:(NSString *)key + onComplete:(void (^)(NSError *_Nullable error))onComplete; + +/** Calculates and returns the total disk size that this storage consumes. + * + * @param onComplete The callback that will be invoked once storage size calculation is complete. + */ +- (void)storageSizeWithCallback:(void (^)(GDTCORStorageSizeBytes storageSize))onComplete; + +@end + +#pragma mark - GDTCORStoragePromiseProtocol + +// TODO(ncooke3): Consider complete replacing block based API by promise API. + +@class GDTCORMetricsMetadata; +@class GDTCORStorageMetadata; + +/** Promise based version of API defined in GDTCORStorageProtocol. See API docs for corresponding + * methods in GDTCORStorageProtocol. */ +@protocol GDTCORStoragePromiseProtocol + +- (FBLPromise *> *)batchIDsForTarget:(GDTCORTarget)target; + +- (FBLPromise *)removeBatchWithID:(NSNumber *)batchID deleteEvents:(BOOL)deleteEvents; + +- (FBLPromise *)removeBatchesWithIDs:(NSSet *)batchIDs + deleteEvents:(BOOL)deleteEvents; + +- (FBLPromise *)removeAllBatchesForTarget:(GDTCORTarget)target + deleteEvents:(BOOL)deleteEvents; + +/// Fetches metrics metadata from storage, passes them to the given handler, and writes the +/// resulting metrics metadata from the given handler to storage. +/// @note This API is thread-safe. +/// @param handler A handler to process the fetch result and return an updated value to store. +/// @return A promise that is fulfilled if the update is successful, and rejected otherwise. +- (FBLPromise *)fetchAndUpdateMetricsWithHandler: + (GDTCORMetricsMetadata * (^)(GDTCORMetricsMetadata *_Nullable fetchedMetadata, + NSError *_Nullable fetchError))handler; + +/// Fetches and returns storage metadata. +- (FBLPromise *)fetchStorageMetadata; + +/** See `hasEventsForTarget:onComplete:`. + * @return A promise object that is resolved with @YES if there are events for the specified target + * and @NO otherwise. + */ +- (FBLPromise *)hasEventsForTarget:(GDTCORTarget)target; + +/** See `batchWithEventSelector:batchExpiration:onComplete:` + * The promise is rejected when there are no events for the specified selector. + */ +- (FBLPromise *)batchWithEventSelector: + (GDTCORStorageEventSelector *)eventSelector + batchExpiration:(NSDate *)expiration; + +@end + +/** Retrieves the storage instance for the given target. + * + * @param target The target. + * * @return The storage instance registered for the target, or nil if there is none. + */ +FOUNDATION_EXPORT +id _Nullable GDTCORStorageInstanceForTarget(GDTCORTarget target); + +FOUNDATION_EXPORT +id _Nullable GDTCORStoragePromiseInstanceForTarget( + GDTCORTarget target); + +#pragma mark - GDTCORStorageDelegate + +/// A type that can be delegated actions from a storage instance. +@protocol GDTCORStorageDelegate + +/// Tells the delegate that the storage instance has removed a set of expired events. +/// @param storage The storage instance informing the delegate of this impending event. +/// @param events A set of events that were removed from storage due to their expiration. +- (void)storage:(id)storage + didRemoveExpiredEvents:(NSSet *)events; + +/// Tells the delegate that the storage instance has dropped an event due to the event cache being +/// full. +/// @param storage The storage instance informing the delegate of this impending event. +/// @param event An event that was dropped due to the event cache being full. +- (void)storage:(id)storage didDropEvent:(GDTCOREvent *)event; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h new file mode 100644 index 0000000..4b24f95 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h @@ -0,0 +1,18 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/// The data type to represent storage size. +typedef uint64_t GDTCORStorageSizeBytes; diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h new file mode 100644 index 0000000..9b5343d --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h @@ -0,0 +1,59 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Options that define a set of upload conditions. This is used to help minimize end user data + * consumption impact. + */ +typedef NS_OPTIONS(NSInteger, GDTCORUploadConditions) { + + /** An upload shouldn't be attempted, because there's no network. */ + GDTCORUploadConditionNoNetwork = 1 << 0, + + /** An upload would likely use mobile data. */ + GDTCORUploadConditionMobileData = 1 << 1, + + /** An upload would likely use wifi data. */ + GDTCORUploadConditionWifiData = 1 << 2, + + /** An upload uses some sort of network connection, but it's unclear which. */ + GDTCORUploadConditionUnclearConnection = 1 << 3, + + /** A high priority event has occurred. */ + GDTCORUploadConditionHighPriority = 1 << 4, +}; + +/** This protocol defines the common interface for uploader implementations. */ +@protocol GDTCORUploader + +@required + +/** Uploads events to the backend using this specific backend's chosen format. + * + * @param conditions The conditions that the upload attempt is likely to occur under. + */ +- (void)uploadTarget:(GDTCORTarget)target withConditions:(GDTCORUploadConditions)conditions; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h new file mode 100644 index 0000000..4b1a903 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h" + +@interface GDTCOREndpoints () + +/** Returns the list of all the upload URLs used by the transport library. + * + * @return Map of the transport target and the URL used for uploading the events for that target. + */ ++ (NSDictionary *)uploadURLs; + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h new file mode 100644 index 0000000..e97eb31 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h @@ -0,0 +1,33 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCOREvent () + +/** The unique ID of the event. This property is for testing only. */ +@property(nonatomic, readwrite) NSString *eventID; + +/** Generates a unique event ID. */ ++ (NSString *)nextEventID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h new file mode 100644 index 0000000..66ea857 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h @@ -0,0 +1,28 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h" + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/// The category extends `GDTCORFlatFileStorage` API with `GDTCORStoragePromiseProtocol` methods. +@interface GDTCORFlatFileStorage (Promises) + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h new file mode 100644 index 0000000..09f1dae --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h @@ -0,0 +1,158 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +@class GDTCOREvent; +@class GDTCORUploadCoordinator; + +NS_ASSUME_NONNULL_BEGIN + +/** The event components eventID dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsEventIDKey; + +/** The event components qosTier dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsQoSTierKey; + +/** The event components mappingID dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsMappingIDKey; + +/** The event components expirationDate dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsExpirationKey; + +/** The batch components target dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCORBatchComponentsTargetKey; + +/** The batch components batchID dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCORBatchComponentsBatchIDKey; + +/** The batch components expiration dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCORBatchComponentsExpirationKey; + +/** The maximum allowed disk space taken by the stored data. */ +FOUNDATION_EXPORT const uint64_t kGDTCORFlatFileStorageSizeLimit; + +FOUNDATION_EXPORT NSString *const GDTCORFlatFileStorageErrorDomain; + +typedef NS_ENUM(NSInteger, GDTCORFlatFileStorageError) { + GDTCORFlatFileStorageErrorSizeLimitReached = 0 +}; + +/** Manages the storage of events. This class is thread-safe. + * + * Event files will be stored as follows: + * /google-sdk-events//gdt_event_data//.. + * + * Library data will be stored as follows: + * /google-sdk-events//gdt_library_data/ + * + * Batch data will be stored as follows: + * /google-sdk-events//gdt_batch_data/./.. + */ +@interface GDTCORFlatFileStorage : NSObject + +/** The queue on which all storage work will occur. */ +@property(nonatomic) dispatch_queue_t storageQueue; + +/** The upload coordinator instance used by this storage instance. */ +@property(nonatomic) GDTCORUploadCoordinator *uploadCoordinator; + +/** Creates and/or returns the storage singleton. + * + * @return The storage singleton. + */ ++ (instancetype)sharedInstance; + +/** Returns the base directory under which all events will be stored. + * + * @return The base directory under which all events will be stored. + */ ++ (NSString *)eventDataStoragePath; + +/** Returns the base directory under which all library data will be stored. + * + * @return The base directory under which all library data will be stored. + */ ++ (NSString *)libraryDataStoragePath; + +/** Returns the base directory under which all batch data will be stored. + * + * @return The base directory under which all batch data will be stored. + */ ++ (NSString *)batchDataStoragePath; + +/** */ ++ (NSString *)batchPathForTarget:(GDTCORTarget)target + batchID:(NSNumber *)batchID + expirationDate:(NSDate *)expirationDate; + +/** Returns a constructed storage path based on the given values. This path may not exist. + * + * @param target The target, which is necessary to be given a path. + * @param eventID The eventID. + * @param qosTier The qosTier. + * @param expirationDate The expirationDate as a 1970-relative time interval. + * @param mappingID The mappingID. + * @return The path representing the combination of the given parameters. + */ ++ (NSString *)pathForTarget:(GDTCORTarget)target + eventID:(NSString *)eventID + qosTier:(NSNumber *)qosTier + expirationDate:(NSDate *)expirationDate + mappingID:(NSString *)mappingID; + +/** Returns extant paths that match all of the given parameters. + * + * @param eventIDs The list of eventIDs to look for, or nil for any. + * @param qosTiers The list of qosTiers to look for, or nil for any. + * @param mappingIDs The list of mappingIDs to look for, or nil for any. + * @param onComplete The completion to call once the paths have been discovered. + */ +- (void)pathsForTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + qosTiers:(nullable NSSet *)qosTiers + mappingIDs:(nullable NSSet *)mappingIDs + onComplete:(void (^)(NSSet *paths))onComplete; + +/** Fetches the current batchID counter value from library storage, increments it, and sets the new + * value. Returns nil if a batchID was not able to be created for some reason. + * + * @param onComplete A block to execute when creating the next batchID is complete. + */ +- (void)nextBatchID:(void (^)(NSNumber *_Nullable batchID))onComplete; + +/** Constructs a dictionary of event filename components. + * + * @param fileName The event filename to split. + * @return The dictionary of event component keys to their values. + */ +- (nullable NSDictionary *)eventComponentsFromFilename:(NSString *)fileName; + +/** Constructs a dictionary of batch filename components. + * + * @param fileName The batch folder name to split. + * @return The dictionary of batch component keys to their values. + */ +- (nullable NSDictionary *)batchComponentsFromFilename:(NSString *)fileName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h new file mode 100644 index 0000000..8722073 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h @@ -0,0 +1,53 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h" + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/// A model object that tracks, per log source, the number of events dropped for a variety of +/// reasons. An event is considered "dropped" when the event is no longer persisted by the SDK. +@interface GDTCORLogSourceMetrics : NSObject + +/// Creates an empty log source metrics instance. ++ (instancetype)metrics; + +/// Creates a log source metrics for a collection of events that were dropped for a given reason. +/// @param events The collection of events that were dropped. +/// @param reason The reason for which given events were dropped. ++ (instancetype)metricsWithEvents:(NSArray *)events + droppedForReason:(GDTCOREventDropReason)reason; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +/// Returns a log source metrics instance created by merging the receiving log +/// source metrics with the given log source metrics. +/// @param logSourceMetrics The given log source metrics to merge with. +- (GDTCORLogSourceMetrics *)logSourceMetricsByMergingWithLogSourceMetrics: + (GDTCORLogSourceMetrics *)logSourceMetrics; + +/// Returns a Boolean value that indicates whether the receiving log source metrics is equal to +/// the given log source metrics. +/// @param otherLogSourceMetrics The log source metrics with which to compare the +/// receiving log source metrics. +- (BOOL)isEqualToLogSourceMetrics:(GDTCORLogSourceMetrics *)otherLogSourceMetrics; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h new file mode 100644 index 0000000..2f3c38f --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h @@ -0,0 +1,61 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h" + +@class GDTCORLogSourceMetrics; +@class GDTCORMetricsMetadata; +@class GDTCORStorageMetadata; + +NS_ASSUME_NONNULL_BEGIN + +/// An object representing metrics that represent a snapshot of the SDK's state and performance. +@interface GDTCORMetrics : NSObject + +/// The start of the time window over which the metrics were collected. +@property(nonatomic, readonly) NSDate *collectionStartDate; + +/// The log source metrics associated with the metrics. +@property(nonatomic, readonly) GDTCORLogSourceMetrics *logSourceMetrics; + +/// The end of the time window over which the metrics were collected. +@property(nonatomic, readonly) NSDate *collectionEndDate; + +/// The number of bytes the event cache was consuming in storage. +@property(nonatomic, readonly) GDTCORStorageSizeBytes currentCacheSize; + +/// The maximum number of bytes that the event cache is allowed to grow. +@property(nonatomic, readonly) GDTCORStorageSizeBytes maxCacheSize; + +/// The bundle ID associated with the metrics being collected. +@property(nonatomic, readonly) NSString *bundleID; + +/// Creates a metrics instance with the provided metadata. +/// @param metricsMetadata The provided metrics metadata. +/// @param storageMetadata The provided storage metadata. ++ (instancetype)metricsWithMetricsMetadata:(GDTCORMetricsMetadata *)metricsMetadata + storageMetadata:(GDTCORStorageMetadata *)storageMetadata; + +/// Returns a Boolean value that indicates whether the receiving metrics is equal to the given +/// metrics. +/// @param otherMetrics The metrics with which to compare the receiving metrics. +- (BOOL)isEqualToMetrics:(GDTCORMetrics *)otherMetrics; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsController.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsController.h new file mode 100644 index 0000000..a47da52 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsController.h @@ -0,0 +1,37 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h" + +@protocol GDTCORStoragePromiseProtocol; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORMetricsController : NSObject + +/// Returns the event metrics controller singleton. ++ (instancetype)sharedInstance; + +/// Designated initializer. +/// @param storage The storage object to read and write metrics data from. +- (instancetype)initWithStorage:(id)storage NS_DESIGNATED_INITIALIZER; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h new file mode 100644 index 0000000..8214c41 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h @@ -0,0 +1,50 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h" + +@class GDTCORLogSourceMetrics; + +NS_ASSUME_NONNULL_BEGIN + +/// An encodable model object that contains metadata that is persisted in storage until ready to be +/// used to create a ``GDTCORMetrics`` instance. +@interface GDTCORMetricsMetadata : NSObject + +/// The start of the time window over which the metrics were collected. +@property(nonatomic, copy, readonly) NSDate *collectionStartDate; + +/// The log source metrics associated with the metrics. +@property(nonatomic, copy, readonly) GDTCORLogSourceMetrics *logSourceMetrics; + +/// Creates a metrics metadata object with the provided information. +/// @param collectedSinceDate The start of the time window over which the metrics were collected. +/// @param logSourceMetrics The metrics object that tracks metrics for each log source. ++ (instancetype)metadataWithCollectionStartDate:(NSDate *)collectedSinceDate + logSourceMetrics:(GDTCORLogSourceMetrics *)logSourceMetrics; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +/// Returns a Boolean value that indicates whether the receiving metrics metadata is equal to +/// the given metrics metadata. +/// @param otherMetricsMetadata The metrics metadata with which to compare the +/// receiving metrics metadata. +- (BOOL)isEqualToMetricsMetadata:(GDTCORMetricsMetadata *)otherMetricsMetadata; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h new file mode 100644 index 0000000..06b1f67 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" + +@interface GDTCORReachability () + +/** Allows manually setting the flags for testing purposes. */ +@property(nonatomic, readwrite) GDTCORNetworkReachabilityFlags flags; + +/** Creates/returns the singleton instance of this class. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h new file mode 100644 index 0000000..9f45548 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" + +@interface GDTCORRegistrar () + +NS_ASSUME_NONNULL_BEGIN + +/** The concurrent queue on which all registration occurs. */ +@property(nonatomic, readonly) dispatch_queue_t registrarQueue; + +/** A map of targets to backend implementations. */ +@property(atomic, readonly) NSMutableDictionary> *targetToUploader; + +/** A map of targets to storage instances. */ +@property(atomic, readonly) + NSMutableDictionary> *targetToStorage; + +/** A map of targets to metrics controller instances. */ +@property(atomic, readonly) + NSMutableDictionary> *targetToMetricsController; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h new file mode 100644 index 0000000..90b529e --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h @@ -0,0 +1,41 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h" + +NS_ASSUME_NONNULL_BEGIN + +/// A model object that contains metadata about the current state of the SDK's storage container. +@interface GDTCORStorageMetadata : NSObject + +/// The number of bytes the event cache is consuming in storage. +@property(nonatomic, readonly) GDTCORStorageSizeBytes currentCacheSize; + +/// The maximum number of bytes that the event cache may consume in storage. +@property(nonatomic, readonly) GDTCORStorageSizeBytes maxCacheSize; + +/// Creates a storage metadata object with the provided information. +/// @param currentCacheSize The current number of bytes the event cache is consuming. +/// @param maxCacheSize The current maximum capacity (in bytes) that the event cache may consume. ++ (instancetype)metadataWithCurrentCacheSize:(GDTCORStorageSizeBytes)currentCacheSize + maxCacheSize:(GDTCORStorageSizeBytes)maxCacheSize; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h new file mode 100644 index 0000000..ccca628 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h @@ -0,0 +1,57 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" + +@class GDTCOREvent; + +@protocol GDTCOREventTransformer; + +NS_ASSUME_NONNULL_BEGIN + +/** Manages the transforming of events. It's desirable for this to be its own class + * because running all events through a single instance ensures that transformers are thread-safe. + * Having a per-transport queue to run on isn't sufficient because transformer objects could + * maintain state (or at least, there's nothing to stop them from doing that) and the same instances + * may be used across multiple instances. + */ +@interface GDTCORTransformer : NSObject + +/** Instantiates or returns the event transformer singleton. + * + * @return The singleton instance of the event transformer. + */ ++ (instancetype)sharedInstance; + +/** Writes the result of applying the given transformers' `transformGDTEvent:` method on the given + * event. + * + * @note If the app is suspended, a background task will be created to complete work in-progress, + * but this method will not send any further events until the app is resumed. + * + * @param event The event to apply transformers on. + * @param transformers The list of transformers to apply. + * @param completion A block to run when an event was written to disk or dropped. + */ +- (void)transformEvent:(GDTCOREvent *)event + withTransformers:(nullable NSArray> *)transformers + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h new file mode 100644 index 0000000..bb86407 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h" + +@protocol GDTCORApplicationProtocol; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORTransformer () + +/** The queue on which all work will occur. */ +@property(nonatomic) dispatch_queue_t eventWritingQueue; + +/** The application instance that is used to begin/end background tasks. */ +@property(nonatomic, readonly) id application; + +/** The internal initializer. Should be used in tests only to create an instance with a + * particular(fake) application instance. */ +- (instancetype)initWithApplication:(id)application; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h new file mode 100644 index 0000000..41a1224 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h" + +@class GDTCORTransformer; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORTransport () + +/** The mapping identifier that the target backend will use to map the transport bytes to proto. */ +@property(nonatomic) NSString *mappingID; + +/** The transformers that will operate on events sent by this transport. */ +@property(nonatomic) NSArray> *transformers; + +/** The target backend of this transport. */ +@property(nonatomic) NSInteger target; + +/** The transformer instance to used to transform events. Allows injecting a fake during testing. */ +@property(nonatomic) GDTCORTransformer *transformerInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h new file mode 100644 index 0000000..8d1fd11 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/// A data object representing a batch of events scheduled for upload. +@interface GDTCORUploadBatch : NSObject + +/// An ID used to identify the batch in the storage. +@property(nonatomic, readonly) NSNumber *batchID; + +/// The collection of the events in the batch. +@property(nonatomic, readonly) NSSet *events; + +/// The default initializer. See also docs for the corresponding properties. +- (instancetype)initWithBatchID:(NSNumber *)batchID events:(NSSet *)events; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h new file mode 100644 index 0000000..bdac3f3 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h @@ -0,0 +1,68 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" + +@class GDTCORClock; + +NS_ASSUME_NONNULL_BEGIN + +/** This class connects storage and uploader implementations, providing events to an uploader + * and informing the storage what events were successfully uploaded or not. + */ +@interface GDTCORUploadCoordinator : NSObject + +/** The queue on which all upload coordination will occur. Also used by a dispatch timer. */ +/** Creates and/or returrns the singleton. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +/** The queue on which all upload coordination will occur. */ +@property(nonatomic, readonly) dispatch_queue_t coordinationQueue; + +/** A timer that will causes regular checks for events to upload. */ +@property(nonatomic, readonly, nullable) dispatch_source_t timer; + +/** The interval the timer will fire. */ +@property(nonatomic, readonly) uint64_t timerInterval; + +/** Some leeway given to libdispatch for the timer interval event. */ +@property(nonatomic, readonly) uint64_t timerLeeway; + +/** The registrar object the coordinator will use. Generally used for testing. */ +@property(nonatomic) GDTCORRegistrar *registrar; + +/** Forces the backend specified by the target to upload the provided set of events. This should + * only ever happen when the QoS tier of an event requires it. + * + * @param target The target that should force an upload. + */ +- (void)forceUploadForTarget:(GDTCORTarget)target; + +/** Starts the upload timer. */ +- (void)startTimer; + +/** Stops the upload timer from running. */ +- (void)stopTimer; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h new file mode 100644 index 0000000..8c75b50 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h @@ -0,0 +1,66 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** This class manages the device clock and produces snapshots of the current time. */ +@interface GDTCORClock : NSObject + +/** The wallclock time, UTC, in milliseconds. */ +@property(nonatomic, readonly) int64_t timeMillis; + +/** The offset from UTC in seconds. */ +@property(nonatomic, readonly) int64_t timezoneOffsetSeconds; + +/** The kernel boot time when this clock was created in nanoseconds. */ +@property(nonatomic, readonly) int64_t kernelBootTimeNanoseconds; + +/** The device uptime when this clock was created in nanoseconds. */ +@property(nonatomic, readonly) int64_t uptimeNanoseconds; + +@property(nonatomic, readonly) int64_t kernelBootTime DEPRECATED_MSG_ATTRIBUTE( + "Please use `kernelBootTimeNanoseconds` instead"); + +@property(nonatomic, readonly) + int64_t uptime DEPRECATED_MSG_ATTRIBUTE("Please use `uptimeNanoseconds` instead"); + +/** Creates a GDTCORClock object using the current time and offsets. + * + * @return A new GDTCORClock object representing the current time state. + */ ++ (instancetype)snapshot; + +/** Creates a GDTCORClock object representing a time in the future, relative to now. + * + * @param millisInTheFuture The millis in the future from now this clock should represent. + * @return An instance representing a future time. + */ ++ (instancetype)clockSnapshotInTheFuture:(uint64_t)millisInTheFuture; + +/** Compares one clock with another, returns YES if the caller is after the parameter. + * + * @return YES if the calling clock's time is after the given clock's time. + */ +- (BOOL)isAfter:(GDTCORClock *)otherClock; + +/** Returns value of `uptime` property in milliseconds. */ +- (int64_t)uptimeMilliseconds; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h new file mode 100644 index 0000000..1fdf732 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h @@ -0,0 +1,144 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** The current logging level. This value and higher will be printed. Declared as volatile to make + * getting and setting atomic. + */ +FOUNDATION_EXPORT volatile NSInteger GDTCORConsoleLoggerLoggingLevel; + +/** A list of logging levels that GDT supports. */ +typedef NS_ENUM(NSInteger, GDTCORLoggingLevel) { + + /** Causes all logs to be printed. */ + GDTCORLoggingLevelDebug = 1, + + /** Causes all non-debug logs to be printed. */ + GDTCORLoggingLevelVerbose = 2, + + /** Causes warnings and errors to be printed. */ + GDTCORLoggingLevelWarnings = 3, + + /** Causes errors to be printed. This is the default value. */ + GDTCORLoggingLevelErrors = 4 +}; + +/** A list of message codes to print in the logger that help to correspond printed messages with + * code locations. + * + * Prefixes: + * - MCD => MessageCodeDebug + * - MCW => MessageCodeWarning + * - MCE => MessageCodeError + */ +typedef NS_ENUM(NSInteger, GDTCORMessageCode) { + + /** For debug logs. */ + GDTCORMCDDebugLog = 0, + + /** For warning messages concerning transportBytes: not being implemented by a data object. */ + GDTCORMCWDataObjectMissingBytesImpl = 1, + + /** For warning messages concerning a failed event upload. */ + GDTCORMCWUploadFailed = 2, + + /** For warning messages concerning a forced event upload. */ + GDTCORMCWForcedUpload = 3, + + /** For warning messages concerning a failed reachability call. */ + GDTCORMCWReachabilityFailed = 4, + + /** For warning messages concerning a database warning. */ + GDTCORMCWDatabaseWarning = 5, + + /** For warning messages concerning the reading of a event file. */ + GDTCORMCWFileReadError = 6, + + /** For error messages concerning transformGDTEvent: not being implemented by an event + transformer. */ + GDTCORMCETransformerDoesntImplementTransform = 1000, + + /** For error messages concerning the creation of a directory failing. */ + GDTCORMCEDirectoryCreationError = 1001, + + /** For error messages concerning the writing of a event file. */ + GDTCORMCEFileWriteError = 1002, + + /** For error messages concerning the lack of a prioritizer for a given backend. */ + GDTCORMCEPrioritizerError = 1003, + + /** For error messages concerning a package delivery API violation. */ + GDTCORMCEDeliverTwice = 1004, + + /** For error messages concerning an error in an implementation of -transportBytes. */ + GDTCORMCETransportBytesError = 1005, + + /** For general purpose error messages in a dependency. */ + GDTCORMCEGeneralError = 1006, + + /** For fatal errors. Please go to https://github.com/firebase/firebase-ios-sdk/issues and open + * an issue if you encounter an error with this code. + */ + GDTCORMCEFatalAssertion = 1007, + + /** For error messages concerning the reading of a event file. */ + GDTCORMCEFileReadError = 1008, + + /** For errors related to running sqlite. */ + GDTCORMCEDatabaseError = 1009, +}; + +/** Prints the given code and format string to the console. + * + * @param code The message code describing the nature of the log. + * @param logLevel The log level of this log. + * @param format The format string. + */ +FOUNDATION_EXPORT +void GDTCORLog(GDTCORMessageCode code, GDTCORLoggingLevel logLevel, NSString *_Nonnull format, ...) + NS_FORMAT_FUNCTION(3, 4); + +/** Prints an assert log to the console. + * + * @param wasFatal Send YES if the assertion should be fatal, NO otherwise. + * @param file The file in which the failure occurred. + * @param line The line number of the failure. + * @param format The format string. + */ +FOUNDATION_EXPORT void GDTCORLogAssert(BOOL wasFatal, + NSString *_Nonnull file, + NSInteger line, + NSString *_Nullable format, + ...) NS_FORMAT_FUNCTION(4, 5); + +/** Returns the string that represents some message code. + * + * @param code The code to convert to a string. + * @return The string representing the message code. + */ +FOUNDATION_EXPORT NSString *_Nonnull GDTCORMessageCodeEnumToString(GDTCORMessageCode code); + +#define GDTCORLogDebug(MESSAGE_FORMAT, ...) \ + GDTCORLog(GDTCORMCDDebugLog, GDTCORLoggingLevelDebug, MESSAGE_FORMAT, __VA_ARGS__); + +// A define to wrap GULLogWarning with slightly more convenient usage. +#define GDTCORLogWarning(MESSAGE_CODE, MESSAGE_FORMAT, ...) \ + GDTCORLog(MESSAGE_CODE, GDTCORLoggingLevelWarnings, MESSAGE_FORMAT, __VA_ARGS__); + +// A define to wrap GULLogError with slightly more convenient usage and a failing assert. +#define GDTCORLogError(MESSAGE_CODE, MESSAGE_FORMAT, ...) \ + GDTCORLog(MESSAGE_CODE, GDTCORLoggingLevelErrors, MESSAGE_FORMAT, __VA_ARGS__); diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h new file mode 100644 index 0000000..836a454 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/* Class that manages the endpoints used by Google data transport library. */ +@interface GDTCOREndpoints : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Returns the upload URL for a target specified. If the target is not available, returns nil. + * + * @param target GoogleDataTransport target for which the upload URL is being looked up for. + * @return URL that will be used for uploading the events for the provided target. + */ ++ (nullable NSURL *)uploadURLForTarget:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h new file mode 100644 index 0000000..8ab3601 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h @@ -0,0 +1,102 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GDTCOREventDataObject.h" +#import "GDTCORTargets.h" + +@class GDTCORClock; +@class GDTCORProductData; + +NS_ASSUME_NONNULL_BEGIN + +/** The different possible quality of service specifiers. High values indicate high priority. */ +typedef NS_ENUM(NSInteger, GDTCOREventQoS) { + /** The QoS tier wasn't set, and won't ever be sent. */ + GDTCOREventQoSUnknown = 0, + + /** This event is internal telemetry data that should not be sent on its own if possible. */ + GDTCOREventQoSTelemetry = 1, + + /** This event should be sent, but in a batch only roughly once per day. */ + GDTCOREventQoSDaily = 2, + + /** This event should be sent when requested by the uploader. */ + GDTCOREventQosDefault = 3, + + /** This event should be sent immediately along with any other data that can be batched. */ + GDTCOREventQoSFast = 4, + + /** This event should only be uploaded on wifi. */ + GDTCOREventQoSWifiOnly = 5, +}; + +@interface GDTCOREvent : NSObject + +/** The unique ID of the event. */ +@property(readonly, nonatomic) NSString *eventID; + +/** The mapping identifier, to allow backends to map the transport bytes to a proto. */ +@property(nullable, readonly, nonatomic) NSString *mappingID; + +/** The identifier for the backend this event will eventually be sent to. */ +@property(readonly, nonatomic) GDTCORTarget target; + +/** The data object encapsulated in the transport of your choice, as long as it implements + * the GDTCOREventDataObject protocol. */ +@property(nullable, nonatomic) id dataObject; + +/** The serialized bytes from calling [dataObject transportBytes]. */ +@property(nullable, readonly, nonatomic) NSData *serializedDataObjectBytes; + +/** The quality of service tier this event belongs to. */ +@property(nonatomic) GDTCOREventQoS qosTier; + +/** The clock snapshot at the time of the event. */ +@property(nonatomic) GDTCORClock *clockSnapshot; + +/** The expiration date of the event. Default is 604800 seconds (7 days) from creation. */ +@property(nonatomic) NSDate *expirationDate; + +/** Bytes that can be used by an uploader later on. */ +@property(nullable, nonatomic) NSData *customBytes; + +/** The product data that the event is associated with, if any. */ +@property(nullable, readonly, nonatomic) GDTCORProductData *productData; + +/** Initializes an instance using the given mapping ID and target. + * + * @param mappingID The mapping identifier. + * @param target The event's target identifier. + * @return An instance of this class. + */ +- (nullable instancetype)initWithMappingID:(NSString *)mappingID target:(GDTCORTarget)target; + +/** Initializes an instance using the given mapping ID, product data, and target. + * + * @param mappingID The mapping identifier. + * @param productData The product data to associate this event with. + * @param target The event's target identifier. + * @return An instance of this class. + */ +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + productData:(nullable GDTCORProductData *)productData + target:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h new file mode 100644 index 0000000..34ef624 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** This protocol defines the common interface that event protos should implement regardless of the + * underlying transport technology (protobuf, nanopb, etc). + */ +@protocol GDTCOREventDataObject + +@required + +/** Returns the serialized proto bytes of the implementing event proto. + * + * @return the serialized proto bytes of the implementing event proto. + */ +- (NSData *)transportBytes; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h new file mode 100644 index 0000000..80dee7d --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/** Defines the API that event transformers must adopt. */ +@protocol GDTCOREventTransformer + +@required + +/** Transforms an event by applying some logic to it. Events returned can be nil, for example, in + * instances where the event should be sampled. + * + * @param event The event to transform. + * @return A transformed event, or nil if the transformation dropped the event. + */ +- (nullable GDTCOREvent *)transformGDTEvent:(GDTCOREvent *)event; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h new file mode 100644 index 0000000..ff99822 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h @@ -0,0 +1,29 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@interface GDTCORProductData : NSObject + +/// The product ID. +@property(nonatomic, readonly) int32_t productID; + +/// Initializes an instance using the given product ID. +/// - Parameter productID: A 32-bit integer. +- (instancetype)initWithProductID:(int32_t)productID; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h new file mode 100644 index 0000000..3163b55 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** The list of targets supported by the shared transport infrastructure. + * These targets map to a specific backend designed to accept GDT payloads. If + * adding a new target, please use the previous value +1. + */ +typedef NS_ENUM(NSInteger, GDTCORTarget) { + + /** Target used for testing purposes. */ + kGDTCORTargetTest = 999, + + /** Target used by internal clients. See go/firelog for more information. */ + kGDTCORTargetCCT = 1000, + + /** Target mapping to the Firelog backend. See go/firelog for more information. */ + kGDTCORTargetFLL = 1001, + + /** Special-purpose Crashlytics target. Please do not use it without permission. */ + kGDTCORTargetCSH = 1002, + + /** Target used for integration testing. */ + kGDTCORTargetINT = 1003, +}; diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h new file mode 100644 index 0000000..33d1ba2 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h @@ -0,0 +1,101 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GDTCOREventTransformer.h" +#import "GDTCORTargets.h" + +@class GDTCOREvent; +@class GDTCORProductData; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORTransport : NSObject + +// Please use the designated initializer. +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes a new transport that will send events to the given target backend. + * + * @param mappingID The mapping identifier used by the backend to map the data object transport + * bytes to a proto. + * @param transformers A list of transformers to be applied to events that are sent. + * @param target The target backend of this transport. + * @return A transport that will send events. + */ +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + transformers: + (nullable NSArray> *)transformers + target:(GDTCORTarget)target NS_DESIGNATED_INITIALIZER; + +/** Copies and sends an internal telemetry event. Events sent using this API are lower in priority, + * and sometimes won't be sent on their own. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + * @param completion A block that will be called when the event has been written or dropped. + */ +- (void)sendTelemetryEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +/** Copies and sends an internal telemetry event. Events sent using this API are lower in priority, + * and sometimes won't be sent on their own. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + */ +- (void)sendTelemetryEvent:(GDTCOREvent *)event; + +/** Copies and sends an SDK service data event. Events send using this API are higher in priority, + * and will cause a network request at some point in the relative near future. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + * @param completion A block that will be called when the event has been written or dropped. + */ +- (void)sendDataEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +/** Copies and sends an SDK service data event. Events send using this API are higher in priority, + * and will cause a network request at some point in the relative near future. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + */ +- (void)sendDataEvent:(GDTCOREvent *)event; + +/** Creates an event for use by this transport. + * + * @return An event that is suited for use by this transport. + */ +- (GDTCOREvent *)eventForTransport; + +/** + * Creates an event with the given product data for use by this transport. + * + * @param productData The given product data to associate with the created event. + * @return An event that is suited for use by this transport. + */ +- (GDTCOREvent *)eventForTransportWithProductData:(nonnull GDTCORProductData *)productData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h new file mode 100644 index 0000000..b5e83d1 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GDTCORClock.h" +#import "GDTCORConsoleLogger.h" +#import "GDTCOREndpoints.h" +#import "GDTCOREvent.h" +#import "GDTCOREventDataObject.h" +#import "GDTCOREventTransformer.h" +#import "GDTCORProductData.h" +#import "GDTCORTargets.h" +#import "GDTCORTransport.h" diff --git a/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/Resources/PrivacyInfo.xcprivacy b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..1e83fa6 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/GoogleDataTransport/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,30 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDiagnosticData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + + + diff --git a/frontend/ios/Pods/GoogleDataTransport/LICENSE b/frontend/ios/Pods/GoogleDataTransport/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/ios/Pods/GoogleDataTransport/README.md b/frontend/ios/Pods/GoogleDataTransport/README.md new file mode 100644 index 0000000..084c2c0 --- /dev/null +++ b/frontend/ios/Pods/GoogleDataTransport/README.md @@ -0,0 +1,236 @@ +[![Version](https://img.shields.io/cocoapods/v/GoogleDataTransport.svg?style=flat)](https://cocoapods.org/pods/GoogleDataTransport) +[![License](https://img.shields.io/cocoapods/l/GoogleDataTransport.svg?style=flat)](https://cocoapods.org/pods/GoogleDataTransport) +[![Platform](https://img.shields.io/cocoapods/p/GoogleDataTransport.svg?style=flat)](https://cocoapods.org/pods/GoogleDataTransport) + +[![Actions Status][gh-datatransport-badge]][gh-actions] + +# GoogleDataTransport + +This library is for internal Google use only. It allows the logging of data and +telemetry from Google SDKs. + +## Integration Testing +These instructions apply to minor and patch version updates. Major versions need +a customized adaptation. + +After the CI is green: +* Determine the next version for release by checking the + [tagged releases](https://github.com/google/GoogleDataTransport/tags). + Ensure that the next release version keeps the Swift PM and CocoaPods versions in sync. +* Verify that the releasing version is the latest entry in the [CHANGELOG.md](CHANGELOG.md), + updating it if necessary. +* Update the version in the podspec to match the latest entry in the [CHANGELOG.md](CHANGELOG.md) +* Checkout the `main` branch and ensure it is up to date. + ```console + git checkout main + git pull + ``` +* Add the CocoaPods tag (`{version}` will be the latest version in the [podspec](GoogleDataTransport.podspec#L3)) + ```console + git tag CocoaPods-{version} + git push origin CocoaPods-{version} + ``` +* Push the podspec to the designated repo + * If this version of GDT is intended to launch **before or with** the next Firebase release: +
+ Push to SpecsStaging + + ```console + pod repo push --skip-tests --use-json staging GoogleDataTransport.podspec + ``` + + If the command fails with `Unable to find the 'staging' repo.`, add the staging repo with: + ```console + pod repo add staging git@github.com:firebase/SpecsStaging.git + ``` +
+ * Otherwise: +
+ Push to SpecsDev + + ```console + pod repo push --skip-tests --use-json dev GoogleDataTransport.podspec + ``` + + If the command fails with `Unable to find the 'dev' repo.`, add the dev repo with: + ```console + pod repo add dev git@github.com:firebase/SpecsDev.git + ``` +
+* Run Firebase CI by waiting until next nightly or adding a PR that touches `Gemfile`. +* On google3, create a workspace and new CL. Then copybara and run a global TAP. +
+  /google/data/ro/teams/copybara/copybara third_party/firebase/ios/Releases/GoogleDataTransport/copy.bara.sky \
+  --piper-description-behavior=OVERWRITE \
+  --destination-cl=YOUR_CL gdt
+  
+ +## Publishing +The release process is as follows: +1. [Tag and release for Swift PM](#swift-package-manager) +2. [Publish to CocoaPods](#cocoapods) +3. [Create GitHub Release](#create-github-release) +4. [Perform post release cleanup](#post-release-cleanup) + +### Swift Package Manager + By creating and [pushing a tag](https://github.com/google/GoogleDataTransport/tags) + for Swift PM, the newly tagged version will be immediately released for public use. + Given this, please verify the intended time of release for Swift PM. + * Add a version tag for Swift PM + ```console + git tag {version} + git push origin {version} + ``` + *Note: Ensure that any inflight PRs that depend on the new `GoogleDataTransport` version are updated to point to the + newly tagged version rather than a checksum.* + +### CocoaPods +* Publish the newly versioned pod to CocoaPods + + It's recommended to point to the `GoogleDataTransport.podspec` in `staging` to make sure the correct spec is being published. + + > [!WARNING] + > Manually update your local SpecsStaging clone or run `pod repo update` + > before proceeding. + + ```console + pod trunk push ~/.cocoapods/repos/staging/GoogleDataTransport/{version}/GoogleDataTransport.podspec.json --skip-tests + ``` + + The pod push was successful if the above command logs: `๐Ÿš€ GoogleDataTransport ({version}) successfully published`. + In addition, a new commit that publishes the new version (co-authored by [CocoaPodsAtGoogle](https://github.com/CocoaPodsAtGoogle)) + should appear in the [CocoaPods specs repo](https://github.com/CocoaPods/Specs). Last, the latest version should be displayed + on [GoogleDataTransport's CocoaPods page](https://cocoapods.org/pods/GoogleDataTransport). + +### [Create GitHub Release](https://github.com/google/GoogleDataTransport/releases/new/) + Update the [release template](https://github.com/google/GoogleDataTransport/releases/new/)'s **Tag version** and **Release title** + fields with the latest version. In addition, reference the [Release Notes](./CHANGELOG.md) in the release's description. + + See [this release](https://github.com/google/GoogleDataTransport/releases/edit/9.0.1) for an example. + + *Don't forget to perform the [post release cleanup](#post-release-cleanup)!* + +### Post Release Cleanup +
+ Clean up SpecsStaging + + ```console + pwd=$(pwd) + mkdir -p /tmp/release-cleanup && cd $_ + git clone git@github.com:firebase/SpecsStaging.git + cd SpecsStaging/ + git rm -rf GoogleDataTransport/ + git commit -m "Post publish cleanup" + git push origin master + rm -rf /tmp/release-cleanup + cd $pwd + ``` +
+ +## Set logging level + +### Swift + +- Import `GoogleDataTransport` module: + ```swift + import GoogleDataTransport + ``` +- Set logging level global variable to the desired value before calling `FirebaseApp.configure()`: + ```swift + GDTCORConsoleLoggerLoggingLevel = GDTCORLoggingLevel.debug.rawValue + ``` +### Objective-C + +- Import `GoogleDataTransport`: + ```objective-c + #import + ``` +- Set logging level global variable to the desired value before calling `-[FIRApp configure]`: + ```objective-c + GDTCORConsoleLoggerLoggingLevel = GDTCORLoggingLevelDebug; + ``` + +## Prereqs + +- `gem install --user cocoapods cocoapods-generate` +- `brew install protobuf nanopb-generator` +- `easy_install --user protobuf` + +## To develop + +- Run `./GoogleDataTransport/generate_project.sh` after installing the prereqs + +## When adding new logging endpoint + +- Use commands similar to: + - `python -c "line='https://www.firebase.com'; print line[0::2]" ` + - `python -c "line='https://www.firebase.com'; print line[1::2]" ` + +## When adding internal code that shouldn't be easily usable on github + +- Consider using go/copybara-library/scrubbing#cc_scrub + +## Development + +Ensure that you have at least the following software: + + * Xcode 12.0 (or later) + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen GoogleDataTransport.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +### Development for Catalyst +* `pod gen GoogleDataTransport.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +iOS SDK. + +## License + +The contents of this repository is licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions +[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m new file mode 100644 index 0000000..3b7280e --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m @@ -0,0 +1,1023 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h" +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +#import +#import + +// Implementations need to be typed before calling the implementation directly to cast the +// arguments and the return types correctly. Otherwise, it will crash the app. +typedef BOOL (*GULRealOpenURLSourceApplicationAnnotationIMP)( + id, SEL, GULApplication *, NSURL *, NSString *, id); + +typedef BOOL (*GULRealOpenURLOptionsIMP)( + id, SEL, GULApplication *, NSURL *, NSDictionary *); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" +typedef void (*GULRealHandleEventsForBackgroundURLSessionIMP)( + id, SEL, GULApplication *, NSString *, void (^)()); +#pragma clang diagnostic pop + +typedef BOOL (*GULRealContinueUserActivityIMP)( + id, SEL, GULApplication *, NSUserActivity *, void (^)(NSArray *restorableObjects)); + +typedef void (*GULRealDidRegisterForRemoteNotificationsIMP)(id, SEL, GULApplication *, NSData *); + +typedef void (*GULRealDidFailToRegisterForRemoteNotificationsIMP)(id, + SEL, + GULApplication *, + NSError *); + +typedef void (*GULRealDidReceiveRemoteNotificationIMP)(id, SEL, GULApplication *, NSDictionary *); + +#if !TARGET_OS_WATCH && !TARGET_OS_OSX +typedef void (*GULRealDidReceiveRemoteNotificationWithCompletionIMP)( + id, SEL, GULApplication *, NSDictionary *, void (^)(UIBackgroundFetchResult)); +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX + +typedef void (^GULAppDelegateInterceptorCallback)(id); + +// The strings below are the keys for associated objects. +static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector"; +static char const *const kGULRealClassKey = "GUL_realClass"; + +static NSString *const kGULAppDelegateKeyPath = @"delegate"; + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/AppDelegateSwizzler]"; + +// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change +// we disable App Delegate proxying when either of these two flags are set to NO. + +/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */ +static NSString *const kGULFirebaseAppDelegateProxyEnabledPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying. + */ +static NSString *const kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey = + @"GoogleUtilitiesAppDelegateProxyEnabled"; + +/** The prefix of the App Delegate. */ +static NSString *const kGULAppDelegatePrefix = @"GUL_"; + +/** The original instance of App Delegate. */ +static id gOriginalAppDelegate; + +/** The original App Delegate class */ +static Class gOriginalAppDelegateClass; + +/** The subclass of the original App Delegate. */ +static Class gAppDelegateSubclass; + +/** Remote notification methods selectors + * + * We have to opt out of referencing APNS related App Delegate methods directly to prevent + * an Apple review warning email about missing Push Notification Entitlement + * (like here: https://github.com/firebase/firebase-ios-sdk/issues/2807). From our experience, the + * warning is triggered when any of the symbols is present in the application sent to review, even + * if the code is never executed. Because GULAppDelegateSwizzler may be used by applications that + * are not using APNS we have to refer to the methods indirectly using selector constructed from + * string. + * + * NOTE: None of the methods is proxied unless it is explicitly requested by calling the method + * +[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods] + */ +static NSString *const kGULDidRegisterForRemoteNotificationsSEL = + @"application:didRegisterForRemoteNotificationsWithDeviceToken:"; +static NSString *const kGULDidFailToRegisterForRemoteNotificationsSEL = + @"application:didFailToRegisterForRemoteNotificationsWithError:"; +static NSString *const kGULDidReceiveRemoteNotificationWithCompletionSEL = + @"application:didReceiveRemoteNotification:fetchCompletionHandler:"; + +/** + * This class is necessary to store the delegates in an NSArray without retaining them. + * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a + * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is + * dealloced. Instead, this container stores a weak, zeroing reference to the object, which + * automatically is set to nil by the runtime when the object is dealloced. + */ +@interface GULZeroingWeakContainer : NSObject + +/** Stores a weak object. */ +@property(nonatomic, weak) id object; + +@end + +@implementation GULZeroingWeakContainer +@end + +@interface GULAppDelegateObserver : NSObject +@end + +@implementation GULAppDelegateObserver { + BOOL _isObserving; +} + ++ (GULAppDelegateObserver *)sharedInstance { + static GULAppDelegateObserver *instance; + static dispatch_once_t once; + dispatch_once(&once, ^{ + instance = [[GULAppDelegateObserver alloc] init]; + }); + return instance; +} + +- (void)observeUIApplication { + if (_isObserving) { + return; + } + [[GULAppDelegateSwizzler sharedApplication] + addObserver:self + forKeyPath:kGULAppDelegateKeyPath + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld + context:nil]; + _isObserving = YES; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if ([keyPath isEqual:kGULAppDelegateKeyPath]) { + id newValue = change[NSKeyValueChangeNewKey]; + id oldValue = change[NSKeyValueChangeOldKey]; + if ([newValue isEqual:oldValue]) { + return; + } + // Free the stored app delegate instance because it has been changed to a different instance to + // avoid keeping it alive forever. + if ([oldValue isEqual:gOriginalAppDelegate]) { + gOriginalAppDelegate = nil; + // Remove the observer. Parse it to NSObject to avoid warning. + [[GULAppDelegateSwizzler sharedApplication] removeObserver:self + forKeyPath:kGULAppDelegateKeyPath]; + _isObserving = NO; + } + } +} + +@end + +@implementation GULAppDelegateSwizzler + +static dispatch_once_t sProxyAppDelegateOnceToken; +static dispatch_once_t sProxyAppDelegateRemoteNotificationOnceToken; + +#pragma mark - Public methods + ++ (BOOL)isAppDelegateProxyEnabled { + NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary; + + id isFirebaseProxyEnabledPlistValue = infoDictionary[kGULFirebaseAppDelegateProxyEnabledPlistKey]; + id isGoogleProxyEnabledPlistValue = + infoDictionary[kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey]; + + // Enabled by default. + BOOL isFirebaseAppDelegateProxyEnabled = YES; + BOOL isGoogleUtilitiesAppDelegateProxyEnabled = YES; + + if ([isFirebaseProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) { + isFirebaseAppDelegateProxyEnabled = [isFirebaseProxyEnabledPlistValue boolValue]; + } + + if ([isGoogleProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) { + isGoogleUtilitiesAppDelegateProxyEnabled = [isGoogleProxyEnabledPlistValue boolValue]; + } + + // Only deactivate the proxy if it is explicitly disabled by app developers using either one of + // the plist flags. + return isFirebaseAppDelegateProxyEnabled && isGoogleUtilitiesAppDelegateProxyEnabled; +} + ++ (GULAppDelegateInterceptorID)registerAppDelegateInterceptor: + (id)interceptor { + NSAssert(interceptor, @"AppDelegateProxy cannot add nil interceptor"); + NSAssert([interceptor conformsToProtocol:@protocol(GULApplicationDelegate)], + @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate"); + + if (!interceptor) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling000], + @"AppDelegateProxy cannot add nil interceptor."); + return nil; + } + if (![interceptor conformsToProtocol:@protocol(GULApplicationDelegate)]) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling001], + @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate"); + return nil; + } + + // The ID should be the same given the same interceptor object. + NSString *interceptorID = [NSString stringWithFormat:@"%@%p", kGULAppDelegatePrefix, interceptor]; + if (!interceptorID.length) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling002], + @"AppDelegateProxy cannot create Interceptor ID."); + return nil; + } + GULZeroingWeakContainer *weakObject = [[GULZeroingWeakContainer alloc] init]; + weakObject.object = interceptor; + [GULAppDelegateSwizzler interceptors][interceptorID] = weakObject; + return interceptorID; +} + ++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID { + NSAssert(interceptorID, @"AppDelegateProxy cannot unregister nil interceptor ID."); + NSAssert(((NSString *)interceptorID).length != 0, + @"AppDelegateProxy cannot unregister empty interceptor ID."); + + if (!interceptorID) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling003], + @"AppDelegateProxy cannot unregister empty interceptor ID."); + return; + } + + GULZeroingWeakContainer *weakContainer = [GULAppDelegateSwizzler interceptors][interceptorID]; + if (!weakContainer.object) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling004], + @"AppDelegateProxy cannot unregister interceptor that was not registered. " + "Interceptor ID %@", + interceptorID); + return; + } + + [[GULAppDelegateSwizzler interceptors] removeObjectForKey:interceptorID]; +} + ++ (void)proxyOriginalDelegate { + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + dispatch_once(&sProxyAppDelegateOnceToken, ^{ + id originalDelegate = + [GULAppDelegateSwizzler sharedApplication].delegate; + [GULAppDelegateSwizzler proxyAppDelegate:originalDelegate]; + }); +} + ++ (void)proxyOriginalDelegateIncludingAPNSMethods { + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + [self proxyOriginalDelegate]; + + dispatch_once(&sProxyAppDelegateRemoteNotificationOnceToken, ^{ + id appDelegate = [GULAppDelegateSwizzler sharedApplication].delegate; + + NSMutableDictionary *realImplementationsBySelector = + [objc_getAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey) mutableCopy]; + + [self proxyRemoteNotificationsMethodsWithAppDelegateSubClass:gAppDelegateSubclass + realClass:gOriginalAppDelegateClass + appDelegate:appDelegate + realImplementationsBySelector:realImplementationsBySelector]; + + objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN); + [self reassignAppDelegate]; + }); +} + +#pragma mark - Create proxy + ++ (GULApplication *)sharedApplication { + if ([GULAppEnvironmentUtil isAppExtension]) { + return nil; + } + id sharedApplication = nil; + Class uiApplicationClass = NSClassFromString(kGULApplicationClassName); + if (uiApplicationClass && + [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) { + sharedApplication = [uiApplicationClass sharedApplication]; + } + return sharedApplication; +} + +#pragma mark - Override default methods + +/** Creates a new subclass of the class of the given object and sets the isa value of the given + * object to the new subclass. Additionally this copies methods to that new subclass that allow us + * to intercept UIApplicationDelegate methods. This is better known as isa swizzling. + * + * @param appDelegate The object to which you want to isa swizzle. This has to conform to the + * UIApplicationDelegate subclass. + * @return Returns the new subclass. + */ ++ (nullable Class)createSubclassWithObject:(id)appDelegate { + Class realClass = [appDelegate class]; + + // Create GUL__ + NSString *classNameWithPrefix = + [kGULAppDelegatePrefix stringByAppendingString:NSStringFromClass(realClass)]; + NSString *newClassName = + [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString]; + + if (NSClassFromString(newClassName)) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling005], + @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " + @"%@, subclass: %@", + NSStringFromClass(realClass), newClassName); + return nil; + } + + // Register the new class as subclass of the real one. Do not allocate more than the real class + // size. + Class appDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0); + if (appDelegateSubClass == Nil) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling006], + @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " + @"%@, subclass: Nil", + NSStringFromClass(realClass)); + return nil; + } + + NSMutableDictionary *realImplementationsBySelector = + [[NSMutableDictionary alloc] init]; + + // For application:continueUserActivity:restorationHandler: + SEL continueUserActivitySEL = @selector(application:continueUserActivity:restorationHandler:); + [self proxyDestinationSelector:continueUserActivitySEL + implementationsFromSourceSelector:continueUserActivitySEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + +#if TARGET_OS_IOS || TARGET_OS_TV + // Add the following methods from GULAppDelegate class, and store the real implementation so it + // can forward to the real one. + // For application:openURL:options: + SEL applicationOpenURLOptionsSEL = @selector(application:openURL:options:); + if ([appDelegate respondsToSelector:applicationOpenURLOptionsSEL]) { + // Only add the application:openURL:options: method if the original AppDelegate implements it. + // This fixes a bug if an app only implements application:openURL:sourceApplication:annotation: + // (if we add the `options` method, iOS sees that one exists and does not call the + // `sourceApplication` method, which in this case is the only one the app implements). + + [self proxyDestinationSelector:applicationOpenURLOptionsSEL + implementationsFromSourceSelector:applicationOpenURLOptionsSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + } + + // For application:handleEventsForBackgroundURLSession:completionHandler: + SEL handleEventsForBackgroundURLSessionSEL = @selector(application: + handleEventsForBackgroundURLSession:completionHandler:); + [self proxyDestinationSelector:handleEventsForBackgroundURLSessionSEL + implementationsFromSourceSelector:handleEventsForBackgroundURLSessionSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_IOS + // For application:openURL:sourceApplication:annotation: + SEL openURLSourceApplicationAnnotationSEL = @selector(application: + openURL:sourceApplication:annotation:); + + [self proxyDestinationSelector:openURLSourceApplicationAnnotationSEL + implementationsFromSourceSelector:openURLSourceApplicationAnnotationSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // TARGET_OS_IOS + + // Override the description too so the custom class name will not show up. + [GULAppDelegateSwizzler addInstanceMethodWithDestinationSelector:@selector(description) + withImplementationFromSourceSelector:@selector(fakeDescription) + fromClass:[self class] + toClass:appDelegateSubClass]; + + // Store original implementations to a fake property of the original delegate. + objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(appDelegate, &kGULRealClassKey, realClass, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + // The subclass size has to be exactly the same size with the original class size. The subclass + // cannot have more ivars/properties than its superclass since it will cause an offset in memory + // that can lead to overwriting the isa of an object in the next frame. + if (class_getInstanceSize(realClass) != class_getInstanceSize(appDelegateSubClass)) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling007], + @"Cannot create subclass of App Delegate, because the created subclass is not the " + @"same size. %@", + NSStringFromClass(realClass)); + NSAssert(NO, @"Classes must be the same size to swizzle isa"); + return nil; + } + + // Make the newly created class to be the subclass of the real App Delegate class. + objc_registerClassPair(appDelegateSubClass); + if (object_setClass(appDelegate, appDelegateSubClass)) { + GULOSLogDebug(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling008], + @"Successfully created App Delegate Proxy automatically. To disable the " + @"proxy, set the flag %@ to NO (Boolean) in the Info.plist", + [GULAppDelegateSwizzler correctAppDelegateProxyKey]); + } + + return appDelegateSubClass; +} + ++ (void)proxyRemoteNotificationsMethodsWithAppDelegateSubClass:(Class)appDelegateSubClass + realClass:(Class)realClass + appDelegate:(id)appDelegate + realImplementationsBySelector: + (NSMutableDictionary *)realImplementationsBySelector { + if (realClass == nil || appDelegateSubClass == nil || appDelegate == nil || + realImplementationsBySelector == nil) { + // The App Delegate has not been swizzled. + return; + } + + // For application:didRegisterForRemoteNotificationsWithDeviceToken: + SEL didRegisterForRemoteNotificationsSEL = + NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL); + SEL didRegisterForRemoteNotificationsDonorSEL = @selector(application: + donor_didRegisterForRemoteNotificationsWithDeviceToken:); + + [self proxyDestinationSelector:didRegisterForRemoteNotificationsSEL + implementationsFromSourceSelector:didRegisterForRemoteNotificationsDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didFailToRegisterForRemoteNotificationsWithError: + SEL didFailToRegisterForRemoteNotificationsSEL = + NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL); + SEL didFailToRegisterForRemoteNotificationsDonorSEL = @selector(application: + donor_didFailToRegisterForRemoteNotificationsWithError:); + + [self proxyDestinationSelector:didFailToRegisterForRemoteNotificationsSEL + implementationsFromSourceSelector:didFailToRegisterForRemoteNotificationsDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didReceiveRemoteNotification:fetchCompletionHandler: +#if !TARGET_OS_WATCH && !TARGET_OS_OSX + SEL didReceiveRemoteNotificationWithCompletionSEL = + NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL); + SEL didReceiveRemoteNotificationWithCompletionDonorSEL = + @selector(application:donor_didReceiveRemoteNotification:fetchCompletionHandler:); + [self proxyDestinationSelector:didReceiveRemoteNotificationWithCompletionSEL + implementationsFromSourceSelector:didReceiveRemoteNotificationWithCompletionDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX +} + +/// We have to do this to invalidate the cache that caches the original respondsToSelector of +/// openURL handlers. Without this, it won't call the default implementations because the system +/// checks and caches them. +/// Register KVO only once. Otherwise, the observing method will be called as many times as +/// being registered. ++ (void)reassignAppDelegate { +#if !TARGET_OS_WATCH + id delegate = [self sharedApplication].delegate; + [self sharedApplication].delegate = nil; + [self sharedApplication].delegate = delegate; + gOriginalAppDelegate = delegate; + [[GULAppDelegateObserver sharedInstance] observeUIApplication]; +#endif +} + +#pragma mark - Helper methods + ++ (GULMutableDictionary *)interceptors { + static dispatch_once_t onceToken; + static GULMutableDictionary *sInterceptors; + dispatch_once(&onceToken, ^{ + sInterceptors = [[GULMutableDictionary alloc] init]; + }); + return sInterceptors; +} + ++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object { + NSDictionary *realImplementationBySelector = + objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey); + return realImplementationBySelector[NSStringFromSelector(selector)]; +} + ++ (void)proxyDestinationSelector:(SEL)destinationSelector + implementationsFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)sourceClass + toClass:(Class)destinationClass + realClass:(Class)realClass + storeDestinationImplementationTo: + (NSMutableDictionary *)destinationImplementationsBySelector { + [self addInstanceMethodWithDestinationSelector:destinationSelector + withImplementationFromSourceSelector:sourceSelector + fromClass:sourceClass + toClass:destinationClass]; + IMP sourceImplementation = + [GULAppDelegateSwizzler implementationOfMethodSelector:destinationSelector + fromClass:realClass]; + NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation]; + + NSString *destinationSelectorString = NSStringFromSelector(destinationSelector); + destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer; +} + +/** Copies a method identified by the methodSelector from one class to the other. After this method + * is called, performing [toClassInstance methodSelector] will be similar to calling + * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method + * identified by methodSelector. + * + * @param methodSelector The SEL that identifies both the method on the fromClass as well as the + * one on the toClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithSelector:(SEL)methodSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + [self addInstanceMethodWithDestinationSelector:methodSelector + withImplementationFromSourceSelector:methodSelector + fromClass:fromClass + toClass:toClass]; +} + +/** Copies a method identified by the sourceSelector from the fromClass as a method for the + * destinationSelector on the toClass. After this method is called, performing + * [toClassInstance destinationSelector] will be similar to calling + * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method + * identified by destinationSelector. + * + * @param destinationSelector The SEL that identifies the method on the toClass. + * @param sourceSelector The SEL that identifies the method on the fromClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector + withImplementationFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + Method method = class_getInstanceMethod(fromClass, sourceSelector); + IMP methodIMP = method_getImplementation(method); + const char *types = method_getTypeEncoding(method); + if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) { + GULOSLogWarning( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling009], + @"Cannot copy method to destination selector %@ as it already exists", + NSStringFromSelector(destinationSelector)); + } +} + +/** Gets the IMP of the instance method on the class identified by the selector. + * + * @param selector The selector of which the IMP is to be fetched. + * @param aClass The class from which the IMP is to be fetched. + * @return The IMP of the instance method identified by selector and aClass. + */ ++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass { + Method aMethod = class_getInstanceMethod(aClass, selector); + return method_getImplementation(aMethod); +} + +/** Enumerates through all the interceptors and if they respond to a given selector, executes a + * GULAppDelegateInterceptorCallback with the interceptor. + * + * @param methodSelector The SEL to check if an interceptor responds to. + * @param callback the GULAppDelegateInterceptorCallback. + */ ++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector + callback:(GULAppDelegateInterceptorCallback)callback { + if (!callback) { + return; + } + + NSDictionary *interceptors = [GULAppDelegateSwizzler interceptors].dictionary; + [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + GULZeroingWeakContainer *interceptorContainer = obj; + id interceptor = interceptorContainer.object; + if (!interceptor) { + GULOSLogWarning( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling010], + @"AppDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key); + [[GULAppDelegateSwizzler interceptors] removeObjectForKey:key]; + return; + } + if ([interceptor respondsToSelector:methodSelector]) { + callback(interceptor); + } + }]; +} + +// The methods below are donor methods which are added to the dynamic subclass of the App Delegate. +// They are called within the scope of the real App Delegate so |self| does not refer to the +// GULAppDelegateSwizzler instance but the real App Delegate instance. + +#pragma mark - [Donor Methods] Overridden instance description method + +- (NSString *)fakeDescription { + Class realClass = objc_getAssociatedObject(self, &kGULRealClassKey); + return [NSString stringWithFormat:@"<%@: %p>", realClass, self]; +} + +#pragma mark - [Donor Methods] URL overridden handler methods +#if TARGET_OS_IOS || TARGET_OS_TV + +- (BOOL)application:(GULApplication *)application + openURL:(NSURL *)url + options:(NSDictionary *)options { + SEL methodSelector = @selector(application:openURL:options:); + // Call the real implementation if the real App Delegate has any. + NSValue *openURLIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealOpenURLOptionsIMP openURLOptionsIMP = [openURLIMPPointer pointerValue]; + + __block BOOL returnedValue = NO; + +// This is needed to for the library to be warning free on iOS versions < 9. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + returnedValue |= [interceptor application:application + openURL:url + options:options]; + }]; +#pragma clang diagnostic pop + if (openURLOptionsIMP) { + returnedValue |= openURLOptionsIMP(self, methodSelector, application, url, options); + } + return returnedValue; +} + +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_IOS + +- (BOOL)application:(GULApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation { + SEL methodSelector = @selector(application:openURL:sourceApplication:annotation:); + + // Call the real implementation if the real App Delegate has any. + NSValue *openURLSourceAppAnnotationIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealOpenURLSourceApplicationAnnotationIMP openURLSourceApplicationAnnotationIMP = + [openURLSourceAppAnnotationIMPPointer pointerValue]; + + __block BOOL returnedValue = NO; + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + returnedValue |= [interceptor application:application + openURL:url + sourceApplication:sourceApplication + annotation:annotation]; +#pragma clang diagnostic pop + }]; + if (openURLSourceApplicationAnnotationIMP) { + returnedValue |= openURLSourceApplicationAnnotationIMP(self, methodSelector, application, url, + sourceApplication, annotation); + } + return returnedValue; +} + +#endif // TARGET_OS_IOS + +#pragma mark - [Donor Methods] Network overridden handler methods + +#if TARGET_OS_IOS || TARGET_OS_TV + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" +- (void)application:(GULApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(void (^)())completionHandler { +#pragma clang diagnostic pop + SEL methodSelector = @selector(application: + handleEventsForBackgroundURLSession:completionHandler:); + NSValue *handleBackgroundSessionPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealHandleEventsForBackgroundURLSessionIMP handleBackgroundSessionIMP = + [handleBackgroundSessionPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + [interceptor application:application + handleEventsForBackgroundURLSession:identifier + completionHandler:completionHandler]; + }]; + // Call the real implementation if the real App Delegate has any. + if (handleBackgroundSessionIMP) { + handleBackgroundSessionIMP(self, methodSelector, application, identifier, completionHandler); + } +} + +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#pragma mark - [Donor Methods] User Activities overridden handler methods + +- (BOOL)application:(GULApplication *)application + continueUserActivity:(NSUserActivity *)userActivity + restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { + SEL methodSelector = @selector(application:continueUserActivity:restorationHandler:); + NSValue *continueUserActivityIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealContinueUserActivityIMP continueUserActivityIMP = + continueUserActivityIMPPointer.pointerValue; + + __block BOOL returnedValue = NO; +#if !TARGET_OS_WATCH + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + returnedValue |= [interceptor application:application + continueUserActivity:userActivity + restorationHandler:restorationHandler]; + }]; +#endif + // Call the real implementation if the real App Delegate has any. + if (continueUserActivityIMP) { + returnedValue |= continueUserActivityIMP(self, methodSelector, application, userActivity, + restorationHandler); + } + return returnedValue; +} + +#pragma mark - [Donor Methods] Remote Notifications + +- (void)application:(GULApplication *)application + donor_didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + SEL methodSelector = NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL); + + NSValue *didRegisterForRemoteNotificationsIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidRegisterForRemoteNotificationsIMP didRegisterForRemoteNotificationsIMP = + [didRegisterForRemoteNotificationsIMPPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&deviceToken) atIndex:3]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didRegisterForRemoteNotificationsIMP) { + didRegisterForRemoteNotificationsIMP(self, methodSelector, application, deviceToken); + } +} + +- (void)application:(GULApplication *)application + donor_didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { + SEL methodSelector = NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL); + NSValue *didFailToRegisterForRemoteNotificationsIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidFailToRegisterForRemoteNotificationsIMP didFailToRegisterForRemoteNotificationsIMP = + [didFailToRegisterForRemoteNotificationsIMPPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&error) atIndex:3]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didFailToRegisterForRemoteNotificationsIMP) { + didFailToRegisterForRemoteNotificationsIMP(self, methodSelector, application, error); + } +} + +#if !TARGET_OS_WATCH && !TARGET_OS_OSX +- (void)application:(GULApplication *)application + donor_didReceiveRemoteNotification:(NSDictionary *)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { + SEL methodSelector = NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL); + NSValue *didReceiveRemoteNotificationWithCompletionIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidReceiveRemoteNotificationWithCompletionIMP + didReceiveRemoteNotificationWithCompletionIMP = + [didReceiveRemoteNotificationWithCompletionIMPPointer pointerValue]; + + dispatch_group_t __block callbackGroup = dispatch_group_create(); + NSMutableArray *__block fetchResults = [NSMutableArray array]; + + void (^localCompletionHandler)(UIBackgroundFetchResult) = + ^void(UIBackgroundFetchResult fetchResult) { + [fetchResults addObject:[NSNumber numberWithInt:(int)fetchResult]]; + dispatch_group_leave(callbackGroup); + }; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + dispatch_group_enter(callbackGroup); + + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&userInfo) atIndex:3]; + [invocation setArgument:(void *)(&localCompletionHandler) + atIndex:4]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didReceiveRemoteNotificationWithCompletionIMP) { + dispatch_group_enter(callbackGroup); + + didReceiveRemoteNotificationWithCompletionIMP(self, methodSelector, application, userInfo, + localCompletionHandler); + } + + dispatch_group_notify(callbackGroup, dispatch_get_main_queue(), ^() { + BOOL allFetchesFailed = YES; + BOOL anyFetchHasNewData = NO; + + for (NSNumber *oneResult in fetchResults) { + UIBackgroundFetchResult result = oneResult.intValue; + + switch (result) { + case UIBackgroundFetchResultNoData: + allFetchesFailed = NO; + break; + case UIBackgroundFetchResultNewData: + allFetchesFailed = NO; + anyFetchHasNewData = YES; + break; + case UIBackgroundFetchResultFailed: + + break; + } + } + + UIBackgroundFetchResult finalFetchResult = UIBackgroundFetchResultNoData; + + if (allFetchesFailed) { + finalFetchResult = UIBackgroundFetchResultFailed; + } else if (anyFetchHasNewData) { + finalFetchResult = UIBackgroundFetchResultNewData; + } else { + finalFetchResult = UIBackgroundFetchResultNoData; + } + + completionHandler(finalFetchResult); + }); +} +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX + ++ (nullable NSInvocation *)appDelegateInvocationForSelector:(SEL)selector { + struct objc_method_description methodDescription = + protocol_getMethodDescription(@protocol(GULApplicationDelegate), selector, NO, YES); + if (methodDescription.types == NULL) { + return nil; + } + + NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:methodDescription.types]; + return [NSInvocation invocationWithMethodSignature:signature]; +} + ++ (void)proxyAppDelegate:(id)appDelegate { + if (![appDelegate conformsToProtocol:@protocol(GULApplicationDelegate)]) { + GULOSLogNotice( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate], + @"App Delegate does not conform to UIApplicationDelegate protocol. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + + id originalDelegate = appDelegate; + // Do not create a subclass if it is not enabled. + if (![GULAppDelegateSwizzler isAppDelegateProxyEnabled]) { + GULOSLogNotice(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling011], + @"App Delegate Proxy is disabled. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + // Do not accept nil delegate. + if (!originalDelegate) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling012], + @"Cannot create App Delegate Proxy because App Delegate instance is nil. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + + @try { + gOriginalAppDelegateClass = [originalDelegate class]; + gAppDelegateSubclass = [self createSubclassWithObject:originalDelegate]; + [self reassignAppDelegate]; + } @catch (NSException *exception) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling013], + @"Cannot create App Delegate Proxy. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } +} + +#pragma mark - Methods to print correct debug logs + ++ (NSString *)correctAppDelegateProxyKey { + return NSClassFromString(@"FIRCore") ? kGULFirebaseAppDelegateProxyEnabledPlistKey + : kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey; +} + ++ (NSString *)correctAlternativeWhenAppDelegateProxyNotCreated { + return NSClassFromString(@"FIRCore") + ? @"To log deep link campaigns manually, call the methods in " + @"FIRAnalytics+AppDelegate.h." + : @""; +} + +#pragma mark - Private Methods for Testing + ++ (void)clearInterceptors { + [[self interceptors] removeAllObjects]; +} + ++ (void)resetProxyOriginalDelegateOnceToken { + sProxyAppDelegateOnceToken = 0; + sProxyAppDelegateRemoteNotificationOnceToken = 0; +} + ++ (id)originalDelegate { + return gOriginalAppDelegate; +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m new file mode 100644 index 0000000..87adac4 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m @@ -0,0 +1,444 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h" + +#import "GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h" +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +#import + +#if UISCENE_SUPPORTED +API_AVAILABLE(ios(13.0), tvos(13.0)) +typedef void (*GULOpenURLContextsIMP)(id, SEL, UIScene *, NSSet *); + +API_AVAILABLE(ios(13.0), tvos(13.0)) +typedef void (^GULSceneDelegateInterceptorCallback)(id); + +// The strings below are the keys for associated objects. +static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector"; +static char const *const kGULRealClassKey = "GUL_realClass"; +#endif // UISCENE_SUPPORTED + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/SceneDelegateSwizzler]"; + +// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change +// we disable App Delegate proxying when either of these two flags are set to NO. + +/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */ +static NSString *const kGULFirebaseSceneDelegateProxyEnabledPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying. + */ +static NSString *const kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey = + @"GoogleUtilitiesAppDelegateProxyEnabled"; + +/** The prefix of the Scene Delegate. */ +static NSString *const kGULSceneDelegatePrefix = @"GUL_"; + +/** + * This class is necessary to store the delegates in an NSArray without retaining them. + * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a + * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is + * dealloced. Instead, this container stores a weak, zeroing reference to the object, which + * automatically is set to nil by the runtime when the object is dealloced. + */ +@interface GULSceneZeroingWeakContainer : NSObject + +/** Stores a weak object. */ +@property(nonatomic, weak) id object; + +@end + +@implementation GULSceneZeroingWeakContainer +@end + +@implementation GULSceneDelegateSwizzler + +#pragma mark - Public methods + ++ (BOOL)isSceneDelegateProxyEnabled { + return [GULAppDelegateSwizzler isAppDelegateProxyEnabled]; +} + ++ (void)proxyOriginalSceneDelegate { +#if UISCENE_SUPPORTED + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (@available(iOS 13.0, tvOS 13.0, *)) { + if (![GULSceneDelegateSwizzler isSceneDelegateProxyEnabled]) { + return; + } + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(handleSceneWillConnectToNotification:) + name:UISceneWillConnectNotification + object:nil]; + } + }); +#endif // UISCENE_SUPPORTED +} + +#if UISCENE_SUPPORTED ++ (GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor:(id)interceptor { + NSAssert(interceptor, @"SceneDelegateProxy cannot add nil interceptor"); + NSAssert([interceptor conformsToProtocol:@protocol(UISceneDelegate)], + @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate"); + + if (!interceptor) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling000], + @"SceneDelegateProxy cannot add nil interceptor."); + return nil; + } + if (![interceptor conformsToProtocol:@protocol(UISceneDelegate)]) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling001], + @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate"); + return nil; + } + + // The ID should be the same given the same interceptor object. + NSString *interceptorID = + [NSString stringWithFormat:@"%@%p", kGULSceneDelegatePrefix, interceptor]; + if (!interceptorID.length) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling002], + @"SceneDelegateProxy cannot create Interceptor ID."); + return nil; + } + GULSceneZeroingWeakContainer *weakObject = [[GULSceneZeroingWeakContainer alloc] init]; + weakObject.object = interceptor; + [GULSceneDelegateSwizzler interceptors][interceptorID] = weakObject; + return interceptorID; +} + ++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID { + NSAssert(interceptorID, @"SceneDelegateProxy cannot unregister nil interceptor ID."); + NSAssert(((NSString *)interceptorID).length != 0, + @"SceneDelegateProxy cannot unregister empty interceptor ID."); + + if (!interceptorID) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling003], + @"SceneDelegateProxy cannot unregister empty interceptor ID."); + return; + } + + GULSceneZeroingWeakContainer *weakContainer = + [GULSceneDelegateSwizzler interceptors][interceptorID]; + if (!weakContainer.object) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling004], + @"SceneDelegateProxy cannot unregister interceptor that was not registered. " + "Interceptor ID %@", + interceptorID); + return; + } + + [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:interceptorID]; +} + +#pragma mark - Helper methods + ++ (GULMutableDictionary *)interceptors { + static dispatch_once_t onceToken; + static GULMutableDictionary *sInterceptors; + dispatch_once(&onceToken, ^{ + sInterceptors = [[GULMutableDictionary alloc] init]; + }); + return sInterceptors; +} + ++ (void)clearInterceptors { + [[self interceptors] removeAllObjects]; +} + ++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object { + NSDictionary *realImplementationBySelector = + objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey); + return realImplementationBySelector[NSStringFromSelector(selector)]; +} + ++ (void)proxyDestinationSelector:(SEL)destinationSelector + implementationsFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)sourceClass + toClass:(Class)destinationClass + realClass:(Class)realClass + storeDestinationImplementationTo: + (NSMutableDictionary *)destinationImplementationsBySelector { + [self addInstanceMethodWithDestinationSelector:destinationSelector + withImplementationFromSourceSelector:sourceSelector + fromClass:sourceClass + toClass:destinationClass]; + IMP sourceImplementation = + [GULSceneDelegateSwizzler implementationOfMethodSelector:destinationSelector + fromClass:realClass]; + NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation]; + + NSString *destinationSelectorString = NSStringFromSelector(destinationSelector); + destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer; +} + +/** Copies a method identified by the methodSelector from one class to the other. After this method + * is called, performing [toClassInstance methodSelector] will be similar to calling + * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method + * identified by methodSelector. + * + * @param methodSelector The SEL that identifies both the method on the fromClass as well as the + * one on the toClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithSelector:(SEL)methodSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + [self addInstanceMethodWithDestinationSelector:methodSelector + withImplementationFromSourceSelector:methodSelector + fromClass:fromClass + toClass:toClass]; +} + +/** Copies a method identified by the sourceSelector from the fromClass as a method for the + * destinationSelector on the toClass. After this method is called, performing + * [toClassInstance destinationSelector] will be similar to calling + * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method + * identified by destinationSelector. + * + * @param destinationSelector The SEL that identifies the method on the toClass. + * @param sourceSelector The SEL that identifies the method on the fromClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector + withImplementationFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + Method method = class_getInstanceMethod(fromClass, sourceSelector); + IMP methodIMP = method_getImplementation(method); + const char *types = method_getTypeEncoding(method); + if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) { + GULOSLogWarning( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling009], + @"Cannot copy method to destination selector %@ as it already exists", + NSStringFromSelector(destinationSelector)); + } +} + +/** Gets the IMP of the instance method on the class identified by the selector. + * + * @param selector The selector of which the IMP is to be fetched. + * @param aClass The class from which the IMP is to be fetched. + * @return The IMP of the instance method identified by selector and aClass. + */ ++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass { + Method aMethod = class_getInstanceMethod(aClass, selector); + return method_getImplementation(aMethod); +} + +/** Enumerates through all the interceptors and if they respond to a given selector, executes a + * GULSceneDelegateInterceptorCallback with the interceptor. + * + * @param methodSelector The SEL to check if an interceptor responds to. + * @param callback the GULSceneDelegateInterceptorCallback. + */ ++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector + callback:(GULSceneDelegateInterceptorCallback)callback + API_AVAILABLE(ios(13.0)) { + if (!callback) { + return; + } + + NSDictionary *interceptors = [GULSceneDelegateSwizzler interceptors].dictionary; + [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + GULSceneZeroingWeakContainer *interceptorContainer = obj; + id interceptor = interceptorContainer.object; + if (!interceptor) { + GULOSLogWarning( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling010], + @"SceneDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key); + [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:key]; + return; + } + if ([interceptor respondsToSelector:methodSelector]) { + callback(interceptor); + } + }]; +} + ++ (void)handleSceneWillConnectToNotification:(NSNotification *)notification { + if (@available(iOS 13.0, tvOS 13.0, *)) { + if ([notification.object isKindOfClass:[UIScene class]]) { + UIScene *scene = (UIScene *)notification.object; + [GULSceneDelegateSwizzler proxySceneDelegateIfNeeded:scene]; + } + } +} + +#pragma mark - [Donor Methods] UISceneDelegate URL handler + +- (void)scene:(UIScene *)scene + openURLContexts:(NSSet *)URLContexts API_AVAILABLE(ios(13.0), tvos(13.0)) { + if (@available(iOS 13.0, tvOS 13.0, *)) { + SEL methodSelector = @selector(scene:openURLContexts:); + // Call the real implementation if the real Scene Delegate has any. + NSValue *openURLContextsIMPPointer = + [GULSceneDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULOpenURLContextsIMP openURLContextsIMP = [openURLContextsIMPPointer pointerValue]; + + [GULSceneDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + if ([interceptor + conformsToProtocol:@protocol(UISceneDelegate)]) { + id sceneInterceptor = + (id)interceptor; + [sceneInterceptor scene:scene openURLContexts:URLContexts]; + } + }]; + + if (openURLContextsIMP) { + openURLContextsIMP(self, methodSelector, scene, URLContexts); + } + } +} + ++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene { + Class realClass = [scene.delegate class]; + NSString *className = NSStringFromClass(realClass); + + // Skip proxying if failed to get the delegate class name for some reason (e.g. `delegate == nil`) + // or the class has a prefix of kGULAppDelegatePrefix, which means it has been proxied before. + if (className == nil || [className hasPrefix:kGULSceneDelegatePrefix]) { + return; + } + + NSString *classNameWithPrefix = [kGULSceneDelegatePrefix stringByAppendingString:className]; + NSString *newClassName = + [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString]; + + if (NSClassFromString(newClassName)) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class" + @": %@, subclass: %@", + className, newClassName); + return; + } + + // Register the new class as subclass of the real one. Do not allocate more than the real class + // size. + Class sceneDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0); + if (sceneDelegateSubClass == Nil) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class" + @": %@, subclass: Nil", + className); + return; + } + + NSMutableDictionary *realImplementationsBySelector = + [[NSMutableDictionary alloc] init]; + + // For scene:openURLContexts: + SEL openURLContextsSEL = @selector(scene:openURLContexts:); + [self proxyDestinationSelector:openURLContextsSEL + implementationsFromSourceSelector:openURLContextsSEL + fromClass:[GULSceneDelegateSwizzler class] + toClass:sceneDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // Store original implementations to a fake property of the original delegate. + objc_setAssociatedObject(scene.delegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(scene.delegate, &kGULRealClassKey, realClass, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + // The subclass size has to be exactly the same size with the original class size. The subclass + // cannot have more ivars/properties than its superclass since it will cause an offset in memory + // that can lead to overwriting the isa of an object in the next frame. + if (class_getInstanceSize(realClass) != class_getInstanceSize(sceneDelegateSubClass)) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create subclass of Scene Delegate, because the created subclass is not the " + @"same size. %@", + className); + NSAssert(NO, @"Classes must be the same size to swizzle isa"); + return; + } + + // Make the newly created class to be the subclass of the real Scene Delegate class. + objc_registerClassPair(sceneDelegateSubClass); + if (object_setClass(scene.delegate, sceneDelegateSubClass)) { + GULOSLogDebug( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Successfully created Scene Delegate Proxy automatically. To disable the " + @"proxy, set the flag %@ to NO (Boolean) in the Info.plist", + [GULSceneDelegateSwizzler correctSceneDelegateProxyKey]); + } +} + ++ (NSString *)correctSceneDelegateProxyKey { + return NSClassFromString(@"FIRCore") ? kGULFirebaseSceneDelegateProxyEnabledPlistKey + : kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey; +} + +#endif // UISCENE_SUPPORTED + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h new file mode 100644 index 0000000..38e9315 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +@class GULApplication; + +NS_ASSUME_NONNULL_BEGIN + +@interface GULAppDelegateSwizzler () + +/** ISA Swizzles the given appDelegate as the original app delegate would be. + * + * @param appDelegate The object that needs to be isa swizzled. This should conform to the + * application delegate protocol. + */ ++ (void)proxyAppDelegate:(id)appDelegate; + +/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. + * + * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is + * the interceptorID. + */ ++ (GULMutableDictionary *)interceptors; + +/** Deletes all the registered interceptors. */ ++ (void)clearInterceptors; + +/** Resets the token that prevents the app delegate proxy from being isa swizzled multiple times. */ ++ (void)resetProxyOriginalDelegateOnceToken; + +/** Returns the original app delegate that was proxied. + * + * @return The original app delegate instance that was proxied. + */ ++ (id)originalDelegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h new file mode 100644 index 0000000..89896f7 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GULSceneDelegateSwizzler () + +#if UISCENE_SUPPORTED + +/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. + * + * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is + * the interceptorID. + */ ++ (GULMutableDictionary *)interceptors; + +/** Deletes all the registered interceptors. */ ++ (void)clearInterceptors; + +/** ISA Swizzles the given appDelegate as the original app delegate would be. + * + * @param scene The scene whose delegate needs to be isa swizzled. This should conform to the + * scene delegate protocol. + */ ++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)); + +#endif // UISCENE_SUPPORTED + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h new file mode 100644 index 0000000..58dec49 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h @@ -0,0 +1,107 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULApplication.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NSString *const GULAppDelegateInterceptorID; + +/** This class contains methods that isa swizzle the app delegate. */ +@interface GULAppDelegateSwizzler : NSProxy + +/** Registers an app delegate interceptor whose methods will be invoked as they're invoked on the + * original app delegate. + * + * @param interceptor An instance of a class that conforms to the application delegate protocol. + * The interceptor is NOT retained. + * @return A unique GULAppDelegateInterceptorID if interceptor was successfully registered; nil + * if it fails. + */ ++ (nullable GULAppDelegateInterceptorID)registerAppDelegateInterceptor: + (id)interceptor; + +/** Unregisters an interceptor with the given ID if it exists. + * + * @param interceptorID The object that was generated when the interceptor was registered. + */ ++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID; + +/** This method ensures that the original app delegate has been proxied. Call this before + * registering your interceptor. This method is safe to call multiple times (but it only proxies + * the app delegate once). + * + * This method doesn't proxy APNS related methods: + * @code + * - application:didRegisterForRemoteNotificationsWithDeviceToken: + * - application:didFailToRegisterForRemoteNotificationsWithError: + * - application:didReceiveRemoteNotification:fetchCompletionHandler: + * - application:didReceiveRemoteNotification: + * @endcode + * + * To proxy these methods use +[GULAppDelegateSwizzler + * proxyOriginalDelegateIncludingAPNSMethods]. The methods have to be proxied separately to + * avoid potential warnings from Apple review about missing Push Notification Entitlement (e.g. + * https://github.com/firebase/firebase-ios-sdk/issues/2807) + * + * The method has no effect for extensions. + * + * @see proxyOriginalDelegateIncludingAPNSMethods + */ ++ (void)proxyOriginalDelegate; + +/** This method ensures that the original app delegate has been proxied including APNS related + * methods. Call this before registering your interceptor. This method is safe to call multiple + * times (but it only proxies the app delegate once) or + * after +[GULAppDelegateSwizzler proxyOriginalDelegate] + * + * This method calls +[GULAppDelegateSwizzler proxyOriginalDelegate] under the hood. + * After calling this method the following App Delegate methods will be proxied in addition to + * the methods proxied by proxyOriginalDelegate: + * @code + * - application:didRegisterForRemoteNotificationsWithDeviceToken: + * - application:didFailToRegisterForRemoteNotificationsWithError: + * - application:didReceiveRemoteNotification:fetchCompletionHandler: + * - application:didReceiveRemoteNotification: + * @endcode + * + * The method has no effect for extensions. + * + * @see proxyOriginalDelegate + */ ++ (void)proxyOriginalDelegateIncludingAPNSMethods; + +/** Indicates whether app delegate proxy is explicitly disabled or enabled. Enabled by default. + * + * @return YES if AppDelegateProxy is Enabled, NO otherwise. + */ ++ (BOOL)isAppDelegateProxyEnabled; + +/** Returns the current sharedApplication. + * + * @return the current application instance if in an app, or nil if in extension or if it doesn't + * exist. + */ ++ (nullable GULApplication *)sharedApplication; + +/** Do not initialize this class. */ +- (instancetype)init NS_UNAVAILABLE; + +NS_ASSUME_NONNULL_END + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h new file mode 100644 index 0000000..9311a17 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + +#import + +#define GULApplication UIApplication +#define GULApplicationDelegate UIApplicationDelegate +#define GULUserActivityRestoring UIUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"UIApplication"; + +#elif TARGET_OS_OSX + +#import + +#define GULApplication NSApplication +#define GULApplicationDelegate NSApplicationDelegate +#define GULUserActivityRestoring NSUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"NSApplication"; + +#elif TARGET_OS_WATCH + +#import + +// We match the according watchOS API but swizzling should not work in watch +#define GULApplication WKExtension +#define GULApplicationDelegate WKExtensionDelegate +#define GULUserActivityRestoring NSUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"WKExtension"; + +#endif diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h new file mode 100644 index 0000000..d6d8937 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import + +#if __has_include() +#import +#endif + +#if TARGET_OS_IOS || TARGET_OS_TV +#define UISCENE_SUPPORTED 1 +#endif + +NS_ASSUME_NONNULL_BEGIN + +typedef NSString *const GULSceneDelegateInterceptorID; + +/** This class contains methods that isa swizzle the scene delegate. */ +@interface GULSceneDelegateSwizzler : NSProxy + +#if UISCENE_SUPPORTED + +/** Registers a scene delegate interceptor whose methods will be invoked as they're invoked on the + * original scene delegate. + * + * @param interceptor An instance of a class that conforms to the application delegate protocol. + * The interceptor is NOT retained. + * @return A unique GULSceneDelegateInterceptorID if interceptor was successfully registered; nil + * if it fails. + */ ++ (nullable GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor: + (id)interceptor API_AVAILABLE(ios(13.0), tvos(13.0)); + +/** Unregisters an interceptor with the given ID if it exists. + * + * @param interceptorID The object that was generated when the interceptor was registered. + */ ++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID + API_AVAILABLE(ios(13.0), tvos(13.0)); + +/** Do not initialize this class. */ +- (instancetype)init NS_UNAVAILABLE; + +#endif // UISCENE_SUPPORTED + +/** This method ensures that the original scene delegate has been proxied. Call this before + * registering your interceptor. This method is safe to call multiple times (but it only proxies + * the scene delegate once). + * + * The method has no effect for extensions. + */ ++ (void)proxyOriginalSceneDelegate; + +/** Indicates whether scene delegate proxy is explicitly disabled or enabled. Enabled by default. + * + * @return YES if SceneDelegateProxy is Enabled, NO otherwise. + */ ++ (BOOL)isSceneDelegateProxyEnabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h new file mode 100644 index 0000000..053ce84 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h @@ -0,0 +1,56 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +typedef NS_ENUM(NSInteger, GULSwizzlerMessageCode) { + // App Delegate Swizzling. + kGULSwizzlerMessageCodeAppDelegateSwizzling000 = 1000, // I-SWZ001000 + kGULSwizzlerMessageCodeAppDelegateSwizzling001 = 1001, // I-SWZ001001 + kGULSwizzlerMessageCodeAppDelegateSwizzling002 = 1002, // I-SWZ001002 + kGULSwizzlerMessageCodeAppDelegateSwizzling003 = 1003, // I-SWZ001003 + kGULSwizzlerMessageCodeAppDelegateSwizzling004 = 1004, // I-SWZ001004 + kGULSwizzlerMessageCodeAppDelegateSwizzling005 = 1005, // I-SWZ001005 + kGULSwizzlerMessageCodeAppDelegateSwizzling006 = 1006, // I-SWZ001006 + kGULSwizzlerMessageCodeAppDelegateSwizzling007 = 1007, // I-SWZ001007 + kGULSwizzlerMessageCodeAppDelegateSwizzling008 = 1008, // I-SWZ001008 + kGULSwizzlerMessageCodeAppDelegateSwizzling009 = 1009, // I-SWZ001009 + kGULSwizzlerMessageCodeAppDelegateSwizzling010 = 1010, // I-SWZ001010 + kGULSwizzlerMessageCodeAppDelegateSwizzling011 = 1011, // I-SWZ001011 + kGULSwizzlerMessageCodeAppDelegateSwizzling012 = 1012, // I-SWZ001012 + kGULSwizzlerMessageCodeAppDelegateSwizzling013 = 1013, // I-SWZ001013 + kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate = 1014, // I-SWZ001014 + + // Scene Delegate Swizzling. + kGULSwizzlerMessageCodeSceneDelegateSwizzling000 = 1100, // I-SWZ001100 + kGULSwizzlerMessageCodeSceneDelegateSwizzling001 = 1101, // I-SWZ001101 + kGULSwizzlerMessageCodeSceneDelegateSwizzling002 = 1102, // I-SWZ001102 + kGULSwizzlerMessageCodeSceneDelegateSwizzling003 = 1103, // I-SWZ001103 + kGULSwizzlerMessageCodeSceneDelegateSwizzling004 = 1104, // I-SWZ001104 + kGULSwizzlerMessageCodeSceneDelegateSwizzling005 = 1105, // I-SWZ001105 + kGULSwizzlerMessageCodeSceneDelegateSwizzling006 = 1106, // I-SWZ001106 + kGULSwizzlerMessageCodeSceneDelegateSwizzling007 = 1107, // I-SWZ001107 + kGULSwizzlerMessageCodeSceneDelegateSwizzling008 = 1108, // I-SWZ001108 + kGULSwizzlerMessageCodeSceneDelegateSwizzling009 = 1109, // I-SWZ001109 + kGULSwizzlerMessageCodeSceneDelegateSwizzling010 = 1110, // I-SWZ001110 + kGULSwizzlerMessageCodeSceneDelegateSwizzling011 = 1111, // I-SWZ001111 + kGULSwizzlerMessageCodeSceneDelegateSwizzling012 = 1112, // I-SWZ001112 + kGULSwizzlerMessageCodeSceneDelegateSwizzling013 = 1113, // I-SWZ001113 + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate = 1114, // I-SWZ001114 + + // Method Swizzling. + kGULSwizzlerMessageCodeMethodSwizzling000 = 2000, // I-SWZ002000 +}; diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULAppEnvironmentUtil.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULAppEnvironmentUtil.m new file mode 100644 index 0000000..8170c6a --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/GULAppEnvironmentUtil.m @@ -0,0 +1,300 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" + +#import +#import +#import +#import + +#import "third_party/IsAppEncrypted/Public/IsAppEncrypted.h" + +#if TARGET_OS_IOS +#import +#endif // TARGET_OS_IOS + +@implementation GULAppEnvironmentUtil + +/// A key for the Info.plist to enable or disable checking if the App Store is running in a sandbox. +/// This will affect your data integrity when using Firebase Analytics, as it will disable some +/// necessary checks. +static NSString *const kFIRAppStoreReceiptURLCheckEnabledKey = + @"FirebaseAppStoreReceiptURLCheckEnabled"; + +/// The file name of the sandbox receipt. This is available on iOS >= 8.0 +static NSString *const kFIRAIdentitySandboxReceiptFileName = @"sandboxReceipt"; + +static BOOL HasSCInfoFolder(void) { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + NSString *bundlePath = [NSBundle mainBundle].bundlePath; + NSString *scInfoPath = [bundlePath stringByAppendingPathComponent:@"SC_Info"]; + return [[NSFileManager defaultManager] fileExistsAtPath:scInfoPath]; +#elif TARGET_OS_OSX + return NO; +#endif +} + +static BOOL HasEmbeddedMobileProvision(void) { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + return [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"].length > 0; +#elif TARGET_OS_OSX + return NO; +#endif +} + ++ (BOOL)isFromAppStore { + static dispatch_once_t isEncryptedOnce; + static BOOL isEncrypted = NO; + + dispatch_once(&isEncryptedOnce, ^{ + isEncrypted = IsAppEncrypted(); + }); + + if ([GULAppEnvironmentUtil isSimulator]) { + return NO; + } + + // If an app contain the sandboxReceipt file, it means its coming from TestFlight + // This must be checked before the SCInfo Folder check below since TestFlight apps may + // also have an SCInfo folder. + if ([GULAppEnvironmentUtil isAppStoreReceiptSandbox]) { + return NO; + } + + if (HasSCInfoFolder()) { + // When iTunes downloads a .ipa, it also gets a customized .sinf file which is added to the + // main SC_Info directory. + return YES; + } + + // For iOS >= 8.0, iTunesMetadata.plist is moved outside of the sandbox. Any attempt to read + // the iTunesMetadata.plist outside of the sandbox will be rejected by Apple. + // If the app does not contain the embedded.mobileprovision which is stripped out by Apple when + // the app is submitted to store, then it is highly likely that it is from Apple Store. + return isEncrypted && !HasEmbeddedMobileProvision(); +} + ++ (BOOL)isAppStoreReceiptSandbox { + // Since checking the App Store's receipt URL can be memory intensive, check the option in the + // Info.plist if developers opted out of this check. + id enableSandboxCheck = + [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRAppStoreReceiptURLCheckEnabledKey]; + if (enableSandboxCheck && [enableSandboxCheck isKindOfClass:[NSNumber class]] && + ![enableSandboxCheck boolValue]) { + return NO; + } + + NSURL *appStoreReceiptURL = [NSBundle mainBundle].appStoreReceiptURL; + NSString *appStoreReceiptFileName = appStoreReceiptURL.lastPathComponent; + return [appStoreReceiptFileName isEqualToString:kFIRAIdentitySandboxReceiptFileName]; +} + ++ (BOOL)isSimulator { +#if TARGET_OS_SIMULATOR + return YES; +#elif TARGET_OS_MACCATALYST + return NO; +#elif TARGET_OS_IOS || TARGET_OS_TV + NSString *platform = [GULAppEnvironmentUtil deviceModel]; + return [platform isEqual:@"x86_64"] || [platform isEqual:@"i386"]; +#elif TARGET_OS_OSX + return NO; +#endif + return NO; +} + ++ (NSString *)getSysctlEntry:(const char *)sysctlKey { + static NSString *entryValue; + size_t size; + sysctlbyname(sysctlKey, NULL, &size, NULL, 0); + if (size > 0) { + char *entryValueCStr = malloc(size); + sysctlbyname(sysctlKey, entryValueCStr, &size, NULL, 0); + entryValue = [NSString stringWithCString:entryValueCStr encoding:NSUTF8StringEncoding]; + free(entryValueCStr); + return entryValue; + } else { + return nil; + } +} + ++ (NSString *)deviceModel { + static dispatch_once_t once; + static NSString *deviceModel; + +#if TARGET_OS_OSX || TARGET_OS_MACCATALYST + dispatch_once(&once, ^{ + // The `uname` function only returns x86_64 for Macs. Use `sysctlbyname` instead, but fall back + // to the `uname` function if it fails. + deviceModel = [GULAppEnvironmentUtil getSysctlEntry:"hw.model"]; + if (deviceModel.length == 0) { + struct utsname systemInfo; + if (uname(&systemInfo) == 0) { + deviceModel = [NSString stringWithUTF8String:systemInfo.machine]; + } + } + }); +#else + dispatch_once(&once, ^{ + struct utsname systemInfo; + if (uname(&systemInfo) == 0) { + deviceModel = [NSString stringWithUTF8String:systemInfo.machine]; + } + }); +#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST + return deviceModel; +} + ++ (NSString *)deviceSimulatorModel { + static dispatch_once_t once; + static NSString *model = nil; + + dispatch_once(&once, ^{ +#if TARGET_OS_SIMULATOR +#if TARGET_OS_WATCH + model = @"watchOS Simulator"; +#elif TARGET_OS_TV + model = @"tvOS Simulator"; +#elif TARGET_OS_VISION + model = @"visionOS Simulator"; +#elif TARGET_OS_IOS + switch ([[UIDevice currentDevice] userInterfaceIdiom]) { + case UIUserInterfaceIdiomPhone: + model = @"iOS Simulator (iPhone)"; + break; + case UIUserInterfaceIdiomPad: + model = @"iOS Simulator (iPad)"; + break; + default: + model = @"iOS Simulator (Unknown)"; + break; + } +#endif +#elif TARGET_OS_EMBEDDED + model = [GULAppEnvironmentUtil getSysctlEntry:"hw.machine"]; +#else + model = [GULAppEnvironmentUtil getSysctlEntry:"hw.model"]; +#endif + }); + + return model; +} + ++ (NSString *)systemVersion { +#if TARGET_OS_IOS + return [UIDevice currentDevice].systemVersion; +#elif TARGET_OS_OSX || TARGET_OS_TV || TARGET_OS_WATCH || TARGET_OS_VISION + // Assemble the systemVersion, excluding the patch version if it's 0. + NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; + NSMutableString *versionString = [[NSMutableString alloc] + initWithFormat:@"%ld.%ld", (long)osVersion.majorVersion, (long)osVersion.minorVersion]; + if (osVersion.patchVersion != 0) { + [versionString appendFormat:@".%ld", (long)osVersion.patchVersion]; + } + return versionString; +#endif +} + ++ (BOOL)isAppExtension { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + // Documented by Apple + BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + return appExtension; +#elif TARGET_OS_OSX + return NO; +#endif +} + ++ (BOOL)isAppClip { +#if TARGET_OS_IOS + // Documented by Apple + // App clips have an NSAppClip entry in the top level of their Info.plist. + NSDictionary *appClipEntry = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSAppClip"]; + return appClipEntry != nil; +#elif TARGET_OS_OSX || TARGET_OS_TV || TARGET_OS_WATCH || TARGET_OS_VISION + return NO; +#endif +} + ++ (BOOL)supportsBackgroundURLSessionUploads { + // Neither app extensions nor App Clips support background uploads. + BOOL isExtension = self.isAppExtension; + BOOL isAppClip = self.isAppClip; + return !(isExtension || isAppClip); +} + ++ (NSString *)applePlatform { + NSString *applePlatform = @"unknown"; + + // When a Catalyst app is run on macOS then both `TARGET_OS_MACCATALYST` and `TARGET_OS_IOS` are + // `true`, which means the condition list is order-sensitive. +#if TARGET_OS_MACCATALYST + applePlatform = @"maccatalyst"; +#elif TARGET_OS_IOS + if (@available(iOS 14.0, *)) { + // Early iOS 14 betas do not include isiOSAppOnMac (#6969) + applePlatform = ([[NSProcessInfo processInfo] respondsToSelector:@selector(isiOSAppOnMac)] && + [NSProcessInfo processInfo].isiOSAppOnMac) + ? @"ios_on_mac" + : @"ios"; + } else { + applePlatform = @"ios"; + } +#elif TARGET_OS_TV + applePlatform = @"tvos"; +#elif TARGET_OS_OSX + applePlatform = @"macos"; +#elif TARGET_OS_WATCH + applePlatform = @"watchos"; +#elif TARGET_OS_VISION + applePlatform = @"visionos"; +#endif // TARGET_OS_MACCATALYST + + return applePlatform; +} + ++ (NSString *)appleDevicePlatform { + NSString *firebasePlatform = [GULAppEnvironmentUtil applePlatform]; +#if TARGET_OS_IOS + // This check is necessary because iOS-only apps running on iPad + // will report UIUserInterfaceIdiomPhone via UI_USER_INTERFACE_IDIOM(). + if ([firebasePlatform isEqualToString:@"ios"] && + ([[UIDevice currentDevice].model.lowercaseString containsString:@"ipad"] || + [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)) { + return @"ipados"; + } +#endif + + return firebasePlatform; +} + ++ (NSString *)deploymentType { +#if SWIFT_PACKAGE + NSString *deploymentType = @"swiftpm"; +#elif FIREBASE_BUILD_CARTHAGE + NSString *deploymentType = @"carthage"; +#elif FIREBASE_BUILD_ZIP_FILE + NSString *deploymentType = @"zip"; +#elif COCOAPODS + NSString *deploymentType = @"cocoapods"; +#else + NSString *deploymentType = @"unknown"; +#endif + + return deploymentType; +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m new file mode 100644 index 0000000..fa3b878 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m @@ -0,0 +1,80 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h" + +#import + +#import +#if __has_include("CoreTelephony/CTTelephonyNetworkInfo.h") && !TARGET_OS_MACCATALYST && \ + !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH +#define TARGET_HAS_MOBILE_CONNECTIVITY +#import +#import +#endif + +@implementation GULNetworkInfo + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY ++ (CTTelephonyNetworkInfo *)getNetworkInfo { + static CTTelephonyNetworkInfo *networkInfo; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + networkInfo = [[CTTelephonyNetworkInfo alloc] init]; + }); + return networkInfo; +} +#endif + ++ (GULNetworkType)getNetworkType { + GULNetworkType networkType = GULNetworkTypeNone; + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + static SCNetworkReachabilityRef reachabilityRef = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorSystemDefault, "google.com"); + }); + + if (!reachabilityRef) { + return GULNetworkTypeNone; + } + + SCNetworkReachabilityFlags reachabilityFlags = 0; + SCNetworkReachabilityGetFlags(reachabilityRef, &reachabilityFlags); + + // Parse the network flags to set the network type. + if (reachabilityFlags & kSCNetworkReachabilityFlagsReachable) { + if (reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN) { + networkType = GULNetworkTypeMobile; + } else { + networkType = GULNetworkTypeWIFI; + } + } +#endif + + return networkType; +} + ++ (NSString *)getNetworkRadioType { +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + CTTelephonyNetworkInfo *networkInfo = [GULNetworkInfo getNetworkInfo]; + if (networkInfo.serviceCurrentRadioAccessTechnology.count) { + return networkInfo.serviceCurrentRadioAccessTechnology.allValues[0] ?: @""; + } +#endif + return @""; +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h new file mode 100644 index 0000000..6eea4a8 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h @@ -0,0 +1,69 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GULAppEnvironmentUtil : NSObject + +/// Indicates whether the app is from Apple Store or not. Returns NO if the app is on simulator, +/// development environment or sideloaded. ++ (BOOL)isFromAppStore; + +/// Indicates whether the app is a Testflight app. Returns YES if the app has sandbox receipt. +/// Returns NO otherwise. ++ (BOOL)isAppStoreReceiptSandbox; + +/// Indicates whether the app is on simulator or not at runtime depending on the device +/// architecture. ++ (BOOL)isSimulator; + +/// The current device model. Returns an empty string if device model cannot be retrieved. ++ (nullable NSString *)deviceModel; + +/// The current device model, with simulator-specific values. Returns an empty string if device +/// model cannot be retrieved. ++ (nullable NSString *)deviceSimulatorModel; + +/// The current operating system version. Returns an empty string if the system version cannot be +/// retrieved. ++ (NSString *)systemVersion; + +/// Indicates whether it is running inside an extension or an app. ++ (BOOL)isAppExtension; + +/// Indicates whether it is running inside an app clip or a full app. ++ (BOOL)isAppClip; + +/// Indicates whether the current target supports background URL session uploads. +/// App extensions and app clips do not support background URL sessions. ++ (BOOL)supportsBackgroundURLSessionUploads; + +/// @return An Apple platform. Possible values "ios", "tvos", "macos", "watchos", "maccatalyst", and +/// "visionos". ++ (NSString *)applePlatform; + +/// @return An Apple Device platform. Same possible values as `applePlatform`, with the addition of +/// "ipados". ++ (NSString *)appleDevicePlatform; + +/// @return The way the library was added to the app, e.g. "swiftpm", "cocoapods", etc. ++ (NSString *)deploymentType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h new file mode 100644 index 0000000..eb90ea3 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h @@ -0,0 +1,84 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// The class provides a convenient, multiplatform abstraction of the Keychain. +/// +/// When using this API on macOS, the corresponding target must be signed with a provisioning +/// profile that has the Keychain Sharing capability enabled. +@interface GULKeychainStorage : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes the keychain storage with Keychain Service name. + * @param service A Keychain Service name that will be used to store and retrieve objects. See also + * `kSecAttrService`. + */ +- (instancetype)initWithService:(NSString *)service; + +/// Get an object by key. +/// @param key The key. +/// @param objectClass The expected object class required by `NSSecureCoding`. +/// @param accessGroup The Keychain Access Group. +/// @param completionHandler The completion handler to call when the +/// synchronized keychain read is complete. An error is passed to the +/// completion handler if the keychain read fails. Else, the object stored in +/// the keychain, or `nil` if it does not exist, is passed to the completion +/// handler. +- (void)getObjectForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler; + +/// Saves the given object by the given key. +/// @param object The object to store. +/// @param key The key to store the object. If there is an existing object by the key, it will be +/// overridden. +/// @param accessGroup The Keychain Access Group. +/// @param completionHandler The completion handler to call when the +/// synchronized keychain write is complete. An error is passed to the +/// completion handler if the keychain read fails. Else, the object written to +/// the keychain is passed to the completion handler. +- (void)setObject:(id)object + forKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler; + +/// Removes the object by the given key. +/// @param key The key to store the object. If there is an existing object by +/// the key, it will be overridden. +/// @param accessGroup The Keychain Access Group. +/// @param completionHandler The completion handler to call when the +/// synchronized keychain removal is complete. An error is passed to the +/// completion handler if the keychain removal fails. +- (void)removeObjectForKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler:(void (^)(NSError *_Nullable error))completionHandler; + +#if TARGET_OS_OSX +/// If not `nil`, then only this keychain will be used to save and read data (see +/// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests. +@property(nonatomic, nullable) SecKeychainRef keychainRef; +#endif // TARGET_OS_OSX + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h new file mode 100644 index 0000000..9c17356 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kGULKeychainUtilsErrorDomain; + +/// A collection of helper functions that abstract away common Keychain operations. +/// +/// When using this API on macOS, the corresponding target must be signed with a provisioning +/// profile that has the Keychain Sharing capability enabled. +@interface GULKeychainUtils : NSObject + +/** Fetches a keychain item data matching to the provided query. + * @param query A dictionary with Keychain query parameters. See docs for `SecItemCopyMatching` for + * details. + * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be + * assigned with an error if there is. + * @returns Data for the first Keychain Item matching the provided query or `nil` if there is not + * such an item (`outError` will be `nil` in this case) or an error occurred. + */ ++ (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** Stores data to a Keychain Item matching to the provided query. An existing Keychain Item + * matching the query parameters will be updated or a new will be created. + * @param item A Keychain Item data to store. + * @param query A dictionary with Keychain query parameters. See docs for `SecItemAdd` and + * `SecItemUpdate` for details. + * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be + * assigned with an error if there is. + * @returns `YES` when data was successfully stored, `NO` otherwise. + */ ++ (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** Removes a Keychain Item matching to the provided query. + * @param query A dictionary with Keychain query parameters. See docs for `SecItemDelete` for + * details. + * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be + * assigned with an error if there is. + * @returns `YES` if the item was removed successfully or doesn't exist, `NO` otherwise. + */ ++ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h new file mode 100644 index 0000000..0613941 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h @@ -0,0 +1,43 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// The type of network that the device is running with. Values should correspond to the NetworkType +/// values in android/play/playlog/proto/clientanalytics.proto +typedef NS_ENUM(NSInteger, GULNetworkType) { + GULNetworkTypeNone = -1, + GULNetworkTypeMobile = 0, + GULNetworkTypeWIFI = 1, +}; + +/// Collection of utilities to read network status information +@interface GULNetworkInfo : NSObject + +/// Returns an enum indicating the network type. The enum values should be easily transferrable to +/// the NetworkType value in android/play/playlog/proto/clientanalytics.proto. Right now this always +/// returns None on platforms other than iOS. This should be updated in the future to return Wi-Fi +/// values for the other platforms when applicable. ++ (GULNetworkType)getNetworkType; + +/// Returns a string indicating the radio access technology used by the app. The return value will +/// be one of CTRadioAccess constants defined in +/// https://developer.apple.com/documentation/coretelephony/cttelephonynetworkinfo/radio_access_technology_constants ++ (NSString *)getNetworkRadioType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m new file mode 100644 index 0000000..e6aa69a --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m @@ -0,0 +1,196 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h" +#import + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" + +@interface GULKeychainStorage () +@property(nonatomic, readonly) dispatch_queue_t keychainQueue; +@property(nonatomic, readonly) dispatch_queue_t inMemoryCacheQueue; +@property(nonatomic, readonly) NSString *service; +@property(nonatomic, readonly) NSCache> *inMemoryCache; +@end + +@implementation GULKeychainStorage + +- (instancetype)initWithService:(NSString *)service { + NSCache *cache = [[NSCache alloc] init]; + // Cache up to 5 installations. + cache.countLimit = 5; + return [self initWithService:service cache:cache]; +} + +- (instancetype)initWithService:(NSString *)service cache:(NSCache *)cache { + self = [super init]; + if (self) { + _keychainQueue = + dispatch_queue_create("com.gul.KeychainStorage.Keychain", DISPATCH_QUEUE_SERIAL); + _inMemoryCacheQueue = + dispatch_queue_create("com.gul.KeychainStorage.InMemoryCache", DISPATCH_QUEUE_SERIAL); + _service = [service copy]; + _inMemoryCache = cache; + } + return self; +} + +#pragma mark - Public + +- (void)getObjectForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler { + dispatch_async(self.inMemoryCacheQueue, ^{ + // Return cached object or fail otherwise. + id object = [self.inMemoryCache objectForKey:key]; + if (object) { + completionHandler(object, nil); + } else { + // Look for the object in the keychain. + [self getObjectFromKeychainForKey:key + objectClass:objectClass + accessGroup:accessGroup + completionHandler:completionHandler]; + } + }); +} + +- (void)setObject:(id)object + forKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler { + dispatch_async(self.inMemoryCacheQueue, ^{ + // Save to the in-memory cache first. + [self.inMemoryCache setObject:object forKey:[key copy]]; + + dispatch_async(self.keychainQueue, ^{ + // Then store the object to the keychain. + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object + requiringSecureCoding:YES + error:&error]; + if (!encodedObject) { + completionHandler(nil, error); + return; + } + + if (![GULKeychainUtils setItem:encodedObject withQuery:query error:&error]) { + completionHandler(nil, error); + return; + } + + completionHandler(object, nil); + }); + }); +} + +- (void)removeObjectForKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler:(void (^)(NSError *_Nullable error))completionHandler { + dispatch_async(self.inMemoryCacheQueue, ^{ + [self.inMemoryCache removeObjectForKey:key]; + dispatch_async(self.keychainQueue, ^{ + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + + NSError *error; + if (![GULKeychainUtils removeItemWithQuery:query error:&error]) { + completionHandler(error); + } else { + completionHandler(nil); + } + }); + }); +} + +#pragma mark - Private + +- (void)getObjectFromKeychainForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup + completionHandler:(void (^)(id _Nullable obj, + NSError *_Nullable error))completionHandler { + // Look for the object in the keychain. + dispatch_async(self.keychainQueue, ^{ + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [GULKeychainUtils getItemWithQuery:query error:&error]; + + if (error) { + completionHandler(nil, error); + return; + } + if (!encodedObject) { + completionHandler(nil, nil); + return; + } + id object = [NSKeyedUnarchiver unarchivedObjectOfClass:objectClass + fromData:encodedObject + error:&error]; + if (error) { + completionHandler(nil, error); + return; + } + + dispatch_async(self.inMemoryCacheQueue, ^{ + // Save object to the in-memory cache if exists and return the object. + if (object) { + [self.inMemoryCache setObject:object forKey:[key copy]]; + } + + completionHandler(object, nil); + }); + }); +} + +- (void)resetInMemoryCache { + [self.inMemoryCache removeAllObjects]; +} + +#pragma mark - Keychain + +- (NSMutableDictionary *)keychainQueryWithKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup { + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + + query[(__bridge NSString *)kSecClass] = (__bridge NSString *)kSecClassGenericPassword; + query[(__bridge NSString *)kSecAttrService] = self.service; + query[(__bridge NSString *)kSecAttrAccount] = key; + + if (accessGroup) { + query[(__bridge NSString *)kSecAttrAccessGroup] = accessGroup; + } + + if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { + // Ensures that the keychain query behaves the same across all platforms. + // See go/firebase-macos-keychain-popups for details. + query[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; + } + +#if TARGET_OS_OSX + if (self.keychainRef) { + query[(__bridge NSString *)kSecUseKeychain] = (__bridge id)(self.keychainRef); + query[(__bridge NSString *)kSecMatchSearchList] = @[ (__bridge id)(self.keychainRef) ]; + } +#endif // TARGET_OS_OSX + + return query; +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m new file mode 100644 index 0000000..57855a0 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m @@ -0,0 +1,133 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" + +NSString *const kGULKeychainUtilsErrorDomain = @"com.gul.keychain.ErrorDomain"; + +@implementation GULKeychainUtils + ++ (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *mutableGetItemQuery = + [[[self class] multiplatformQueryWithQuery:query] mutableCopy]; + + mutableGetItemQuery[(__bridge id)kSecReturnData] = @YES; + mutableGetItemQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; + + CFDataRef result = NULL; + OSStatus status = + SecItemCopyMatching((__bridge CFDictionaryRef)mutableGetItemQuery, (CFTypeRef *)&result); + + if (status == errSecSuccess && result != NULL) { + if (outError) { + *outError = nil; + } + + return (__bridge_transfer NSData *)result; + } + + if (status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + } else { + if (outError) { + *outError = [self keychainErrorWithFunction:@"SecItemCopyMatching" status:status]; + } + } + return nil; +} + ++ (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSDictionary *multiplatformQuery = [[self class] multiplatformQueryWithQuery:query]; + + NSData *existingItem = [self getItemWithQuery:multiplatformQuery error:outError]; + if (outError && *outError) { + return NO; + } + + OSStatus status; + if (!existingItem) { + NSMutableDictionary *mutableAddItemQuery = [multiplatformQuery mutableCopy]; + mutableAddItemQuery[(__bridge id)kSecAttrAccessible] = + (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + mutableAddItemQuery[(__bridge id)kSecValueData] = item; + + status = SecItemAdd((__bridge CFDictionaryRef)mutableAddItemQuery, NULL); + } else { + NSDictionary *attributes = @{(__bridge id)kSecValueData : item}; + status = SecItemUpdate((__bridge CFDictionaryRef)multiplatformQuery, + (__bridge CFDictionaryRef)attributes); + } + + if (status == noErr) { + if (outError) { + *outError = nil; + } + return YES; + } + + NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd"; + if (outError) { + *outError = [self keychainErrorWithFunction:function status:status]; + } + return NO; +} + ++ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError { + NSDictionary *deleteItemQuery = [[self class] multiplatformQueryWithQuery:query]; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteItemQuery); + + if (status == noErr || status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + return YES; + } + + if (outError) { + *outError = [self keychainErrorWithFunction:@"SecItemDelete" status:status]; + } + return NO; +} + +#pragma mark - Private + +/// Returns a `NSDictionary` query that behaves the same across all platforms. +/// - Note: In practice, this API only makes a difference to keychain queries on macOS. +/// See go/firebase-macos-keychain-popups for details. +/// - Parameter query: A query to create the protected keychain query with. ++ (NSDictionary *)multiplatformQueryWithQuery:(NSDictionary *)query { + NSMutableDictionary *multiplatformQuery = [query mutableCopy]; + if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { + multiplatformQuery[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; + } + return [multiplatformQuery copy]; +} + +#pragma mark - Errors + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { + NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; + NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey : failureReason}; + return [NSError errorWithDomain:kGULKeychainUtilsErrorDomain code:0 userInfo:userInfo]; +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m new file mode 100644 index 0000000..a2eb29e --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m @@ -0,0 +1,223 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +#import + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h" + +static dispatch_once_t sGULLoggerOnceToken; + +static dispatch_queue_t sGULClientQueue; + +static BOOL sGULLoggerDebugMode; + +static GULLoggerLevel sGULLoggerMaximumLevel; + +// Allow clients to register a version to include in the log. +static NSString *sVersion = @""; + +NSString *const kGULLogSubsystem = @"com.google.utilities.logger"; + +static GULLoggerService kGULLoggerLogger = @"[GULLogger]"; + +static NSMutableDictionary *> + *sGULServiceLogs; + +#ifdef DEBUG +/// The regex pattern for the message code. +static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$"; +static NSRegularExpression *sMessageCodeRegex; +#endif + +void GULLoggerInitialize(void) { + dispatch_once(&sGULLoggerOnceToken, ^{ + sGULLoggerMaximumLevel = GULLoggerLevelNotice; + sGULClientQueue = dispatch_queue_create("GULLoggingClientQueue", DISPATCH_QUEUE_SERIAL); + dispatch_set_target_queue(sGULClientQueue, + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)); + sGULServiceLogs = [NSMutableDictionary dictionary]; +#ifdef DEBUG + sMessageCodeRegex = [NSRegularExpression regularExpressionWithPattern:kMessageCodePattern + options:0 + error:NULL]; +#endif + }); +} + +void GULLoggerForceDebug(void) { + // We should enable debug mode if we're not running from App Store. + if (![GULAppEnvironmentUtil isFromAppStore]) { + sGULLoggerDebugMode = YES; + GULSetLoggerLevel(GULLoggerLevelDebug); + } +} + +GULLoggerLevel GULGetLoggerLevel(void) { + return sGULLoggerMaximumLevel; +} + +__attribute__((no_sanitize("thread"))) void GULSetLoggerLevel(GULLoggerLevel loggerLevel) { + if (loggerLevel < GULLoggerLevelMin || loggerLevel > GULLoggerLevelMax) { + GULOSLogError(kGULLogSubsystem, kGULLoggerLogger, YES, @"I-COR000023", + @"Invalid logger level, %ld", (long)loggerLevel); + return; + } + GULLoggerInitialize(); + // We should not raise the logger level if we are running from App Store. + if (loggerLevel >= GULLoggerLevelNotice && [GULAppEnvironmentUtil isFromAppStore]) { + return; + } + + sGULLoggerMaximumLevel = loggerLevel; +} + +/** + * Check if the level is high enough to be loggable. + */ +__attribute__((no_sanitize("thread"))) BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel) { + GULLoggerInitialize(); + if (sGULLoggerDebugMode) { + return YES; + } + return (BOOL)(loggerLevel <= sGULLoggerMaximumLevel); +} + +#ifdef DEBUG +void GULResetLogger(void) { + sGULLoggerOnceToken = 0; + sGULLoggerDebugMode = NO; + sGULLoggerMaximumLevel = GULLoggerLevelNotice; +} + +dispatch_queue_t getGULClientQueue(void) { + return sGULClientQueue; +} + +BOOL getGULLoggerDebugMode(void) { + return sGULLoggerDebugMode; +} +#endif + +void GULLoggerRegisterVersion(NSString *version) { + sVersion = version; +} + +os_log_type_t GULLoggerLevelToOSLogType(GULLoggerLevel level) { + switch (level) { + case GULLoggerLevelError: + return OS_LOG_TYPE_ERROR; + case GULLoggerLevelWarning: + case GULLoggerLevelNotice: + return OS_LOG_TYPE_DEFAULT; + case GULLoggerLevelInfo: + return OS_LOG_TYPE_INFO; + case GULLoggerLevelDebug: + return OS_LOG_TYPE_DEBUG; + } +} + +void GULOSLogBasic(GULLoggerLevel level, + NSString *subsystem, + NSString *category, + BOOL forceLog, + NSString *messageCode, + NSString *message, + va_list args_ptr) { + GULLoggerInitialize(); + if (!(level <= sGULLoggerMaximumLevel || sGULLoggerDebugMode || forceLog)) { + return; + } + +#ifdef DEBUG + NSCAssert(messageCode.length == 11, @"Incorrect message code length."); + NSRange messageCodeRange = NSMakeRange(0, messageCode.length); + NSUInteger __unused numberOfMatches = + [sMessageCodeRegex numberOfMatchesInString:messageCode options:0 range:messageCodeRange]; + NSCAssert(numberOfMatches == 1, @"Incorrect message code format."); +#endif + NSString *logMsg; + if (args_ptr == NULL) { + logMsg = message; + } else { + logMsg = [[NSString alloc] initWithFormat:message arguments:args_ptr]; + } + logMsg = [NSString stringWithFormat:@"%@ - %@[%@] %@", sVersion, category, messageCode, logMsg]; + dispatch_async(sGULClientQueue, ^{ + NSMutableDictionary *subsystemLogs = sGULServiceLogs[subsystem]; + if (!subsystemLogs) { + subsystemLogs = [NSMutableDictionary dictionary]; + sGULServiceLogs[subsystem] = subsystemLogs; + } + + os_log_t serviceLog = [subsystemLogs objectForKey:subsystem]; + if (!serviceLog) { + serviceLog = os_log_create(subsystem.UTF8String, category.UTF8String); + subsystemLogs[category] = serviceLog; + } + + os_log_with_type(serviceLog, GULLoggerLevelToOSLogType(level), "%{public}@", logMsg); + }); +} + +/** + * Generates the logging functions using macros. + * + * Calling GULLogError({service}, @"I-XYZ000001", @"Configure %@ failed.", @"blah") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [{service}][I-XYZ000001] Configure blah failed. + * Calling GULLogDebug({service}, @"I-XYZ000001", @"Configure succeed.") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [{service}][I-XYZ000001] Configure succeed. + */ +#define GUL_LOGGING_FUNCTION(level) \ + void GULOSLog##level(NSString *subsystem, NSString *category, BOOL force, NSString *messageCode, \ + NSString *message, ...) { \ + va_list args_ptr; \ + va_start(args_ptr, message); \ + GULOSLogBasic(GULLoggerLevel##level, subsystem, category, force, messageCode, message, \ + args_ptr); \ + va_end(args_ptr); \ + } + +GUL_LOGGING_FUNCTION(Error) +GUL_LOGGING_FUNCTION(Warning) +GUL_LOGGING_FUNCTION(Notice) +GUL_LOGGING_FUNCTION(Info) +GUL_LOGGING_FUNCTION(Debug) + +#undef GUL_LOGGING_FUNCTION + +#pragma mark - GULLoggerWrapper + +@implementation GULLoggerWrapper + ++ (void)logWithLevel:(GULLoggerLevel)level + subsystem:(NSString *)subsystem + category:(GULLoggerService)category + messageCode:(NSString *)messageCode + message:(NSString *)message + arguments:(va_list)args { + GULOSLogBasic(level, subsystem, category, NO, messageCode, message, args); +} + ++ (void)logWithLevel:(GULLoggerLevel)level + withService:(GULLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args { + GULOSLogBasic(level, kGULLogSubsystem, service, NO, messageCode, message, args); +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h new file mode 100644 index 0000000..6702219 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h @@ -0,0 +1,165 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULLoggerLevel.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * The services used in the logger. + * + * DEPRECATED; use NSString instead. + */ +typedef NSString *const GULLoggerService; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/// Used for other GoogleUtilities logging. +extern NSString *const kGULLogSubsystem; + +/// Initialize GULLogger. +extern void GULLoggerInitialize(void); + +/// Override log level to Debug. +void GULLoggerForceDebug(void); + +/// Gets the current `GULLoggerLevel`. +extern GULLoggerLevel GULGetLoggerLevel(void); + +/** + * Changes the default logging level of GULLoggerLevelNotice to a user-specified level. + * The default level cannot be set above GULLoggerLevelNotice if the app is running from App Store. + * (required) log level (one of the GULLoggerLevel enum values). + */ +extern void GULSetLoggerLevel(GULLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the GULLoggerLevel enum values). + */ +extern BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel); + +/** + * Register version to include in logs. + * (required) version + */ +extern void GULLoggerRegisterVersion(NSString *version); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than GULLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the GULLoggerLevel enum values). + * (required) service name of type GULLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void GULOSLogBasic(GULLoggerLevel level, + NSString *subsystem, + NSString *category, + BOOL forceLog, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type GULLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * GULLogError(kGULLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void GULOSLogError(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); +extern void GULOSLogWarning(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); +extern void GULOSLogNotice(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); +extern void GULOSLogInfo(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); +extern void GULOSLogDebug(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +@interface GULLoggerWrapper : NSObject + +/// Objective-C wrapper for `GULOSLogBasic` to allow weak linking to `GULLogger`. +/// +/// - Parameters: +/// - level: The log level (one of the `GULLoggerLevel` enum values). +/// - subsystem: An identifier for the subsystem performing logging, e.g., `com.example.logger`. +/// - category: The category name within the `subsystem` to group related messages, e.g., +/// `[GoogleUtilities/Example]`. +/// - messageCode: The message code starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: The message to log, which may be a format string. +/// - args: The variable arguments list obtained from calling va_start, used when message is +/// a format string; optional if `message` is not a format string. ++ (void)logWithLevel:(GULLoggerLevel)level + subsystem:(NSString *)subsystem + category:(NSString *)category + messageCode:(NSString *)messageCode + message:(NSString *)message + arguments:(va_list)args; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h new file mode 100644 index 0000000..6a68eb1 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h @@ -0,0 +1,47 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// The log levels used by internal logging. +typedef NS_ENUM(NSInteger, GULLoggerLevel) { + /// Error level, corresponding to `OS_LOG_TYPE_ERROR`. + GULLoggerLevelError = 3, // For backwards compatibility, the enum value matches `ASL_LEVEL_ERR`. + + /// Warning level, corresponding to `OS_LOG_TYPE_DEFAULT`. + /// + /// > Note: Since OSLog doesn't have a WARNING type, this is equivalent to `GULLoggerLevelNotice`. + GULLoggerLevelWarning = 4, // For backwards compatibility, the value matches `ASL_LEVEL_WARNING`. + + /// Notice level, corresponding to `OS_LOG_TYPE_DEFAULT`. + GULLoggerLevelNotice = 5, // For backwards compatibility, the value matches `ASL_LEVEL_NOTICE`. + + /// Info level, corresponding to `OS_LOG_TYPE_INFO`. + GULLoggerLevelInfo = 6, // For backwards compatibility, the enum value matches `ASL_LEVEL_INFO`. + + /// Debug level, corresponding to `OS_LOG_TYPE_DEBUG`. + GULLoggerLevelDebug = 7, // For backwards compatibility, the value matches `ASL_LEVEL_DEBUG`. + + /// The minimum (most severe) supported logging level. + GULLoggerLevelMin = GULLoggerLevelError, + + /// The maximum (least severe) supported logging level. + GULLoggerLevelMax = GULLoggerLevelDebug +} NS_SWIFT_NAME(GoogleLoggerLevel); + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m new file mode 100644 index 0000000..cec621e --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m @@ -0,0 +1,207 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h" + +#import + +#define kChunkSize 1024 +#define Z_DEFAULT_COMPRESSION (-1) + +NSString *const GULNSDataZlibErrorDomain = @"com.google.GULNSDataZlibErrorDomain"; +NSString *const GULNSDataZlibErrorKey = @"GULNSDataZlibErrorKey"; +NSString *const GULNSDataZlibRemainingBytesKey = @"GULNSDataZlibRemainingBytesKey"; + +@implementation NSData (GULGzip) + ++ (nullable NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error { + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + int windowBits = 15; // 15 to enable any window size + windowBits += 32; // and +32 to enable zlib or gzip header detection. + + int retCode; + if ((retCode = inflateInit2(&strm, windowBits)) != Z_OK) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + } + + // Hint the size at 4x the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length * 4)]; + unsigned char output[kChunkSize]; + + // Loop to collect the data. + do { + // Update what we're passing in. + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = inflate(&strm, Z_NO_FLUSH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSMutableDictionary *userInfo = + [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + if (strm.msg) { + NSString *message = [NSString stringWithUTF8String:strm.msg]; + if (message) { + [userInfo setObject:message forKey:NSLocalizedDescriptionKey]; + } + } + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + inflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // Make sure there wasn't more data tacked onto the end of a valid compressed stream. + if (strm.avail_in != 0) { + if (error) { + NSDictionary *userInfo = + [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:strm.avail_in] + forKey:GULNSDataZlibRemainingBytesKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorDataRemaining + userInfo:userInfo]; + } + result = nil; + } + // The only way out of the loop was by hitting the end of the stream. + NSAssert(retCode == Z_STREAM_END, + @"Thought we finished inflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + inflateEnd(&strm); + + return result; +} + ++ (nullable NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error { + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + + int level = Z_DEFAULT_COMPRESSION; + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + if (error) { + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorGreaterThan32BitsToCompress + userInfo:nil]; + } + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int memLevel = 8; // Default. + int windowBits = 15 + 16; // Enable gzip header instead of zlib header. + + int retCode; + if ((retCode = deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel, + Z_DEFAULT_STRATEGY)) != Z_OK) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + } + + // Hint the size at 1/4 the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length / 4)]; + unsigned char output[kChunkSize]; + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + // Collect the data. + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + deflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // If the loop exits, it used all input and the stream ended. + NSAssert(strm.avail_in == 0, + @"Should have finished deflating without using all input, %u bytes left", strm.avail_in); + NSAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + deflateEnd(&strm); + + return result; +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h new file mode 100644 index 0000000..f195d57 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h @@ -0,0 +1,53 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// This is a copy of Google Toolbox for Mac library to avoid creating an extra framework. + +// NOTE: For 64bit, none of these apis handle input sizes >32bits, they will return nil when given +// such data. To handle data of that size you really should be streaming it rather then doing it all +// in memory. + +@interface NSData (GULGzip) + +/// Returns an data as the result of decompressing the payload of |data|.The data to decompress must +/// be a gzipped payloads. ++ (nullable NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error; + +/// Returns an compressed data with the result of gzipping the payload of |data|. Uses the default +/// compression level. ++ (nullable NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error; + +FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorDomain; +FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorKey; // NSNumber +FOUNDATION_EXPORT NSString *const GULNSDataZlibRemainingBytesKey; // NSNumber + +typedef NS_ENUM(NSInteger, GULNSDataZlibError) { + GULNSDataZlibErrorGreaterThan32BitsToCompress = 1024, + // An internal zlib error. + // GULNSDataZlibErrorKey will contain the error value. + // NSLocalizedDescriptionKey may contain an error string from zlib. + // Look in zlib.h for list of errors. + GULNSDataZlibErrorInternal, + // There was left over data in the buffer that was not used. + // GULNSDataZlibRemainingBytesKey will contain number of remaining bytes. + GULNSDataZlibErrorDataRemaining +}; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m new file mode 100644 index 0000000..7726d15 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m @@ -0,0 +1,101 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +@implementation GULMutableDictionary { + /// The mutable dictionary. + NSMutableDictionary *_objects; + + /// Serial synchronization queue. All reads should use dispatch_sync, while writes use + /// dispatch_async. + dispatch_queue_t _queue; +} + +- (instancetype)init { + self = [super init]; + + if (self) { + _objects = [[NSMutableDictionary alloc] init]; + _queue = dispatch_queue_create("GULMutableDictionary", DISPATCH_QUEUE_SERIAL); + } + + return self; +} + +- (NSString *)description { + __block NSString *description; + dispatch_sync(_queue, ^{ + description = self->_objects.description; + }); + return description; +} + +- (id)objectForKey:(id)key { + __block id object; + dispatch_sync(_queue, ^{ + object = [self->_objects objectForKey:key]; + }); + return object; +} + +- (void)setObject:(id)object forKey:(id)key { + dispatch_async(_queue, ^{ + [self->_objects setObject:object forKey:key]; + }); +} + +- (void)removeObjectForKey:(id)key { + dispatch_async(_queue, ^{ + [self->_objects removeObjectForKey:key]; + }); +} + +- (void)removeAllObjects { + dispatch_async(_queue, ^{ + [self->_objects removeAllObjects]; + }); +} + +- (NSUInteger)count { + __block NSUInteger count; + dispatch_sync(_queue, ^{ + count = self->_objects.count; + }); + return count; +} + +- (id)objectForKeyedSubscript:(id)key { + __block id object; + dispatch_sync(_queue, ^{ + object = self->_objects[key]; + }); + return object; +} + +- (void)setObject:(id)obj forKeyedSubscript:(id)key { + dispatch_async(_queue, ^{ + self->_objects[key] = obj; + }); +} + +- (NSDictionary *)dictionary { + __block NSDictionary *dictionary; + dispatch_sync(_queue, ^{ + dictionary = [self->_objects copy]; + }); + return dictionary; +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m new file mode 100644 index 0000000..23b3bb0 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m @@ -0,0 +1,406 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h" +#import "GoogleUtilities/Network/GULNetworkInternal.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +/// Constant string for request header Content-Encoding. +static NSString *const kGULNetworkContentCompressionKey = @"Content-Encoding"; + +/// Constant string for request header Content-Encoding value. +static NSString *const kGULNetworkContentCompressionValue = @"gzip"; + +/// Constant string for request header Content-Length. +static NSString *const kGULNetworkContentLengthKey = @"Content-Length"; + +/// Constant string for request header Content-Type. +static NSString *const kGULNetworkContentTypeKey = @"Content-Type"; + +/// Constant string for request header Content-Type value. +static NSString *const kGULNetworkContentTypeValue = @"application/x-www-form-urlencoded"; + +/// Constant string for GET request method. +static NSString *const kGULNetworkGETRequestMethod = @"GET"; + +/// Constant string for POST request method. +static NSString *const kGULNetworkPOSTRequestMethod = @"POST"; + +/// Default constant string as a prefix for network logger. +static NSString *const kGULNetworkLogTag = @"Google/Utilities/Network"; + +@interface GULNetwork () +@end + +@implementation GULNetwork { + /// Network reachability. + GULReachabilityChecker *_reachability; + + /// The dictionary of requests by session IDs { NSString : id }. + GULMutableDictionary *_requests; +} + +- (instancetype)init { + return [self initWithReachabilityHost:kGULNetworkReachabilityHost]; +} + +- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost { + self = [super init]; + if (self) { + // Setup reachability. + _reachability = [[GULReachabilityChecker alloc] initWithReachabilityDelegate:self + withHost:reachabilityHost]; + if (![_reachability start]) { + return nil; + } + + _requests = [[GULMutableDictionary alloc] init]; + _timeoutInterval = kGULNetworkTimeOutInterval; + } + return self; +} + +- (void)dealloc { + _reachability.reachabilityDelegate = nil; + [_reachability stop]; +} + +#pragma mark - External Methods + ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler { + [GULNetworkURLSession handleEventsForBackgroundURLSessionID:sessionID + completionHandler:completionHandler]; +} + +- (nullable NSString *)postURL:(NSURL *)url + payload:(NSData *)payload + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + return [self postURL:url + headers:nil + payload:payload + queue:queue + usingBackgroundSession:usingBackgroundSession + completionHandler:handler]; +} + +- (nullable NSString *)postURL:(NSURL *)url + headers:(nullable NSDictionary *)headers + payload:(NSData *)payload + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + if (!url.absoluteString.length) { + [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; + return nil; + } + + NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval; + + NSMutableURLRequest *request = + [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeOutInterval]; + + if (!request) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + request.allHTTPHeaderFields = headers; + + NSError *compressError = nil; + NSData *compressedData = [NSData gul_dataByGzippingData:payload error:&compressError]; + if (!compressedData || compressError) { + if (compressError || payload.length > 0) { + // If the payload is not empty but it fails to compress the payload, something has been wrong. + [self handleErrorWithCode:GULErrorCodeNetworkPayloadCompression + queue:queue + withHandler:handler]; + return nil; + } + compressedData = [[NSData alloc] init]; + } + + NSString *postLength = @(compressedData.length).stringValue; + + // Set up the request with the compressed data. + [request setValue:postLength forHTTPHeaderField:kGULNetworkContentLengthKey]; + request.HTTPBody = compressedData; + request.HTTPMethod = kGULNetworkPOSTRequestMethod; + [request setValue:kGULNetworkContentTypeValue forHTTPHeaderField:kGULNetworkContentTypeKey]; + [request setValue:kGULNetworkContentCompressionValue + forHTTPHeaderField:kGULNetworkContentCompressionKey]; + + GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; + fetcher.backgroundNetworkEnabled = usingBackgroundSession; + + __weak GULNetwork *weakSelf = self; + NSString *requestID = [fetcher + sessionIDFromAsyncPOSTRequest:request + completionHandler:^(NSHTTPURLResponse *response, NSData *data, + NSString *sessionID, NSError *error) { + GULNetwork *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + if (sessionID.length) { + [strongSelf->_requests removeObjectForKey:sessionID]; + } + if (handler) { + handler(response, data, error); + } + }); + }]; + if (!requestID) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeNetwork000 + message:@"Uploading data. Host" + context:url]; + _requests[requestID] = fetcher; + return requestID; +} + +- (nullable NSString *)getURL:(NSURL *)url + headers:(nullable NSDictionary *)headers + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + if (!url.absoluteString.length) { + [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; + return nil; + } + + NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval; + NSMutableURLRequest *request = + [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeOutInterval]; + + if (!request) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + request.HTTPMethod = kGULNetworkGETRequestMethod; + request.allHTTPHeaderFields = headers; + + GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; + fetcher.backgroundNetworkEnabled = usingBackgroundSession; + + __weak GULNetwork *weakSelf = self; + NSString *requestID = [fetcher + sessionIDFromAsyncGETRequest:request + completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSString *sessionID, + NSError *error) { + GULNetwork *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + if (sessionID.length) { + [strongSelf->_requests removeObjectForKey:sessionID]; + } + if (handler) { + handler(response, data, error); + } + }); + }]; + + if (!requestID) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeNetwork001 + message:@"Downloading data. Host" + context:url]; + _requests[requestID] = fetcher; + return requestID; +} + +- (BOOL)hasUploadInProgress { + return _requests.count > 0; +} + +#pragma mark - Network Reachability + +/// Tells reachability delegate to call reachabilityDidChangeToStatus: to notify the network +/// reachability has changed. +- (void)reachability:(GULReachabilityChecker *)reachability + statusChanged:(GULReachabilityStatus)status { + _networkConnected = (status == kGULReachabilityViaCellular || status == kGULReachabilityViaWifi); + [_reachabilityDelegate reachabilityDidChange]; +} + +#pragma mark - Network logger delegate + +- (void)setLoggerDelegate:(id)loggerDelegate { + // Explicitly check whether the delegate responds to the methods because conformsToProtocol does + // not work correctly even though the delegate does respond to the methods. + if (!loggerDelegate || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:contexts:)] || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:context:)] || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:)]) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork002], + @"Cannot set the network logger delegate: delegate does not conform to the network " + "logger protocol."); + return; + } + _loggerDelegate = loggerDelegate; +} + +#pragma mark - Private methods + +/// Handles network error and calls completion handler with the error. +- (void)handleErrorWithCode:(NSInteger)code + queue:(dispatch_queue_t)queue + withHandler:(GULNetworkCompletionHandler)handler { + NSDictionary *userInfo = @{kGULNetworkErrorContext : @"Failed to create network request"}; + NSError *error = [[NSError alloc] initWithDomain:kGULNetworkErrorDomain + code:code + userInfo:userInfo]; + [self GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeNetwork002 + message:@"Failed to create network request. Code, error" + contexts:@[ @(code), error ]]; + if (handler) { + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + handler(nil, nil, error); + }); + } +} + +#pragma mark - Network logger + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + contexts:(NSArray *)contexts { + // Let the delegate log the message if there is a valid logger delegate. Otherwise, just log + // errors/warnings/info messages to the console log. + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel + messageCode:messageCode + message:message + contexts:contexts]; + return; + } + if (_isDebugModeEnabled || logLevel == kGULNetworkLogLevelError || + logLevel == kGULNetworkLogLevelWarning || logLevel == kGULNetworkLogLevelInfo) { + NSString *formattedMessage = GULStringWithLogMessage(message, logLevel, contexts); + NSLog(@"%@", formattedMessage); + GULOSLogBasic((GULLoggerLevel)logLevel, kGULLogSubsystem, kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)messageCode], formattedMessage, + NULL); + } +} + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + context:(id)context { + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel + messageCode:messageCode + message:message + context:context]; + return; + } + NSArray *contexts = context ? @[ context ] : @[]; + [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:contexts]; +} + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message { + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message]; + return; + } + [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:@[]]; +} + +/// Returns a string for the given log level (e.g. kGULNetworkLogLevelError -> @"ERROR"). +static NSString *GULLogLevelDescriptionFromLogLevel(GULNetworkLogLevel logLevel) { + static NSDictionary *levelNames = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + levelNames = @{ + @(kGULNetworkLogLevelError) : @"ERROR", + @(kGULNetworkLogLevelWarning) : @"WARNING", + @(kGULNetworkLogLevelInfo) : @"INFO", + @(kGULNetworkLogLevelDebug) : @"DEBUG" + }; + }); + return levelNames[@(logLevel)]; +} + +/// Returns a formatted string to be used for console logging. +static NSString *GULStringWithLogMessage(NSString *message, + GULNetworkLogLevel logLevel, + NSArray *contexts) { + if (!message) { + message = @"(Message was nil)"; + } else if (!message.length) { + message = @"(Message was empty)"; + } + NSMutableString *result = [[NSMutableString alloc] + initWithFormat:@"<%@/%@> %@", kGULNetworkLogTag, GULLogLevelDescriptionFromLogLevel(logLevel), + message]; + + if (!contexts.count) { + return result; + } + + NSMutableArray *formattedContexts = [[NSMutableArray alloc] init]; + for (id item in contexts) { + [formattedContexts addObject:(item != [NSNull null] ? item : @"(nil)")]; + } + + [result appendString:@": "]; + [result appendString:[formattedContexts componentsJoinedByString:@", "]]; + return result; +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m new file mode 100644 index 0000000..e4b8469 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m @@ -0,0 +1,41 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +#import + +NSString *const kGULNetworkBackgroundSessionConfigIDPrefix = @"com.gul.network.background-upload"; +NSString *const kGULNetworkApplicationSupportSubdirectory = @"GUL/Network"; +NSString *const kGULNetworkTempDirectoryName = @"GULNetworkTemporaryDirectory"; +const NSTimeInterval kGULNetworkTempFolderExpireTime = 60 * 60; // 1 hour +const NSTimeInterval kGULNetworkTimeOutInterval = 60; // 1 minute. +NSString *const kGULNetworkReachabilityHost = @"app-measurement.com"; +NSString *const kGULNetworkErrorContext = @"Context"; + +const int kGULNetworkHTTPStatusOK = 200; +const int kGULNetworkHTTPStatusNoContent = 204; +const int kGULNetworkHTTPStatusCodeMultipleChoices = 300; +const int kGULNetworkHTTPStatusCodeMovedPermanently = 301; +const int kGULNetworkHTTPStatusCodeFound = 302; +const int kGULNetworkHTTPStatusCodeNotModified = 304; +const int kGULNetworkHTTPStatusCodeMovedTemporarily = 307; +const int kGULNetworkHTTPStatusCodeNotFound = 404; +const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic = 429; +const int kGULNetworkHTTPStatusCodeUnavailable = 503; + +NSString *const kGULNetworkErrorDomain = @"com.gul.network.ErrorDomain"; + +GULLoggerService kGULLoggerNetwork = @"[GULNetwork]"; diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h new file mode 100644 index 0000000..5aca9fd --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +extern NSString *const kGULNetworkErrorDomain; + +/// The logger service for GULNetwork. +extern GULLoggerService kGULLoggerNetwork; diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m new file mode 100644 index 0000000..c29de0c --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m @@ -0,0 +1,729 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/GULNetworkInternal.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h" + +@interface GULNetworkURLSession () +@end + +@implementation GULNetworkURLSession { + /// The handler to be called when the request completes or error has occurs. + GULNetworkURLSessionCompletionHandler _completionHandler; + + /// Session ID generated randomly with a fixed prefix. + NSString *_sessionID; + + /// The session configuration. + NSURLSessionConfiguration *_sessionConfig; + + /// The current NSURLSession. + NSURLSession *__weak _Nullable _URLSession; + + /// The path to the directory where all temporary files are stored before uploading. + NSURL *_networkDirectoryURL; + + /// The downloaded data from fetching. + NSData *_downloadedData; + + /// The path to the temporary file which stores the uploading data. + NSURL *_uploadingFileURL; + + /// The current request. + NSURLRequest *_request; +} + +#pragma mark - Init + +- (instancetype)initWithNetworkLoggerDelegate:(id)networkLoggerDelegate { + self = [super init]; + if (self) { + // Create URL to the directory where all temporary files to upload have to be stored. +#if TARGET_OS_TV + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); +#else + NSArray *paths = + NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); +#endif + NSString *storageDirectory = paths.firstObject; + NSArray *tempPathComponents = @[ + storageDirectory, kGULNetworkApplicationSupportSubdirectory, kGULNetworkTempDirectoryName + ]; + _networkDirectoryURL = [NSURL fileURLWithPathComponents:tempPathComponents]; + _sessionID = [NSString stringWithFormat:@"%@-%@", kGULNetworkBackgroundSessionConfigIDPrefix, + [[NSUUID UUID] UUIDString]]; + _loggerDelegate = networkLoggerDelegate; + } + return self; +} + +#pragma mark - External Methods + +#pragma mark - To be called from AppDelegate + ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler: + (GULNetworkSystemCompletionHandler)systemCompletionHandler { + // The session may not be Analytics background. Ignore those that do not have the prefix. + if (![sessionID hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) { + return; + } + GULNetworkURLSession *fetcher = [self fetcherWithSessionIdentifier:sessionID]; + if (fetcher != nil) { + [fetcher addSystemCompletionHandler:systemCompletionHandler forSession:sessionID]; + } else { + GULOSLogError(kGULLogSubsystem, kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork003], + @"Failed to retrieve background session with ID %@ after app is relaunched.", + sessionID); + } +} + +#pragma mark - External Methods + +/// Sends an async POST request using `NSURLSession`, and returns an ID of the connection. +- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request + completionHandler: + (GULNetworkURLSessionCompletionHandler)handler { + // NSURLSessionUploadTask does not work with NSData in the background. + // To avoid this issue, write the data to a temporary file to upload it. + // Make a temporary file with the data subset. + _uploadingFileURL = [self temporaryFilePathWithSessionID:_sessionID]; + NSError *writeError; + NSURLSessionUploadTask *postRequestTask; + NSURLSession *session; + BOOL didWriteFile = NO; + + // Clean up the entire temp folder to avoid temp files that remain in case the previous session + // crashed and did not clean up. + [self maybeRemoveTempFilesAtURL:_networkDirectoryURL + expiringTime:kGULNetworkTempFolderExpireTime]; + + // If there is no background network enabled, no need to write to file. This will allow default + // network session which runs on the foreground. + if (_backgroundNetworkEnabled && [self ensureTemporaryDirectoryExists]) { + didWriteFile = [request.HTTPBody writeToFile:_uploadingFileURL.path + options:NSDataWritingAtomic + error:&writeError]; + + if (writeError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession000 + message:@"Failed to write request data to file" + context:writeError]; + } + } + + if (didWriteFile) { + // Exclude this file from backing up to iTunes. There are conflicting reports that excluding + // directory from backing up does not exclude files of that directory from backing up. + [self excludeFromBackupForURL:_uploadingFileURL]; + + _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; + } else { + // If we cannot write to file, just send it in the foreground. + _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + } + [self populateSessionConfig:_sessionConfig withRequest:request]; + session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + // To avoid a runtime warning in Xcode 15 Beta 4, the given `URLRequest` + // should have a nil `HTTPBody`. To workaround this, the given `URLRequest` + // is copied and the `HTTPBody` data is removed. + NSData *givenRequestHTTPBody = [request.HTTPBody copy]; + NSMutableURLRequest *requestWithoutHTTPBody = [request mutableCopy]; + requestWithoutHTTPBody.HTTPBody = nil; + + if (didWriteFile) { + postRequestTask = [session uploadTaskWithRequest:requestWithoutHTTPBody + fromFile:_uploadingFileURL]; + } else { + postRequestTask = [session uploadTaskWithRequest:requestWithoutHTTPBody + fromData:givenRequestHTTPBody]; + } + + if (!session || !postRequestTask) { + NSError *error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkRequestCreation + userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}]; + [self callCompletionHandler:handler withResponse:nil data:nil error:error]; + return nil; + } + + _URLSession = session; + + // Save the session into memory. + [[self class] setSessionInFetcherMap:self forSessionID:_sessionID]; + + _request = [request copy]; + + // Store completion handler because background session does not accept handler block but custom + // delegate. + _completionHandler = [handler copy]; + [postRequestTask resume]; + + return _sessionID; +} + +/// Sends an async GET request using `NSURLSession`, and returns an ID of the session. +- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler { + if (_backgroundNetworkEnabled) { + _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; + } else { + _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + } + + [self populateSessionConfig:_sessionConfig withRequest:request]; + + // Do not cache the GET request. + _sessionConfig.URLCache = nil; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request]; + + if (!session || !downloadTask) { + NSError *error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkRequestCreation + userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}]; + [self callCompletionHandler:handler withResponse:nil data:nil error:error]; + return nil; + } + + _URLSession = session; + + // Save the session into memory. + [[self class] setSessionInFetcherMap:self forSessionID:_sessionID]; + + _request = [request copy]; + + _completionHandler = [handler copy]; + [downloadTask resume]; + + return _sessionID; +} + +#pragma mark - NSURLSessionDataDelegate + +/// Called by the NSURLSession when the data task has received some of the expected data. +/// Once the session is completed, URLSession:task:didCompleteWithError will be called and the +/// completion handler will be called with the downloaded data. +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + @synchronized(self) { + NSMutableData *mutableData = [[NSMutableData alloc] init]; + if (_downloadedData) { + mutableData = _downloadedData.mutableCopy; + } + [mutableData appendData:data]; + _downloadedData = mutableData; + } +} + +#pragma mark - NSURLSessionTaskDelegate + +/// Called by the NSURLSession once the download task is completed. The file is saved in the +/// provided URL so we need to read the data and store into _downloadedData. Once the session is +/// completed, URLSession:task:didCompleteWithError will be called and the completion handler will +/// be called with the downloaded data. +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)task + didFinishDownloadingToURL:(NSURL *)url { + if (!url.path) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession001 + message:@"Unable to read downloaded data from empty temp path"]; + _downloadedData = nil; + return; + } + + NSError *error; + _downloadedData = [NSData dataWithContentsOfFile:url.path options:0 error:&error]; + + if (error) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession002 + message:@"Cannot read the content of downloaded data" + context:error]; + _downloadedData = nil; + } +} + +#if TARGET_OS_IOS || TARGET_OS_TV +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession003 + message:@"Background session finished" + context:session.configuration.identifier]; + [self callSystemCompletionHandler:session.configuration.identifier]; +} +#endif + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { + // Avoid any chance of recursive behavior leading to it being used repeatedly. + GULNetworkURLSessionCompletionHandler handler = _completionHandler; + _completionHandler = nil; + + if (task.response) { + // The following assertion should always be true for HTTP requests, see https://goo.gl/gVLxT7. + NSAssert([task.response isKindOfClass:[NSHTTPURLResponse class]], @"URL response must be HTTP"); + + // The server responded so ignore the error created by the system. + error = nil; + } else if (!error) { + error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkInvalidResponse + userInfo:@{kGULNetworkErrorContext : @"Network Error: Empty network response"}]; + } + + [self callCompletionHandler:handler + withResponse:(NSHTTPURLResponse *)task.response + data:_downloadedData + error:error]; + + // Remove the temp file to avoid trashing devices with lots of temp files. + [self removeTempItemAtURL:_uploadingFileURL]; + + // Try to clean up stale files again. + [self maybeRemoveTempFilesAtURL:_networkDirectoryURL + expiringTime:kGULNetworkTempFolderExpireTime]; + + // This is called without checking the sessionID here since non-background sessions + // won't have an ID. + [session finishTasksAndInvalidate]; + + // Explicitly remove the session so it won't be reused. The weak map table should + // remove the session on deallocation, but dealloc may not happen immediately after + // calling `finishTasksAndInvalidate`. + NSString *sessionID = session.configuration.identifier; + [[self class] setSessionInFetcherMap:nil forSessionID:sessionID]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *credential))completionHandler { + // The handling is modeled after GTMSessionFetcher. + if ([challenge.protectionSpace.authenticationMethod + isEqualToString:NSURLAuthenticationMethodServerTrust]) { + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + if (serverTrust == NULL) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession004 + message:@"Received empty server trust for host. Host" + context:_request.URL]; + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + return; + } + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + if (!credential) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession005 + message:@"Unable to verify server identity. Host" + context:_request.URL]; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + return; + } + + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession006 + message:@"Received SSL challenge for host. Host" + context:_request.URL]; + + void (^callback)(BOOL) = ^(BOOL allow) { + if (allow) { + completionHandler(NSURLSessionAuthChallengeUseCredential, credential); + } else { + [self->_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession007 + message:@"Cancelling authentication challenge for host. Host" + context:self->_request.URL]; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + }; + + // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. + CFRetain(serverTrust); + + // Evaluate the certificate chain. + // + // The delegate queue may be the main thread. Trust evaluation could cause some + // blocking network activity, so we must evaluate async, as documented at + // https://developer.apple.com/library/ios/technotes/tn2232/ + dispatch_queue_t evaluateBackgroundQueue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + dispatch_async(evaluateBackgroundQueue, ^{ + BOOL shouldAllow; + CFErrorRef errorRef = NULL; + + @synchronized([GULNetworkURLSession class]) { + shouldAllow = SecTrustEvaluateWithError(serverTrust, &errorRef); + } + + if (errorRef) { + [self->_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession008 + message:@"Cannot evaluate server trust. Error, host" + contexts:@[ @((int)CFErrorGetCode(errorRef)), self->_request.URL ]]; + CFRelease(errorRef); + } + + // Call the call back with the permission. + callback(shouldAllow); + + CFRelease(serverTrust); + }); + return; + } + + // Default handling for other Auth Challenges. + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); +} + +#pragma mark - Internal Methods + +/// Stores system completion handler with session ID as key. +- (void)addSystemCompletionHandler:(GULNetworkSystemCompletionHandler)handler + forSession:(NSString *)identifier { + if (!handler) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession009 + message:@"Cannot store nil system completion handler in network"]; + return; + } + + if (!identifier.length) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession010 + message:@"Cannot store system completion handler with empty network " + "session identifier"]; + return; + } + + GULMutableDictionary *systemCompletionHandlers = + [[self class] sessionIDToSystemCompletionHandlerDictionary]; + if (systemCompletionHandlers[identifier]) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession011 + message:@"Got multiple system handlers for a single session ID" + context:identifier]; + } + + systemCompletionHandlers[identifier] = handler; +} + +/// Calls the system provided completion handler with the session ID stored in the dictionary. +/// The handler will be removed from the dictionary after being called. +- (void)callSystemCompletionHandler:(NSString *)identifier { + GULMutableDictionary *systemCompletionHandlers = + [[self class] sessionIDToSystemCompletionHandlerDictionary]; + GULNetworkSystemCompletionHandler handler = [systemCompletionHandlers objectForKey:identifier]; + + if (handler) { + [systemCompletionHandlers removeObjectForKey:identifier]; + + dispatch_async(dispatch_get_main_queue(), ^{ + handler(); + }); + } +} + +/// Sets or updates the session ID of this session. +- (void)setSessionID:(NSString *)sessionID { + _sessionID = [sessionID copy]; +} + +/// Creates a background session configuration with the session ID using the supported method. +- (NSURLSessionConfiguration *)backgroundSessionConfigWithSessionID:(NSString *)sessionID { + return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID]; +} + +- (void)maybeRemoveTempFilesAtURL:(NSURL *)folderURL expiringTime:(NSTimeInterval)staleTime { + if (!folderURL.absoluteString.length) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + NSArray *properties = @[ NSURLCreationDateKey ]; + NSArray *directoryContent = + [fileManager contentsOfDirectoryAtURL:folderURL + includingPropertiesForKeys:properties + options:NSDirectoryEnumerationSkipsSubdirectoryDescendants + error:&error]; + if (error && error.code != NSFileReadNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession012 + message:@"Cannot get files from the temporary network folder. Error" + context:error]; + return; + } + + if (!directoryContent.count) { + return; + } + + NSTimeInterval now = [NSDate date].timeIntervalSince1970; + for (NSURL *tempFile in directoryContent) { + NSDate *creationDate; + BOOL getCreationDate = [tempFile getResourceValue:&creationDate + forKey:NSURLCreationDateKey + error:NULL]; + if (!getCreationDate) { + continue; + } + NSTimeInterval creationTimeInterval = creationDate.timeIntervalSince1970; + if (fabs(now - creationTimeInterval) > staleTime) { + [self removeTempItemAtURL:tempFile]; + } + } +} + +/// Removes the temporary file written to disk for sending the request. It has to be cleaned up +/// after the session is done. +- (void)removeTempItemAtURL:(NSURL *)fileURL { + if (!fileURL.absoluteString.length) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + if (![fileManager removeItemAtURL:fileURL error:&error] && error.code != NSFileNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession013 + message:@"Failed to remove temporary uploading data file. Error" + context:error.localizedDescription]; + } +} + +/// Gets the fetcher with the session ID. ++ (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { + GULNetworkURLSession *session = [self sessionFromFetcherMapForSessionID:sessionIdentifier]; + if (!session && [sessionIdentifier hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) { + session = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:nil]; + [session setSessionID:sessionIdentifier]; + [self setSessionInFetcherMap:session forSessionID:sessionIdentifier]; + } + return session; +} + +/// Returns a map of the fetcher by session ID. Creates a map if it is not created. +/// When reading and writing from/to the session map, don't use this method directly. +/// To avoid thread safety issues, use one of the helper methods at the bottom of the +/// file: setSessionInFetcherMap:forSessionID:, sessionFromFetcherMapForSessionID: ++ (NSMapTable *)sessionIDToFetcherMap { + static NSMapTable *sessionIDToFetcherMap; + + static dispatch_once_t sessionMapOnceToken; + dispatch_once(&sessionMapOnceToken, ^{ + sessionIDToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; + }); + return sessionIDToFetcherMap; +} + ++ (NSLock *)sessionIDToFetcherMapReadWriteLock { + static NSLock *lock; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + lock = [[NSLock alloc] init]; + }); + return lock; +} + +/// Returns a map of system provided completion handler by session ID. Creates a map if it is not +/// created. ++ (GULMutableDictionary *)sessionIDToSystemCompletionHandlerDictionary { + static GULMutableDictionary *systemCompletionHandlers; + + static dispatch_once_t systemCompletionHandlerOnceToken; + dispatch_once(&systemCompletionHandlerOnceToken, ^{ + systemCompletionHandlers = [[GULMutableDictionary alloc] init]; + }); + return systemCompletionHandlers; +} + +- (NSURL *)temporaryFilePathWithSessionID:(NSString *)sessionID { + NSString *tempName = [NSString stringWithFormat:@"GULUpload_temp_%@", sessionID]; + return [_networkDirectoryURL URLByAppendingPathComponent:tempName]; +} + +/// Makes sure that the directory to store temp files exists. If not, tries to create it and returns +/// YES. If there is anything wrong, returns NO. +- (BOOL)ensureTemporaryDirectoryExists { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + // Create a temporary directory if it does not exist or was deleted. + if ([_networkDirectoryURL checkResourceIsReachableAndReturnError:&error]) { + return YES; + } + + if (error && error.code != NSFileReadNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession014 + message:@"Error while trying to access Network temp folder. Error" + context:error]; + } + + NSError *writeError = nil; + + [fileManager createDirectoryAtURL:_networkDirectoryURL + withIntermediateDirectories:YES + attributes:nil + error:&writeError]; + if (writeError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession015 + message:@"Cannot create temporary directory. Error" + context:writeError]; + return NO; + } + + // Set the iCloud exclusion attribute on the Documents URL. + [self excludeFromBackupForURL:_networkDirectoryURL]; + + return YES; +} + +- (void)excludeFromBackupForURL:(NSURL *)url { + if (!url.path) { + return; + } + + // Set the iCloud exclusion attribute on the Documents URL. + NSError *preventBackupError = nil; + [url setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&preventBackupError]; + if (preventBackupError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession016 + message:@"Cannot exclude temporary folder from iTunes backup"]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler { + NSArray *nonAllowedRedirectionCodes = @[ + @(kGULNetworkHTTPStatusCodeFound), @(kGULNetworkHTTPStatusCodeMovedPermanently), + @(kGULNetworkHTTPStatusCodeMovedTemporarily), @(kGULNetworkHTTPStatusCodeMultipleChoices) + ]; + + // Allow those not in the non allowed list to be followed. + if (![nonAllowedRedirectionCodes containsObject:@(response.statusCode)]) { + completionHandler(request); + return; + } + + // Do not allow redirection if the response code is in the non-allowed list. + NSURLRequest *newRequest = request; + + if (response) { + newRequest = nil; + } + + completionHandler(newRequest); +} + +#pragma mark - Helper Methods + ++ (void)setSessionInFetcherMap:(GULNetworkURLSession *)session forSessionID:(NSString *)sessionID { + [[self sessionIDToFetcherMapReadWriteLock] lock]; + GULNetworkURLSession *existingSession = + [[[self class] sessionIDToFetcherMap] objectForKey:sessionID]; + if (existingSession) { + if (session) { + NSString *message = [NSString stringWithFormat:@"Discarding session: %@", existingSession]; + [existingSession->_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelInfo + messageCode:kGULNetworkMessageCodeURLSession019 + message:message]; + } + [existingSession->_URLSession finishTasksAndInvalidate]; + } + if (session) { + [[[self class] sessionIDToFetcherMap] setObject:session forKey:sessionID]; + } else { + [[[self class] sessionIDToFetcherMap] removeObjectForKey:sessionID]; + } + [[self sessionIDToFetcherMapReadWriteLock] unlock]; +} + ++ (nullable GULNetworkURLSession *)sessionFromFetcherMapForSessionID:(NSString *)sessionID { + [[self sessionIDToFetcherMapReadWriteLock] lock]; + GULNetworkURLSession *session = [[[self class] sessionIDToFetcherMap] objectForKey:sessionID]; + [[self sessionIDToFetcherMapReadWriteLock] unlock]; + return session; +} + +- (void)callCompletionHandler:(GULNetworkURLSessionCompletionHandler)handler + withResponse:(NSHTTPURLResponse *)response + data:(NSData *)data + error:(NSError *)error { + if (error) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession017 + message:@"Encounter network error. Code, error" + contexts:@[ @(error.code), error ]]; + } + + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(response, data, self->_sessionID, error); + }); + } +} + +// Always use the request parameters even if the default session configuration is more restrictive. +- (void)populateSessionConfig:(NSURLSessionConfiguration *)sessionConfig + withRequest:(NSURLRequest *)request { + sessionConfig.HTTPAdditionalHeaders = request.allHTTPHeaderFields; + sessionConfig.timeoutIntervalForRequest = request.timeoutInterval; + sessionConfig.timeoutIntervalForResource = request.timeoutInterval; + sessionConfig.requestCachePolicy = request.cachePolicy; +} + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h new file mode 100644 index 0000000..02f25db --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h @@ -0,0 +1,50 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A mutable dictionary that provides atomic accessor and mutators. +@interface GULMutableDictionary : NSObject + +/// Returns an object given a key in the dictionary or nil if not found. +- (id)objectForKey:(id)key; + +/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. +- (void)setObject:(id)object forKey:(id)key; + +/// Removes the object given its session ID from the dictionary. +- (void)removeObjectForKey:(id)key; + +/// Removes all objects. +- (void)removeAllObjects; + +/// Returns the number of current objects in the dictionary. +- (NSUInteger)count; + +/// Returns an object given a key in the dictionary or nil if not found. +- (id)objectForKeyedSubscript:(id)key; + +/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. +- (void)setObject:(id)obj forKeyedSubscript:(id)key; + +/// Returns the immutable dictionary. +- (NSDictionary *)dictionary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h new file mode 100644 index 0000000..4c5b5f5 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h @@ -0,0 +1,101 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULNetworkConstants.h" +#import "GULNetworkLoggerProtocol.h" +#import "GULNetworkURLSession.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Delegate protocol for GULNetwork events. +@protocol GULNetworkReachabilityDelegate + +/// Tells the delegate to handle events when the network reachability changes to connected or not +/// connected. +- (void)reachabilityDidChange; + +@end + +/// The Network component that provides network status and handles network requests and responses. +/// This is not thread safe. +/// +/// NOTE: +/// User must add FIRAnalytics handleEventsForBackgroundURLSessionID:completionHandler to the +/// AppDelegate application:handleEventsForBackgroundURLSession:completionHandler: +@interface GULNetwork : NSObject + +/// Indicates if network connectivity is available. +@property(nonatomic, readonly, getter=isNetworkConnected) BOOL networkConnected; + +/// Indicates if there are any uploads in progress. +@property(nonatomic, readonly, getter=hasUploadInProgress) BOOL uploadInProgress; + +/// An optional delegate that can be used in the event when network reachability changes. +@property(nonatomic, weak) id reachabilityDelegate; + +/// An optional delegate that can be used to log messages, warnings or errors that occur in the +/// network operations. +@property(nonatomic, weak) id loggerDelegate; + +/// Indicates whether the logger should display debug messages. +@property(nonatomic, assign) BOOL isDebugModeEnabled; + +/// The time interval in seconds for the network request to timeout. +@property(nonatomic, assign) NSTimeInterval timeoutInterval; + +/// Initializes with the default reachability host. +- (instancetype)init; + +/// Initializes with a custom reachability host. +- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost; + +/// Handles events when background session with the given ID has finished. ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; + +/// Compresses and sends a POST request with the provided data to the URL. The session will be +/// background session if usingBackgroundSession is YES. Otherwise, the POST session is default +/// session. Returns a session ID or nil if an error occurs. +- (nullable NSString *)postURL:(NSURL *)url + payload:(NSData *)payload + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +/// Compresses and sends a POST request with the provided headers and data to the URL. The session +/// will be background session if usingBackgroundSession is YES. Otherwise, the POST session is +/// default session. Returns a session ID or nil if an error occurs. +- (nullable NSString *)postURL:(NSURL *)url + headers:(nullable NSDictionary *)headers + payload:(NSData *)payload + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +/// Sends a GET request with the provided data to the URL. The session will be background session +/// if usingBackgroundSession is YES. Otherwise, the GET session is default session. Returns a +/// session ID or nil if an error occurs. +- (nullable NSString *)getURL:(NSURL *)url + headers:(nullable NSDictionary *)headers + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h new file mode 100644 index 0000000..341b974 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h @@ -0,0 +1,75 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Error codes in Firebase Network error domain. +/// Note: these error codes should never change. It would make it harder to decode the errors if +/// we inadvertently altered any of these codes in a future SDK version. +typedef NS_ENUM(NSInteger, GULNetworkErrorCode) { + /// Unknown error. + GULNetworkErrorCodeUnknown = 0, + /// Error occurs when the request URL is invalid. + GULErrorCodeNetworkInvalidURL = 1, + /// Error occurs when request cannot be constructed. + GULErrorCodeNetworkRequestCreation = 2, + /// Error occurs when payload cannot be compressed. + GULErrorCodeNetworkPayloadCompression = 3, + /// Error occurs when session task cannot be created. + GULErrorCodeNetworkSessionTaskCreation = 4, + /// Error occurs when there is no response. + GULErrorCodeNetworkInvalidResponse = 5 +}; + +#pragma mark - Network constants + +/// The prefix of the ID of the background session. +extern NSString *const kGULNetworkBackgroundSessionConfigIDPrefix; + +/// The sub directory to store the files of data that is being uploaded in the background. +extern NSString *const kGULNetworkApplicationSupportSubdirectory; + +/// Name of the temporary directory that stores files for background uploading. +extern NSString *const kGULNetworkTempDirectoryName; + +/// The period when the temporary uploading file can stay. +extern const NSTimeInterval kGULNetworkTempFolderExpireTime; + +/// The default network request timeout interval. +extern const NSTimeInterval kGULNetworkTimeOutInterval; + +/// The host to check the reachability of the network. +extern NSString *const kGULNetworkReachabilityHost; + +/// The key to get the error context of the UserInfo. +extern NSString *const kGULNetworkErrorContext; + +#pragma mark - Network Status Code + +extern const int kGULNetworkHTTPStatusOK; +extern const int kGULNetworkHTTPStatusNoContent; +extern const int kGULNetworkHTTPStatusCodeMultipleChoices; +extern const int kGULNetworkHTTPStatusCodeMovedPermanently; +extern const int kGULNetworkHTTPStatusCodeFound; +extern const int kGULNetworkHTTPStatusCodeNotModified; +extern const int kGULNetworkHTTPStatusCodeMovedTemporarily; +extern const int kGULNetworkHTTPStatusCodeNotFound; +extern const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic; +extern const int kGULNetworkHTTPStatusCodeUnavailable; + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h new file mode 100644 index 0000000..b9e93ec --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h @@ -0,0 +1,53 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULNetworkMessageCode.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The log levels used by GULNetworkLogger. +typedef NS_ENUM(NSInteger, GULNetworkLogLevel) { + kGULNetworkLogLevelError = 3, + kGULNetworkLogLevelWarning = 4, + kGULNetworkLogLevelInfo = 6, + kGULNetworkLogLevelDebug = 7, +}; + +@protocol GULNetworkLoggerDelegate + +@required +/// Tells the delegate to log a message with an array of contexts and the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + contexts:(NSArray *)contexts; + +/// Tells the delegate to log a message with a context and the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + context:(id)context; + +/// Tells the delegate to log a message with the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h new file mode 100644 index 0000000..2d45ec6 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h @@ -0,0 +1,51 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. +typedef NS_ENUM(NSInteger, GULNetworkMessageCode) { + // GULNetwork.m + kGULNetworkMessageCodeNetwork000 = 900000, // I-NET900000 + kGULNetworkMessageCodeNetwork001 = 900001, // I-NET900001 + kGULNetworkMessageCodeNetwork002 = 900002, // I-NET900002 + kGULNetworkMessageCodeNetwork003 = 900003, // I-NET900003 + // GULNetworkURLSession.m + kGULNetworkMessageCodeURLSession000 = 901000, // I-NET901000 + kGULNetworkMessageCodeURLSession001 = 901001, // I-NET901001 + kGULNetworkMessageCodeURLSession002 = 901002, // I-NET901002 + kGULNetworkMessageCodeURLSession003 = 901003, // I-NET901003 + kGULNetworkMessageCodeURLSession004 = 901004, // I-NET901004 + kGULNetworkMessageCodeURLSession005 = 901005, // I-NET901005 + kGULNetworkMessageCodeURLSession006 = 901006, // I-NET901006 + kGULNetworkMessageCodeURLSession007 = 901007, // I-NET901007 + kGULNetworkMessageCodeURLSession008 = 901008, // I-NET901008 + kGULNetworkMessageCodeURLSession009 = 901009, // I-NET901009 + kGULNetworkMessageCodeURLSession010 = 901010, // I-NET901010 + kGULNetworkMessageCodeURLSession011 = 901011, // I-NET901011 + kGULNetworkMessageCodeURLSession012 = 901012, // I-NET901012 + kGULNetworkMessageCodeURLSession013 = 901013, // I-NET901013 + kGULNetworkMessageCodeURLSession014 = 901014, // I-NET901014 + kGULNetworkMessageCodeURLSession015 = 901015, // I-NET901015 + kGULNetworkMessageCodeURLSession016 = 901016, // I-NET901016 + kGULNetworkMessageCodeURLSession017 = 901017, // I-NET901017 + kGULNetworkMessageCodeURLSession018 = 901018, // I-NET901018 + kGULNetworkMessageCodeURLSession019 = 901019, // I-NET901019 +}; + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h new file mode 100644 index 0000000..3f9f7f9 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULNetworkLoggerProtocol.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^GULNetworkCompletionHandler)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, + NSError *_Nullable error); +typedef void (^GULNetworkURLSessionCompletionHandler)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, + NSString *sessionID, + NSError *_Nullable error); +typedef void (^GULNetworkSystemCompletionHandler)(void); + +/// The protocol that uses NSURLSession for iOS >= 7.0 to handle requests and responses. +@interface GULNetworkURLSession : NSObject + +/// Indicates whether the background network is enabled. Default value is NO. +@property(nonatomic, getter=isBackgroundNetworkEnabled) BOOL backgroundNetworkEnabled; + +/// The logger delegate to log message, errors or warnings that occur during the network operations. +@property(nonatomic, weak, nullable) id loggerDelegate; + +/// Calls the system provided completion handler after the background session is finished. ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; + +/// Initializes with logger delegate. +- (instancetype)initWithNetworkLoggerDelegate: + (nullable id)networkLoggerDelegate NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +/// Sends an asynchronous POST request and calls the provided completion handler when the request +/// completes or when errors occur, and returns an ID of the session/connection. +- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler; + +/// Sends an asynchronous GET request and calls the provided completion handler when the request +/// completes or when errors occur, and returns an ID of the session. +- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler; + +NS_ASSUME_NONNULL_END +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Privacy/Resources/PrivacyInfo.xcprivacy b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Privacy/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..1c9e1a6 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Privacy/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,34 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + C56D.1 + + + + + + diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h new file mode 100644 index 0000000..103ed3b --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +#if !TARGET_OS_WATCH +typedef SCNetworkReachabilityRef (*GULReachabilityCreateWithNameFn)(CFAllocatorRef allocator, + const char *host); + +typedef Boolean (*GULReachabilitySetCallbackFn)(SCNetworkReachabilityRef target, + SCNetworkReachabilityCallBack callback, + SCNetworkReachabilityContext *context); +typedef Boolean (*GULReachabilityScheduleWithRunLoopFn)(SCNetworkReachabilityRef target, + CFRunLoopRef runLoop, + CFStringRef runLoopMode); +typedef Boolean (*GULReachabilityUnscheduleFromRunLoopFn)(SCNetworkReachabilityRef target, + CFRunLoopRef runLoop, + CFStringRef runLoopMode); + +typedef void (*GULReachabilityReleaseFn)(CFTypeRef cf); + +struct GULReachabilityApi { + GULReachabilityCreateWithNameFn createWithNameFn; + GULReachabilitySetCallbackFn setCallbackFn; + GULReachabilityScheduleWithRunLoopFn scheduleWithRunLoopFn; + GULReachabilityUnscheduleFromRunLoopFn unscheduleFromRunLoopFn; + GULReachabilityReleaseFn releaseFn; +}; +#endif +@interface GULReachabilityChecker (Internal) + +- (const struct GULReachabilityApi *)reachabilityApi; +- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi; + +@end diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m new file mode 100644 index 0000000..e3745c6 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m @@ -0,0 +1,263 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +#import "GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h" +#import "GoogleUtilities/Reachability/GULReachabilityMessageCode.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +static GULLoggerService kGULLoggerReachability = @"[GULReachability]"; +#if !TARGET_OS_WATCH +static void ReachabilityCallback(SCNetworkReachabilityRef reachability, + SCNetworkReachabilityFlags flags, + void *info); + +static const struct GULReachabilityApi kGULDefaultReachabilityApi = { + SCNetworkReachabilityCreateWithName, + SCNetworkReachabilitySetCallback, + SCNetworkReachabilityScheduleWithRunLoop, + SCNetworkReachabilityUnscheduleFromRunLoop, + CFRelease, +}; + +static NSString *const kGULReachabilityUnknownStatus = @"Unknown"; +static NSString *const kGULReachabilityConnectedStatus = @"Connected"; +static NSString *const kGULReachabilityDisconnectedStatus = @"Disconnected"; +#endif +@interface GULReachabilityChecker () + +@property(nonatomic, assign) const struct GULReachabilityApi *reachabilityApi; +@property(nonatomic, assign) GULReachabilityStatus reachabilityStatus; +@property(nonatomic, copy) NSString *host; +#if !TARGET_OS_WATCH +@property(nonatomic, assign) SCNetworkReachabilityRef reachability; +#endif + +@end + +@implementation GULReachabilityChecker + +@synthesize reachabilityApi = reachabilityApi_; +#if !TARGET_OS_WATCH +@synthesize reachability = reachability_; +#endif + +- (const struct GULReachabilityApi *)reachabilityApi { + return reachabilityApi_; +} + +- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi { +#if !TARGET_OS_WATCH + if (reachability_) { + GULOSLogError(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode000], + @"Cannot change reachability API while reachability is running. " + @"Call stop first."); + return; + } + reachabilityApi_ = reachabilityApi; +#endif +} + +@synthesize reachabilityStatus = reachabilityStatus_; +@synthesize host = host_; +@synthesize reachabilityDelegate = reachabilityDelegate_; + +- (BOOL)isActive { +#if !TARGET_OS_WATCH + return reachability_ != nil; +#else + return NO; +#endif +} + +- (void)setReachabilityDelegate:(id)reachabilityDelegate { + if (reachabilityDelegate && + (![(NSObject *)reachabilityDelegate conformsToProtocol:@protocol(GULReachabilityDelegate)])) { + GULOSLogError(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULReachabilityMessageCode005], + @"Reachability delegate doesn't conform to Reachability protocol."); + return; + } + reachabilityDelegate_ = reachabilityDelegate; +} + +- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate + withHost:(NSString *)host { + self = [super init]; + + if (!host || !host.length) { + GULOSLogError(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode001], + @"Invalid host specified"); + return nil; + } + if (self) { +#if !TARGET_OS_WATCH + [self setReachabilityDelegate:reachabilityDelegate]; + reachabilityApi_ = &kGULDefaultReachabilityApi; + reachabilityStatus_ = kGULReachabilityUnknown; + host_ = [host copy]; + reachability_ = nil; +#endif + } + return self; +} + +- (void)dealloc { + reachabilityDelegate_ = nil; + [self stop]; +} + +- (BOOL)start { +#if TARGET_OS_WATCH + return NO; +#else + + if (!reachability_) { + reachability_ = reachabilityApi_->createWithNameFn(kCFAllocatorDefault, [host_ UTF8String]); + if (!reachability_) { + return NO; + } + SCNetworkReachabilityContext context = { + 0, /* version */ + (__bridge void *)(self), /* info (passed as last parameter to reachability callback) */ + NULL, /* retain */ + NULL, /* release */ + NULL /* copyDescription */ + }; + if (!reachabilityApi_->setCallbackFn(reachability_, ReachabilityCallback, &context) || + !reachabilityApi_->scheduleWithRunLoopFn(reachability_, CFRunLoopGetMain(), + kCFRunLoopCommonModes)) { + reachabilityApi_->releaseFn(reachability_); + reachability_ = nil; + + GULOSLogError(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode002], + @"Failed to start reachability handle"); + return NO; + } + } + GULOSLogDebug(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode003], + @"Monitoring the network status"); + return YES; +#endif +} + +- (void)stop { +#if !TARGET_OS_WATCH + if (reachability_) { + reachabilityStatus_ = kGULReachabilityUnknown; + reachabilityApi_->unscheduleFromRunLoopFn(reachability_, CFRunLoopGetMain(), + kCFRunLoopCommonModes); + reachabilityApi_->releaseFn(reachability_); + reachability_ = nil; + } +#endif +} + +#if !TARGET_OS_WATCH +- (GULReachabilityStatus)statusForFlags:(SCNetworkReachabilityFlags)flags { + GULReachabilityStatus status = kGULReachabilityNotReachable; + // If the Reachable flag is not set, we definitely don't have connectivity. + if (flags & kSCNetworkReachabilityFlagsReachable) { + // Reachable flag is set. Check further flags. + if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) { +// Connection required flag is not set, so we have connectivity. +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular + : kGULReachabilityViaWifi; +#elif TARGET_OS_OSX + status = kGULReachabilityViaWifi; +#endif + } else if ((flags & (kSCNetworkReachabilityFlagsConnectionOnDemand | + kSCNetworkReachabilityFlagsConnectionOnTraffic)) && + !(flags & kSCNetworkReachabilityFlagsInterventionRequired)) { +// If the connection on demand or connection on traffic flag is set, and user intervention +// is not required, we have connectivity. +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular + : kGULReachabilityViaWifi; +#elif TARGET_OS_OSX + status = kGULReachabilityViaWifi; +#endif + } + } + return status; +} + +- (void)reachabilityFlagsChanged:(SCNetworkReachabilityFlags)flags { + GULReachabilityStatus status = [self statusForFlags:flags]; + if (reachabilityStatus_ != status) { + NSString *reachabilityStatusString; + if (status == kGULReachabilityUnknown) { + reachabilityStatusString = kGULReachabilityUnknownStatus; + } else { + reachabilityStatusString = (status == kGULReachabilityNotReachable) + ? kGULReachabilityDisconnectedStatus + : kGULReachabilityConnectedStatus; + } + + GULOSLogDebug(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode004], + @"Network status has changed. Code:%@, status:%@", @(status), + reachabilityStatusString); + reachabilityStatus_ = status; + [reachabilityDelegate_ reachability:self statusChanged:reachabilityStatus_]; + } +} + +#endif +@end + +#if !TARGET_OS_WATCH +static void ReachabilityCallback(SCNetworkReachabilityRef reachability, + SCNetworkReachabilityFlags flags, + void *info) { + GULReachabilityChecker *checker = (__bridge GULReachabilityChecker *)info; + [checker reachabilityFlagsChanged:flags]; +} +#endif + +// This function used to be at the top of the file, but it was moved here +// as a workaround for a suspected compiler bug. When compiled in Release mode +// and run on an iOS device with WiFi disabled, the reachability code crashed +// when calling SCNetworkReachabilityScheduleWithRunLoop, or shortly thereafter. +// After unsuccessfully trying to diagnose the cause of the crash, it was +// discovered that moving this function to the end of the file magically fixed +// the crash. If you are going to edit this file, exercise caution and make sure +// to test thoroughly with an iOS device under various network conditions. +const NSString *GULReachabilityStatusString(GULReachabilityStatus status) { + switch (status) { + case kGULReachabilityUnknown: + return @"Reachability Unknown"; + + case kGULReachabilityNotReachable: + return @"Not reachable"; + + case kGULReachabilityViaWifi: + return @"Reachable via Wifi"; + + case kGULReachabilityViaCellular: + return @"Reachable via Cellular Data"; + + default: + return [NSString stringWithFormat:@"Invalid reachability status %d", (int)status]; + } +} diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h new file mode 100644 index 0000000..373e0af --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. +typedef NS_ENUM(NSInteger, GULReachabilityMessageCode) { + // GULReachabilityChecker.m + kGULReachabilityMessageCode000 = 902000, // I-NET902000 + kGULReachabilityMessageCode001 = 902001, // I-NET902001 + kGULReachabilityMessageCode002 = 902002, // I-NET902002 + kGULReachabilityMessageCode003 = 902003, // I-NET902003 + kGULReachabilityMessageCode004 = 902004, // I-NET902004 + kGULReachabilityMessageCode005 = 902005, // I-NET902005 + kGULReachabilityMessageCode006 = 902006, // I-NET902006 +}; diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h new file mode 100644 index 0000000..cac5ca3 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h @@ -0,0 +1,83 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#if !TARGET_OS_WATCH +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +/// Reachability Status +typedef enum { + kGULReachabilityUnknown, ///< Have not yet checked or been notified whether host is reachable. + kGULReachabilityNotReachable, ///< Host is not reachable. + kGULReachabilityViaWifi, ///< Host is reachable via Wifi. + kGULReachabilityViaCellular, ///< Host is reachable via cellular. +} GULReachabilityStatus; + +const NSString *GULReachabilityStatusString(GULReachabilityStatus status); + +@class GULReachabilityChecker; + +/// Google Analytics iOS Reachability Checker. +@protocol GULReachabilityDelegate +@required +/// Called when network status has changed. +- (void)reachability:(GULReachabilityChecker *)reachability + statusChanged:(GULReachabilityStatus)status; +@end + +/// Google Analytics iOS Network Status Checker. +@interface GULReachabilityChecker : NSObject + +/// The last known reachability status, or GULReachabilityStatusUnknown if the +/// checker is not active. +@property(nonatomic, readonly) GULReachabilityStatus reachabilityStatus; +/// The host to which reachability status is to be checked. +@property(nonatomic, copy, readonly) NSString *host; +/// The delegate to be notified of reachability status changes. +@property(nonatomic, weak) id reachabilityDelegate; +/// `YES` if the reachability checker is active, `NO` otherwise. +@property(nonatomic, readonly) BOOL isActive; + +/// Initialize the reachability checker. Note that you must call start to begin checking for and +/// receiving notifications about network status changes. +/// +/// @param reachabilityDelegate The delegate to be notified when reachability status to host +/// changes. +/// +/// @param host The name of the host. +/// +- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate + withHost:(NSString *)host; + +- (instancetype)init NS_UNAVAILABLE; + +/// Start checking for reachability to the specified host. This has no effect if the status +/// checker is already checking for connectivity. +/// +/// @return `YES` if initiating status checking was successful or the status checking has already +/// been initiated, `NO` otherwise. +- (BOOL)start; + +/// Stop checking for reachability to the specified host. This has no effect if the status +/// checker is not checking for connectivity. +- (void)stop; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m new file mode 100644 index 0000000..b4ac798 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m @@ -0,0 +1,165 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSString *const kGULLogFormat = @"I-GUL%06ld"; + +static GULLoggerService kGULLogUserDefaultsService = @"[GoogleUtilities/UserDefaults]"; + +typedef NS_ENUM(NSInteger, GULUDMessageCode) { + GULUDMessageCodeInvalidKeyGet = 1, + GULUDMessageCodeInvalidKeySet = 2, + GULUDMessageCodeInvalidObjectSet = 3, + GULUDMessageCodeSynchronizeFailed = 4, +}; + +@interface GULUserDefaults () + +@property(nonatomic, readonly) NSUserDefaults *userDefaults; + +@end + +@implementation GULUserDefaults + ++ (GULUserDefaults *)standardUserDefaults { + static GULUserDefaults *standardUserDefaults; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + standardUserDefaults = [[GULUserDefaults alloc] init]; + }); + return standardUserDefaults; +} + +- (instancetype)init { + return [self initWithSuiteName:nil]; +} + +- (instancetype)initWithSuiteName:(nullable NSString *)suiteName { + self = [super init]; + + NSString *name = [suiteName copy]; + + if (self) { + _userDefaults = name.length ? [[NSUserDefaults alloc] initWithSuiteName:name] + : [NSUserDefaults standardUserDefaults]; + } + + return self; +} + +- (nullable id)objectForKey:(NSString *)defaultName { + NSString *key = [defaultName copy]; + if (![key isKindOfClass:[NSString class]] || !key.length) { + GULOSLogWarning(kGULLogSubsystem, @"", NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeyGet], + @"Cannot get object for invalid user default key."); + return nil; + } + + return [self.userDefaults objectForKey:key]; +} + +- (void)setObject:(nullable id)value forKey:(NSString *)defaultName { + NSString *key = [defaultName copy]; + if (![key isKindOfClass:[NSString class]] || !key.length) { + GULOSLogWarning(kGULLogSubsystem, kGULLogUserDefaultsService, NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeySet], + @"Cannot set object for invalid user default key."); + return; + } + if (!value) { + [self.userDefaults removeObjectForKey:key]; + return; + } + BOOL isAcceptableValue = + [value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]] || + [value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]] || + [value isKindOfClass:[NSDate class]] || [value isKindOfClass:[NSData class]]; + if (!isAcceptableValue) { + GULOSLogWarning( + kGULLogSubsystem, kGULLogUserDefaultsService, NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidObjectSet], + @"Cannot set invalid object to user defaults. Must be a string, number, array, " + @"dictionary, date, or data. Value: %@", + value); + return; + } + + [self.userDefaults setObject:value forKey:key]; +} + +- (void)removeObjectForKey:(NSString *)key { + [self setObject:nil forKey:key]; +} + +#pragma mark - Getters + +- (NSInteger)integerForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.integerValue; +} + +- (float)floatForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.floatValue; +} + +- (double)doubleForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.doubleValue; +} + +- (BOOL)boolForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.boolValue; +} + +- (nullable NSString *)stringForKey:(NSString *)defaultName { + return [self objectForKey:defaultName]; +} + +- (nullable NSArray *)arrayForKey:(NSString *)defaultName { + return [self objectForKey:defaultName]; +} + +- (nullable NSDictionary *)dictionaryForKey:(NSString *)defaultName { + return [self objectForKey:defaultName]; +} + +#pragma mark - Setters + +- (void)setInteger:(NSInteger)integer forKey:(NSString *)defaultName { + [self setObject:@(integer) forKey:defaultName]; +} + +- (void)setFloat:(float)value forKey:(NSString *)defaultName { + [self setObject:@(value) forKey:defaultName]; +} + +- (void)setDouble:(double)doubleNumber forKey:(NSString *)defaultName { + [self setObject:@(doubleNumber) forKey:defaultName]; +} + +- (void)setBool:(BOOL)boolValue forKey:(NSString *)defaultName { + [self setObject:@(boolValue) forKey:defaultName]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h new file mode 100644 index 0000000..83b23fa --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h @@ -0,0 +1,105 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A thread-safe user defaults that uses C functions from CFPreferences.h instead of +/// `NSUserDefaults`. This is to avoid sending an `NSNotification` when it's changed from a +/// background thread to avoid crashing. // TODO: Insert radar number here. +@interface GULUserDefaults : NSObject + +/// A shared user defaults similar to +[NSUserDefaults standardUserDefaults] and accesses the same +/// data of the standardUserDefaults. ++ (GULUserDefaults *)standardUserDefaults; + +/// Initializes preferences with a suite name that is the same with the NSUserDefaults' suite name. +/// Both of CFPreferences and NSUserDefaults share the same plist file so their data will exactly +/// the same. +/// +/// @param suiteName The name of the suite of the user defaults. +- (instancetype)initWithSuiteName:(nullable NSString *)suiteName; + +#pragma mark - Getters + +/// Searches the receiver's search list for a default with the key 'defaultName' and return it. If +/// another process has changed defaults in the search list, NSUserDefaults will automatically +/// update to the latest values. If the key in question has been marked as ubiquitous via a Defaults +/// Configuration File, the latest value may not be immediately available, and the registered value +/// will be returned instead. +- (nullable id)objectForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it will return nil if the value is not an NSArray. +- (nullable NSArray *)arrayForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it will return nil if the value +/// is not an NSDictionary. +- (nullable NSDictionary *)dictionaryForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it will convert NSNumber values to their NSString +/// representation. If a non-string non-number value is found, nil will be returned. +- (nullable NSString *)stringForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it converts the returned value to an NSInteger. If the +/// value is an NSNumber, the result of -integerValue will be returned. If the value is an NSString, +/// it will be converted to NSInteger if possible. If the value is a boolean, it will be converted +/// to either 1 for YES or 0 for NO. If the value is absent or can't be converted to an integer, 0 +/// will be returned. +- (NSInteger)integerForKey:(NSString *)defaultName; + +/// Similar to -integerForKey:, except that it returns a float, and boolean values will not be +/// converted. +- (float)floatForKey:(NSString *)defaultName; + +/// Similar to -integerForKey:, except that it returns a double, and boolean values will not be +/// converted. +- (double)doubleForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it converts the returned value to a BOOL. If the value +/// is an NSNumber, NO will be returned if the value is 0, YES otherwise. If the value is an +/// NSString, values of "YES" or "1" will return YES, and values of "NO", "0", or any other string +/// will return NO. If the value is absent or can't be converted to a BOOL, NO will be returned. +- (BOOL)boolForKey:(NSString *)defaultName; + +#pragma mark - Setters + +/// Immediately stores a value (or removes the value if `nil` is passed as the value) for the +/// provided key in the search list entry for the receiver's suite name in the current user and any +/// host, then asynchronously stores the value persistently, where it is made available to other +/// processes. +- (void)setObject:(nullable id)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from a float to an NSNumber. +- (void)setFloat:(float)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from a double to an +/// NSNumber. +- (void)setDouble:(double)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from an NSInteger to an +/// NSNumber. +- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from a BOOL to an NSNumber. +- (void)setBool:(BOOL)value forKey:(NSString *)defaultName; + +#pragma mark - Removing Defaults + +/// Equivalent to -[... setObject:nil forKey:defaultName] +- (void)removeObjectForKey:(NSString *)defaultName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/GoogleUtilities/LICENSE b/frontend/ios/Pods/GoogleUtilities/LICENSE new file mode 100644 index 0000000..47e7301 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/LICENSE @@ -0,0 +1,224 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +================================================================================ + +Copyright (c) 2017 Landon J. Fuller +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/frontend/ios/Pods/GoogleUtilities/README.md b/frontend/ios/Pods/GoogleUtilities/README.md new file mode 100644 index 0000000..56659d9 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/README.md @@ -0,0 +1,180 @@ +[![Version](https://img.shields.io/cocoapods/v/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) +[![License](https://img.shields.io/cocoapods/l/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) +[![Platform](https://img.shields.io/cocoapods/p/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) + +[![Actions Status][gh-google-utilities-badge]][gh-actions] + +# GoogleUtilities + +GoogleUtilities provides a set of utilities for Firebase and other Google SDKs for Apple platform +development. + +The utilities are not directly supported for non-Google library usage. + +## Integration Testing +These instructions apply to minor and patch version updates. Major versions need +a customized adaptation. + +After the CI is green: +* Determine the next version for release by checking the + [tagged releases](https://github.com/google/GoogleUtilities/tags). + Ensure that the next release version keeps the Swift PM and CocoaPods versions in sync. +* Verify that the releasing version is the latest entry in the [CHANGELOG.md](CHANGELOG.md), + updating it if necessary. +* Update the version in the podspec to match the latest entry in the [CHANGELOG.md](CHANGELOG.md) +* Checkout the `main` branch and ensure it is up to date + ```console + git checkout main + git pull + ``` +* Add the CocoaPods tag (`{version}` will be the latest version in the [podspec](GoogleUtilities.podspec#L3)) + ```console + git tag CocoaPods-{version} + git push origin CocoaPods-{version} + ``` +* Push the podspec to the designated repo + * If this version of GoogleUtilities is intended to launch **before or with** the next Firebase release: +
+ Push to SpecsStaging + + ```console + pod repo push --skip-tests --use-json staging GoogleUtilities.podspec + ``` + + If the command fails with `Unable to find the 'staging' repo.`, add the staging repo with: + ```console + pod repo add staging git@github.com:firebase/SpecsStaging.git + ``` +
+ * Otherwise: +
+ Push to SpecsDev + + ```console + pod repo push --skip-tests --use-json dev GoogleUtilities.podspec + ``` + + If the command fails with `Unable to find the 'dev' repo.`, add the dev repo with: + ```console + pod repo add dev git@github.com:firebase/SpecsDev.git + ``` +
+* Run Firebase CI by waiting until next nightly or adding a PR that touches `Gemfile`. +* On google3, run copybara using the command below. Then, start a global TAP on the generated CL. Deflake as needed. + ```console + third_party/firebase/ios/Releases/run_copy_bara.py --directory GoogleUtilities --branch main + ``` + +## Publishing +The release process is as follows: +1. [Tag and release for Swift PM](#swift-package-manager) +2. [Publish to CocoaPods](#cocoapods) +3. [Create GitHub Release](#create-github-release) +4. [Perform post release cleanup](#post-release-cleanup) + +### Swift Package Manager + By creating and [pushing a tag](https://github.com/google/GoogleUtilities/tags) + for Swift PM, the newly tagged version will be immediately released for public use. + Given this, please verify the intended time of release for Swift PM. + * Add a version tag for Swift PM + ```console + git tag {version} + git push origin {version} + ``` + *Note: Ensure that any inflight PRs that depend on the new `GoogleUtilities` version are updated to point to the + newly tagged version rather than a checksum.* + +### CocoaPods +* Publish the newly versioned pod to CocoaPods + + It's recommended to point to the `GoogleUtilities.podspec` in `staging` to make sure the correct spec is being published. + ```console + pod trunk push ~/.cocoapods/repos/staging/GoogleUtilities/{version}/GoogleUtilities.podspec.json + ``` + *Note: In some cases, it may be acceptable to `pod trunk push` with the `--skip-tests` flag. Please double check with + the maintainers before doing so.* + + The pod push was successful if the above command logs: `๐Ÿš€ GoogleUtilities ({version}) successfully published`. + In addition, a new commit that publishes the new version (co-authored by [CocoaPodsAtGoogle](https://github.com/CocoaPodsAtGoogle)) + should appear in the [CocoaPods specs repo](https://github.com/CocoaPods/Specs). Last, the latest version should be displayed + on [GoogleUtilities's CocoaPods page](https://cocoapods.org/pods/GoogleUtilities). + +### [Create GitHub Release](https://github.com/google/GoogleUtilities/releases/new/) + Update the [release template](https://github.com/google/GoogleUtilities/releases/new/)'s **Tag version** and **Release title** + fields with the latest version. In addition, reference the [Release Notes](./CHANGELOG.md) in the release's description. + + See [this release](https://github.com/google/GoogleUtilities/releases/edit/7.7.0) for an example. + + *Don't forget to perform the [post release cleanup](#post-release-cleanup)!* + +### Post Release Cleanup +
+ Clean up SpecsStaging + + ```console + pwd=$(pwd) + mkdir -p /tmp/release-cleanup && cd $_ + git clone git@github.com:firebase/SpecsStaging.git + cd SpecsStaging/ + git rm -rf GoogleUtilities/ + git commit -m "Post publish cleanup" + git push origin master + rm -rf /tmp/release-cleanup + cd $pwd + ``` +
+ +## Development + +To develop in this repository, ensure that you have at least the following software: + + * Xcode 12.0 (or later) + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen GoogleUtilities.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +### Development for Catalyst +* `pod gen GoogleUtilities.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Code Formatting + +See [firebase-ios-sdk's code formatting docs][firebase-ios-sdk-formatting]. + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +## Contributing + +See [Contributing](CONTRIBUTING.md). + +## License + +The contents of this repository is licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions +[gh-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg +[firebase-ios-sdk-formatting]: https://github.com/firebase/firebase-ios-sdk?tab=readme-ov-file#code-formatting diff --git a/frontend/ios/Pods/GoogleUtilities/third_party/IsAppEncrypted/IsAppEncrypted.m b/frontend/ios/Pods/GoogleUtilities/third_party/IsAppEncrypted/IsAppEncrypted.m new file mode 100644 index 0000000..e2f7275 --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/third_party/IsAppEncrypted/IsAppEncrypted.m @@ -0,0 +1,104 @@ +// Copyright (c) 2017 Landon J. Fuller +// All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// +// Comment from +// iPhone Dev +// Wiki Crack Prevention: +// App Store binaries are signed by both their developer and Apple. This +// encrypts the binary so that decryption keys are needed in order to make the +// binary readable. When iOS executes the binary, the decryption keys are used +// to decrypt the binary into a readable state where it is then loaded into +// memory and executed. iOS can tell the encryption status of a binary via the +// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If +// cryptid is a non-zero value then the binary is encrypted. +// +// 'Cracking' works by letting the kernel decrypt the binary then siphoning the +// decrypted data into a new binary file, resigning, and repackaging. This will +// only work on jailbroken devices as codesignature validation has been +// removed. Resigning takes place because while the codesignature doesn't have +// to be valid thanks to the jailbreak, it does have to be in place unless you +// have AppSync or similar to disable codesignature checks. +// +// More information at +// Landon Fuller's blog + +#import "third_party/IsAppEncrypted/Public/IsAppEncrypted.h" + +#import +#import + +/// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from +/// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just +/// provide the definitions here. +#if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO) +#define LC_ENCRYPTION_INFO 0x21 +struct encryption_info_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t cryptoff; + uint32_t cryptsize; + uint32_t cryptid; +}; +#endif + +BOOL IsAppEncrypted(void) { + const struct mach_header *executableHeader = NULL; + for (uint32_t i = 0; i < _dyld_image_count(); i++) { + const struct mach_header *header = _dyld_get_image_header(i); + if (header && header->filetype == MH_EXECUTE) { + executableHeader = header; + break; + } + } + + if (!executableHeader) { + return NO; + } + + BOOL is64bit = (executableHeader->magic == MH_MAGIC_64); + uintptr_t cursor = (uintptr_t)executableHeader + + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); + const struct segment_command *segmentCommand = NULL; + uint32_t i = 0; + + while (i++ < executableHeader->ncmds) { + segmentCommand = (struct segment_command *)cursor; + + if (!segmentCommand) { + continue; + } + + if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) || + (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) { + if (is64bit) { + struct encryption_info_command_64 *cryptCmd = + (struct encryption_info_command_64 *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } else { + struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } + } + cursor += segmentCommand->cmdsize; + } + + return NO; +} diff --git a/frontend/ios/Pods/GoogleUtilities/third_party/IsAppEncrypted/Public/IsAppEncrypted.h b/frontend/ios/Pods/GoogleUtilities/third_party/IsAppEncrypted/Public/IsAppEncrypted.h new file mode 100644 index 0000000..1a4305a --- /dev/null +++ b/frontend/ios/Pods/GoogleUtilities/third_party/IsAppEncrypted/Public/IsAppEncrypted.h @@ -0,0 +1,24 @@ +// Copyright (c) 2017 Landon J. Fuller +// All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#import + +BOOL IsAppEncrypted(void); diff --git a/frontend/ios/Pods/Headers/Private/Firebase/Firebase.h b/frontend/ios/Pods/Headers/Private/Firebase/Firebase.h new file mode 120000 index 0000000..07ac6eb --- /dev/null +++ b/frontend/ios/Pods/Headers/Private/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/CoreOnly/Sources/Firebase.h \ No newline at end of file diff --git a/frontend/ios/Pods/Headers/Public/Firebase/Firebase.h b/frontend/ios/Pods/Headers/Public/Firebase/Firebase.h new file mode 120000 index 0000000..07ac6eb --- /dev/null +++ b/frontend/ios/Pods/Headers/Public/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/CoreOnly/Sources/Firebase.h \ No newline at end of file diff --git a/frontend/ios/Pods/Local Podspecs/Flutter.podspec.json b/frontend/ios/Pods/Local Podspecs/Flutter.podspec.json new file mode 100644 index 0000000..d67a7c7 --- /dev/null +++ b/frontend/ios/Pods/Local Podspecs/Flutter.podspec.json @@ -0,0 +1,20 @@ +{ + "name": "Flutter", + "version": "1.0.0", + "summary": "A UI toolkit for beautiful and fast apps.", + "homepage": "https://flutter.dev", + "license": { + "type": "BSD" + }, + "authors": { + "Flutter Dev Team": "flutter-dev@googlegroups.com" + }, + "source": { + "git": "https://github.com/flutter/engine", + "tag": "1.0.0" + }, + "platforms": { + "ios": "13.0" + }, + "vendored_frameworks": "path/to/nothing" +} diff --git a/frontend/ios/Pods/Local Podspecs/firebase_core.podspec.json b/frontend/ios/Pods/Local Podspecs/firebase_core.podspec.json new file mode 100644 index 0000000..cf6429f --- /dev/null +++ b/frontend/ios/Pods/Local Podspecs/firebase_core.podspec.json @@ -0,0 +1,30 @@ +{ + "name": "firebase_core", + "version": "3.15.2", + "summary": "Flutter plugin for Firebase Core, enabling connecting to multiple Firebase apps.", + "description": "Flutter plugin for Firebase Core, enabling connecting to multiple Firebase apps.", + "homepage": "https://firebase.google.com/docs/flutter/setup", + "license": { + "file": "../LICENSE" + }, + "authors": "The Chromium Authors", + "source": { + "path": "." + }, + "source_files": "firebase_core/Sources/firebase_core/**/*.{h,m}", + "public_header_files": "firebase_core/Sources/firebase_core/include/**/*.h", + "platforms": { + "ios": "13.0" + }, + "dependencies": { + "Flutter": [], + "Firebase/CoreOnly": [ + "11.15.0" + ] + }, + "static_framework": true, + "pod_target_xcconfig": { + "GCC_PREPROCESSOR_DEFINITIONS": "LIBRARY_VERSION=\\\"3.15.2\\\" LIBRARY_NAME=\\\"flutter-fire-core\\\"", + "DEFINES_MODULE": "YES" + } +} diff --git a/frontend/ios/Pods/Local Podspecs/firebase_messaging.podspec.json b/frontend/ios/Pods/Local Podspecs/firebase_messaging.podspec.json new file mode 100644 index 0000000..6f600d0 --- /dev/null +++ b/frontend/ios/Pods/Local Podspecs/firebase_messaging.podspec.json @@ -0,0 +1,34 @@ +{ + "name": "firebase_messaging", + "version": "15.2.10", + "summary": "Flutter plugin for Firebase Cloud Messaging, a cross-platform messaging solution that lets you reliably deliver messages on Android and iOS.", + "description": "Flutter plugin for Firebase Cloud Messaging, a cross-platform messaging solution that lets you reliably deliver messages on Android and iOS.", + "homepage": "https://firebase.google.com/docs/cloud-messaging", + "license": { + "file": "../LICENSE" + }, + "authors": "The Chromium Authors", + "source": { + "path": "." + }, + "source_files": "firebase_messaging/Sources/firebase_messaging/**/*.{h,m}", + "public_header_files": "firebase_messaging/Sources/firebase_messaging/include/*.h", + "platforms": { + "ios": "13.0" + }, + "dependencies": { + "Flutter": [], + "firebase_core": [], + "Firebase/Messaging": [ + "11.15.0" + ] + }, + "resource_bundles": { + "firebase_messaging_Privacy": "Resources/PrivacyInfo.xcprivacy" + }, + "static_framework": true, + "pod_target_xcconfig": { + "GCC_PREPROCESSOR_DEFINITIONS": "LIBRARY_VERSION=\\\"15.2.10\\\" LIBRARY_NAME=\\\"flutter-fire-fcm\\\"", + "DEFINES_MODULE": "YES" + } +} diff --git a/frontend/ios/Pods/Local Podspecs/flutter_local_notifications.podspec.json b/frontend/ios/Pods/Local Podspecs/flutter_local_notifications.podspec.json new file mode 100644 index 0000000..1dbcf99 --- /dev/null +++ b/frontend/ios/Pods/Local Podspecs/flutter_local_notifications.podspec.json @@ -0,0 +1,30 @@ +{ + "name": "flutter_local_notifications", + "version": "0.0.1", + "summary": "Flutter plugin for displaying local notifications.", + "description": "Flutter plugin for displaying local notifications.", + "homepage": "https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications", + "license": { + "type": "BSD", + "file": "../LICENSE" + }, + "authors": { + "Michael Bui": "michael@dexterx.dev" + }, + "source": { + "path": "." + }, + "source_files": "Classes/**/*", + "public_header_files": "Classes/**/*.h", + "dependencies": { + "Flutter": [] + }, + "resource_bundles": { + "flutter_local_notifications_privacy": [ + "Resources/PrivacyInfo.xcprivacy" + ] + }, + "platforms": { + "ios": "11.0" + } +} diff --git a/frontend/ios/Pods/Local Podspecs/image_picker_ios.podspec.json b/frontend/ios/Pods/Local Podspecs/image_picker_ios.podspec.json new file mode 100644 index 0000000..48dd052 --- /dev/null +++ b/frontend/ios/Pods/Local Podspecs/image_picker_ios.podspec.json @@ -0,0 +1,35 @@ +{ + "name": "image_picker_ios", + "version": "0.0.1", + "summary": "Flutter plugin that shows an image picker.", + "description": "A Flutter plugin for picking images from the image library, and taking new pictures with the camera.\nDownloaded by pub (not CocoaPods).", + "homepage": "https://github.com/flutter/packages", + "license": { + "type": "BSD", + "file": "../LICENSE" + }, + "authors": { + "Flutter Dev Team": "flutter-dev@googlegroups.com" + }, + "source": { + "http": "https://github.com/flutter/packages/tree/main/packages/image_picker_ios" + }, + "documentation_url": "https://pub.dev/packages/image_picker_ios", + "source_files": "image_picker_ios/Sources/image_picker_ios/**/*.{h,m}", + "public_header_files": "image_picker_ios/Sources/image_picker_ios/**/*.h", + "module_map": "image_picker_ios/Sources/image_picker_ios/include/ImagePickerPlugin.modulemap", + "dependencies": { + "Flutter": [] + }, + "platforms": { + "ios": "13.0" + }, + "pod_target_xcconfig": { + "DEFINES_MODULE": "YES" + }, + "resource_bundles": { + "image_picker_ios_privacy": [ + "image_picker_ios/Sources/image_picker_ios/Resources/PrivacyInfo.xcprivacy" + ] + } +} diff --git a/frontend/ios/Pods/Manifest.lock b/frontend/ios/Pods/Manifest.lock new file mode 100644 index 0000000..07041af --- /dev/null +++ b/frontend/ios/Pods/Manifest.lock @@ -0,0 +1,122 @@ +PODS: + - Firebase/CoreOnly (11.15.0): + - FirebaseCore (~> 11.15.0) + - Firebase/Messaging (11.15.0): + - Firebase/CoreOnly + - FirebaseMessaging (~> 11.15.0) + - firebase_core (3.15.2): + - Firebase/CoreOnly (= 11.15.0) + - Flutter + - firebase_messaging (15.2.10): + - Firebase/Messaging (= 11.15.0) + - firebase_core + - Flutter + - FirebaseCore (11.15.0): + - FirebaseCoreInternal (~> 11.15.0) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/Logger (~> 8.1) + - FirebaseCoreInternal (11.15.0): + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - FirebaseInstallations (11.15.0): + - FirebaseCore (~> 11.15.0) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/UserDefaults (~> 8.1) + - PromisesObjC (~> 2.4) + - FirebaseMessaging (11.15.0): + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleDataTransport (~> 10.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/Environment (~> 8.1) + - GoogleUtilities/Reachability (~> 8.1) + - GoogleUtilities/UserDefaults (~> 8.1) + - nanopb (~> 3.30910.0) + - Flutter (1.0.0) + - flutter_local_notifications (0.0.1): + - Flutter + - GoogleDataTransport (10.1.0): + - nanopb (~> 3.30910.0) + - PromisesObjC (~> 2.4) + - GoogleUtilities/AppDelegateSwizzler (8.1.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Privacy + - GoogleUtilities/Environment (8.1.0): + - GoogleUtilities/Privacy + - GoogleUtilities/Logger (8.1.0): + - GoogleUtilities/Environment + - GoogleUtilities/Privacy + - GoogleUtilities/Network (8.1.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Privacy + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (8.1.0)": + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (8.1.0) + - GoogleUtilities/Reachability (8.1.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GoogleUtilities/UserDefaults (8.1.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - image_picker_ios (0.0.1): + - Flutter + - nanopb (3.30910.0): + - nanopb/decode (= 3.30910.0) + - nanopb/encode (= 3.30910.0) + - nanopb/decode (3.30910.0) + - nanopb/encode (3.30910.0) + - PromisesObjC (2.4.0) + +DEPENDENCIES: + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) + - Flutter (from `Flutter`) + - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + +SPEC REPOS: + trunk: + - Firebase + - FirebaseCore + - FirebaseCoreInternal + - FirebaseInstallations + - FirebaseMessaging + - GoogleDataTransport + - GoogleUtilities + - nanopb + - PromisesObjC + +EXTERNAL SOURCES: + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_messaging: + :path: ".symlinks/plugins/firebase_messaging/ios" + Flutter: + :path: Flutter + flutter_local_notifications: + :path: ".symlinks/plugins/flutter_local_notifications/ios" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" + +SPEC CHECKSUMS: + Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e + firebase_core: 995454a784ff288be5689b796deb9e9fa3601818 + firebase_messaging: f4a41dd102ac18b840eba3f39d67e77922d3f707 + FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e + FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 + FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 + FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + flutter_local_notifications: 395056b3175ba4f08480a7c5de30cd36d69827e4 + GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 + GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 + image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 + nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + +PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e + +COCOAPODS: 1.16.2 diff --git a/frontend/ios/Pods/Pods.xcodeproj/project.pbxproj b/frontend/ios/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..8b1c345 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,8450 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 072CEA044D2EF26F03496D5996BBF59F /* Firebase */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 044818E6F13FF69D67D99BB49C808856 /* Build configuration list for PBXAggregateTarget "Firebase" */; + buildPhases = ( + ); + dependencies = ( + D87D7501B4DB30CE959EE8EB0D788B17 /* PBXTargetDependency */, + B30C651328C33AE9AF917D41339CE4DD /* PBXTargetDependency */, + ); + name = Firebase; + }; + 1EFDDC32A34D56D411E640A81DCD9E73 /* Flutter */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 94078A06C17E946ADC1F2C06726219E5 /* Build configuration list for PBXAggregateTarget "Flutter" */; + buildPhases = ( + ); + dependencies = ( + ); + name = Flutter; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 00629DB3E27C092CCBE10C553B8BC4B0 /* FIRMessagingUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FEB5CEB94D970450A0BBA5577A80F61 /* FIRMessagingUtilities.m */; }; + 009AE534528CDDAE7E5E5BEC0E83981A /* nanopb-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 1113950F760FBB488BA6EFD6F5B7B649 /* nanopb-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 00A8EF145409B6264F85D45182E6F11C /* GULNetworkLoggerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 92A5185EE87E3B7A214986492CCC6B06 /* GULNetworkLoggerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 00CE183CDBD142197C384084C51D478D /* PromisesObjC-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C613D4CE88F0AF4F9A718CB8F6CB748 /* PromisesObjC-dummy.m */; }; + 0587C0EEAEB4C3D21491C6EE0A620178 /* pb.h in Headers */ = {isa = PBXBuildFile; fileRef = 2857105885BD433FDC1DF8F4846851DC /* pb.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 06237A16A8BAC89D177AF533730FDBB8 /* FIRCurrentDateProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 87934EF8F3D60D9A8C773E4D2A0BA3B3 /* FIRCurrentDateProvider.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 06618627DDD00F3992F51FBAAEF7B5BC /* FIRCurrentDateProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = FF8D2EC06176343EF1EACEF6206CC015 /* FIRCurrentDateProvider.m */; }; + 074401DD0ECBA53E57075F84BDE3C310 /* image_picker_ios-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 3ABA51F489706FFEBF9DE0135C0C0FCA /* image_picker_ios-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0785621278D71B1DE67F4BAC1E860E69 /* FBLPromise+Reduce.h in Headers */ = {isa = PBXBuildFile; fileRef = B83C30F28A2D3A9276FE5DE6F46E1766 /* FBLPromise+Reduce.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 07BCEFB4A881BEAD7733853378252048 /* FBLPromise+Timeout.h in Headers */ = {isa = PBXBuildFile; fileRef = A38E222418E1BD45495FCA32F1873620 /* FBLPromise+Timeout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 07C770B6244A7D148CEDC70E279CC0D1 /* FBLPromise+Race.m in Sources */ = {isa = PBXBuildFile; fileRef = 916ED4F015F6F56B913472172EB23B0D /* FBLPromise+Race.m */; }; + 0826E6A5DF896E479AE2642B4E37BF1F /* FlutterLocalNotificationsPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = E0DF8F36727B0D343DF681ED004FD2E6 /* FlutterLocalNotificationsPlugin.m */; }; + 08ECE8151E4DFCFE4311F5E4C9B5A3BB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 09E8AEF6A2333C2AF970994B5A4F81AB /* GDTCORStorageProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = EF5E4FCAEC3D44A5DF86D667C0A1F738 /* GDTCORStorageProtocol.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 09ED7C9E0D2AD0089F0A963AB722D00F /* Pods-Runner-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = BCC84BDE7260B712B097666E169A193C /* Pods-Runner-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0B06543A58DA0D4CBDC34716A1E19AE4 /* FIRMessagingTokenStore.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF87156BDDD108EE55A558C722D79EA /* FIRMessagingTokenStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0B26180FB07A238EB65995A651441012 /* GDTCORUploadBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 8FD58877AD51D8F920444C2D00B20F3D /* GDTCORUploadBatch.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0BB369A5618D2911E4EEB5B16F274847 /* GDTCORConsoleLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = B6E1889709D64FDA47F85E4DA3319BCE /* GDTCORConsoleLogger.m */; }; + 0BF67FE9A6EEF75C7DF88C5A427D0A43 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 0C0796C7D48DD78256A8FEEB7413F6D0 /* FirebaseCore-FirebaseCore_Privacy in Resources */ = {isa = PBXBuildFile; fileRef = 8BB937B1C0DFFCF92F41861C2BC54DDA /* FirebaseCore-FirebaseCore_Privacy */; }; + 0C3010023CDB0908759D6B5C1E5E63FA /* GoogleUtilities-GoogleUtilities_Privacy in Resources */ = {isa = PBXBuildFile; fileRef = 44E291D18340EAC3F761346198515323 /* GoogleUtilities-GoogleUtilities_Privacy */; }; + 0C6E2C0C66F1050EBD6675CD2CF943AF /* FIRMessaging+ExtensionHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = BD0A6B8D25BE47384E9E9BDED1204071 /* FIRMessaging+ExtensionHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0CF6202C8A8CA2A354C91B2548BE2E72 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21D9E6AABF6D4CF5BC663A230EF53A42 /* UIKit.framework */; }; + 0D1BC3F8872405F5215A111915BF0FA4 /* FIRLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 70B2477B7080994FF019740F97FDA027 /* FIRLogger.m */; }; + 0D2872C9FF381C30DE475A675AED4C67 /* FBLPromise+Validate.h in Headers */ = {isa = PBXBuildFile; fileRef = 34E0FF48D6D2CD42238C1A65D59CED2F /* FBLPromise+Validate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0DD0CC775C037EE7BAA4BA1497D15EDB /* GDTCOREvent_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ED2F58D2160FEAAC3E745D0085755B1 /* GDTCOREvent_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0DFBDA661534DFF7B7161F3D9A36C1A3 /* GDTCORMetrics+GDTCCTSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 986A3F2324959A8B87BB0F95403C0DB4 /* GDTCORMetrics+GDTCCTSupport.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0E3F8A6978592652C2EA5EF3A75C0727 /* FBLPromise+All.m in Sources */ = {isa = PBXBuildFile; fileRef = B25ED3E90C5098A71F9E5478214441B0 /* FBLPromise+All.m */; }; + 0F06FE337A62AFA36D005589967BC90D /* GULNetworkInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C205268B2949B720B83A78AA2A2F6C /* GULNetworkInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 0F5A053CBEC500A7E84633E29A32651B /* FBLPromise+Then.h in Headers */ = {isa = PBXBuildFile; fileRef = C521DDFFCA95CC5736F10248D9812971 /* FBLPromise+Then.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0FBB7A21EB00E443EEC886E940E4ED27 /* FIRComponent.m in Sources */ = {isa = PBXBuildFile; fileRef = 52D6E9B0E720A5CC03B91F3CCE939F1D /* FIRComponent.m */; }; + 104FF72FD2BEFCBDFDD392930A21378D /* FIRMessagingTokenDeleteOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D76A6F64A9F9AC8C80C62153642E906 /* FIRMessagingTokenDeleteOperation.m */; }; + 11C2E0C3CE9E7BBD53FF9A879ADFC54F /* GDTCORFlatFileStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = CCB99A06CCC77919B7446EEF57659E87 /* GDTCORFlatFileStorage.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 132ABC6A00573AA57C690B9577B22E9F /* compliance.nanopb.c in Sources */ = {isa = PBXBuildFile; fileRef = 4F4B9BE06777680B5A22621207B01882 /* compliance.nanopb.c */; }; + 13CA40B9275CF297C782BE9486ADB6F2 /* FBLPromise+Wrap.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FC1F7D9B41F4C5EC44785ED4449DABD /* FBLPromise+Wrap.m */; }; + 158E75642E31997D32F8CAA6ED8C3D69 /* FIRInstallationsIDController.h in Headers */ = {isa = PBXBuildFile; fileRef = CF581185566FAB365575D1B37BF1296C /* FIRInstallationsIDController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1592FC1F961CCC2F8FDAE4DE102C2A8D /* FirebaseCoreInternal-FirebaseCoreInternal_Privacy in Resources */ = {isa = PBXBuildFile; fileRef = 4DB03FD262B678178A44272143846563 /* FirebaseCoreInternal-FirebaseCoreInternal_Privacy */; }; + 1683F46BFD010E525F099B091E72C3CE /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 5F79E91E59676DD40F34E8E5DEFC6A9E /* PrivacyInfo.xcprivacy */; }; + 16D77ED94360918B9B6C001B243A1D6C /* FIRInteropParameterNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 425208C5EBD0D6B01AB909862DE50BAA /* FIRInteropParameterNames.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 17C6DA08C7213732A9978A61551D596A /* FlutterLocalNotificationsPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 490DC0C7050C99937B5FAA5B60745755 /* FlutterLocalNotificationsPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 18DB9163B1CC2366698518359F84871B /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 6AAFE120840A05E53C241E4B7F3C64E8 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 190F94C0F26BE05ED84B38273B61E3AE /* FIRInstallationsHTTPError.m in Sources */ = {isa = PBXBuildFile; fileRef = C40988385EFE5D8754088D1EBBDF7BAD /* FIRInstallationsHTTPError.m */; }; + 19149081E4D94571DA14231CBEB5B69B /* FIRMessagingKeychain.h in Headers */ = {isa = PBXBuildFile; fileRef = 673C3318F9A1D81116EEE5349A511A7F /* FIRMessagingKeychain.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 19451FEC797AB117546FEC0D36D8AB36 /* FIRInstallationsSingleOperationPromiseCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 51E163742B3DECE034022C24CEA961D7 /* FIRInstallationsSingleOperationPromiseCache.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 19FFA03079E30FBB6884BCAC56DD2132 /* FIRInstallationsAuthTokenResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 38E268C4172837796B505246635355EA /* FIRInstallationsAuthTokenResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1A438F3B4C0C2739358FF5DAD9F5A4C1 /* GDTCCTUploadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = CF05C45883497B3E21CA51BF8DE0F678 /* GDTCCTUploadOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1A5892FC1D4BD280BA38213030D30A2D /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 6B31EC9A7B428F4713B87CE4DF630775 /* PrivacyInfo.xcprivacy */; }; + 1AFDC4C1679F0A6AD83D1652B8CB08CC /* GDTCORMetricsMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = D908E95DE9E1E5FAA4F57148C5FC790B /* GDTCORMetricsMetadata.m */; }; + 1B60A4B1E41A656934200C3CCAE63D4B /* FIRMessagingExtensionHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = FB1460C0D5E3BF3EFFDA6E70D347BD42 /* FIRMessagingExtensionHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1B94F23129421A5CC48403B8178218F8 /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 197CD7DF8C5D74CD76AFB946CABF0B91 /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1C3A09E95B8444D58F7D19A9A9812742 /* ActionEventSink.m in Sources */ = {isa = PBXBuildFile; fileRef = 895B93138E15C0598E60030F41FD9104 /* ActionEventSink.m */; }; + 1C4BC995FAF21B8F8CF5F4CA16476B3A /* FIRMessagingAPNSInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 922274B4EC30676D7427163E9BB88BDB /* FIRMessagingAPNSInfo.m */; }; + 1CC94C695A8D7E61B92E44ED84B88D50 /* GDTCOREvent+GDTCCTSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = ED62F9AF2BC8736E949B2CB879B6445D /* GDTCOREvent+GDTCCTSupport.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1CF1B04DBE905C2336EA637574DC884A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 1CF9D1DC095D24970CFC8E135F7616D3 /* GULUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A46168EEE10D0596CA807ED75B57AAC /* GULUserDefaults.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1D845CA31916DB3CA63E5B76BC4FBE46 /* FBLPromise+Timeout.m in Sources */ = {isa = PBXBuildFile; fileRef = 01C21144A7A96E0CDBABE621D3EC79CD /* FBLPromise+Timeout.m */; }; + 1E678DEABDD346FA91C6A0503F1E8789 /* FBLPromisePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 84F8E1FB429C5EB93170E449E74D75B1 /* FBLPromisePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 1F07E5C1F822DD99C54C88E97A974058 /* GDTCORLogSourceMetrics.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E74DC0FD5217C11B99B434ACE6CD425 /* GDTCORLogSourceMetrics.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 1F4B7B2479B0430452AA32F8218495A9 /* pb_encode.h in Headers */ = {isa = PBXBuildFile; fileRef = AE06A6A60D50DA808B0072CE08DCC3E5 /* pb_encode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 215495EF2965BB009E9A6C9E224651BB /* FLTImagePickerMetaDataUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 9245949F7AF50C5640000F79C1110624 /* FLTImagePickerMetaDataUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2182B73EA7F410DC5AA130F5E501E496 /* FBLPromise+Always.m in Sources */ = {isa = PBXBuildFile; fileRef = A67F9CA5CA48ED7EC5EC8BDCEBA8414F /* FBLPromise+Always.m */; }; + 21BEF5DA11B1DBC9D7DBAA2032842F13 /* GoogleDataTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C495C7955782B478F1F6B5A9B7E1CF /* GoogleDataTransport.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 220954F9E123D8C3938D1B7630C6FD5C /* IsAppEncrypted.h in Headers */ = {isa = PBXBuildFile; fileRef = 422185136707E9DE2A78DC226625C9D5 /* IsAppEncrypted.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2282F718E7770C41D6BD7FB0AE6508A6 /* GDTCORUploadBatch.m in Sources */ = {isa = PBXBuildFile; fileRef = 49AE84DBBAD701EE2CB8545AAC680E6E /* GDTCORUploadBatch.m */; }; + 22BD42F0338D295125A9731250A8215B /* FLTImagePickerPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 00FFDE3AE7E0091D819430E2EA48408E /* FLTImagePickerPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2315F86A6673F07D6059CA6C0D406A3D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 239863429DD644D3C8FD31BB9592B347 /* dummy.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F83DB803875BEAAF3F411BC01D3472E /* dummy.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 23B81E60D7CC6BBAD1A1F7C4A07D424B /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C0783D1DCE2D70C01DE8F66368E3525 /* CoreTelephony.framework */; }; + 2490496B11F00A0DA461D6CE37BE903E /* FIRConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 93320CABD301A5AEBACABF6E8637270F /* FIRConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2513C5C0DB00539C0026FA3729A6D2C5 /* pb_decode.h in Headers */ = {isa = PBXBuildFile; fileRef = 635395842F105EACF3067D6B54D82C8F /* pb_decode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 258701CDB6197462997789A95414A3BB /* me.nanopb.c in Sources */ = {isa = PBXBuildFile; fileRef = 50D270FC2FB999A0D0BA29B73B9B2DFB /* me.nanopb.c */; }; + 25CC61FBFBF14E34D42AA32298DC71DD /* messages.g.m in Sources */ = {isa = PBXBuildFile; fileRef = A1BD49BD040680F98EB5578FF93E0C8B /* messages.g.m */; }; + 26027AD6D367CD1788F3332165FEAA7A /* FIRInstallationsStoredAuthToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 9E39F1849E3712A9D9DFEB11809CD4F8 /* FIRInstallationsStoredAuthToken.m */; }; + 275ECCAB21ADAB686EE232016D4F92FE /* FIRMessagingCheckinPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 89E70F54AFC72D650C16A032C725BCD9 /* FIRMessagingCheckinPreferences.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 276A96E8DFA740171098223E83C76817 /* GDTCORTransformer_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = B938FBAF03B6ED7A749BE73D476B7B15 /* GDTCORTransformer_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 285E16ED3A35B853639E6100AFCEFBCF /* FIRMessagingCheckinService.h in Headers */ = {isa = PBXBuildFile; fileRef = 645C467BE75EA8292CD0BAC07F1DD5A5 /* FIRMessagingCheckinService.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 297DEA43F5E592D731A47F1A5C0B413C /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 2D8EA9E33C58DFF057693997F6C8D831 /* PrivacyInfo.xcprivacy */; }; + 2A285780C26D334E131321067FF165D0 /* FIRMessagingPendingTopicsList.m in Sources */ = {isa = PBXBuildFile; fileRef = AAF898F203112836152F0FEF6B14DF2B /* FIRMessagingPendingTopicsList.m */; }; + 2B5B0F628F0FE3CD032B8CA1FA3A9902 /* image_picker_ios-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EDDBD54960ABBA9D0898075ADB7A56C /* image_picker_ios-dummy.m */; }; + 2BCEE7F546EE3000EBB2D140C64C6EDC /* FlutterEngineManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0449AF94882DAC62AA57B3FD5760D8B0 /* FlutterEngineManager.m */; }; + 2C08D6A1AB540EA72D250B54E8CF9C3D /* GDTCOREventTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = D56C33CE6C883DF8D154067576FC8FCB /* GDTCOREventTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2C0E76791D2814239B3C5B93F6F11DD0 /* FirebaseInstallationsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BE9CF5E1CA26178487BCD7E48951DE8 /* FirebaseInstallationsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2C1B8D99B5F7257C2F90DDFF8CBB76F3 /* FIRInstallationsStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 29D1AD200DC6E547E00A68ED01A09C6D /* FIRInstallationsStatus.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2CC677CAF6F511B9D0BC37FAFF3A3A63 /* FIRInstallationsStoredItem.h in Headers */ = {isa = PBXBuildFile; fileRef = F1A1B6D700EBB61E205BD7BFC87E2845 /* FIRInstallationsStoredItem.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 2D6CAB6076DD88C5FEF5044C38C50758 /* _ObjC_HeartbeatController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2428D4B9A1ADDA45215CD1FC1F3207AD /* _ObjC_HeartbeatController.swift */; }; + 2DC132ABBFF98D1617F6BFB15928CA0B /* GDTCORTransport.h in Headers */ = {isa = PBXBuildFile; fileRef = 3431FD1E5FCA48FEF6E835D77FC47AE9 /* GDTCORTransport.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2DC9FB7E7BDB2C5F1F4A53856E6C2AFC /* messages.g.m in Sources */ = {isa = PBXBuildFile; fileRef = 44B37CE36850E344D08C7C42DC1B036A /* messages.g.m */; }; + 2F8291AB02BA74E440205A516575FA08 /* GULAppDelegateSwizzler.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EA7FEFB5AC53EBAF907B0E73D03959D /* GULAppDelegateSwizzler.m */; }; + 2FBC11779C522B4E6B0C74C8A75C9F74 /* FIRMessagingLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 50F392EB97CBED8788C50990F6BAB160 /* FIRMessagingLogger.m */; }; + 30EEB99A07CCC1682F5007DC779DB6DA /* FIRComponentContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D630B865AE0C8F8420AEEA5D9729BEA /* FIRComponentContainer.m */; }; + 31669F21EC4AA5BBB6DD01B51612CDEB /* FIRVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = EBF3BFE26470C008E106EB355D9C4277 /* FIRVersion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 335B5194B81E15303D4B124FFFD61422 /* AtomicBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0DF8FF5022D896FDA41D434C0F6EF5 /* AtomicBox.swift */; }; + 349A362BFDBCE10DC57DFB6A19AF65A2 /* GDTCOREvent.m in Sources */ = {isa = PBXBuildFile; fileRef = F62A706AAE45E348C3A5AF903610CBA3 /* GDTCOREvent.m */; }; + 34C107B2B498E0E9938E09AD436D7C20 /* FLTFirebaseMessagingPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 042074816A9B5A4CFF2C78D349B025D7 /* FLTFirebaseMessagingPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3638C218BDFEFC0C5484CC46569BDC0A /* FBLPromiseError.h in Headers */ = {isa = PBXBuildFile; fileRef = 12C8D8D85F32CD7F51280DC4963FA9A0 /* FBLPromiseError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3648AB694DB575E7E60E787F307CCF2D /* external_prequest_context.nanopb.h in Headers */ = {isa = PBXBuildFile; fileRef = 76C1F6C5D89AD24DC65E947B2C95504E /* external_prequest_context.nanopb.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 36751170F570E5241CC3A11282BD0341 /* FIRInstallationsErrorUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BB7063CC89B497ABCC22BCC4F19BA33 /* FIRInstallationsErrorUtil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 369CEECE1E95709A6F0740CAF57DD1B2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 37C4392EA3367F629410DAC46D87AA4A /* FirebaseMessaging.h in Headers */ = {isa = PBXBuildFile; fileRef = FE8579D48A79E1302D02298969B675E6 /* FirebaseMessaging.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 384C25A1E858BA823349DED7C0D94DCC /* FIRMessagingTokenManager.h in Headers */ = {isa = PBXBuildFile; fileRef = B5D20E78EE54D5C48ACEEDD6D89CEA6B /* FIRMessagingTokenManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 39BE841D795846D04215DAD70567FD93 /* HeartbeatsBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3B80750D3B364B9E166CCEB905EACF7 /* HeartbeatsBundle.swift */; }; + 3A706CF97C1EDA8D155C153CBD7121A6 /* FirebaseCoreInternal-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = BD75CD0508AD16FB45C1DD6842B85A77 /* FirebaseCoreInternal-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3A8F1ED7C5FF7C67F8FA7331837AD2BC /* GDTCORTransport.m in Sources */ = {isa = PBXBuildFile; fileRef = 5849D105D1C2834E540A65AE4ABE3C27 /* GDTCORTransport.m */; }; + 3B56BCBA48E035A238B77B3A225EC6AC /* GDTCORMetricsMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 03AE6CA1DBA607C545A3B791D8E2AF51 /* GDTCORMetricsMetadata.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3BDA20732B8B8C91D5013016EC32B7F5 /* GDTCORLifecycle.m in Sources */ = {isa = PBXBuildFile; fileRef = 03408913A9DA374E2493D330A980E8CC /* GDTCORLifecycle.m */; }; + 3C5C68623B8428B3C9A15638A80B7048 /* FBLPromise+Do.h in Headers */ = {isa = PBXBuildFile; fileRef = 727E3D670FEDA09567F4E93499135B7E /* FBLPromise+Do.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3D8C0E872A44DAB97F4DED0B0C32DD85 /* GDTCORStorageMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 16F47DBFD334E095900DAD45D515CFE7 /* GDTCORStorageMetadata.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 3F197F4F335A992690C00BE47D82C02E /* image_picker_ios-image_picker_ios_privacy in Resources */ = {isa = PBXBuildFile; fileRef = F0C7EFBFF01CFAAB52BA74E6CB40CE2C /* image_picker_ios-image_picker_ios_privacy */; }; + 3FEA9D3B888B3980702E68214ABADA5E /* external_privacy_context.nanopb.h in Headers */ = {isa = PBXBuildFile; fileRef = 466AEE01B8DBE6158A57A5141A851070 /* external_privacy_context.nanopb.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 40122AC85B3F1699C34744E7EDA39C8A /* GULNSData+zlib.h in Headers */ = {isa = PBXBuildFile; fileRef = 11E183230D34CC5B062D1D1049A366B6 /* GULNSData+zlib.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 404A66D9391BC3DD7D99828504E2BDF5 /* FIRMessagingTokenDeleteOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 310D0CD7273827DB2A2442B0149E6B9F /* FIRMessagingTokenDeleteOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4060F7F3B3994466089B08C6B344FE1B /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = BA0D0C8AF5CDA0A632B05B589AF94132 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 40754B9673CD03A705FFDD2734E0181A /* GDTCOREventDropReason.h in Headers */ = {isa = PBXBuildFile; fileRef = 78A647CF2AA2FEDD71CFDAB7BAA6CB01 /* GDTCOREventDropReason.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 438A690FC09DEE64359AB9D6F43A9FF4 /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D75104223B5E3CD6623422BDAF96AC4 /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 43C273D9572DDD1D6D6C662F919F6EF0 /* FLTImagePickerPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 36D1D380AC0FAE1558B1433A94C5939C /* FLTImagePickerPlugin.m */; }; + 4475763B57CBB56D34AD86A90F7498D5 /* FIRInstallationsStore.h in Headers */ = {isa = PBXBuildFile; fileRef = C2758FE22DBE0DF635FED68706680916 /* FIRInstallationsStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 447A1B593F685BA5674A44C3529BA5F2 /* FIRMessagingAuthKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 6F530CD2447E7BB4E8F245B5578D0E43 /* FIRMessagingAuthKeychain.m */; }; + 4509E9FE5C25CAA4EBD707934BA118E9 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B193AA1062E3BDA9FD9F681F8B33A4FB /* SystemConfiguration.framework */; }; + 45E57A7308BEAD7135BDBC9C8E4CFCC1 /* GDTCORTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = EAA203D51C6952F039B16DA1C6886296 /* GDTCORTransformer.m */; }; + 46571670CA3978B72CFB440F1228CE28 /* FBLPromise+Any.m in Sources */ = {isa = PBXBuildFile; fileRef = 511BBAD2CBB8A874EDF7B10BE3A86FB5 /* FBLPromise+Any.m */; }; + 472479E65845A87D981A2DEE1A85214D /* FIRMessagingPersistentSyncMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 905E98607B71266F977964D0380B9E8F /* FIRMessagingPersistentSyncMessage.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 493D43EF0F30335CA5779D3C6A065588 /* GDTCCTNanopbHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = B4671189B401A63804AEDF5B26C05A56 /* GDTCCTNanopbHelpers.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 49645BA65DD9ED60A716A4BCA65C7D49 /* GULNetworkURLSession.h in Headers */ = {isa = PBXBuildFile; fileRef = A15DFB7CC7A259F61E840FBA0257AABA /* GULNetworkURLSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 499E1800B68C714B4BB042E76C79FD66 /* FBLPromise+Delay.h in Headers */ = {isa = PBXBuildFile; fileRef = 00D77329FD54061BC8C4922FDEED6DF9 /* FBLPromise+Delay.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 49B88E5079B9DE42AB4A205DE9689897 /* FIRTimestamp.m in Sources */ = {isa = PBXBuildFile; fileRef = A28ECC14C6767FD5BF201D0A0585F63A /* FIRTimestamp.m */; }; + 4A94139A1289CE6297ABC9EAFD4E37BC /* FBLPromise+Await.h in Headers */ = {isa = PBXBuildFile; fileRef = 1878E7A7CE833995A4A9C1C8C5241E9F /* FBLPromise+Await.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4A974B87D9F1F4D0A5E6BA49601CBFD3 /* GDTCORFlatFileStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 551651297586403CD2F85A86DB9035D4 /* GDTCORFlatFileStorage.m */; }; + 4AC8EF6AF50C4384AD13CBE73D88A6E9 /* FIRInstallationsStoredItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 905B7DD657BA252E11F011C073B15B04 /* FIRInstallationsStoredItem.m */; }; + 4B190AD25B05A37B843797054274323E /* FBLPromise+Await.m in Sources */ = {isa = PBXBuildFile; fileRef = E29FF4FADCEBFFF58991819DA709FC0E /* FBLPromise+Await.m */; }; + 4B8187E18881BD774BD62686E71527FD /* GULMutableDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = CF3313E1A4AAD2C8C90168A130ED02C8 /* GULMutableDictionary.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C2A196BFB3D9BF5091632A60B885A13 /* FIRMessagingCheckinService.m in Sources */ = {isa = PBXBuildFile; fileRef = D6891EE2C0F69454EAE3D9E045FE3E1A /* FIRMessagingCheckinService.m */; }; + 4C8503BD05FBA66601D70F75C5082A3A /* FLTFirebaseMessagingPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 85297D57D31AF535B35107FA3534855A /* FLTFirebaseMessagingPlugin.m */; }; + 4D01D550A60A382E2944308B17150B8A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 619E6A45528E9255637879488FB26EDF /* Security.framework */; }; + 4D0780433AAE191F9E90337E264A5BD8 /* FIRMessagingTokenInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 445871E06F8049863AA09E1A3C325E3E /* FIRMessagingTokenInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 4DE6C1CFFCD152E770A1433419AD8E34 /* FIRInstallationsErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 74253B13C3296B401730EDF3CA4B17C1 /* FIRInstallationsErrors.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5019D7BE0BF1B9EC313A35D344349DFE /* flutter_local_notifications-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C76A440189B37018CF064EDA9E1007B9 /* flutter_local_notifications-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 51B0830A8ADC47C7AAB55DE15719C24A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 521E334B4F1329AEF35C863453F97A61 /* GULMutableDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 27BAF00DDE21BC901CDDFBC3E0E51ACB /* GULMutableDictionary.m */; }; + 5380AD627C4A430574E2DAD3F48AE8CC /* GULNetworkInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DEF857F1E2D5063DB5343E9A4F23F782 /* GULNetworkInfo.m */; }; + 5382B2C6ACF2D1F0F1711E71EFBCA736 /* GULNetworkInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = E18168F03FAF8DF950345F0DB50BFF92 /* GULNetworkInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 53DC0DA5AD85987E2AC963F80B89ADE7 /* FIRMessagingRmqManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4044D1DCE0CEDBE513D95BE2120704F9 /* FIRMessagingRmqManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 544280ADC86CD3645E5CA2495F18D452 /* GDTCOREventDataObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E173B14DD49E212545D1962FACBA586 /* GDTCOREventDataObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5479AE51693F1FB446F24BF9164E1419 /* GDTCOREndpoints.m in Sources */ = {isa = PBXBuildFile; fileRef = 597586DD100925D126C1C463DD575398 /* GDTCOREndpoints.m */; }; + 54A0EBF36971E9AC4B2E9011816EAE7F /* me.nanopb.h in Headers */ = {isa = PBXBuildFile; fileRef = BFD12588B0D0F7405A96DE2EA7396A34 /* me.nanopb.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5507D046C4E8455B1CBA2B9E80B627DA /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = 28BF0A4825F5A1C942E39489A06D32FF /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 56BE3DD72BA291E2CE00ED26A89B22A0 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = F9C0C8FF6D363C392626B70C996CB3B9 /* PrivacyInfo.xcprivacy */; }; + 56F29D607373445789154C630E5B4804 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 77574C1B35FAEFA284EB091A05D3777F /* PrivacyInfo.xcprivacy */; }; + 570310B6BB9D1B9AF8F2FE0398A244E2 /* Converters.m in Sources */ = {isa = PBXBuildFile; fileRef = 7C871D09740CE9D74171701136D65B99 /* Converters.m */; }; + 571BF6B1BB079A51BAFBB50CEE883CDA /* firebase_core-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = FDDD8D05205C5EE7B1CC69B162A85388 /* firebase_core-dummy.m */; }; + 586072F26AEE6AB93375562DC6D3D54A /* flutter_local_notifications-flutter_local_notifications_privacy in Resources */ = {isa = PBXBuildFile; fileRef = 513486288D9850EF657161C39358ED93 /* flutter_local_notifications-flutter_local_notifications_privacy */; }; + 58AD4E1DE1536902C995397B3D3C07F9 /* ActionEventSink.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A0F986347F2F1609FFC4F0D31B89630 /* ActionEventSink.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5A0BCFE4A98520629466933A5B7C2E3E /* GDTCORStorageEventSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = AC70B4B71CC9B390381A08D1429D6519 /* GDTCORStorageEventSelector.m */; }; + 5A5B4E3D28CC29759858A1512AC0E4D6 /* FIRInstallationsAuthTokenResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E3C1BE5EE5B7F7FE8218A78F05F362D /* FIRInstallationsAuthTokenResult.m */; }; + 5B38B7AD5DBC6762CD10D24DD1DBB933 /* GDTCCTUploader.m in Sources */ = {isa = PBXBuildFile; fileRef = FB2298AE8D3CC3C6ABB941D9CB1CBA09 /* GDTCCTUploader.m */; }; + 5C048357DBF589975F0094D11A25FF22 /* GULLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = C94ADD90B6B07B25ED550BCBE0EC2FB7 /* GULLogger.m */; }; + 5C0814943AFDA883ABE9FBA93D14BA07 /* GULLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AD9F2841591395962459F34DBA6F234 /* GULLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5D89D22A2709CE7E0BB89B03B7423628 /* FLTImagePickerPlugin_Test.h in Headers */ = {isa = PBXBuildFile; fileRef = DE501C91B85AD9DEF66B570B8F7C637B /* FLTImagePickerPlugin_Test.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5D8E977CE74A5307508857D10BAB5D3A /* FIRMessagingPubSub.m in Sources */ = {isa = PBXBuildFile; fileRef = DB8C49B0B5734A01DE048CA85F1069EE /* FIRMessagingPubSub.m */; }; + 5D916C6AF9F15F17055C7EA9D2DA73D8 /* FIRInteropEventNames.h in Headers */ = {isa = PBXBuildFile; fileRef = AC37499B722B10926F29985F2F626B61 /* FIRInteropEventNames.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5DA5FA0CB3AEE2A705640929B960522B /* GULSceneDelegateSwizzler_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 00830C5FFBF7D722EFA837254CFA5443 /* GULSceneDelegateSwizzler_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5DF7E819580A5C8044073197A5F2D21B /* FIRMessagingCheckinPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E99CA1C85E12A4F6F18BC1B1CBF6DAB /* FIRMessagingCheckinPreferences.m */; }; + 5E43A31995CAC5C41E291FD562CBB823 /* GDTCOREvent+GDTMetricsSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = CB9C404F2038079531D51B37205F6FA6 /* GDTCOREvent+GDTMetricsSupport.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 5F6E613D13BEEF2240EB8DC45C1E445F /* GDTCORProductData.m in Sources */ = {isa = PBXBuildFile; fileRef = 6308A2BF48F37BFCC2D67C547F4FFC31 /* GDTCORProductData.m */; }; + 60409D502F9E75B6BA3A7FC9F697E90C /* FIRHeartbeatLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 92999C4A70B803D6BB4A68BBA0D010FE /* FIRHeartbeatLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 613B690A8FE3B32CB1E35E082787469C /* FirebaseMessaging-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C334D9E95131AD50108A1C67E238989 /* FirebaseMessaging-dummy.m */; }; + 61CBAEADE7CDDF9E6DA1B468C2180BC1 /* GULLoggerCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = A17B442DCEB9C47D544B82CE2BFDB986 /* GULLoggerCodes.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 61CEBE947F27DD5E937A541ACFAC757E /* FIRInstallationsAPIService.m in Sources */ = {isa = PBXBuildFile; fileRef = A773AD7AC2BDC4D59F7D44F165DDE579 /* FIRInstallationsAPIService.m */; }; + 61D8E48C8F979AB44479550A3F40E672 /* FIRMessagingAuthKeychain.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A975AC758C10E2751E29D23149C3F8A /* FIRMessagingAuthKeychain.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 61F8891E091E3B6588E727E00DF94770 /* GULApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B0C1FD0FEE536657E3F3752322EE5F6 /* GULApplication.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 620C4EDB9C0FA59FAD2487301B386B82 /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E186EAC5470DCC01B54AD829AB67040 /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6323383CC1216A37D613D2608C001940 /* GDTCOREndpoints_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C201419AAEB1684E8D3357D88541EC5 /* GDTCOREndpoints_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 64BFAE5154200351C22E8E9DFCBA9519 /* FIRMessagingBackupExcludedPlist.h in Headers */ = {isa = PBXBuildFile; fileRef = CB675655530559C4E017C19318F89546 /* FIRMessagingBackupExcludedPlist.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 65A63308DC9D8A29BDC2566DC596C6BF /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = D655DF7B1D831EAF390B40308E74B9A4 /* PrivacyInfo.xcprivacy */; }; + 67F5C250302A291A794C510EAE9F863B /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = BE28E7364E1EFEE4FDCAE35B7550F06D /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 688490CB29644F8758A46C3C042F10CB /* FIRLoggerLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A4D3DB3BE1854CAF9DDABE31710F76C /* FIRLoggerLevel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 68C3CA9A7A088553FEDF725120477E7A /* FBLPromise+Retry.h in Headers */ = {isa = PBXBuildFile; fileRef = AF370489BA290D16F746A5FC144C8ED5 /* FBLPromise+Retry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 69D68A7BB88BDB2D9CA3B81401DB3F03 /* FIRComponentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 9896FC50EDA315757C5C60709679C840 /* FIRComponentType.m */; }; + 6A61C6D8BA03B9675E35694AA7BFFD00 /* FIRInstallationsAPIService.h in Headers */ = {isa = PBXBuildFile; fileRef = 72E84C770071D5A1531FAE5D14D85044 /* FIRInstallationsAPIService.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6A7F71291F8499AE4C5EA03A137948D9 /* FIRMessagingContextManagerService.h in Headers */ = {isa = PBXBuildFile; fileRef = 99065A5299D40284C591F13F428CCA1A /* FIRMessagingContextManagerService.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6AEDFFDC5780162138E8D7DE0698F649 /* GULLoggerLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = E73067A4812023AA71C5F5DE2A7A1549 /* GULLoggerLevel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6AFE45EDE1C2A889617FBC9734CF3029 /* RingBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DC9C663B1C9C9C7D6D450E2475A8960 /* RingBuffer.swift */; }; + 6B64390E7A14853A1204E075A2C12033 /* FIRMessagingInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = C0C2B36D833E272B8DEBDB540B84847A /* FIRMessagingInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6BADFD60DB75B4AF1D28EEA6B9A715E2 /* FIRMessagingTokenFetchOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CFEE5BEEE3B72CCB9414344913144FD /* FIRMessagingTokenFetchOperation.m */; }; + 6CF412935C7B90C13242614A2BC4261E /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 202227937DC19626B6162B984AC7B94B /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6E7EBB4FDEFFA4EEF8A7E57AF5B3A94F /* FIRApp.h in Headers */ = {isa = PBXBuildFile; fileRef = DB95A71164E10C96C48CA96BB0C2C871 /* FIRApp.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6EB1422201E4BC496256783843401BE9 /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = DD77AADE9BB2391A80E5DE0B44F9B2C7 /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 6ED29C09EB0823C0305A238D34A3CC3A /* FIRMessagingUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 10CFAF9FFD1CC96384F77C2950681BD4 /* FIRMessagingUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7014ED4D94FDBD4EDD1A3A5F29ACD9A7 /* GDTCORDirectorySizeTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = FF44DE1588F3EB44D30CE17C5922D3C3 /* GDTCORDirectorySizeTracker.m */; }; + 70760F93398A854AA6EC92A099F31B46 /* FBLPromise+Catch.m in Sources */ = {isa = PBXBuildFile; fileRef = D0E98CC50462D87B324B0B4B3C712778 /* FBLPromise+Catch.m */; }; + 71ABE471529580AFD720CA76711E5637 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 72D7E53AE93FAA6CF9BA9301EAC7E6B0 /* GULKeychainStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 91281858E7C5C6A953ACFCCB0F0E8759 /* GULKeychainStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 72FA74901D64A09C1F55D8DF8F52B176 /* GDTCORClock.h in Headers */ = {isa = PBXBuildFile; fileRef = 965331C3BB09EADB3C0D9516C974726B /* GDTCORClock.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7304F433C6347EB07D4142B01875E1F1 /* FIRMessagingAPNSInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = D7B7454BF5334670ECF3A33191A92E6C /* FIRMessagingAPNSInfo.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 73052EEFCB43DDEA0F82F1BF874C2F0E /* FIRMessagingContextManagerService.m in Sources */ = {isa = PBXBuildFile; fileRef = A2DC8CBC904B18E1936ED362DFA6CCB2 /* FIRMessagingContextManagerService.m */; }; + 7334A11AE4BEB61513F3BD568CF06A88 /* FIRMessagingSyncMessageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 936ACF7D90A1E6DAEEA75462AC5C9CCC /* FIRMessagingSyncMessageManager.m */; }; + 73D7985E3D8DA2E28A794979EDD4A1CB /* firebase_messaging-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F41AF401ECD6D59105FD217BFA68A35 /* firebase_messaging-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7457CF2B4D9B476CF1318103FE7830F2 /* FBLPromise+Testing.h in Headers */ = {isa = PBXBuildFile; fileRef = D3CBFEF9C55D8B8C77DC8B0311BBB9CE /* FBLPromise+Testing.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 74601E4C287C1065C3FC68008551691F /* FLTImagePickerPhotoAssetUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 252ED5705010489B5DDE7E1A4E37EF6E /* FLTImagePickerPhotoAssetUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 74605073686CA98767108F9F06638602 /* FIRMessagingAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 554D791CC412A5751A7D867492682EB9 /* FIRMessagingAnalytics.m */; }; + 750D0629F1E212AAEBC050275771A101 /* FBLPromise+Catch.h in Headers */ = {isa = PBXBuildFile; fileRef = B4BBEFB2C73F81F446CAC134CC2546E4 /* FBLPromise+Catch.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 751479F72F20B4861E68ABD6C985F2ED /* FIRMessagingConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 293CA810B9F9A627CF1B04985BBABB47 /* FIRMessagingConstants.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 75401C13C09D439800C91514D75E6F32 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3E39342DADE8E8CA6D1D925BCFF34D3C /* PrivacyInfo.xcprivacy */; }; + 7569264A765ABBC5B22A8D1FEA13BDD0 /* client_metrics.nanopb.h in Headers */ = {isa = PBXBuildFile; fileRef = 37264F9F27D2E16057E0E305FA5BCCCB /* client_metrics.nanopb.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 757E9C717CB2D5CA0CC6C6C5A1BE72E2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 761C30A7606CD20926EB925556278C83 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 18360B97FCA68E6CB98056F40009B735 /* PrivacyInfo.xcprivacy */; }; + 76BC09C29C6545ADE3608271AED0555B /* GoogleDataTransport-GoogleDataTransport_Privacy in Resources */ = {isa = PBXBuildFile; fileRef = F73AA961F4AEFF2B46B00AE435DF6BE3 /* GoogleDataTransport-GoogleDataTransport_Privacy */; }; + 7789C9324F79D1A739BF260EB7CB46B4 /* FBLPromise+Reduce.m in Sources */ = {isa = PBXBuildFile; fileRef = F7DFFA85CEF0CB6E8D3932BE99635EB6 /* FBLPromise+Reduce.m */; }; + 7851CFF4F7E792321144B8939167E84B /* FIRFirebaseUserAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = B6A067FEC2F7D21562E67BC5305FB65D /* FIRFirebaseUserAgent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 78EF505756B7A2E9E0BBB07E44B01248 /* FirebaseInstallations-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F58BAB8D1B897095AA76F603F58EBFD /* FirebaseInstallations-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7AC356CA025D0FEF92051678F0A18AFC /* GULAppEnvironmentUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 9EA4EC1164AD4A64AD408A4F74ECCD8B /* GULAppEnvironmentUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7AD65DC99362610A75A7E598EE6F5F33 /* GDTCORStorageEventSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = C9232E4B48A37102EEF6856FD90C953A /* GDTCORStorageEventSelector.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7ADD9AAFE22BFF4095EE499109CB8437 /* HeartbeatStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B48F659C78E38331874678992458C9B /* HeartbeatStorage.swift */; }; + 7B044EC231D1AF36640ACEC0023E63E8 /* FIRAnalyticsInterop.h in Headers */ = {isa = PBXBuildFile; fileRef = B06CC20D8B264C65422A00B2ECA1BC21 /* FIRAnalyticsInterop.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7B57B2EAB92952ABE214A49A637CCB82 /* GDTCORStorageSizeBytes.h in Headers */ = {isa = PBXBuildFile; fileRef = 424A93A150F9A2832A97CB7932DD2206 /* GDTCORStorageSizeBytes.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7BCC6BCDA6C263A4F83BE7EC5F205353 /* GDTCORMetrics+GDTCCTSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E0EE42F5223017E57B7B7D51B4CF1B4 /* GDTCORMetrics+GDTCCTSupport.m */; }; + 7C84F224579B7C273F8CF870C0D39DB9 /* FIRMessaging.m in Sources */ = {isa = PBXBuildFile; fileRef = B0ECBAFC8D346176B5C9430AAC93D937 /* FIRMessaging.m */; }; + 7CAA207102D0B204B3515750F1FD183B /* FIRMessagingAuthService.m in Sources */ = {isa = PBXBuildFile; fileRef = 94EBBDCB1362A8DB35DD72A83BCE41D5 /* FIRMessagingAuthService.m */; }; + 7CE8A75DC1A2B02DC6CFE116AF26CF83 /* FIRInstallationsItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 72C335FC7A27042501497C43922F7C50 /* FIRInstallationsItem.m */; }; + 7D307E2F6DA3935A528D0A23A6AFBC39 /* FirebaseCoreInternal-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = BA6F9C82EF49DC1505AB92789AC3C133 /* FirebaseCoreInternal-dummy.m */; }; + 7D3F85C5EA471C4551F2BD8A5009B52A /* GDTCORRegistrar_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 20AF87A6F49B0CEA59EC599CAEDFD41A /* GDTCORRegistrar_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 7DC81AF87DF6B545372C326DD683B2A4 /* GULSceneDelegateSwizzler.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6CB67271C76EA4A1308844DF06B701 /* GULSceneDelegateSwizzler.m */; }; + 7E621877E882B58DA8C15C788BDEA6C7 /* FirebaseCore-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = AC350D7331C62B3D5200AEB896375605 /* FirebaseCore-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7EBCEC932DA76198A8A28C15C5BA7154 /* FIRMessagingBackupExcludedPlist.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A7219D1FBE5F86E63958153ED0BF377 /* FIRMessagingBackupExcludedPlist.m */; }; + 7EE849AB55EC83CAC57754C57BD49F1B /* FLTFirebaseCorePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 28DDAFBBF7DC1837B7CB4B7401725191 /* FLTFirebaseCorePlugin.m */; }; + 7F3BE46873691FC48F3DF3A5D7E20126 /* PromisesObjC-FBLPromises_Privacy in Resources */ = {isa = PBXBuildFile; fileRef = 3F238BB22C5201CE689CAF2F766AED95 /* PromisesObjC-FBLPromises_Privacy */; }; + 7F79644506B07B238B26434BFB71DC75 /* FIRInstallations.h in Headers */ = {isa = PBXBuildFile; fileRef = D129CBF9B6659C2212C9D0E35165E9E3 /* FIRInstallations.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7F7997025ACDAAA3F86F2BE4545FF616 /* FIRInstallationsSingleOperationPromiseCache.m in Sources */ = {isa = PBXBuildFile; fileRef = DE16863F43AFC398785AB95591472899 /* FIRInstallationsSingleOperationPromiseCache.m */; }; + 7F7E8D1AEE11D58BC85ECD6A22048AB9 /* FIRAllocatedUnfairLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192ABD450F0C793BE1E734A176E27E26 /* FIRAllocatedUnfairLock.swift */; }; + 7FC7DADC5F23D90E94F19D4A71444D35 /* GDTCOREvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 37EF8E7FBD37768317274AA49494D9D7 /* GDTCOREvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80DFF208DB00F875CDF7A0871CFEB350 /* FirebaseInstallations.h in Headers */ = {isa = PBXBuildFile; fileRef = B646BBDFE3CEA2C26F26ADD034CD74D7 /* FirebaseInstallations.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 80FBAA97526FE8395E5745B3D5FD9BFA /* FIRMessagingDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = B2FEF990F569E7CC05C3AFED1D83F505 /* FIRMessagingDefines.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 816A43F3F940EA10A0E082CCE3C2784D /* FIRInstallationsHTTPError.h in Headers */ = {isa = PBXBuildFile; fileRef = 45CF41DF5693A36FD86A879BE06D0382 /* FIRInstallationsHTTPError.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8242A992829FEFFA2B3781F60F01EDC5 /* FIRAnalyticsConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 77E4E0DF346BC55702A7F97C83759EB7 /* FIRAnalyticsConfiguration.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8322F80818695D2EB9FAFD859BDF5331 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 842329951AFD13954BF159C504EED836 /* FIRComponentContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E86D9F1294ECE2C483FD6166223BD86 /* FIRComponentContainer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 848B7ED460EB7294EB77162995F21573 /* GDTCORClock.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B06B15554EC98005C5A2A6E4F9A4503 /* GDTCORClock.m */; }; + 84EAD76FFB65566ABC8E5903AB04AD0C /* FIRMessaging.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EC3E7E7FF9E0F3BF5F8FBF7A3BBF8DB /* FIRMessaging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 861377892C783984902287CE914076F8 /* external_privacy_context.nanopb.c in Sources */ = {isa = PBXBuildFile; fileRef = EFE38C75A3D217CDE7B18F9027CC4F8F /* external_privacy_context.nanopb.c */; }; + 874AB5A539D2DB1698AEAD9C71DFB7A7 /* FIRHeartbeatLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = F72DE1533AD7657E655356E31E3A5475 /* FIRHeartbeatLogger.m */; }; + 87586DAA45B3C853A2C09663187F2D56 /* FBLPromises.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EB64290BD8F25183F5F3B6E893CEC55 /* FBLPromises.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 87D87718A1AF94E63DD1CA91964D77BD /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AEB19A22ADF808E67367F1FB5B2A554 /* Storage.swift */; }; + 8824711A652C0411EE942C273CBB67DB /* FIRMessagingRemoteNotificationsProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8634CC3175F30B9D18008895B3D338AC /* FIRMessagingRemoteNotificationsProxy.m */; }; + 88F2E9580ADEE4C0B0FA25B82AFE5A9F /* FLTImagePickerImageUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E585DF573298497CD9445A79B513D8 /* FLTImagePickerImageUtil.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 891106CC3E66B8377A856E948607FC9C /* Heartbeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3047D3277103F27E21BE1D377E7FDA4 /* Heartbeat.swift */; }; + 897899B6759269070488C811DEB03E42 /* FIRMessagingTokenOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = F846B09E79FE5A1BE2108540AD98A6B0 /* FIRMessagingTokenOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 89DC4CFE4B7E8EEB8DD6933AA505B5BB /* GULNetworkMessageCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B07CCA749AC3691235E002653AA08F8 /* GULNetworkMessageCode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8A8D2FD34936A0F16995CABAE682BB69 /* FIRInstallationsBackoffController.m in Sources */ = {isa = PBXBuildFile; fileRef = AB598EB2A3C10C454BDF7F082CBF13E2 /* FIRInstallationsBackoffController.m */; }; + 8B8DCB001A1BDF664F9FD7D72AF7DAE3 /* FIRInstallationsErrorUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 71BEE6C7B8B888271C132B6206500966 /* FIRInstallationsErrorUtil.m */; }; + 8C5951DCC3226AA3B75DA1618216B15B /* GULNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AEEA5FC7114C4A84FE61786766702D8 /* GULNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8C68316D150BEDFBDCA3EFCD82BA49F5 /* FBLPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = F30DC71EBEC30BD542B7B8BAD2061FB1 /* FBLPromise.m */; }; + 8CCDD0321249EDC12E1878FCBA0ACFFC /* FIRMessagingTokenManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 90E4953F898CE5FB797B791B5411722B /* FIRMessagingTokenManager.m */; }; + 8CE5FBABF9724D94146D04CB23BB9780 /* GDTCCTURLSessionDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B2C2824B00198C89C8796514A539E69 /* GDTCCTURLSessionDataResponse.m */; }; + 8D1756998759D2A6BB960AA128C43129 /* nanopb-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 362A936B488A8BC83F35FE595CF39E60 /* nanopb-dummy.m */; }; + 8D8A6A88D28463F025D2C1A1545BFE99 /* FIRBundleUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 778F816687F31D011CF7B8600D15C99C /* FIRBundleUtil.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 8E066B23F49B2C880C85C0C7D75A071A /* FIRMessagingRmqManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EF1D0E06F214361137D35D1ED4EDE67 /* FIRMessagingRmqManager.m */; }; + 8EE9C67DDCF4CEE8B4DD33A27410CB22 /* FBLPromise+Wrap.h in Headers */ = {isa = PBXBuildFile; fileRef = 545009CB939B8FA897EBC1023E6DA94C /* FBLPromise+Wrap.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8FA9812545B4E33A5F1FCE78D2E7958E /* FLTFirebasePluginRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CACAF5FAD3F5001091F6F489F1D22AC /* FLTFirebasePluginRegistry.m */; }; + 9046613449009EB6FD58DB70A2EDB388 /* GULNetworkURLSession.m in Sources */ = {isa = PBXBuildFile; fileRef = B1DA64C7F3DEAD8DF2E9C85AFE1682E7 /* GULNetworkURLSession.m */; }; + 90FD76ED3DF523463354549A94AE5A06 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = BDFC14A8280221C515A9AFE2CE99D65B /* PrivacyInfo.xcprivacy */; }; + 9154C7945BC9328823005BD246F0F4BA /* FIRHeartbeatLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 08579575396173B32867108F604F151C /* FIRHeartbeatLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 91B90D51F260BB17A2EB29F9D3CE4C9E /* GoogleDataTransport-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B2387C526D96360EC27318C6A56C9530 /* GoogleDataTransport-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 91F80BDF63CDDEA0D3487E227DF9FF5B /* GDTCCTCompressionHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = E6D3C3E840BD79066822FDA834733864 /* GDTCCTCompressionHelper.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 91F8E57F87FED95335A57C5C724CEA07 /* PromisesObjC-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = EAA0F2B1CA18EB072F0B6672F56FF88C /* PromisesObjC-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9212CB7F5D22BEA7CAFC45714545EAD3 /* FIRComponentContainerInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 17FF3FD8C34AE6E60B8CAEBA719DEA21 /* FIRComponentContainerInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9270C74C406F0F608346E1E9B2F1535C /* FBLPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = E61CC707F35A1D8DFF986E0272AE2433 /* FBLPromise.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 931DB7CBE666982D4227D56B4D4B48F1 /* Converters.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BB83D91F5873A1F19C583E5BC73CB30 /* Converters.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 934946C3A556F12CA77F218649CDA697 /* FIRHeartbeatLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E3D3451D357BAC83914C1402577267F /* FIRHeartbeatLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9390D5972BB446FEC1BF3C7C7577FC3C /* GDTCORPlatform.m in Sources */ = {isa = PBXBuildFile; fileRef = D1E3607447AF036E85C9F1FF89B9B44E /* GDTCORPlatform.m */; }; + 9443B33116703E1817AA29E6DBCBEBC8 /* FIRConfigurationInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 656C5FB7BFF6EBCF232183D77650236F /* FIRConfigurationInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9478BF72A1EB6C4A947C9BD449A9BDBA /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FFE58E8153EEA5BBD4ADEA1792F2C39 /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 94E3463FFBB12FD10087C2F2B27C2DCD /* GULAppEnvironmentUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = ABA0FD5A71EE712584651CF55F1558E6 /* GULAppEnvironmentUtil.m */; }; + 957F9FD0D2CCE99FE2AD30DCAFFFFDE2 /* HeartbeatController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D7A14EF7C31BD4B3BC7F920226167FC /* HeartbeatController.swift */; }; + 962FF4B0914D6FECCDDBFBB68981225C /* GDTCCTUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CCF6202512922098E47F97220393B797 /* GDTCCTUploadOperation.m */; }; + 979FC74FB51633CCE1283ED32A496BEF /* GULReachabilityChecker+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 007C2472BFF7E2E14B4BF86E9A99997B /* GULReachabilityChecker+Internal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 98B873497D2CAB99A2FD1A57455067AE /* FIRMessagingCheckinStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 62E4E821E9D7CB7F725D9FF9D5C20D14 /* FIRMessagingCheckinStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 993E450FBC85DC9A0FB759FCFD8C1228 /* FIRInstallationsIIDTokenStore.m in Sources */ = {isa = PBXBuildFile; fileRef = B5BCF95BE69FDCDB288B6DD2D650398F /* FIRInstallationsIIDTokenStore.m */; }; + 99555EE2EA3C7BF7A43DFC46B9A8A53A /* FLTImagePickerMetaDataUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C7C11EC9AC85A39FC2DA6B03D4EA2A36 /* FLTImagePickerMetaDataUtil.m */; }; + 99B415F3939EB6DCE907A67B7178F172 /* FBLPromise+Async.m in Sources */ = {isa = PBXBuildFile; fileRef = 98DB6F70F9386301F5C36CD6C1299D73 /* FBLPromise+Async.m */; }; + 99B920AA9E73B9F4F7AE1C5AF4E69DC2 /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = BCAEF4B6CC33BA3FDC7A5EFC1081A150 /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9A3021D76E2B754738B65ADC8ED11181 /* GDTCORProductData.h in Headers */ = {isa = PBXBuildFile; fileRef = C586DD178A496B2B6864BA1A72B66182 /* GDTCORProductData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9B476394CDE8C9CF8D586BC575A19D32 /* pb_common.c in Sources */ = {isa = PBXBuildFile; fileRef = C020E1647C73F291B7B8232080B21AB5 /* pb_common.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc -fno-objc-arc -fno-objc-arc"; }; }; + 9B4E040836612266D4738000DCD0BB46 /* FIRMessagingCode.h in Headers */ = {isa = PBXBuildFile; fileRef = CF172E90C36C492AB298888A29405014 /* FIRMessagingCode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9BAC0155AEE5E5CF0003C7E9D94485E4 /* IsAppEncrypted.m in Sources */ = {isa = PBXBuildFile; fileRef = 26B9F97490E01D18CE5B3F13AF177F32 /* IsAppEncrypted.m */; }; + 9BD72C002DD685377F9BDF27B04C1DB6 /* FirebaseCore.h in Headers */ = {isa = PBXBuildFile; fileRef = DDAC6D191B54B707F402B200DA9BCCCF /* FirebaseCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9D47597085C9D008DCEE9015B4BCAB2D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + 9D703371D3CD787AE857A36BEDEE2AA7 /* FIRAnalyticsInteropListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 2253E23F9EAEA9EE71A0073BE86B5E16 /* FIRAnalyticsInteropListener.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9DD757379090CA5206E073BE4F5E3457 /* FIRInstallationsItem.h in Headers */ = {isa = PBXBuildFile; fileRef = D88ABCF86F232D838F567FDACBEB3FD3 /* FIRInstallationsItem.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9E3E5D5CDB90A05026A0C1992F892580 /* FIRInstallationsIIDStore.m in Sources */ = {isa = PBXBuildFile; fileRef = BEF18B32324D7103B23F4A901C785607 /* FIRInstallationsIIDStore.m */; }; + 9F60D4B837062AF7F00AF5870E7F08F9 /* cct.nanopb.h in Headers */ = {isa = PBXBuildFile; fileRef = 478136BE01D032987B5DF1FB1694472C /* cct.nanopb.h */; settings = {ATTRIBUTES = (Project, ); }; }; + 9F8F96C7051EF3BDBDC764B07A37E130 /* GDTCCTUploader.h in Headers */ = {isa = PBXBuildFile; fileRef = FE714E74EA2B7E26A7EDC9208B5BA435 /* GDTCCTUploader.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A0D07E5309FE40DD3B60BAEC0EE9702F /* Pods-Runner-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB131F3BC1D6D2C79680B59CF30EF6B /* Pods-Runner-dummy.m */; }; + A2BAEBCD6D1CAAEC9BCFAE3DC4819C14 /* GDTCORReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 850D0BDD3B07A173617227FD60A6231C /* GDTCORReachability.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A375B78D2AD54614602D49E5984931F4 /* messages.g.h in Headers */ = {isa = PBXBuildFile; fileRef = A502B0A40F92792DB2223688F14EF403 /* messages.g.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A5EAA55959CA9B9269CE684D82D5D79A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + A7592A0B36BDBDB6BE45BC03242B6D0D /* GULNSData+zlib.m in Sources */ = {isa = PBXBuildFile; fileRef = 07CF8CA0F334DC28EDEC31A017D7EB45 /* GULNSData+zlib.m */; }; + A7FBF0C702FEC57796B4C65CD6C0EF44 /* FIRMessagingTopicsCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 78F891CC63C36BCCAE34673B49F6DD9D /* FIRMessagingTopicsCommon.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A81C3DC8BE904F38FE3B39C6EA08D975 /* FirebaseCore-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D889199081E3C4524D59D648514AF05C /* FirebaseCore-dummy.m */; }; + A81C7E40BB1B12D81377B6E4943E0221 /* pb_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = 35414041146136B679F51AE9058D762F /* pb_encode.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc -fno-objc-arc"; }; }; + A838944C074357D7A1770D93C190BE46 /* FIRMessagingTokenFetchOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A4ADC3E70449C2D6DDAD177ABCBBB5F /* FIRMessagingTokenFetchOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A9455B109C5A7FB8C5E6D1AE2CFB6619 /* GULAppDelegateSwizzler.h in Headers */ = {isa = PBXBuildFile; fileRef = CCC1B87A6B369D883DC59DA1A876FB48 /* GULAppDelegateSwizzler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + A9711647DDFC9AAC568DD346AEDE5EBD /* FLTImagePickerImageUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B62F8176908F7C7B39EEA7BA2DF3C364 /* FLTImagePickerImageUtil.m */; }; + A9A43073BD51BE92865A43477940A3DA /* FIRMessagingKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 026994D707584EFF3A96BC447ACB8B4B /* FIRMessagingKeychain.m */; }; + A9B88AF4BF6260F8378F14F7506ECF89 /* GDTCORMetricsControllerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 481E832C9E13CB11704E3B80B0A61F8A /* GDTCORMetricsControllerProtocol.h */; settings = {ATTRIBUTES = (Project, ); }; }; + A9CB232876B453BA32933CA6C8932022 /* GDTCORReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B11C51237E5D56456A68EABAE481D91 /* GDTCORReachability.m */; }; + AB85D677B4693F37FB0289E4E1B43635 /* FIRMessagingTokenOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 066B519E3C90539086F1B9869EDBEB8A /* FIRMessagingTokenOperation.m */; }; + AC19EF1EBF438BA93F976199EC9C357B /* FBLPromise+All.h in Headers */ = {isa = PBXBuildFile; fileRef = C00EBC7A4974174FA9C5F1FBAA0E7308 /* FBLPromise+All.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AC1ADE881BF50CD7ABABA58EB080B629 /* FIRMessaging_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E8FEF536CAF0C03226B8AE23FE454C1 /* FIRMessaging_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ACC60E8A6204093A2A5B71497385FA7A /* GULAppDelegateSwizzler_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 71CDF1D9C3D3B35FD852BBFCF671E4B6 /* GULAppDelegateSwizzler_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + ACF4F3EE73B67DE6C5F84E2E126331C9 /* FirebaseMessaging.h in Headers */ = {isa = PBXBuildFile; fileRef = F8E3D4F092146A52F08248A9674D2F43 /* FirebaseMessaging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AE45411B1C58FC1EE4F48E723CB6CA14 /* GDTCORTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F24A03162482FB4B37596AA1170AA70 /* GDTCORTransformer.h */; settings = {ATTRIBUTES = (Project, ); }; }; + AF51A5733F3FD02A34D21274D980B91F /* GDTCCTNanopbHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = CE9BD927B75EFA6B4F63E3EF7F76C142 /* GDTCCTNanopbHelpers.m */; }; + AF5E6A1F926F94BFB5389039FD0B871C /* FirebaseInstallations-FirebaseInstallations_Privacy in Resources */ = {isa = PBXBuildFile; fileRef = 47C581450CDB4A6111CB97EEE0711A8C /* FirebaseInstallations-FirebaseInstallations_Privacy */; }; + AF98A71F63A1C7C96F6F5276B6C6E294 /* GULSceneDelegateSwizzler.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E25A842CB04F9B78FCBA6BF7F0C5CA /* GULSceneDelegateSwizzler.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B06F806AC06F78F2ADCE0159B115705F /* GDTCCTURLSessionDataResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = E8A3A7295F345E685EABEEFE068CCEE6 /* GDTCCTURLSessionDataResponse.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B19DBCE20486E645459623A4196D71E6 /* StorageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FE54C96AAFD6CECAA849DB5EA8452F1 /* StorageFactory.swift */; }; + B201F1BAE6C0AC68CE89122CC62192F3 /* FIRInstallationsLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = EDD9A3C2E72FAF155EF4D0403E6D9C3F /* FIRInstallationsLogger.m */; }; + B27501336005608A6DDC7115DB3EF829 /* FIRMessagingTokenInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = D7D8E0360DD7C3C4C53443E53FB2D047 /* FIRMessagingTokenInfo.m */; }; + B2990D3BC02A58DE4814C1ADF56C8C18 /* FBLPromise+Validate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AEADD8988B976B2FC825995D7A877AD /* FBLPromise+Validate.m */; }; + B2DF94E9A2C1E8636F07B902A18FBEDB /* FIRMessagingTokenStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 49A6AF4F7D6CCA75CB3493CBDFEAE6FD /* FIRMessagingTokenStore.m */; }; + B375EA128E6579366091BAA390BBDD34 /* Pods-RunnerTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8758A56177F57A2EE30894AA6F81B31A /* Pods-RunnerTests-dummy.m */; }; + B41C90799FC590798C47087B4581295C /* GDTCORFlatFileStorage+Promises.m in Sources */ = {isa = PBXBuildFile; fileRef = 18A6D34071FD583FE9C58FCE5CF837F8 /* GDTCORFlatFileStorage+Promises.m */; }; + B576B9C541C214280BF77606E022B14A /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 1597161DD3BB968D29E7B45448AA14CB /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B5FCC5B73EA83034C63477419EC69BE7 /* FIRMessagingAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = E5BF9CEDCABEB953A0F74A583477329D /* FIRMessagingAnalytics.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B6A5387072A26F8F7F51DA746CDE80E5 /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = E2BA5760A60FB76A5D0DA6B6592378C9 /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B731645D792DAE16A62DA50AC1245AC0 /* FIRLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = B2CC463A480A8EE4BB1C8BAB7EC6A811 /* FIRLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B74DE84140BDE18B1242DD0D620DFAC0 /* NSDictionary+FIRMessaging.h in Headers */ = {isa = PBXBuildFile; fileRef = E7E682D58A22915DE40E4BC2C50995BF /* NSDictionary+FIRMessaging.h */; settings = {ATTRIBUTES = (Project, ); }; }; + B7D28D2E9CEFF69C2A3516DD3734ABFA /* FIRMessagingCheckinStore.m in Sources */ = {isa = PBXBuildFile; fileRef = D4380D9849871F7D36C7E7CBA98E87EA /* FIRMessagingCheckinStore.m */; }; + B91C165E3CB57866BD2C36F4220CC467 /* FIRVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0344A89EE65F8D04A56A2B0A15E832 /* FIRVersion.m */; }; + BA84AE2395BC044BF80418CD6030E54B /* FIRMessagingTopicOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = F15F7CD527312C51FC5532AFF29B0CCC /* FIRMessagingTopicOperation.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BB694DA12F8A49C9D40D2C3FE43D9AC4 /* FIRInstallationsItem+RegisterInstallationAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = D95A493523FB2DFA4265B765F8BFA06E /* FIRInstallationsItem+RegisterInstallationAPI.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BD07A6D1833C206CCDF7F92845225991 /* FIRAppInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D4A46F116BFFAE9C3ECDC7EF00A6E6A /* FIRAppInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BDA978C9EAD726C618B126E9839199E3 /* GDTCORUploader.h in Headers */ = {isa = PBXBuildFile; fileRef = B60A2D97A08A79D950561A5CC0A9494B /* GDTCORUploader.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BDAFAC271C65BB7F19F10CDB115403DE /* FBLPromise+Race.h in Headers */ = {isa = PBXBuildFile; fileRef = FF09DBF131ED32352049DD973E63FA75 /* FBLPromise+Race.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BDD0240723D11CC1C424FCAE1CE8D881 /* FIRInstallationsItem+RegisterInstallationAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B5F7F6DD4538CB6DE8986871A2965EA /* FIRInstallationsItem+RegisterInstallationAPI.m */; }; + BEAC8F429499100F442589D4AACA6D50 /* FIRMessagingAuthService.h in Headers */ = {isa = PBXBuildFile; fileRef = 65E68F8C9B22A7FF7F1B3F3948BBB254 /* FIRMessagingAuthService.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BEC9964729B6B2C2017EB6BF664DDBCC /* FIRTimestampInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 06FEAB1B0AE18AA2E6311F4327D6F2D0 /* FIRTimestampInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + BFD528F6A70B42CAE79FBD2B41427A1A /* FIRInstallations.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A03990672E97F082CE5D42C4DA88AE3 /* FIRInstallations.m */; }; + C0B9117B0CE538886275E248E19346B7 /* firebase_core-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = E8613A3C37426EBD5058C1EACD29B4D3 /* firebase_core-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C0DA634B37A4964EC148F3CFBCF55AE7 /* FirebaseMessaging-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 50F613F74218D55303469A0613633B7E /* FirebaseMessaging-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C11F71971DA2059D684AD5816443A802 /* NSError+FIRMessaging.h in Headers */ = {isa = PBXBuildFile; fileRef = C801FDA12C657DA4D652A2352A705D04 /* NSError+FIRMessaging.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C141A77C29333EF7BCE884F4B2C33304 /* FIRFirebaseUserAgent.m in Sources */ = {isa = PBXBuildFile; fileRef = 94449CA47C2641CC67085CB779439A41 /* FIRFirebaseUserAgent.m */; }; + C2447EC9582F167F7131165BF09E9246 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = D703F68C62134D846E9AFE6B0B29AD69 /* PrivacyInfo.xcprivacy */; }; + C2F85245D2701CC4F30C979C51259C31 /* FBLPromise+Recover.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ECD27E226247CC6BEE22DBFBF905F60 /* FBLPromise+Recover.m */; }; + C3F511EA3E1AF5A8CDD921D6C96F35BF /* GDTCORLifecycle.h in Headers */ = {isa = PBXBuildFile; fileRef = 600AC3F60588265C01A074792402E2BC /* GDTCORLifecycle.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C455A7E8B9BC54B1EE93D4F5A0D77F38 /* GULNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D28E6CD2A57E7F53F190E76FDADBD54 /* GULNetwork.m */; }; + C47204FDE9B53CBCE9613B73579400F4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + C4BF4DA0B89971CDD9E7027A9C2B4467 /* WeakContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE20B56087FB4F4CA7131763C35DDC67 /* WeakContainer.swift */; }; + C4D47F5765D8F5C5CD1D4F86E89DA8AF /* FIRComponentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F3048B48A2FE22ED08DA327695BC2D9 /* FIRComponentType.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C56E771DC3DBD1A7F38FFB5073511D74 /* GoogleUtilities-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4790FE35CCE78F042C4976E095FC08E7 /* GoogleUtilities-dummy.m */; }; + C6953122A45255AE149D469609596AD6 /* flutter_local_notifications-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = ECE416D5B8F4153F022C16A087BF2E26 /* flutter_local_notifications-dummy.m */; }; + C741E544E6FEE0679FB092AD4568DC76 /* GDTCORFlatFileStorage+Promises.h in Headers */ = {isa = PBXBuildFile; fileRef = 601B9BE94C9A2AEB8E3FAF0E5B8480B1 /* GDTCORFlatFileStorage+Promises.h */; settings = {ATTRIBUTES = (Project, ); }; }; + C8037AF1C8933CBBAF84A662DEC885FE /* FIRApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A10DCC568131817410FB1AEF9178715 /* FIRApp.m */; }; + C8226DCEB4533579AF653E4C536CD2F7 /* GDTCOREvent+GDTMetricsSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 5973651CFCFFEC1F7B81A2D131B46CCA /* GDTCOREvent+GDTMetricsSupport.m */; }; + C8B38E4BCD0E9883E40D871881C2569C /* GDTCORLogSourceMetrics.m in Sources */ = {isa = PBXBuildFile; fileRef = C23D989186917D690D6E35EAEE950DAC /* GDTCORLogSourceMetrics.m */; }; + C900955D2D8838EC4DE9E2782BAC873B /* GDTCORAssert.m in Sources */ = {isa = PBXBuildFile; fileRef = 317558E06CC941F96264F2804571871D /* GDTCORAssert.m */; }; + C9926BF1ECE48D4F5608B85D23172F58 /* pb_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = 499A09DE888645CBC456DD808F91F0C0 /* pb_decode.c */; settings = {COMPILER_FLAGS = "-fno-objc-arc -fno-objc-arc"; }; }; + C9A3CCA63CADCE3F2527142CB886B3F8 /* GULUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = AAD3BC28C09DA52886D6B8681F7F5FBD /* GULUserDefaults.m */; }; + C9E3A70F5A9E32DBF7A2CB44A76DE9C1 /* compliance.nanopb.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CB3716BCB4F04E1DFCEA30BECF2BC60 /* compliance.nanopb.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CA90913666ED773FD6C6B148EBF1C9B8 /* GDTCORMetricsController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C31E883DF59327EFA2F3C02699CCA15 /* GDTCORMetricsController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CAACD4CA74C961236A37792C8A4BFBC2 /* FBLPromise+Do.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D78F29C73286A17F514D3070039F716 /* FBLPromise+Do.m */; }; + CAB72AF2BCBA56C4E6D5BDA273941399 /* GDTCORUploadCoordinator.h in Headers */ = {isa = PBXBuildFile; fileRef = BDCA34BFBDAE2A8CD8404ECE64D14D00 /* GDTCORUploadCoordinator.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CAE8B5B491E97FAE423D537B9D3AF329 /* FLTImagePickerPhotoAssetUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = DF2202BFB27E7E8B535986D8ACA2A11A /* FLTImagePickerPhotoAssetUtil.m */; }; + CB37C4826B004B6D04CB0DA533B257E3 /* GDTCORTransport_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = AA3D5E76E8D7DF4C02A1061D71983979 /* GDTCORTransport_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CC2EB95352E40B738326F72DD72EC151 /* firebase_messaging-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C05080F60D04271D75AD4FB3A338D84 /* firebase_messaging-dummy.m */; }; + CDE19547447CB737FC76C275C88BB7D6 /* GDTCORRegistrar.h in Headers */ = {isa = PBXBuildFile; fileRef = DF1F5F4906A736BC65D87CBEDAFE1894 /* GDTCORRegistrar.h */; settings = {ATTRIBUTES = (Project, ); }; }; + CEBD84922D2CCEF26C272418EC3EB3A6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + D0B5A819F9DF9C4D282A62A3E745EA32 /* FLTFirebasePluginRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = B04FDD8DDB07A0183A4E103A9D101302 /* FLTFirebasePluginRegistry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D0E43C5A3C366E325CBC48A2A3DCB827 /* FIROptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AA41421D42B0E9F83F0034ED34A520D /* FIROptions.m */; }; + D0F633AE6ECFB289BD02C8870994B87F /* GDTCORMetricsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F498270700E31C3494045615D8186A7 /* GDTCORMetricsController.m */; }; + D122EC7B51B97CE4665506DDA02C4257 /* FlutterEngineManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 45E5FA6F52D158F4FB3C4CBC66E449BC /* FlutterEngineManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D1C210F4F9DABF8892209A992A62D323 /* FBLPromise+Recover.h in Headers */ = {isa = PBXBuildFile; fileRef = 9EFF6746B2289C5FD36C9BC6742995F1 /* FBLPromise+Recover.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D1CA3597FB8047DFC7BCE711E7E91C63 /* GDTCORReachability_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 936F09821C7EE0C3CD7F82890DB3A2CD /* GDTCORReachability_Private.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D22276343FBA6C2562BE9AB3A5620041 /* FIRMessagingPubSub.h in Headers */ = {isa = PBXBuildFile; fileRef = BF34DE84DA4E4042C6880D4E5D0F35DC /* FIRMessagingPubSub.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D256D5171D913FE559EFA69FE4F385E4 /* FBLPromise+Then.m in Sources */ = {isa = PBXBuildFile; fileRef = 919FA6048D25DD3D403B87F067045348 /* FBLPromise+Then.m */; }; + D258FE513187AFE11388A56510D83AA7 /* GULKeychainUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 9121522B9B5A12545EBB589A83BD8F78 /* GULKeychainUtils.m */; }; + D25A30EC156A63A0BAA6C9D733BD2834 /* pb_common.h in Headers */ = {isa = PBXBuildFile; fileRef = B94BEE8D0E30393C9D4D6CBA57B8D263 /* pb_common.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D2C4E19D3184A18BA88FEB3DB9C25680 /* FLTFirebasePlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 79F077D532D1FC3E22DAC2178F2B93DF /* FLTFirebasePlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D30890C71943B3623755D4EC78F004CF /* GDTCORDirectorySizeTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = DA922CF0D0D079AC32082A5020A72150 /* GDTCORDirectorySizeTracker.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D387109882D2DF15EF677B5F7C9ED35D /* GDTCORStorageMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 381BA5E61A58F61BC2D25A380396C078 /* GDTCORStorageMetadata.m */; }; + D3CA68DFBD6760ECAB9662C2E4459EDA /* FirebaseInstallations-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 93CE9B2E15F0CFDDF3305716F26E8467 /* FirebaseInstallations-dummy.m */; }; + D3CA8D9FF4CB7EB16FDBF2BCCF89F979 /* FIRMessagingTopicOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C150D02EC9C5D375CA88FE501C84AC6D /* FIRMessagingTopicOperation.m */; }; + D5644BFA4BACB8E7C3E53FC0C6323E05 /* messages.g.h in Headers */ = {isa = PBXBuildFile; fileRef = 20CFA7FEC659CB53FA77B7DB18BB054C /* messages.g.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D59044973DC2A2F2C10E17DC826A1E85 /* FIRComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = B543F786F7AC662A9B3B4A59604BE673 /* FIRComponent.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D68DEFDF612A8135C271A428204DAC30 /* GDTCORTargets.h in Headers */ = {isa = PBXBuildFile; fileRef = B512FE666020CE015DAEDEB8CBABCAAB /* GDTCORTargets.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D6E56A02CA701D7DF1A692667B5163BD /* FIRMessagingLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = FB3E0B1F27EBFF6B4823EDA87587A8A8 /* FIRMessagingLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D87051785D72FCC6749E51472EBADF70 /* GDTCORPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = B371BCA4519038B554B5CE8AE4330B6C /* GDTCORPlatform.h */; settings = {ATTRIBUTES = (Project, ); }; }; + D970FF5E30342365D35A8EA77860069A /* FBLPromise+Async.h in Headers */ = {isa = PBXBuildFile; fileRef = 27C6F7D9AFD28A5F991FCC1ADF5594EF /* FBLPromise+Async.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA3B145B67A281C7D6DE12EDCA55620A /* FIRMessagingConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 403BA008E85450C1AAAEF7B741D81AA3 /* FIRMessagingConstants.m */; }; + DB6FA7F9C81D6A05761CEF5A9BC11E56 /* FLTPHPickerSaveImageToPathOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 857B278AF026E36C0BD658D6411E29FA /* FLTPHPickerSaveImageToPathOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DBD066F5DECE546710B8F46F407C322E /* GULReachabilityChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 28C991FA4F9E8DB769F528C9B6AB0F23 /* GULReachabilityChecker.m */; }; + DBD16C9FE34200CFBE4750E049F73595 /* GULReachabilityMessageCode.h in Headers */ = {isa = PBXBuildFile; fileRef = D436772E65625479E300E56250E3F274 /* GULReachabilityMessageCode.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DC7EA112BA576E2F6389F0D41073BDB6 /* FIRMessagingExtensionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A3F9414556C6E7943F21A35632157C2 /* FIRMessagingExtensionHelper.m */; }; + DCC14056D1B279416B8245E7D21BB970 /* GULReachabilityChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F7961550B6D6E457B016978E275F440 /* GULReachabilityChecker.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DD344F36D2BB7A4AFEB42DDB87360542 /* FIRConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D10767A89F4C2717508593913943165 /* FIRConfiguration.m */; }; + DFE6EBE75E9A7639156E22E266C5E32D /* FIROptionsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AC7C482E6D07C1D873A78BAD801C86A /* FIROptionsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + DFF57F85C04952479C8BA9ABA0FD54DF /* FLTPHPickerSaveImageToPathOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F1B1A3CB7EF62D9C362CFF5A14098E7 /* FLTPHPickerSaveImageToPathOperation.m */; }; + E05B14440006C13142B1D6600528233E /* FIRInstallationsStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 073788DD1F3BA0D6A1E4F105FEE47626 /* FIRInstallationsStore.m */; }; + E0C844B78D8CD5CA4A344FAE18FE2D47 /* NSError+FIRMessaging.m in Sources */ = {isa = PBXBuildFile; fileRef = 8664F6601EE686C6DBC6F3C7E5078272 /* NSError+FIRMessaging.m */; }; + E13FBC9788A0862DC162AC67FD55AFB9 /* FIRInstallationsAuthTokenResultInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 33FC9CF96CA23D0419B6024FA5B7B9CE /* FIRInstallationsAuthTokenResultInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E15444EFB3802537E7C30B3D687BD68C /* FIRTimestamp.h in Headers */ = {isa = PBXBuildFile; fileRef = E22BD45F6FB773C33141B618168C4A8F /* FIRTimestamp.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E1E1270BD9A3CB344C4B31B44C3E502D /* dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FE570758D07A5EE6A12AF7E45FFC15B /* dummy.m */; }; + E32449EDBFAA292BE64E912E48DA0A3D /* GDTCCTCompressionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F67BA8239D8A9976F471301DA705FC65 /* GDTCCTCompressionHelper.m */; }; + E37D698A247D3F60BFCF14A6E5ACAFD0 /* FIROptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 739528119751A21100A633EC4AFD6198 /* FIROptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E396037E322A716F65D76406D805D13F /* GDTCORMetrics.m in Sources */ = {isa = PBXBuildFile; fileRef = E9EDD23A28B53B116FCC2B249E7ABB62 /* GDTCORMetrics.m */; }; + E41A6A8F763C5FAD662CA8BE33577E70 /* GULNetworkConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CFB397A9898BDBB88BBCFFC0548617D /* GULNetworkConstants.m */; }; + E4E105868F5E9B636CDCDC5296FEB98A /* FIRMessagingPendingTopicsList.h in Headers */ = {isa = PBXBuildFile; fileRef = 067B1A306E1D71331FFB0C7B4842C96D /* FIRMessagingPendingTopicsList.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E532F0A39000EBA4FEC76E115C32030E /* GoogleUtilities-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 5215464BB80A41FB505019E963220AE0 /* GoogleUtilities-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E6171E5D20D270CA833B5176AD614B26 /* HeartbeatLoggingTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9608F18BDF2DDE520187B9B5D6E6D2A4 /* HeartbeatLoggingTestUtils.swift */; }; + E63CDE7BF4ABF68C58E0110698286A53 /* GDTCORMetrics.h in Headers */ = {isa = PBXBuildFile; fileRef = A6B1DDCFBD3CF418AC193FE5F753B7A0 /* GDTCORMetrics.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E63FE480CF9EFC9E296EF362F05EE98D /* FBLPromise+Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B6B934456F9D9272269319603A5F9C3 /* FBLPromise+Testing.m */; }; + E68510190917732CC725615AA847A331 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B193AA1062E3BDA9FD9F681F8B33A4FB /* SystemConfiguration.framework */; }; + E6C95844ACBB8AA73161C5E7AA4D689E /* GDTCORConsoleLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = A5F3FE81EB27FB2162597E4C38CF7A2B /* GDTCORConsoleLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E700869F7CD4BC498C4C22937E0848D0 /* GULNetworkConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 12CE4326B05B13F9BDF9FDD0DEC5EEF6 /* GULNetworkConstants.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E735396838D12795BB9F1B0F8C0E4B25 /* FIRLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = B813F4D2F842FDC08628BEC65FF4ED40 /* FIRLibrary.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E75A4388F9E48E29720A7CAD7EE87ACA /* GDTCORUploadCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = D2DBBD201333C23533BD538E84DA3E09 /* GDTCORUploadCoordinator.m */; }; + E78EB8DAE38E6379F08424C3F42C53E7 /* FIRInstallationsIIDStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C6B8ABF0A5FBF262DEA5F49AEAFD28 /* FIRInstallationsIIDStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + E7E9ECA6ADB3393B08C2B762984F5FAF /* FIRBundleUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 194D87AC7FA8ACD1ADC48E9094B1DD8F /* FIRBundleUtil.m */; }; + E95E65AE1524C8F63325E910CEFEFCFB /* FBLPromise+Retry.m in Sources */ = {isa = PBXBuildFile; fileRef = D8080290C8FF379AAFE127072282B83E /* FBLPromise+Retry.m */; }; + E9F2141C25A0A76A2F931E9E38F04F09 /* client_metrics.nanopb.c in Sources */ = {isa = PBXBuildFile; fileRef = 425AB8995EF76A7A41250B2B39B918A9 /* client_metrics.nanopb.c */; }; + EB2DC96CDCF638AB89007D2DB0F3119A /* Pods-RunnerTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 2CB04EB554430E41E5A19EDE6D62C9F2 /* Pods-RunnerTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EB4605DE8A17BB46F9DD0032A62CE6A2 /* FLTFirebasePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E7BEB959A6F7D8070CB1E6B209A8C76 /* FLTFirebasePlugin.m */; }; + EC1AF0772124F73D9CC857F2B4C3FA58 /* FIRMessagingPersistentSyncMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A65DC251AC8459E96CF62A9A28D7FA9 /* FIRMessagingPersistentSyncMessage.m */; }; + EE040CAA65AB77AF561A8F906609FDDD /* cct.nanopb.c in Sources */ = {isa = PBXBuildFile; fileRef = C91F16BB997A1432E3E845FB58E5419A /* cct.nanopb.c */; }; + EE135FF14BFA3B4F66801408C125B41F /* FBLPromiseError.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D5E75344C12FBE305143C4EE160EF82 /* FBLPromiseError.m */; }; + EE6FD1E0FC78308189FCECE05EC4D332 /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = AADC5B5B4544956F7DD190C8434971BB /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EEB114A1198D178FB1C6C8BC5B2DB442 /* GDTCORAssert.h in Headers */ = {isa = PBXBuildFile; fileRef = B49E2EBD1B89DC348FB58AD368278DA1 /* GDTCORAssert.h */; settings = {ATTRIBUTES = (Project, ); }; }; + EEECBF4E927482BAF8199FD81F79C1BD /* GULKeychainUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 081DB68F10FD71B7A8E743FC93039FCC /* GULKeychainUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EF4F910815C5A3FDB124F1468E180A7C /* FIRInstallationsIDController.m in Sources */ = {isa = PBXBuildFile; fileRef = 044C8F52069D02324E0E1334EC92CBC8 /* FIRInstallationsIDController.m */; }; + F07AD4215638DC0BB6294D26F724455F /* FIRInstallationsIIDTokenStore.h in Headers */ = {isa = PBXBuildFile; fileRef = A06777B4DB78BB55C72E6640E8BA41DE /* FIRInstallationsIIDTokenStore.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F084F5844715E1103AF57EB0EBF82AC2 /* FBLPromise+Always.h in Headers */ = {isa = PBXBuildFile; fileRef = 5551C50E78F600068DECA3941CFDC868 /* FBLPromise+Always.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F09896DD6EA71BEFBF61A0CF86A9B0E2 /* external_prequest_context.nanopb.c in Sources */ = {isa = PBXBuildFile; fileRef = 0644B8CAE7E33A4B091322FB566D2BBA /* external_prequest_context.nanopb.c */; }; + F0CD29D00D4DE451539A6D01D2F2E7F9 /* nanopb-nanopb_Privacy in Resources */ = {isa = PBXBuildFile; fileRef = 3227F3FC45681D7CEE5D1355A532398A /* nanopb-nanopb_Privacy */; }; + F117AE9AFD9CA0918457364B5224BA7D /* FIRInstallationsLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 4213C92093942202692742B0F6E8A372 /* FIRInstallationsLogger.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F11EF322E540186F60A2785DC6A6FEF6 /* HeartbeatsPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35B82E32D28724379DF7521589FEBFE2 /* HeartbeatsPayload.swift */; }; + F16D33178A8A34F24C722F1B94AFA432 /* GDTCORRegistrar.m in Sources */ = {isa = PBXBuildFile; fileRef = 053E79D285ED081E8D3A467E9057432F /* GDTCORRegistrar.m */; }; + F2147820B509266A415E62BA877B9918 /* FIRMessaging+ExtensionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = CD22F9E01ED5FA1020DE6283E509A9CE /* FIRMessaging+ExtensionHelper.m */; }; + F2852D062145348D0706025C88866693 /* GDTCOREndpoints.h in Headers */ = {isa = PBXBuildFile; fileRef = FA8650F57B8928F747DF6C8DAAADBA7A /* GDTCOREndpoints.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F321B3889222BD0F720696D092E95968 /* _ObjC_HeartbeatsPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EA71D30421D81D90A45FD77D6FB2976 /* _ObjC_HeartbeatsPayload.swift */; }; + F354E23D48F280BED18EE1E7109BC0EF /* FIRInstallationsStoredAuthToken.h in Headers */ = {isa = PBXBuildFile; fileRef = DF76ABCF8FC780F5A09634D08E40A690 /* FIRInstallationsStoredAuthToken.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F39765586A881C4E7171A53A4BA8BD47 /* FirebaseInstallationsInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = CCFCE0BE21B0FC0352C603586D9642FD /* FirebaseInstallationsInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F5D07E81A16752CBA1D145854D561752 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B193AA1062E3BDA9FD9F681F8B33A4FB /* SystemConfiguration.framework */; }; + F65AC7A62611BD5E26E1BAC990F4AD96 /* NSDictionary+FIRMessaging.m in Sources */ = {isa = PBXBuildFile; fileRef = CB5EA4244DC66422A84FB2F4C7803614 /* NSDictionary+FIRMessaging.m */; }; + F6F533DB29E1D3E34B55A0052FEDE521 /* FIRMessagingSyncMessageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = A68052862F5BAE7158CA697BF80807F4 /* FIRMessagingSyncMessageManager.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F8D3DF5F1BBE22C17BEA8A3245F85592 /* FIRAnalyticsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = AAD8085D8AFEEB3417EF649424648779 /* FIRAnalyticsConfiguration.m */; }; + F8FF1998A797C15F68434F157B9B5D1C /* FIRInstallationsBackoffController.h in Headers */ = {isa = PBXBuildFile; fileRef = 55086D223D9FF08447F190FF4EC56B2B /* FIRInstallationsBackoffController.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F91B5A5C597C72F11B80B16E41167055 /* FirebaseMessaging-FirebaseMessaging_Privacy in Resources */ = {isa = PBXBuildFile; fileRef = B0B6501341FD6783C6874C54AB31A9CF /* FirebaseMessaging-FirebaseMessaging_Privacy */; }; + F934DFC104F5662200123E6AA5E2A207 /* FIRMessagingRemoteNotificationsProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8DA801B2D8F4EC374CCF24A7CAA24A5D /* FIRMessagingRemoteNotificationsProxy.h */; settings = {ATTRIBUTES = (Project, ); }; }; + F98570EE85F37E3B97540660F9CE9061 /* FBLPromise+Any.h in Headers */ = {isa = PBXBuildFile; fileRef = 9867C191C8BCE953F2C1239417D48C59 /* FBLPromise+Any.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F9996DFB48D26874343B0BADAC5AE7F2 /* GULKeychainStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 942ACCA965CADB64D429066DA899D930 /* GULKeychainStorage.m */; }; + F9A9D2DDE5E2B67AC92E8946EC84006C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 619E6A45528E9255637879488FB26EDF /* Security.framework */; }; + FBA062E88B0EB24276EC596147DC883A /* GoogleDataTransport-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = BB67577D73012DFE877DCAA6A5A0CFBD /* GoogleDataTransport-dummy.m */; }; + FC08C647E5AD9FB89636C914A2520EC6 /* FirebaseCoreInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 886C3E05AA567BEB1219A0D5E1FD0E26 /* FirebaseCoreInternal.h */; settings = {ATTRIBUTES = (Project, ); }; }; + FCC88198892649F6D51E02FD2E2918D5 /* FLTFirebaseCorePlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 307006891C36268C3ABD5CA9F826AFC0 /* FLTFirebaseCorePlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FE30981B92CAAFA17348779A73DEF09D /* GDTCOREvent+GDTCCTSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = BD2F62558CF728467E423DE871BCE8A8 /* GDTCOREvent+GDTCCTSupport.m */; }; + FF0F13E0126A7A0C66E7F2D1B76D38E1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 411C572D658946450319E3438E61FBCC /* Foundation.framework */; }; + FF7B53EF3C76928B265DE076684235AD /* FBLPromise+Delay.m in Sources */ = {isa = PBXBuildFile; fileRef = CE08696E0972B7E5F2A377E2874A05FE /* FBLPromise+Delay.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 0192270253ECFED942C0F4F590FFEC16 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + 044E87AB58E48E9C05DF65978B3D8571 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 0762CC5A81893BA8BE745719D8AB885B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5895B432FE4D2F6826C8FF25A09DB6D2; + remoteInfo = FirebaseMessaging; + }; + 0DBF59B522E2B64B7F8788C45573BAED /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1BFBEDBF7E03729D43C96530EE190825; + remoteInfo = "PromisesObjC-FBLPromises_Privacy"; + }; + 13E7F305BB38CDE8DA75F8F9F7B578A1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DD0D41A9315A48004E57F4F0E54095F1; + remoteInfo = "GoogleDataTransport-GoogleDataTransport_Privacy"; + }; + 1DDEC92A71C75B2B0423E0F810B08991 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C0371EE948D0357B8EE0E34ABB44BF0; + remoteInfo = GoogleDataTransport; + }; + 219D323EE3BDBB104346CD612616BCF3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 25E9E9A17BC3F670357D7385C521E48E; + remoteInfo = FirebaseCoreInternal; + }; + 33F5930894B3A36E1F65F7AA35711543 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + 36BA05CA1EE73578C6222FF960F63B78 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 072CEA044D2EF26F03496D5996BBF59F; + remoteInfo = Firebase; + }; + 3A64087E666ACD9DFF57B700EACED484 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1EFDDC32A34D56D411E640A81DCD9E73; + remoteInfo = Flutter; + }; + 3B641A062009906C2948E0F10A1F653B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1EFDDC32A34D56D411E640A81DCD9E73; + remoteInfo = Flutter; + }; + 3EC43A0AA2CFD9AFF53ECAEF03306581 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 21FB29F43C8A2A81ABFE8C478370070E; + remoteInfo = "FirebaseMessaging-FirebaseMessaging_Privacy"; + }; + 44444840A079E028F5B565C0B80F382C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2949783F7EDB27AD4666B5427B63DC79; + remoteInfo = "FirebaseCoreInternal-FirebaseCoreInternal_Privacy"; + }; + 4FCD2E72D793A8DAD6C50DE106645D9B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1001C16510D946B47CFF8B19DBC0B787; + remoteInfo = "FirebaseCore-FirebaseCore_Privacy"; + }; + 5969D7170D106F4A1AB192E1216F15AA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 87803597EB3F20FC46472B85392EC4FD; + remoteInfo = FirebaseInstallations; + }; + 5E4A5B3DD62A4C720EC874F4302A4EBF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DAA3DF4B8C2F11E7A1764EF4EC560AC8; + remoteInfo = firebase_core; + }; + 663E3630442241D6D8F1320596DBA7A1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 743B1C5626A92F8FC4AFBE2602CA840F; + remoteInfo = "flutter_local_notifications-flutter_local_notifications_privacy"; + }; + 69008D115C5DAA717898D2837D54428C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8B74B458B450D74B75744B87BD747314; + remoteInfo = "Pods-Runner"; + }; + 6C278D1E93E8D812EE3F535EB225FC59 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1EFDDC32A34D56D411E640A81DCD9E73; + remoteInfo = Flutter; + }; + 703FBA9CB960246229152C34031EE17D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = A450BF39E3E5256209A256E278D71BFD; + remoteInfo = "image_picker_ios-image_picker_ios_privacy"; + }; + 7051DFF3BD836497C1B9299F679A1D5F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 072CEA044D2EF26F03496D5996BBF59F; + remoteInfo = Firebase; + }; + 7914C1F45A8D35F6B63535ED188247A4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5C0371EE948D0357B8EE0E34ABB44BF0; + remoteInfo = GoogleDataTransport; + }; + 7C952A87E3C258490947FA285883D816 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + 7F7A8CD4EE0915D7F18EDF09B23B2F1E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 3EB14444A17F9D4F1F697F7C1FF32245; + remoteInfo = "FirebaseInstallations-FirebaseInstallations_Privacy"; + }; + 8105158DB66AF0EBA32C7C70553000DF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 87803597EB3F20FC46472B85392EC4FD; + remoteInfo = FirebaseInstallations; + }; + 822FF24129B4ABB459510733D3AB564C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5895B432FE4D2F6826C8FF25A09DB6D2; + remoteInfo = FirebaseMessaging; + }; + 869347A98F9B8E8F4DFB537047767585 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + 8AA15153DC0CBB3A3DED625817ECBE3E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; + 916EECCCF2ECA3A4E92A5B7F46695892 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B92347C3E503ADBA2F0EF79DE5320B2D; + remoteInfo = firebase_messaging; + }; + 93F636FEEDFEEF58D7F0937791C0F9BB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; + 94B899FA05698E30EA21B0135F230128 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F64AA263B9D7877A7D58823DEF7F113B; + remoteInfo = flutter_local_notifications; + }; + 97655442E1EB5F14C91CD15648367707 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 845DF30C6C93A1F35C6DCEBAFECA8F8A; + remoteInfo = image_picker_ios; + }; + A36A467FF580B3943E553101F7099554 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DAA3DF4B8C2F11E7A1764EF4EC560AC8; + remoteInfo = firebase_core; + }; + AAB279BAEABD7F0D2546D881A16B3189 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + AAE2C625E2E4822114201AA84A528C9D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + AE6224D1282DEF839D31B5C9F4FEEAFE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + AF4B247048ACDCAB34391B6BE8DBB1E7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4402AFF83DBDC4DD07E198685FDC2DF2; + remoteInfo = FirebaseCore; + }; + B548E029B6A1C5304B6EA24842B71888 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DF331B019C7101D6AF15978FDCEC828E; + remoteInfo = "firebase_messaging-firebase_messaging_Privacy"; + }; + B916F5018DFF5EF404096B17FF1E6670 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 25E9E9A17BC3F670357D7385C521E48E; + remoteInfo = FirebaseCoreInternal; + }; + D0456CA7DA8E033585FE84F690D6D985 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + D77479D78C6DFAAC53455BED820DEE1C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 072CEA044D2EF26F03496D5996BBF59F; + remoteInfo = Firebase; + }; + DAF6D916715838ADEABEB4D9AC715D7F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1EFDDC32A34D56D411E640A81DCD9E73; + remoteInfo = Flutter; + }; + DDCEB7C86EFCF4DF9F42E25D3A63AAB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 55522A91938FF505CFEBEAD2DD85AE2D; + remoteInfo = "nanopb-nanopb_Privacy"; + }; + DF63A07312E00CAD6561968DEBFBC90A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D2B5E7DCCBBFB32341D857D01211A1A3; + remoteInfo = nanopb; + }; + F27493F13218D5AB3810ACCB60F7B4F6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D7F5D5DD528D21A72DC87ADA5B12E2D; + remoteInfo = GoogleUtilities; + }; + F2E64398D8064A66DBA59415CFE2A648 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5FF1A58DEEC5DB749FCD6C120B97CC82; + remoteInfo = "GoogleUtilities-GoogleUtilities_Privacy"; + }; + F43AF25452369BC5A3F4C31900856C45 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1EFDDC32A34D56D411E640A81DCD9E73; + remoteInfo = Flutter; + }; + FF8DB6F0FC60C5D49C51FE0D408905AE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BBF7206D7FAC92C82A042A99C4A98F8; + remoteInfo = PromisesObjC; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 007C2472BFF7E2E14B4BF86E9A99997B /* GULReachabilityChecker+Internal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GULReachabilityChecker+Internal.h"; path = "GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h"; sourceTree = ""; }; + 00817846E0BC0BA43768612211393B49 /* FirebaseMessaging.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseMessaging.release.xcconfig; sourceTree = ""; }; + 00830C5FFBF7D722EFA837254CFA5443 /* GULSceneDelegateSwizzler_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULSceneDelegateSwizzler_Private.h; path = GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h; sourceTree = ""; }; + 00A8890A6B80A0582F6CAFA39FA57375 /* nanopb-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "nanopb-prefix.pch"; sourceTree = ""; }; + 00D77329FD54061BC8C4922FDEED6DF9 /* FBLPromise+Delay.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Delay.h"; path = "Sources/FBLPromises/include/FBLPromise+Delay.h"; sourceTree = ""; }; + 00FFDE3AE7E0091D819430E2EA48408E /* FLTImagePickerPlugin.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTImagePickerPlugin.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTImagePickerPlugin.h"; sourceTree = ""; }; + 01C21144A7A96E0CDBABE621D3EC79CD /* FBLPromise+Timeout.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Timeout.m"; path = "Sources/FBLPromises/FBLPromise+Timeout.m"; sourceTree = ""; }; + 026994D707584EFF3A96BC447ACB8B4B /* FIRMessagingKeychain.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingKeychain.m; path = FirebaseMessaging/Sources/Token/FIRMessagingKeychain.m; sourceTree = ""; }; + 029E5A0553893B0C6A0A8FC483F5F56E /* GoogleUtilities.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = GoogleUtilities.modulemap; sourceTree = ""; }; + 02B09E1438E8A0C58CFD12510B6FB36E /* ResourceBundle-FirebaseMessaging_Privacy-FirebaseMessaging-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-FirebaseMessaging_Privacy-FirebaseMessaging-Info.plist"; sourceTree = ""; }; + 03408913A9DA374E2493D330A980E8CC /* GDTCORLifecycle.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORLifecycle.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m; sourceTree = ""; }; + 03AE6CA1DBA607C545A3B791D8E2AF51 /* GDTCORMetricsMetadata.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORMetricsMetadata.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h; sourceTree = ""; }; + 042074816A9B5A4CFF2C78D349B025D7 /* FLTFirebaseMessagingPlugin.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTFirebaseMessagingPlugin.h; path = "../../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/ios/firebase_messaging/Sources/firebase_messaging/include/FLTFirebaseMessagingPlugin.h"; sourceTree = ""; }; + 0449AF94882DAC62AA57B3FD5760D8B0 /* FlutterEngineManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FlutterEngineManager.m; path = "../../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/Classes/FlutterEngineManager.m"; sourceTree = ""; }; + 044C8F52069D02324E0E1334EC92CBC8 /* FIRInstallationsIDController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsIDController.m; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m; sourceTree = ""; }; + 053E79D285ED081E8D3A467E9057432F /* GDTCORRegistrar.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORRegistrar.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m; sourceTree = ""; }; + 0644B8CAE7E33A4B091322FB566D2BBA /* external_prequest_context.nanopb.c */ = {isa = PBXFileReference; includeInIndex = 1; name = external_prequest_context.nanopb.c; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.c; sourceTree = ""; }; + 066B519E3C90539086F1B9869EDBEB8A /* FIRMessagingTokenOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingTokenOperation.m; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.m; sourceTree = ""; }; + 067B1A306E1D71331FFB0C7B4842C96D /* FIRMessagingPendingTopicsList.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingPendingTopicsList.h; path = FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.h; sourceTree = ""; }; + 06FC5C9CF96D60C50FCD47D339C91951 /* nanopb */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = nanopb; path = nanopb.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 06FEAB1B0AE18AA2E6311F4327D6F2D0 /* FIRTimestampInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTimestampInternal.h; path = FirebaseCore/Sources/FIRTimestampInternal.h; sourceTree = ""; }; + 073788DD1F3BA0D6A1E4F105FEE47626 /* FIRInstallationsStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsStore.m; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m; sourceTree = ""; }; + 07C6B8ABF0A5FBF262DEA5F49AEAFD28 /* FIRInstallationsIIDStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsIIDStore.h; path = FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h; sourceTree = ""; }; + 07CF8CA0F334DC28EDEC31A017D7EB45 /* GULNSData+zlib.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GULNSData+zlib.m"; path = "GoogleUtilities/NSData+zlib/GULNSData+zlib.m"; sourceTree = ""; }; + 081DB68F10FD71B7A8E743FC93039FCC /* GULKeychainUtils.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULKeychainUtils.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h; sourceTree = ""; }; + 08579575396173B32867108F604F151C /* FIRHeartbeatLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatLogger.h; path = FirebaseCore/Extension/FIRHeartbeatLogger.h; sourceTree = ""; }; + 0A7219D1FBE5F86E63958153ED0BF377 /* FIRMessagingBackupExcludedPlist.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingBackupExcludedPlist.m; path = FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.m; sourceTree = ""; }; + 0C55AD722325AEB399EE8A894204E0C7 /* image_picker_ios.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = image_picker_ios.modulemap; sourceTree = ""; }; + 0C6A42B0370A0BB6545A0CCA144AF3F4 /* nanopb.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = nanopb.release.xcconfig; sourceTree = ""; }; + 0D351F23C38290B0C3B49DC7310E8B45 /* Pods-Runner.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Runner.modulemap"; sourceTree = ""; }; + 0D4A46F116BFFAE9C3ECDC7EF00A6E6A /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Extension/FIRAppInternal.h; sourceTree = ""; }; + 0F83DB803875BEAAF3F411BC01D3472E /* dummy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = dummy.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/include/firebase_core/dummy.h"; sourceTree = ""; }; + 10CFAF9FFD1CC96384F77C2950681BD4 /* FIRMessagingUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingUtilities.h; path = FirebaseMessaging/Sources/FIRMessagingUtilities.h; sourceTree = ""; }; + 1113950F760FBB488BA6EFD6F5B7B649 /* nanopb-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "nanopb-umbrella.h"; sourceTree = ""; }; + 11E183230D34CC5B062D1D1049A366B6 /* GULNSData+zlib.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GULNSData+zlib.h"; path = "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h"; sourceTree = ""; }; + 12C8D8D85F32CD7F51280DC4963FA9A0 /* FBLPromiseError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromiseError.h; path = Sources/FBLPromises/include/FBLPromiseError.h; sourceTree = ""; }; + 12CE4326B05B13F9BDF9FDD0DEC5EEF6 /* GULNetworkConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkConstants.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h; sourceTree = ""; }; + 12F5C151D4D75DC95504E85575964C8C /* ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist"; sourceTree = ""; }; + 13C8C8B254851998F9289F71229B28A2 /* FirebaseInstallations */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseInstallations; path = FirebaseInstallations.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 148D0F9E8C7373FEAF40D800FC5F1BAA /* FirebaseCoreInternal */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseCoreInternal; path = FirebaseCoreInternal.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1597161DD3BB968D29E7B45448AA14CB /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Extension/FirebaseCoreInternal.h; sourceTree = ""; }; + 16754451CC068C973247E72B5EACF78C /* Pods-Runner-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Runner-Info.plist"; sourceTree = ""; }; + 16F47DBFD334E095900DAD45D515CFE7 /* GDTCORStorageMetadata.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORStorageMetadata.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h; sourceTree = ""; }; + 1792230F1C96C80BBCBE1F3E25A86437 /* nanopb.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = nanopb.debug.xcconfig; sourceTree = ""; }; + 17FF3FD8C34AE6E60B8CAEBA719DEA21 /* FIRComponentContainerInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainerInternal.h; path = FirebaseCore/Sources/FIRComponentContainerInternal.h; sourceTree = ""; }; + 18360B97FCA68E6CB98056F40009B735 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = "../../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/Resources/PrivacyInfo.xcprivacy"; sourceTree = ""; }; + 1878E7A7CE833995A4A9C1C8C5241E9F /* FBLPromise+Await.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Await.h"; path = "Sources/FBLPromises/include/FBLPromise+Await.h"; sourceTree = ""; }; + 18A6D34071FD583FE9C58FCE5CF837F8 /* GDTCORFlatFileStorage+Promises.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GDTCORFlatFileStorage+Promises.m"; path = "GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m"; sourceTree = ""; }; + 192ABD450F0C793BE1E734A176E27E26 /* FIRAllocatedUnfairLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FIRAllocatedUnfairLock.swift; path = FirebaseCore/Internal/Sources/Utilities/FIRAllocatedUnfairLock.swift; sourceTree = ""; }; + 194D87AC7FA8ACD1ADC48E9094B1DD8F /* FIRBundleUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRBundleUtil.m; path = FirebaseCore/Sources/FIRBundleUtil.m; sourceTree = ""; }; + 197CD7DF8C5D74CD76AFB946CABF0B91 /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Extension/FIRAppInternal.h; sourceTree = ""; }; + 1A0F986347F2F1609FFC4F0D31B89630 /* ActionEventSink.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ActionEventSink.h; path = "../../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/Classes/ActionEventSink.h"; sourceTree = ""; }; + 1ADB61306F50F60E65BED44878011822 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 1B11C51237E5D56456A68EABAE481D91 /* GDTCORReachability.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORReachability.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m; sourceTree = ""; }; + 1C613D4CE88F0AF4F9A718CB8F6CB748 /* PromisesObjC-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "PromisesObjC-dummy.m"; sourceTree = ""; }; + 1C6CB67271C76EA4A1308844DF06B701 /* GULSceneDelegateSwizzler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULSceneDelegateSwizzler.m; path = GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m; sourceTree = ""; }; + 1CFEE5BEEE3B72CCB9414344913144FD /* FIRMessagingTokenFetchOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingTokenFetchOperation.m; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.m; sourceTree = ""; }; + 1D5E75344C12FBE305143C4EE160EF82 /* FBLPromiseError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBLPromiseError.m; path = Sources/FBLPromises/FBLPromiseError.m; sourceTree = ""; }; + 1EA7FEFB5AC53EBAF907B0E73D03959D /* GULAppDelegateSwizzler.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULAppDelegateSwizzler.m; path = GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m; sourceTree = ""; }; + 1F1B1A3CB7EF62D9C362CFF5A14098E7 /* FLTPHPickerSaveImageToPathOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLTPHPickerSaveImageToPathOperation.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/FLTPHPickerSaveImageToPathOperation.m"; sourceTree = ""; }; + 1F41AF401ECD6D59105FD217BFA68A35 /* firebase_messaging-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "firebase_messaging-umbrella.h"; sourceTree = ""; }; + 1F498270700E31C3494045615D8186A7 /* GDTCORMetricsController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORMetricsController.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORMetricsController.m; sourceTree = ""; }; + 1FC1F7D9B41F4C5EC44785ED4449DABD /* FBLPromise+Wrap.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Wrap.m"; path = "Sources/FBLPromises/FBLPromise+Wrap.m"; sourceTree = ""; }; + 1FC96341216BBB5BBE3744FB1F35DEEE /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 202227937DC19626B6162B984AC7B94B /* FIRAppInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAppInternal.h; path = FirebaseCore/Extension/FIRAppInternal.h; sourceTree = ""; }; + 20A4EB78766C836C5E6356204E56EB54 /* FirebaseMessaging-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseMessaging-Info.plist"; sourceTree = ""; }; + 20AF87A6F49B0CEA59EC599CAEDFD41A /* GDTCORRegistrar_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORRegistrar_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h; sourceTree = ""; }; + 20CFA7FEC659CB53FA77B7DB18BB054C /* messages.g.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = messages.g.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/messages.g.h"; sourceTree = ""; }; + 21D9E6AABF6D4CF5BC663A230EF53A42 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + 2253E23F9EAEA9EE71A0073BE86B5E16 /* FIRAnalyticsInteropListener.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAnalyticsInteropListener.h; path = Interop/Analytics/Public/FIRAnalyticsInteropListener.h; sourceTree = ""; }; + 2428D4B9A1ADDA45215CD1FC1F3207AD /* _ObjC_HeartbeatController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = _ObjC_HeartbeatController.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift; sourceTree = ""; }; + 252ED5705010489B5DDE7E1A4E37EF6E /* FLTImagePickerPhotoAssetUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTImagePickerPhotoAssetUtil.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTImagePickerPhotoAssetUtil.h"; sourceTree = ""; }; + 26B9F97490E01D18CE5B3F13AF177F32 /* IsAppEncrypted.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = IsAppEncrypted.m; path = third_party/IsAppEncrypted/IsAppEncrypted.m; sourceTree = ""; }; + 279906FE251A2F87816561487A4BBB08 /* FirebaseCoreInternal.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCoreInternal.release.xcconfig; sourceTree = ""; }; + 27BAF00DDE21BC901CDDFBC3E0E51ACB /* GULMutableDictionary.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULMutableDictionary.m; path = GoogleUtilities/Network/GULMutableDictionary.m; sourceTree = ""; }; + 27C6F7D9AFD28A5F991FCC1ADF5594EF /* FBLPromise+Async.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Async.h"; path = "Sources/FBLPromises/include/FBLPromise+Async.h"; sourceTree = ""; }; + 27F45BB476A5698F78222A71E4F39AE1 /* PromisesObjC-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "PromisesObjC-Info.plist"; sourceTree = ""; }; + 2857105885BD433FDC1DF8F4846851DC /* pb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb.h; sourceTree = ""; }; + 28BF0A4825F5A1C942E39489A06D32FF /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Extension/FIRLibrary.h; sourceTree = ""; }; + 28C991FA4F9E8DB769F528C9B6AB0F23 /* GULReachabilityChecker.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULReachabilityChecker.m; path = GoogleUtilities/Reachability/GULReachabilityChecker.m; sourceTree = ""; }; + 28DDAFBBF7DC1837B7CB4B7401725191 /* FLTFirebaseCorePlugin.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLTFirebaseCorePlugin.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/FLTFirebaseCorePlugin.m"; sourceTree = ""; }; + 293CA810B9F9A627CF1B04985BBABB47 /* FIRMessagingConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingConstants.h; path = FirebaseMessaging/Sources/FIRMessagingConstants.h; sourceTree = ""; }; + 29D1AD200DC6E547E00A68ED01A09C6D /* FIRInstallationsStatus.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsStatus.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h; sourceTree = ""; }; + 2AEADD8988B976B2FC825995D7A877AD /* FBLPromise+Validate.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Validate.m"; path = "Sources/FBLPromises/FBLPromise+Validate.m"; sourceTree = ""; }; + 2B2C2824B00198C89C8796514A539E69 /* GDTCCTURLSessionDataResponse.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCCTURLSessionDataResponse.m; path = GoogleDataTransport/GDTCCTLibrary/GDTCCTURLSessionDataResponse.m; sourceTree = ""; }; + 2B3AF9D90D4B088422687FFF4641CBC3 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 2C0DF8FF5022D896FDA41D434C0F6EF5 /* AtomicBox.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AtomicBox.swift; path = FirebaseCore/Internal/Sources/Utilities/AtomicBox.swift; sourceTree = ""; }; + 2C83B649D5208B12A39151A858969DD4 /* firebase_messaging.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = firebase_messaging.podspec; path = "../../../../../../../../.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/ios/firebase_messaging.podspec"; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 2CB04EB554430E41E5A19EDE6D62C9F2 /* Pods-RunnerTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-RunnerTests-umbrella.h"; sourceTree = ""; }; + 2D8EA9E33C58DFF057693997F6C8D831 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = GoogleUtilities/Privacy/Resources/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 2DC9C663B1C9C9C7D6D450E2475A8960 /* RingBuffer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RingBuffer.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift; sourceTree = ""; }; + 2E3135844263DBDB97D0179BDAB2CB68 /* flutter_local_notifications.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = flutter_local_notifications.debug.xcconfig; sourceTree = ""; }; + 2E3C1BE5EE5B7F7FE8218A78F05F362D /* FIRInstallationsAuthTokenResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsAuthTokenResult.m; path = FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m; sourceTree = ""; }; + 2E7BEB959A6F7D8070CB1E6B209A8C76 /* FLTFirebasePlugin.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLTFirebasePlugin.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/FLTFirebasePlugin.m"; sourceTree = ""; }; + 2E99CA1C85E12A4F6F18BC1B1CBF6DAB /* FIRMessagingCheckinPreferences.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingCheckinPreferences.m; path = FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.m; sourceTree = ""; }; + 2EB64290BD8F25183F5F3B6E893CEC55 /* FBLPromises.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromises.h; path = Sources/FBLPromises/include/FBLPromises.h; sourceTree = ""; }; + 2F0908B8A5026151E2800777E4B17F20 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 2F3048B48A2FE22ED08DA327695BC2D9 /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Extension/FIRComponentType.h; sourceTree = ""; }; + 2FE54C96AAFD6CECAA849DB5EA8452F1 /* StorageFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StorageFactory.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift; sourceTree = ""; }; + 307006891C36268C3ABD5CA9F826AFC0 /* FLTFirebaseCorePlugin.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTFirebaseCorePlugin.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/include/firebase_core/FLTFirebaseCorePlugin.h"; sourceTree = ""; }; + 310D0CD7273827DB2A2442B0149E6B9F /* FIRMessagingTokenDeleteOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingTokenDeleteOperation.h; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.h; sourceTree = ""; }; + 317558E06CC941F96264F2804571871D /* GDTCORAssert.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORAssert.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m; sourceTree = ""; }; + 3227F3FC45681D7CEE5D1355A532398A /* nanopb-nanopb_Privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "nanopb-nanopb_Privacy"; path = nanopb_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 3347A1AB6546F0A3977529B8F199DC41 /* PromisesObjC */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = PromisesObjC; path = FBLPromises.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 33FC9CF96CA23D0419B6024FA5B7B9CE /* FIRInstallationsAuthTokenResultInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsAuthTokenResultInternal.h; path = FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h; sourceTree = ""; }; + 3431FD1E5FCA48FEF6E835D77FC47AE9 /* GDTCORTransport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTransport.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h; sourceTree = ""; }; + 34E0FF48D6D2CD42238C1A65D59CED2F /* FBLPromise+Validate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Validate.h"; path = "Sources/FBLPromises/include/FBLPromise+Validate.h"; sourceTree = ""; }; + 35414041146136B679F51AE9058D762F /* pb_encode.c */ = {isa = PBXFileReference; includeInIndex = 1; path = pb_encode.c; sourceTree = ""; }; + 35B82E32D28724379DF7521589FEBFE2 /* HeartbeatsPayload.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatsPayload.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift; sourceTree = ""; }; + 35E25A842CB04F9B78FCBA6BF7F0C5CA /* GULSceneDelegateSwizzler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULSceneDelegateSwizzler.h; path = GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h; sourceTree = ""; }; + 362A936B488A8BC83F35FE595CF39E60 /* nanopb-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "nanopb-dummy.m"; sourceTree = ""; }; + 36D1D380AC0FAE1558B1433A94C5939C /* FLTImagePickerPlugin.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLTImagePickerPlugin.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPlugin.m"; sourceTree = ""; }; + 37264F9F27D2E16057E0E305FA5BCCCB /* client_metrics.nanopb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = client_metrics.nanopb.h; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h; sourceTree = ""; }; + 37EF8E7FBD37768317274AA49494D9D7 /* GDTCOREvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREvent.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h; sourceTree = ""; }; + 381BA5E61A58F61BC2D25A380396C078 /* GDTCORStorageMetadata.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORStorageMetadata.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORStorageMetadata.m; sourceTree = ""; }; + 38E268C4172837796B505246635355EA /* FIRInstallationsAuthTokenResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsAuthTokenResult.h; path = FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h; sourceTree = ""; }; + 3A46168EEE10D0596CA807ED75B57AAC /* GULUserDefaults.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULUserDefaults.h; path = GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h; sourceTree = ""; }; + 3ABA51F489706FFEBF9DE0135C0C0FCA /* image_picker_ios-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "image_picker_ios-umbrella.h"; path = "../../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios-umbrella.h"; sourceTree = ""; }; + 3AEB19A22ADF808E67367F1FB5B2A554 /* Storage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Storage.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift; sourceTree = ""; }; + 3B5F7F6DD4538CB6DE8986871A2965EA /* FIRInstallationsItem+RegisterInstallationAPI.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FIRInstallationsItem+RegisterInstallationAPI.m"; path = "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m"; sourceTree = ""; }; + 3BE9CF5E1CA26178487BCD7E48951DE8 /* FirebaseInstallationsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseInstallationsInternal.h; path = FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h; sourceTree = ""; }; + 3C0783D1DCE2D70C01DE8F66368E3525 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/CoreTelephony.framework; sourceTree = DEVELOPER_DIR; }; + 3D7A14EF7C31BD4B3BC7F920226167FC /* HeartbeatController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatController.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift; sourceTree = ""; }; + 3D91810E20A5CC45F9D6656F71A636BD /* firebase_core.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = firebase_core.modulemap; sourceTree = ""; }; + 3E249AAAE8E92B5750DB3E8ADB534D8F /* Pods-RunnerTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-RunnerTests-acknowledgements.plist"; sourceTree = ""; }; + 3E39342DADE8E8CA6D1D925BCFF34D3C /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = FirebaseMessaging/Sources/Resources/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 3EA71D30421D81D90A45FD77D6FB2976 /* _ObjC_HeartbeatsPayload.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = _ObjC_HeartbeatsPayload.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift; sourceTree = ""; }; + 3F238BB22C5201CE689CAF2F766AED95 /* PromisesObjC-FBLPromises_Privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "PromisesObjC-FBLPromises_Privacy"; path = FBLPromises_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 3F24A03162482FB4B37596AA1170AA70 /* GDTCORTransformer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTransformer.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h; sourceTree = ""; }; + 3F9429AEFF528448C4A75318298FA20A /* firebase_core.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = firebase_core.debug.xcconfig; sourceTree = ""; }; + 403BA008E85450C1AAAEF7B741D81AA3 /* FIRMessagingConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingConstants.m; path = FirebaseMessaging/Sources/FIRMessagingConstants.m; sourceTree = ""; }; + 4044D1DCE0CEDBE513D95BE2120704F9 /* FIRMessagingRmqManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingRmqManager.h; path = FirebaseMessaging/Sources/FIRMessagingRmqManager.h; sourceTree = ""; }; + 405713E74388D08C5EA84CD978C15709 /* ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist"; sourceTree = ""; }; + 411C572D658946450319E3438E61FBCC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 42090CBE9D81332CD5F6058E81F380CC /* firebase_messaging-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "firebase_messaging-prefix.pch"; sourceTree = ""; }; + 4213C92093942202692742B0F6E8A372 /* FIRInstallationsLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsLogger.h; path = FirebaseInstallations/Source/Library/FIRInstallationsLogger.h; sourceTree = ""; }; + 422185136707E9DE2A78DC226625C9D5 /* IsAppEncrypted.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = IsAppEncrypted.h; path = third_party/IsAppEncrypted/Public/IsAppEncrypted.h; sourceTree = ""; }; + 424A93A150F9A2832A97CB7932DD2206 /* GDTCORStorageSizeBytes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORStorageSizeBytes.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h; sourceTree = ""; }; + 425208C5EBD0D6B01AB909862DE50BAA /* FIRInteropParameterNames.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInteropParameterNames.h; path = Interop/Analytics/Public/FIRInteropParameterNames.h; sourceTree = ""; }; + 425AB8995EF76A7A41250B2B39B918A9 /* client_metrics.nanopb.c */ = {isa = PBXFileReference; includeInIndex = 1; name = client_metrics.nanopb.c; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.c; sourceTree = ""; }; + 43761187E271796633E239446DAD0EB1 /* image_picker_ios-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "image_picker_ios-prefix.pch"; sourceTree = ""; }; + 4410AC3B578C5D7B3CC7EFF95034B347 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; name = LICENSE; path = "../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/LICENSE"; sourceTree = ""; }; + 445871E06F8049863AA09E1A3C325E3E /* FIRMessagingTokenInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingTokenInfo.h; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.h; sourceTree = ""; }; + 44B37CE36850E344D08C7C42DC1B036A /* messages.g.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = messages.g.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/messages.g.m"; sourceTree = ""; }; + 44E291D18340EAC3F761346198515323 /* GoogleUtilities-GoogleUtilities_Privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "GoogleUtilities-GoogleUtilities_Privacy"; path = GoogleUtilities_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 45CF41DF5693A36FD86A879BE06D0382 /* FIRInstallationsHTTPError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsHTTPError.h; path = FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h; sourceTree = ""; }; + 45E120F4A9F7D13802BA4D4E76E24EFC /* Pods-Runner-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Runner-acknowledgements.plist"; sourceTree = ""; }; + 45E5FA6F52D158F4FB3C4CBC66E449BC /* FlutterEngineManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FlutterEngineManager.h; path = "../../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/Classes/FlutterEngineManager.h"; sourceTree = ""; }; + 466AEE01B8DBE6158A57A5141A851070 /* external_privacy_context.nanopb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = external_privacy_context.nanopb.h; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h; sourceTree = ""; }; + 478136BE01D032987B5DF1FB1694472C /* cct.nanopb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = cct.nanopb.h; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h; sourceTree = ""; }; + 4790FE35CCE78F042C4976E095FC08E7 /* GoogleUtilities-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GoogleUtilities-dummy.m"; sourceTree = ""; }; + 47C581450CDB4A6111CB97EEE0711A8C /* FirebaseInstallations-FirebaseInstallations_Privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "FirebaseInstallations-FirebaseInstallations_Privacy"; path = FirebaseInstallations_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 481E832C9E13CB11704E3B80B0A61F8A /* GDTCORMetricsControllerProtocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORMetricsControllerProtocol.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h; sourceTree = ""; }; + 490691048F9A43D41B5F491C8D800AA6 /* FirebaseCore.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCore.debug.xcconfig; sourceTree = ""; }; + 490DC0C7050C99937B5FAA5B60745755 /* FlutterLocalNotificationsPlugin.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FlutterLocalNotificationsPlugin.h; path = "../../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/Classes/FlutterLocalNotificationsPlugin.h"; sourceTree = ""; }; + 499A09DE888645CBC456DD808F91F0C0 /* pb_decode.c */ = {isa = PBXFileReference; includeInIndex = 1; path = pb_decode.c; sourceTree = ""; }; + 49A6AF4F7D6CCA75CB3493CBDFEAE6FD /* FIRMessagingTokenStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingTokenStore.m; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.m; sourceTree = ""; }; + 49AE84DBBAD701EE2CB8545AAC680E6E /* GDTCORUploadBatch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORUploadBatch.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m; sourceTree = ""; }; + 4A975AC758C10E2751E29D23149C3F8A /* FIRMessagingAuthKeychain.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingAuthKeychain.h; path = FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.h; sourceTree = ""; }; + 4AD9F2841591395962459F34DBA6F234 /* GULLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULLogger.h; path = GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h; sourceTree = ""; }; + 4B0C1FD0FEE536657E3F3752322EE5F6 /* GULApplication.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULApplication.h; path = GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h; sourceTree = ""; }; + 4C05080F60D04271D75AD4FB3A338D84 /* firebase_messaging-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "firebase_messaging-dummy.m"; sourceTree = ""; }; + 4CB131F3BC1D6D2C79680B59CF30EF6B /* Pods-Runner-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Runner-dummy.m"; sourceTree = ""; }; + 4CFB397A9898BDBB88BBCFFC0548617D /* GULNetworkConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetworkConstants.m; path = GoogleUtilities/Network/GULNetworkConstants.m; sourceTree = ""; }; + 4D28E6CD2A57E7F53F190E76FDADBD54 /* GULNetwork.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetwork.m; path = GoogleUtilities/Network/GULNetwork.m; sourceTree = ""; }; + 4D78F29C73286A17F514D3070039F716 /* FBLPromise+Do.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Do.m"; path = "Sources/FBLPromises/FBLPromise+Do.m"; sourceTree = ""; }; + 4DB03FD262B678178A44272143846563 /* FirebaseCoreInternal-FirebaseCoreInternal_Privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "FirebaseCoreInternal-FirebaseCoreInternal_Privacy"; path = FirebaseCoreInternal_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 4E74DC0FD5217C11B99B434ACE6CD425 /* GDTCORLogSourceMetrics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORLogSourceMetrics.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h; sourceTree = ""; }; + 4E86D9F1294ECE2C483FD6166223BD86 /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Extension/FIRComponentContainer.h; sourceTree = ""; }; + 4E92F5C34E3AB0C48D354F7CA1455254 /* image_picker_ios.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = image_picker_ios.podspec; path = "../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios.podspec"; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 4EC3E7E7FF9E0F3BF5F8FBF7A3BBF8DB /* FIRMessaging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessaging.h; path = FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging.h; sourceTree = ""; }; + 4F4B9BE06777680B5A22621207B01882 /* compliance.nanopb.c */ = {isa = PBXFileReference; includeInIndex = 1; name = compliance.nanopb.c; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.c; sourceTree = ""; }; + 4F58BAB8D1B897095AA76F603F58EBFD /* FirebaseInstallations-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseInstallations-umbrella.h"; sourceTree = ""; }; + 50D270FC2FB999A0D0BA29B73B9B2DFB /* me.nanopb.c */ = {isa = PBXFileReference; includeInIndex = 1; name = me.nanopb.c; path = FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.c; sourceTree = ""; }; + 50F392EB97CBED8788C50990F6BAB160 /* FIRMessagingLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingLogger.m; path = FirebaseMessaging/Sources/FIRMessagingLogger.m; sourceTree = ""; }; + 50F613F74218D55303469A0613633B7E /* FirebaseMessaging-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseMessaging-umbrella.h"; sourceTree = ""; }; + 511BBAD2CBB8A874EDF7B10BE3A86FB5 /* FBLPromise+Any.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Any.m"; path = "Sources/FBLPromises/FBLPromise+Any.m"; sourceTree = ""; }; + 513486288D9850EF657161C39358ED93 /* flutter_local_notifications-flutter_local_notifications_privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "flutter_local_notifications-flutter_local_notifications_privacy"; path = flutter_local_notifications_privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 51E163742B3DECE034022C24CEA961D7 /* FIRInstallationsSingleOperationPromiseCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsSingleOperationPromiseCache.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h; sourceTree = ""; }; + 5215464BB80A41FB505019E963220AE0 /* GoogleUtilities-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GoogleUtilities-umbrella.h"; sourceTree = ""; }; + 52D6E9B0E720A5CC03B91F3CCE939F1D /* FIRComponent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRComponent.m; path = FirebaseCore/Sources/FIRComponent.m; sourceTree = ""; }; + 545009CB939B8FA897EBC1023E6DA94C /* FBLPromise+Wrap.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Wrap.h"; path = "Sources/FBLPromises/include/FBLPromise+Wrap.h"; sourceTree = ""; }; + 546407E1AE82F5A543FB0FF08CFB6A93 /* flutter_local_notifications.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = flutter_local_notifications.modulemap; sourceTree = ""; }; + 55086D223D9FF08447F190FF4EC56B2B /* FIRInstallationsBackoffController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsBackoffController.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h; sourceTree = ""; }; + 551651297586403CD2F85A86DB9035D4 /* GDTCORFlatFileStorage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORFlatFileStorage.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m; sourceTree = ""; }; + 554D791CC412A5751A7D867492682EB9 /* FIRMessagingAnalytics.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingAnalytics.m; path = FirebaseMessaging/Sources/FIRMessagingAnalytics.m; sourceTree = ""; }; + 5551C50E78F600068DECA3941CFDC868 /* FBLPromise+Always.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Always.h"; path = "Sources/FBLPromises/include/FBLPromise+Always.h"; sourceTree = ""; }; + 5849D105D1C2834E540A65AE4ABE3C27 /* GDTCORTransport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORTransport.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m; sourceTree = ""; }; + 5933B364C8A4BF4E4CED5DF0016F175F /* FirebaseCoreInternal-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseCoreInternal-Info.plist"; sourceTree = ""; }; + 5973651CFCFFEC1F7B81A2D131B46CCA /* GDTCOREvent+GDTMetricsSupport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GDTCOREvent+GDTMetricsSupport.m"; path = "GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTMetricsSupport.m"; sourceTree = ""; }; + 597586DD100925D126C1C463DD575398 /* GDTCOREndpoints.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCOREndpoints.m; path = GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m; sourceTree = ""; }; + 5A4ADC3E70449C2D6DDAD177ABCBBB5F /* FIRMessagingTokenFetchOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingTokenFetchOperation.h; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenFetchOperation.h; sourceTree = ""; }; + 5AA41421D42B0E9F83F0034ED34A520D /* FIROptions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIROptions.m; path = FirebaseCore/Sources/FIROptions.m; sourceTree = ""; }; + 5AD9D505359BA32ED31F62F46E5FA68D /* Firebase.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Firebase.h; path = CoreOnly/Sources/Firebase.h; sourceTree = ""; }; + 5B654B4B042BA7DC93766943A643E42B /* FirebaseMessaging */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseMessaging; path = FirebaseMessaging.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5C482693DD66F9BCB854CF7C4D8DDB90 /* GoogleUtilities-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "GoogleUtilities-Info.plist"; sourceTree = ""; }; + 5CB3716BCB4F04E1DFCEA30BECF2BC60 /* compliance.nanopb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = compliance.nanopb.h; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h; sourceTree = ""; }; + 5D72A05D5CC2A779BBB1D8F916B0FF1A /* ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist"; sourceTree = ""; }; + 5D75104223B5E3CD6623422BDAF96AC4 /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Extension/FIRLibrary.h; sourceTree = ""; }; + 5D9309B998555FFB2544D65E50F4A2F9 /* GoogleDataTransport.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleDataTransport.debug.xcconfig; sourceTree = ""; }; + 5DBD8A865F7372556F04F54BEEBC7ADC /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; name = LICENSE; path = "../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/LICENSE"; sourceTree = ""; }; + 5F2A42EA92F0EA92CF755046DDC08290 /* Flutter.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Flutter.release.xcconfig; sourceTree = ""; }; + 5F7961550B6D6E457B016978E275F440 /* GULReachabilityChecker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULReachabilityChecker.h; path = GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h; sourceTree = ""; }; + 5F79E91E59676DD40F34E8E5DEFC6A9E /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = Sources/FBLPromises/Resources/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 5FE570758D07A5EE6A12AF7E45FFC15B /* dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = dummy.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/dummy.m"; sourceTree = ""; }; + 5FEB5CEB94D970450A0BBA5577A80F61 /* FIRMessagingUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingUtilities.m; path = FirebaseMessaging/Sources/FIRMessagingUtilities.m; sourceTree = ""; }; + 600AC3F60588265C01A074792402E2BC /* GDTCORLifecycle.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORLifecycle.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h; sourceTree = ""; }; + 601B9BE94C9A2AEB8E3FAF0E5B8480B1 /* GDTCORFlatFileStorage+Promises.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GDTCORFlatFileStorage+Promises.h"; path = "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h"; sourceTree = ""; }; + 618D7CDD1897742A6C54A37FFB4D0219 /* FirebaseInstallations.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseInstallations.release.xcconfig; sourceTree = ""; }; + 619E6A45528E9255637879488FB26EDF /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + 626B91FA30530F8DA0D892C01BC22133 /* firebase_messaging */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = firebase_messaging; path = firebase_messaging.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 62E4E821E9D7CB7F725D9FF9D5C20D14 /* FIRMessagingCheckinStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingCheckinStore.h; path = FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.h; sourceTree = ""; }; + 6308A2BF48F37BFCC2D67C547F4FFC31 /* GDTCORProductData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORProductData.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORProductData.m; sourceTree = ""; }; + 635395842F105EACF3067D6B54D82C8F /* pb_decode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb_decode.h; sourceTree = ""; }; + 645C467BE75EA8292CD0BAC07F1DD5A5 /* FIRMessagingCheckinService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingCheckinService.h; path = FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.h; sourceTree = ""; }; + 656C5FB7BFF6EBCF232183D77650236F /* FIRConfigurationInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRConfigurationInternal.h; path = FirebaseCore/Sources/FIRConfigurationInternal.h; sourceTree = ""; }; + 65E68F8C9B22A7FF7F1B3F3948BBB254 /* FIRMessagingAuthService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingAuthService.h; path = FirebaseMessaging/Sources/Token/FIRMessagingAuthService.h; sourceTree = ""; }; + 669E8F25E1897672BDB80B7EB784DA24 /* Pods-Runner */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-Runner"; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 673C3318F9A1D81116EEE5349A511A7F /* FIRMessagingKeychain.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingKeychain.h; path = FirebaseMessaging/Sources/Token/FIRMessagingKeychain.h; sourceTree = ""; }; + 67D3334469F5EF9F0C72503D6E4DE412 /* firebase_core-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "firebase_core-Info.plist"; sourceTree = ""; }; + 6814315BA51938939FB36210B07A40D5 /* firebase_messaging.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = firebase_messaging.modulemap; sourceTree = ""; }; + 6A03990672E97F082CE5D42C4DA88AE3 /* FIRInstallations.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallations.m; path = FirebaseInstallations/Source/Library/FIRInstallations.m; sourceTree = ""; }; + 6A10DCC568131817410FB1AEF9178715 /* FIRApp.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRApp.m; path = FirebaseCore/Sources/FIRApp.m; sourceTree = ""; }; + 6A3F9414556C6E7943F21A35632157C2 /* FIRMessagingExtensionHelper.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingExtensionHelper.m; path = FirebaseMessaging/Sources/FIRMessagingExtensionHelper.m; sourceTree = ""; }; + 6AAFE120840A05E53C241E4B7F3C64E8 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Extension/FIRLogger.h; sourceTree = ""; }; + 6B31EC9A7B428F4713B87CE4DF630775 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = GoogleDataTransport/Resources/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 6B6B934456F9D9272269319603A5F9C3 /* FBLPromise+Testing.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Testing.m"; path = "Sources/FBLPromises/FBLPromise+Testing.m"; sourceTree = ""; }; + 6C16E4E43B9D4F77B6DB7BB1766F356E /* image_picker_ios.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = image_picker_ios.debug.xcconfig; sourceTree = ""; }; + 6C3345B1B3CAEDF5B03B1F731FDC492E /* Pods-RunnerTests */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-RunnerTests"; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6CACAF5FAD3F5001091F6F489F1D22AC /* FLTFirebasePluginRegistry.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLTFirebasePluginRegistry.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/FLTFirebasePluginRegistry.m"; sourceTree = ""; }; + 6D057386278D6ACF2F30795937A5D7B6 /* firebase_messaging.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = firebase_messaging.debug.xcconfig; sourceTree = ""; }; + 6D76A6F64A9F9AC8C80C62153642E906 /* FIRMessagingTokenDeleteOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingTokenDeleteOperation.m; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenDeleteOperation.m; sourceTree = ""; }; + 6ED2F58D2160FEAAC3E745D0085755B1 /* GDTCOREvent_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREvent_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h; sourceTree = ""; }; + 6EDDBD54960ABBA9D0898075ADB7A56C /* image_picker_ios-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "image_picker_ios-dummy.m"; sourceTree = ""; }; + 6EF1D0E06F214361137D35D1ED4EDE67 /* FIRMessagingRmqManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingRmqManager.m; path = FirebaseMessaging/Sources/FIRMessagingRmqManager.m; sourceTree = ""; }; + 6F530CD2447E7BB4E8F245B5578D0E43 /* FIRMessagingAuthKeychain.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingAuthKeychain.m; path = FirebaseMessaging/Sources/Token/FIRMessagingAuthKeychain.m; sourceTree = ""; }; + 707F66161F44DCDEE17FC7C063562F45 /* image_picker_ios-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "image_picker_ios-Info.plist"; sourceTree = ""; }; + 70B2477B7080994FF019740F97FDA027 /* FIRLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRLogger.m; path = FirebaseCore/Sources/FIRLogger.m; sourceTree = ""; }; + 71BEE6C7B8B888271C132B6206500966 /* FIRInstallationsErrorUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsErrorUtil.m; path = FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m; sourceTree = ""; }; + 71C8A4AF101980DA93A8A45F8C55DFA2 /* GoogleDataTransport.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = GoogleDataTransport.modulemap; sourceTree = ""; }; + 71CDF1D9C3D3B35FD852BBFCF671E4B6 /* GULAppDelegateSwizzler_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULAppDelegateSwizzler_Private.h; path = GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h; sourceTree = ""; }; + 727E3D670FEDA09567F4E93499135B7E /* FBLPromise+Do.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Do.h"; path = "Sources/FBLPromises/include/FBLPromise+Do.h"; sourceTree = ""; }; + 72C335FC7A27042501497C43922F7C50 /* FIRInstallationsItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsItem.m; path = FirebaseInstallations/Source/Library/FIRInstallationsItem.m; sourceTree = ""; }; + 72E84C770071D5A1531FAE5D14D85044 /* FIRInstallationsAPIService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsAPIService.h; path = FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h; sourceTree = ""; }; + 73215A0276358893231379269AE806A0 /* flutter_local_notifications.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = flutter_local_notifications.podspec; path = "../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/flutter_local_notifications.podspec"; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 739528119751A21100A633EC4AFD6198 /* FIROptions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptions.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h; sourceTree = ""; }; + 74253B13C3296B401730EDF3CA4B17C1 /* FIRInstallationsErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsErrors.h; path = FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h; sourceTree = ""; }; + 75A09089BD5480957D6E683E7B8EEEFA /* GoogleDataTransport-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "GoogleDataTransport-Info.plist"; sourceTree = ""; }; + 75CF387A098437DDEB77C4DD2B48D012 /* firebase_messaging-firebase_messaging_Privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "firebase_messaging-firebase_messaging_Privacy"; path = firebase_messaging_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 75D435FE4E37C337A7F1C57E230D8EBD /* flutter_local_notifications.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = flutter_local_notifications.release.xcconfig; sourceTree = ""; }; + 7658FDF5AEDDE8CAA80B12334DDD9D37 /* GoogleDataTransport.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleDataTransport.release.xcconfig; sourceTree = ""; }; + 768975E636D1D2FB85622FB67DB04E5A /* image_picker_ios */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = image_picker_ios; path = image_picker_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 76C1F6C5D89AD24DC65E947B2C95504E /* external_prequest_context.nanopb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = external_prequest_context.nanopb.h; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h; sourceTree = ""; }; + 77574C1B35FAEFA284EB091A05D3777F /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = FirebaseInstallations/Source/Library/Resources/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 778F816687F31D011CF7B8600D15C99C /* FIRBundleUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRBundleUtil.h; path = FirebaseCore/Sources/FIRBundleUtil.h; sourceTree = ""; }; + 77E4E0DF346BC55702A7F97C83759EB7 /* FIRAnalyticsConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAnalyticsConfiguration.h; path = FirebaseCore/Sources/FIRAnalyticsConfiguration.h; sourceTree = ""; }; + 78A647CF2AA2FEDD71CFDAB7BAA6CB01 /* GDTCOREventDropReason.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREventDropReason.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h; sourceTree = ""; }; + 78CF3937473E3F59F7E47C945F33DB50 /* FirebaseCoreInternal.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCoreInternal.debug.xcconfig; sourceTree = ""; }; + 78F891CC63C36BCCAE34673B49F6DD9D /* FIRMessagingTopicsCommon.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingTopicsCommon.h; path = FirebaseMessaging/Sources/FIRMessagingTopicsCommon.h; sourceTree = ""; }; + 79F077D532D1FC3E22DAC2178F2B93DF /* FLTFirebasePlugin.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTFirebasePlugin.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/include/firebase_core/FLTFirebasePlugin.h"; sourceTree = ""; }; + 7A4D3DB3BE1854CAF9DDABE31710F76C /* FIRLoggerLevel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLoggerLevel.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h; sourceTree = ""; }; + 7B07CCA749AC3691235E002653AA08F8 /* GULNetworkMessageCode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkMessageCode.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h; sourceTree = ""; }; + 7BB7063CC89B497ABCC22BCC4F19BA33 /* FIRInstallationsErrorUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsErrorUtil.h; path = FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h; sourceTree = ""; }; + 7C871D09740CE9D74171701136D65B99 /* Converters.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = Converters.m; path = "../../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/Classes/Converters.m"; sourceTree = ""; }; + 7D0ECCE4F5783E4482638C77ECFF4F5B /* GoogleUtilities.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleUtilities.debug.xcconfig; sourceTree = ""; }; + 7DD9D9497462C5FEAB0716591373B13F /* nanopb.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = nanopb.modulemap; sourceTree = ""; }; + 7E173B14DD49E212545D1962FACBA586 /* GDTCOREventDataObject.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREventDataObject.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h; sourceTree = ""; }; + 7ECD27E226247CC6BEE22DBFBF905F60 /* FBLPromise+Recover.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Recover.m"; path = "Sources/FBLPromises/FBLPromise+Recover.m"; sourceTree = ""; }; + 7F9B3EFD7A0DCF699AA75614DCFE5FFE /* PromisesObjC.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = PromisesObjC.modulemap; sourceTree = ""; }; + 7FA1EE3150AB7E2D7A76E646E7CA6C1E /* Pods-Runner-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Runner-resources.sh"; sourceTree = ""; }; + 8117DDCAB0947EC036DA8BE1D942F629 /* PromisesObjC.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PromisesObjC.debug.xcconfig; sourceTree = ""; }; + 817671F15D4B947F617BD4EE8ACFC278 /* Pods-RunnerTests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-RunnerTests-Info.plist"; sourceTree = ""; }; + 832AE400756F88C7AF9B23A8DE12970F /* firebase_core.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = firebase_core.podspec; path = "../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core.podspec"; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 836799D7AEDE4394FF12B9184A5D77E7 /* FirebaseCoreInternal-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseCoreInternal-prefix.pch"; sourceTree = ""; }; + 83C495C7955782B478F1F6B5A9B7E1CF /* GoogleDataTransport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GoogleDataTransport.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h; sourceTree = ""; }; + 84F8E1FB429C5EB93170E449E74D75B1 /* FBLPromisePrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromisePrivate.h; path = Sources/FBLPromises/include/FBLPromisePrivate.h; sourceTree = ""; }; + 850D0BDD3B07A173617227FD60A6231C /* GDTCORReachability.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORReachability.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h; sourceTree = ""; }; + 85297D57D31AF535B35107FA3534855A /* FLTFirebaseMessagingPlugin.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLTFirebaseMessagingPlugin.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m"; sourceTree = ""; }; + 856B5CD56F194FAD26EA91620B66D614 /* GoogleDataTransport */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GoogleDataTransport; path = GoogleDataTransport.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 857B278AF026E36C0BD658D6411E29FA /* FLTPHPickerSaveImageToPathOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTPHPickerSaveImageToPathOperation.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTPHPickerSaveImageToPathOperation.h"; sourceTree = ""; }; + 8634CC3175F30B9D18008895B3D338AC /* FIRMessagingRemoteNotificationsProxy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingRemoteNotificationsProxy.m; path = FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.m; sourceTree = ""; }; + 8664F6601EE686C6DBC6F3C7E5078272 /* NSError+FIRMessaging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSError+FIRMessaging.m"; path = "FirebaseMessaging/Sources/NSError+FIRMessaging.m"; sourceTree = ""; }; + 8758A56177F57A2EE30894AA6F81B31A /* Pods-RunnerTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-RunnerTests-dummy.m"; sourceTree = ""; }; + 87934EF8F3D60D9A8C773E4D2A0BA3B3 /* FIRCurrentDateProvider.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRCurrentDateProvider.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h; sourceTree = ""; }; + 886C3E05AA567BEB1219A0D5E1FD0E26 /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Extension/FirebaseCoreInternal.h; sourceTree = ""; }; + 895B93138E15C0598E60030F41FD9104 /* ActionEventSink.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = ActionEventSink.m; path = "../../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/Classes/ActionEventSink.m"; sourceTree = ""; }; + 896D97FE0D7AA3609F1D1DB35572DC14 /* FirebaseCore-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseCore-Info.plist"; sourceTree = ""; }; + 8976EF86AC0380FF046DC73A94C240D5 /* FirebaseMessaging.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseMessaging.modulemap; sourceTree = ""; }; + 89E70F54AFC72D650C16A032C725BCD9 /* FIRMessagingCheckinPreferences.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingCheckinPreferences.h; path = FirebaseMessaging/Sources/Token/FIRMessagingCheckinPreferences.h; sourceTree = ""; }; + 8A079A9004A27A365C06CB4DA95B4015 /* flutter_local_notifications-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "flutter_local_notifications-Info.plist"; sourceTree = ""; }; + 8A432929F7E93D3E1AA06A4A8668C699 /* Pods-RunnerTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-RunnerTests-acknowledgements.markdown"; sourceTree = ""; }; + 8A65DC251AC8459E96CF62A9A28D7FA9 /* FIRMessagingPersistentSyncMessage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingPersistentSyncMessage.m; path = FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.m; sourceTree = ""; }; + 8AEEA5FC7114C4A84FE61786766702D8 /* GULNetwork.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetwork.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h; sourceTree = ""; }; + 8BB937B1C0DFFCF92F41861C2BC54DDA /* FirebaseCore-FirebaseCore_Privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "FirebaseCore-FirebaseCore_Privacy"; path = FirebaseCore_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 8C201419AAEB1684E8D3357D88541EC5 /* GDTCOREndpoints_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREndpoints_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h; sourceTree = ""; }; + 8C31E883DF59327EFA2F3C02699CCA15 /* GDTCORMetricsController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORMetricsController.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsController.h; sourceTree = ""; }; + 8C334D9E95131AD50108A1C67E238989 /* FirebaseMessaging-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseMessaging-dummy.m"; sourceTree = ""; }; + 8D10767A89F4C2717508593913943165 /* FIRConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRConfiguration.m; path = FirebaseCore/Sources/FIRConfiguration.m; sourceTree = ""; }; + 8D630B865AE0C8F8420AEEA5D9729BEA /* FIRComponentContainer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRComponentContainer.m; path = FirebaseCore/Sources/FIRComponentContainer.m; sourceTree = ""; }; + 8D8A24088A30A466B083BC03A5AE1101 /* FirebaseInstallations.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseInstallations.debug.xcconfig; sourceTree = ""; }; + 8DA801B2D8F4EC374CCF24A7CAA24A5D /* FIRMessagingRemoteNotificationsProxy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingRemoteNotificationsProxy.h; path = FirebaseMessaging/Sources/FIRMessagingRemoteNotificationsProxy.h; sourceTree = ""; }; + 8E0EE42F5223017E57B7B7D51B4CF1B4 /* GDTCORMetrics+GDTCCTSupport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GDTCORMetrics+GDTCCTSupport.m"; path = "GoogleDataTransport/GDTCCTLibrary/GDTCORMetrics+GDTCCTSupport.m"; sourceTree = ""; }; + 8E186EAC5470DCC01B54AD829AB67040 /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Extension/FIRComponentContainer.h; sourceTree = ""; }; + 8E3D3451D357BAC83914C1402577267F /* FIRHeartbeatLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatLogger.h; path = FirebaseCore/Extension/FIRHeartbeatLogger.h; sourceTree = ""; }; + 8E8FEF536CAF0C03226B8AE23FE454C1 /* FIRMessaging_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessaging_Private.h; path = FirebaseMessaging/Sources/FIRMessaging_Private.h; sourceTree = ""; }; + 8E9255CA321EDC93153298BF92D5B4C9 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; name = LICENSE; path = "../../../../../../../../.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/LICENSE"; sourceTree = ""; }; + 8FD58877AD51D8F920444C2D00B20F3D /* GDTCORUploadBatch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORUploadBatch.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h; sourceTree = ""; }; + 905B7DD657BA252E11F011C073B15B04 /* FIRInstallationsStoredItem.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsStoredItem.m; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m; sourceTree = ""; }; + 905E98607B71266F977964D0380B9E8F /* FIRMessagingPersistentSyncMessage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingPersistentSyncMessage.h; path = FirebaseMessaging/Sources/FIRMessagingPersistentSyncMessage.h; sourceTree = ""; }; + 908FF3C2F86633C7AE8EB9F4F1E80B9C /* FirebaseInstallations.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseInstallations.modulemap; sourceTree = ""; }; + 90E4953F898CE5FB797B791B5411722B /* FIRMessagingTokenManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingTokenManager.m; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.m; sourceTree = ""; }; + 9121522B9B5A12545EBB589A83BD8F78 /* GULKeychainUtils.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULKeychainUtils.m; path = GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m; sourceTree = ""; }; + 91281858E7C5C6A953ACFCCB0F0E8759 /* GULKeychainStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULKeychainStorage.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h; sourceTree = ""; }; + 916ED4F015F6F56B913472172EB23B0D /* FBLPromise+Race.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Race.m"; path = "Sources/FBLPromises/FBLPromise+Race.m"; sourceTree = ""; }; + 919FA6048D25DD3D403B87F067045348 /* FBLPromise+Then.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Then.m"; path = "Sources/FBLPromises/FBLPromise+Then.m"; sourceTree = ""; }; + 922274B4EC30676D7427163E9BB88BDB /* FIRMessagingAPNSInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingAPNSInfo.m; path = FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.m; sourceTree = ""; }; + 9245949F7AF50C5640000F79C1110624 /* FLTImagePickerMetaDataUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTImagePickerMetaDataUtil.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTImagePickerMetaDataUtil.h"; sourceTree = ""; }; + 925C2D5A764E37386204B256CA65AB8B /* FirebaseInstallations-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "FirebaseInstallations-Info.plist"; sourceTree = ""; }; + 92999C4A70B803D6BB4A68BBA0D010FE /* FIRHeartbeatLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRHeartbeatLogger.h; path = FirebaseCore/Extension/FIRHeartbeatLogger.h; sourceTree = ""; }; + 92A5185EE87E3B7A214986492CCC6B06 /* GULNetworkLoggerProtocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkLoggerProtocol.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h; sourceTree = ""; }; + 93320CABD301A5AEBACABF6E8637270F /* FIRConfiguration.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRConfiguration.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h; sourceTree = ""; }; + 936ACF7D90A1E6DAEEA75462AC5C9CCC /* FIRMessagingSyncMessageManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingSyncMessageManager.m; path = FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.m; sourceTree = ""; }; + 936F09821C7EE0C3CD7F82890DB3A2CD /* GDTCORReachability_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORReachability_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h; sourceTree = ""; }; + 93CE9B2E15F0CFDDF3305716F26E8467 /* FirebaseInstallations-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseInstallations-dummy.m"; sourceTree = ""; }; + 93E585DF573298497CD9445A79B513D8 /* FLTImagePickerImageUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTImagePickerImageUtil.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTImagePickerImageUtil.h"; sourceTree = ""; }; + 942ACCA965CADB64D429066DA899D930 /* GULKeychainStorage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULKeychainStorage.m; path = GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m; sourceTree = ""; }; + 94449CA47C2641CC67085CB779439A41 /* FIRFirebaseUserAgent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRFirebaseUserAgent.m; path = FirebaseCore/Sources/FIRFirebaseUserAgent.m; sourceTree = ""; }; + 94918A4BBE2FA240BB3A089559EE38F4 /* ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist"; sourceTree = ""; }; + 94EBBDCB1362A8DB35DD72A83BCE41D5 /* FIRMessagingAuthService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingAuthService.m; path = FirebaseMessaging/Sources/Token/FIRMessagingAuthService.m; sourceTree = ""; }; + 957B5DFE330996813A28975B2930348E /* ResourceBundle-image_picker_ios_privacy-image_picker_ios-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-image_picker_ios_privacy-image_picker_ios-Info.plist"; sourceTree = ""; }; + 95C81102A4DAA71473683800CEF5618C /* Flutter.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = Flutter.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9608F18BDF2DDE520187B9B5D6E6D2A4 /* HeartbeatLoggingTestUtils.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatLoggingTestUtils.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift; sourceTree = ""; }; + 965331C3BB09EADB3C0D9516C974726B /* GDTCORClock.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORClock.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h; sourceTree = ""; }; + 969F41146FA5CA010B9D53DA3F128112 /* firebase_messaging-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "firebase_messaging-Info.plist"; sourceTree = ""; }; + 97EF58920BA75188BEFB815F403ECFD7 /* Firebase.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Firebase.debug.xcconfig; sourceTree = ""; }; + 9867C191C8BCE953F2C1239417D48C59 /* FBLPromise+Any.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Any.h"; path = "Sources/FBLPromises/include/FBLPromise+Any.h"; sourceTree = ""; }; + 986A3F2324959A8B87BB0F95403C0DB4 /* GDTCORMetrics+GDTCCTSupport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GDTCORMetrics+GDTCCTSupport.h"; path = "GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h"; sourceTree = ""; }; + 9896FC50EDA315757C5C60709679C840 /* FIRComponentType.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRComponentType.m; path = FirebaseCore/Sources/FIRComponentType.m; sourceTree = ""; }; + 98DB6F70F9386301F5C36CD6C1299D73 /* FBLPromise+Async.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Async.m"; path = "Sources/FBLPromises/FBLPromise+Async.m"; sourceTree = ""; }; + 99065A5299D40284C591F13F428CCA1A /* FIRMessagingContextManagerService.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingContextManagerService.h; path = FirebaseMessaging/Sources/FIRMessagingContextManagerService.h; sourceTree = ""; }; + 9AC7C482E6D07C1D873A78BAD801C86A /* FIROptionsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIROptionsInternal.h; path = FirebaseCore/Sources/FIROptionsInternal.h; sourceTree = ""; }; + 9B0344A89EE65F8D04A56A2B0A15E832 /* FIRVersion.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRVersion.m; path = FirebaseCore/Sources/FIRVersion.m; sourceTree = ""; }; + 9B06B15554EC98005C5A2A6E4F9A4503 /* GDTCORClock.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORClock.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORClock.m; sourceTree = ""; }; + 9B48F659C78E38331874678992458C9B /* HeartbeatStorage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatStorage.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift; sourceTree = ""; }; + 9BB83D91F5873A1F19C583E5BC73CB30 /* Converters.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Converters.h; path = "../../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/Classes/Converters.h"; sourceTree = ""; }; + 9D925A34FCE9DF5AF00DD4BB47713016 /* FirebaseCore.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseCore.release.xcconfig; sourceTree = ""; }; + 9D929313305FB6B3C350F1CCF65FFEA9 /* firebase_core.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = firebase_core.release.xcconfig; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9E39F1849E3712A9D9DFEB11809CD4F8 /* FIRInstallationsStoredAuthToken.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsStoredAuthToken.m; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m; sourceTree = ""; }; + 9EA4EC1164AD4A64AD408A4F74ECCD8B /* GULAppEnvironmentUtil.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULAppEnvironmentUtil.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h; sourceTree = ""; }; + 9EFF6746B2289C5FD36C9BC6742995F1 /* FBLPromise+Recover.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Recover.h"; path = "Sources/FBLPromises/include/FBLPromise+Recover.h"; sourceTree = ""; }; + 9FFE58E8153EEA5BBD4ADEA1792F2C39 /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Extension/FIRComponent.h; sourceTree = ""; }; + A06777B4DB78BB55C72E6640E8BA41DE /* FIRInstallationsIIDTokenStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsIIDTokenStore.h; path = FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h; sourceTree = ""; }; + A15DFB7CC7A259F61E840FBA0257AABA /* GULNetworkURLSession.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkURLSession.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h; sourceTree = ""; }; + A17B442DCEB9C47D544B82CE2BFDB986 /* GULLoggerCodes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULLoggerCodes.h; path = GoogleUtilities/Common/GULLoggerCodes.h; sourceTree = ""; }; + A1BD49BD040680F98EB5578FF93E0C8B /* messages.g.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = messages.g.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/messages.g.m"; sourceTree = ""; }; + A28ECC14C6767FD5BF201D0A0585F63A /* FIRTimestamp.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRTimestamp.m; path = FirebaseCore/Sources/FIRTimestamp.m; sourceTree = ""; }; + A2DC8CBC904B18E1936ED362DFA6CCB2 /* FIRMessagingContextManagerService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingContextManagerService.m; path = FirebaseMessaging/Sources/FIRMessagingContextManagerService.m; sourceTree = ""; }; + A38E222418E1BD45495FCA32F1873620 /* FBLPromise+Timeout.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Timeout.h"; path = "Sources/FBLPromises/include/FBLPromise+Timeout.h"; sourceTree = ""; }; + A502B0A40F92792DB2223688F14EF403 /* messages.g.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = messages.g.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/include/firebase_core/messages.g.h"; sourceTree = ""; }; + A5F3FE81EB27FB2162597E4C38CF7A2B /* GDTCORConsoleLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORConsoleLogger.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h; sourceTree = ""; }; + A627709EDE767EA9D58552E6AD1A466D /* ResourceBundle-nanopb_Privacy-nanopb-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-nanopb_Privacy-nanopb-Info.plist"; sourceTree = ""; }; + A67F9CA5CA48ED7EC5EC8BDCEBA8414F /* FBLPromise+Always.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Always.m"; path = "Sources/FBLPromises/FBLPromise+Always.m"; sourceTree = ""; }; + A68052862F5BAE7158CA697BF80807F4 /* FIRMessagingSyncMessageManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingSyncMessageManager.h; path = FirebaseMessaging/Sources/FIRMessagingSyncMessageManager.h; sourceTree = ""; }; + A6B1DDCFBD3CF418AC193FE5F753B7A0 /* GDTCORMetrics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORMetrics.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h; sourceTree = ""; }; + A773AD7AC2BDC4D59F7D44F165DDE579 /* FIRInstallationsAPIService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsAPIService.m; path = FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m; sourceTree = ""; }; + A7CC628CA6581A6F7BDABA0490622A6B /* firebase_core-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "firebase_core-prefix.pch"; sourceTree = ""; }; + A8FDBAA5DB30273D3A49EC23FF64001E /* Pods-Runner-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Runner-acknowledgements.markdown"; sourceTree = ""; }; + A98F7B52E50AE5E6285A9A90E0429AFF /* FirebaseCoreInternal.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseCoreInternal.modulemap; sourceTree = ""; }; + AA24167E8696ACD1B99C485B3A3EBF8F /* ResourceBundle-firebase_messaging_Privacy-firebase_messaging-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-firebase_messaging_Privacy-firebase_messaging-Info.plist"; sourceTree = ""; }; + AA3D5E76E8D7DF4C02A1061D71983979 /* GDTCORTransport_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTransport_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h; sourceTree = ""; }; + AAD3BC28C09DA52886D6B8681F7F5FBD /* GULUserDefaults.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULUserDefaults.m; path = GoogleUtilities/UserDefaults/GULUserDefaults.m; sourceTree = ""; }; + AAD8085D8AFEEB3417EF649424648779 /* FIRAnalyticsConfiguration.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRAnalyticsConfiguration.m; path = FirebaseCore/Sources/FIRAnalyticsConfiguration.m; sourceTree = ""; }; + AADC5B5B4544956F7DD190C8434971BB /* FirebaseCoreInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCoreInternal.h; path = FirebaseCore/Extension/FirebaseCoreInternal.h; sourceTree = ""; }; + AAF898F203112836152F0FEF6B14DF2B /* FIRMessagingPendingTopicsList.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingPendingTopicsList.m; path = FirebaseMessaging/Sources/FIRMessagingPendingTopicsList.m; sourceTree = ""; }; + AB598EB2A3C10C454BDF7F082CBF13E2 /* FIRInstallationsBackoffController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsBackoffController.m; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m; sourceTree = ""; }; + ABA0FD5A71EE712584651CF55F1558E6 /* GULAppEnvironmentUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULAppEnvironmentUtil.m; path = GoogleUtilities/Environment/GULAppEnvironmentUtil.m; sourceTree = ""; }; + AC350D7331C62B3D5200AEB896375605 /* FirebaseCore-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseCore-umbrella.h"; sourceTree = ""; }; + AC37499B722B10926F29985F2F626B61 /* FIRInteropEventNames.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInteropEventNames.h; path = Interop/Analytics/Public/FIRInteropEventNames.h; sourceTree = ""; }; + AC70B4B71CC9B390381A08D1429D6519 /* GDTCORStorageEventSelector.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORStorageEventSelector.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m; sourceTree = ""; }; + ADD75767BCDDF56305838AA3576C0D6A /* firebase_messaging.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = firebase_messaging.release.xcconfig; sourceTree = ""; }; + AE06A6A60D50DA808B0072CE08DCC3E5 /* pb_encode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb_encode.h; sourceTree = ""; }; + AF370489BA290D16F746A5FC144C8ED5 /* FBLPromise+Retry.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Retry.h"; path = "Sources/FBLPromises/include/FBLPromise+Retry.h"; sourceTree = ""; }; + B04FDD8DDB07A0183A4E103A9D101302 /* FLTFirebasePluginRegistry.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTFirebasePluginRegistry.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources/firebase_core/include/firebase_core/FLTFirebasePluginRegistry.h"; sourceTree = ""; }; + B06CC20D8B264C65422A00B2ECA1BC21 /* FIRAnalyticsInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRAnalyticsInterop.h; path = Interop/Analytics/Public/FIRAnalyticsInterop.h; sourceTree = ""; }; + B0B6501341FD6783C6874C54AB31A9CF /* FirebaseMessaging-FirebaseMessaging_Privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "FirebaseMessaging-FirebaseMessaging_Privacy"; path = FirebaseMessaging_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + B0ECBAFC8D346176B5C9430AAC93D937 /* FIRMessaging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessaging.m; path = FirebaseMessaging/Sources/FIRMessaging.m; sourceTree = ""; }; + B193AA1062E3BDA9FD9F681F8B33A4FB /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; }; + B1DA64C7F3DEAD8DF2E9C85AFE1682E7 /* GULNetworkURLSession.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetworkURLSession.m; path = GoogleUtilities/Network/GULNetworkURLSession.m; sourceTree = ""; }; + B2387C526D96360EC27318C6A56C9530 /* GoogleDataTransport-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "GoogleDataTransport-umbrella.h"; sourceTree = ""; }; + B25ED3E90C5098A71F9E5478214441B0 /* FBLPromise+All.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+All.m"; path = "Sources/FBLPromises/FBLPromise+All.m"; sourceTree = ""; }; + B2CC463A480A8EE4BB1C8BAB7EC6A811 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Extension/FIRLogger.h; sourceTree = ""; }; + B2FEF990F569E7CC05C3AFED1D83F505 /* FIRMessagingDefines.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingDefines.h; path = FirebaseMessaging/Sources/FIRMessagingDefines.h; sourceTree = ""; }; + B371BCA4519038B554B5CE8AE4330B6C /* GDTCORPlatform.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORPlatform.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h; sourceTree = ""; }; + B3B80750D3B364B9E166CCEB905EACF7 /* HeartbeatsBundle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeartbeatsBundle.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift; sourceTree = ""; }; + B43874C6CBB50E7134FBEC24BABFE14F /* GoogleUtilities */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = GoogleUtilities; path = GoogleUtilities.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B4671189B401A63804AEDF5B26C05A56 /* GDTCCTNanopbHelpers.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCCTNanopbHelpers.h; path = GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h; sourceTree = ""; }; + B49E2EBD1B89DC348FB58AD368278DA1 /* GDTCORAssert.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORAssert.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h; sourceTree = ""; }; + B4BBEFB2C73F81F446CAC134CC2546E4 /* FBLPromise+Catch.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Catch.h"; path = "Sources/FBLPromises/include/FBLPromise+Catch.h"; sourceTree = ""; }; + B512FE666020CE015DAEDEB8CBABCAAB /* GDTCORTargets.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTargets.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h; sourceTree = ""; }; + B543F786F7AC662A9B3B4A59604BE673 /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Extension/FIRComponent.h; sourceTree = ""; }; + B5BCF95BE69FDCDB288B6DD2D650398F /* FIRInstallationsIIDTokenStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsIIDTokenStore.m; path = FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m; sourceTree = ""; }; + B5D20E78EE54D5C48ACEEDD6D89CEA6B /* FIRMessagingTokenManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingTokenManager.h; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenManager.h; sourceTree = ""; }; + B60A2D97A08A79D950561A5CC0A9494B /* GDTCORUploader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORUploader.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h; sourceTree = ""; }; + B62F8176908F7C7B39EEA7BA2DF3C364 /* FLTImagePickerImageUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLTImagePickerImageUtil.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerImageUtil.m"; sourceTree = ""; }; + B646BBDFE3CEA2C26F26ADD034CD74D7 /* FirebaseInstallations.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseInstallations.h; path = FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h; sourceTree = ""; }; + B6937D9D9C997E2BA32C1EA4575FD8BA /* PromisesObjC.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = PromisesObjC.release.xcconfig; sourceTree = ""; }; + B6A067FEC2F7D21562E67BC5305FB65D /* FIRFirebaseUserAgent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRFirebaseUserAgent.h; path = FirebaseCore/Sources/FIRFirebaseUserAgent.h; sourceTree = ""; }; + B6E1889709D64FDA47F85E4DA3319BCE /* GDTCORConsoleLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORConsoleLogger.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m; sourceTree = ""; }; + B813F4D2F842FDC08628BEC65FF4ED40 /* FIRLibrary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLibrary.h; path = FirebaseCore/Extension/FIRLibrary.h; sourceTree = ""; }; + B83C30F28A2D3A9276FE5DE6F46E1766 /* FBLPromise+Reduce.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Reduce.h"; path = "Sources/FBLPromises/include/FBLPromise+Reduce.h"; sourceTree = ""; }; + B903D4DE875B151937BA3E87E4A04205 /* image_picker_ios.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = image_picker_ios.release.xcconfig; sourceTree = ""; }; + B938FBAF03B6ED7A749BE73D476B7B15 /* GDTCORTransformer_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORTransformer_Private.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h; sourceTree = ""; }; + B94BEE8D0E30393C9D4D6CBA57B8D263 /* pb_common.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = pb_common.h; sourceTree = ""; }; + BA0D0C8AF5CDA0A632B05B589AF94132 /* FIRLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRLogger.h; path = FirebaseCore/Extension/FIRLogger.h; sourceTree = ""; }; + BA6F9C82EF49DC1505AB92789AC3C133 /* FirebaseCoreInternal-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseCoreInternal-dummy.m"; sourceTree = ""; }; + BB67577D73012DFE877DCAA6A5A0CFBD /* GoogleDataTransport-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "GoogleDataTransport-dummy.m"; sourceTree = ""; }; + BCAEF4B6CC33BA3FDC7A5EFC1081A150 /* FIRComponent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponent.h; path = FirebaseCore/Extension/FIRComponent.h; sourceTree = ""; }; + BCC84BDE7260B712B097666E169A193C /* Pods-Runner-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Runner-umbrella.h"; sourceTree = ""; }; + BD0A6B8D25BE47384E9E9BDED1204071 /* FIRMessaging+ExtensionHelper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRMessaging+ExtensionHelper.h"; path = "FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessaging+ExtensionHelper.h"; sourceTree = ""; }; + BD2F62558CF728467E423DE871BCE8A8 /* GDTCOREvent+GDTCCTSupport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "GDTCOREvent+GDTCCTSupport.m"; path = "GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m"; sourceTree = ""; }; + BD3BD1D65B117C25A6F2FA906D597A39 /* ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist"; sourceTree = ""; }; + BD75CD0508AD16FB45C1DD6842B85A77 /* FirebaseCoreInternal-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "FirebaseCoreInternal-umbrella.h"; sourceTree = ""; }; + BDCA34BFBDAE2A8CD8404ECE64D14D00 /* GDTCORUploadCoordinator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORUploadCoordinator.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h; sourceTree = ""; }; + BDF87156BDDD108EE55A558C722D79EA /* FIRMessagingTokenStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingTokenStore.h; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenStore.h; sourceTree = ""; }; + BDFC14A8280221C515A9AFE2CE99D65B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = spm_resources/PrivacyInfo.xcprivacy; sourceTree = ""; }; + BE28E7364E1EFEE4FDCAE35B7550F06D /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Extension/FIRComponentType.h; sourceTree = ""; }; + BEF18B32324D7103B23F4A901C785607 /* FIRInstallationsIIDStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsIIDStore.m; path = FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m; sourceTree = ""; }; + BEF781DC1D6001BD3E1397BCE96B912B /* ImagePickerPlugin.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; name = ImagePickerPlugin.modulemap; path = "../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/include/ImagePickerPlugin.modulemap"; sourceTree = ""; }; + BF34DE84DA4E4042C6880D4E5D0F35DC /* FIRMessagingPubSub.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingPubSub.h; path = FirebaseMessaging/Sources/FIRMessagingPubSub.h; sourceTree = ""; }; + BFD12588B0D0F7405A96DE2EA7396A34 /* me.nanopb.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = me.nanopb.h; path = FirebaseMessaging/Sources/Protogen/nanopb/me.nanopb.h; sourceTree = ""; }; + C00EBC7A4974174FA9C5F1FBAA0E7308 /* FBLPromise+All.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+All.h"; path = "Sources/FBLPromises/include/FBLPromise+All.h"; sourceTree = ""; }; + C020E1647C73F291B7B8232080B21AB5 /* pb_common.c */ = {isa = PBXFileReference; includeInIndex = 1; path = pb_common.c; sourceTree = ""; }; + C0C2B36D833E272B8DEBDB540B84847A /* FIRMessagingInterop.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingInterop.h; path = FirebaseMessaging/Interop/FIRMessagingInterop.h; sourceTree = ""; }; + C150D02EC9C5D375CA88FE501C84AC6D /* FIRMessagingTopicOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingTopicOperation.m; path = FirebaseMessaging/Sources/FIRMessagingTopicOperation.m; sourceTree = ""; }; + C23D989186917D690D6E35EAEE950DAC /* GDTCORLogSourceMetrics.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORLogSourceMetrics.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORLogSourceMetrics.m; sourceTree = ""; }; + C2758FE22DBE0DF635FED68706680916 /* FIRInstallationsStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsStore.h; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h; sourceTree = ""; }; + C40988385EFE5D8754088D1EBBDF7BAD /* FIRInstallationsHTTPError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsHTTPError.m; path = FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m; sourceTree = ""; }; + C521DDFFCA95CC5736F10248D9812971 /* FBLPromise+Then.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Then.h"; path = "Sources/FBLPromises/include/FBLPromise+Then.h"; sourceTree = ""; }; + C586DD178A496B2B6864BA1A72B66182 /* GDTCORProductData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORProductData.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h; sourceTree = ""; }; + C76A440189B37018CF064EDA9E1007B9 /* flutter_local_notifications-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "flutter_local_notifications-umbrella.h"; sourceTree = ""; }; + C7C11EC9AC85A39FC2DA6B03D4EA2A36 /* FLTImagePickerMetaDataUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLTImagePickerMetaDataUtil.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerMetaDataUtil.m"; sourceTree = ""; }; + C801FDA12C657DA4D652A2352A705D04 /* NSError+FIRMessaging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSError+FIRMessaging.h"; path = "FirebaseMessaging/Sources/NSError+FIRMessaging.h"; sourceTree = ""; }; + C91F16BB997A1432E3E845FB58E5419A /* cct.nanopb.c */ = {isa = PBXFileReference; includeInIndex = 1; name = cct.nanopb.c; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c; sourceTree = ""; }; + C9232E4B48A37102EEF6856FD90C953A /* GDTCORStorageEventSelector.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORStorageEventSelector.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h; sourceTree = ""; }; + C94ADD90B6B07B25ED550BCBE0EC2FB7 /* GULLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULLogger.m; path = GoogleUtilities/Logger/GULLogger.m; sourceTree = ""; }; + CB5EA4244DC66422A84FB2F4C7803614 /* NSDictionary+FIRMessaging.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+FIRMessaging.m"; path = "FirebaseMessaging/Sources/NSDictionary+FIRMessaging.m"; sourceTree = ""; }; + CB675655530559C4E017C19318F89546 /* FIRMessagingBackupExcludedPlist.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingBackupExcludedPlist.h; path = FirebaseMessaging/Sources/Token/FIRMessagingBackupExcludedPlist.h; sourceTree = ""; }; + CB9C404F2038079531D51B37205F6FA6 /* GDTCOREvent+GDTMetricsSupport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GDTCOREvent+GDTMetricsSupport.h"; path = "GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h"; sourceTree = ""; }; + CCB99A06CCC77919B7446EEF57659E87 /* GDTCORFlatFileStorage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORFlatFileStorage.h; path = GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h; sourceTree = ""; }; + CCC1B87A6B369D883DC59DA1A876FB48 /* GULAppDelegateSwizzler.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULAppDelegateSwizzler.h; path = GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h; sourceTree = ""; }; + CCF6202512922098E47F97220393B797 /* GDTCCTUploadOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCCTUploadOperation.m; path = GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m; sourceTree = ""; }; + CCFCE0BE21B0FC0352C603586D9642FD /* FirebaseInstallationsInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseInstallationsInternal.h; path = FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h; sourceTree = ""; }; + CD22F9E01ED5FA1020DE6283E509A9CE /* FIRMessaging+ExtensionHelper.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FIRMessaging+ExtensionHelper.m"; path = "FirebaseMessaging/Sources/FIRMessaging+ExtensionHelper.m"; sourceTree = ""; }; + CE08696E0972B7E5F2A377E2874A05FE /* FBLPromise+Delay.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Delay.m"; path = "Sources/FBLPromises/FBLPromise+Delay.m"; sourceTree = ""; }; + CE9BD927B75EFA6B4F63E3EF7F76C142 /* GDTCCTNanopbHelpers.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCCTNanopbHelpers.m; path = GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m; sourceTree = ""; }; + CF05C45883497B3E21CA51BF8DE0F678 /* GDTCCTUploadOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCCTUploadOperation.h; path = GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h; sourceTree = ""; }; + CF172E90C36C492AB298888A29405014 /* FIRMessagingCode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingCode.h; path = FirebaseMessaging/Sources/FIRMessagingCode.h; sourceTree = ""; }; + CF25197F3272BC4554DD1795F4C0D9BE /* flutter_local_notifications-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "flutter_local_notifications-prefix.pch"; sourceTree = ""; }; + CF3313E1A4AAD2C8C90168A130ED02C8 /* GULMutableDictionary.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULMutableDictionary.h; path = GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h; sourceTree = ""; }; + CF581185566FAB365575D1B37BF1296C /* FIRInstallationsIDController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsIDController.h; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h; sourceTree = ""; }; + CFA56F7544C7A03823E1D2D749934BFC /* Pods-Runner-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Runner-frameworks.sh"; sourceTree = ""; }; + D0E98CC50462D87B324B0B4B3C712778 /* FBLPromise+Catch.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Catch.m"; path = "Sources/FBLPromises/FBLPromise+Catch.m"; sourceTree = ""; }; + D129CBF9B6659C2212C9D0E35165E9E3 /* FIRInstallations.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallations.h; path = FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h; sourceTree = ""; }; + D1E3607447AF036E85C9F1FF89B9B44E /* GDTCORPlatform.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORPlatform.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m; sourceTree = ""; }; + D2818DB76C14B8736924E987E37A9823 /* flutter_local_notifications */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = flutter_local_notifications; path = flutter_local_notifications.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D2C205268B2949B720B83A78AA2A2F6C /* GULNetworkInternal.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkInternal.h; path = GoogleUtilities/Network/GULNetworkInternal.h; sourceTree = ""; }; + D2DBBD201333C23533BD538E84DA3E09 /* GDTCORUploadCoordinator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORUploadCoordinator.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m; sourceTree = ""; }; + D3CBFEF9C55D8B8C77DC8B0311BBB9CE /* FBLPromise+Testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Testing.h"; path = "Sources/FBLPromises/include/FBLPromise+Testing.h"; sourceTree = ""; }; + D436772E65625479E300E56250E3F274 /* GULReachabilityMessageCode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULReachabilityMessageCode.h; path = GoogleUtilities/Reachability/GULReachabilityMessageCode.h; sourceTree = ""; }; + D4380D9849871F7D36C7E7CBA98E87EA /* FIRMessagingCheckinStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingCheckinStore.m; path = FirebaseMessaging/Sources/Token/FIRMessagingCheckinStore.m; sourceTree = ""; }; + D56C33CE6C883DF8D154067576FC8FCB /* GDTCOREventTransformer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREventTransformer.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h; sourceTree = ""; }; + D655DF7B1D831EAF390B40308E74B9A4 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = FirebaseCore/Internal/Sources/Resources/PrivacyInfo.xcprivacy; sourceTree = ""; }; + D6891EE2C0F69454EAE3D9E045FE3E1A /* FIRMessagingCheckinService.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingCheckinService.m; path = FirebaseMessaging/Sources/Token/FIRMessagingCheckinService.m; sourceTree = ""; }; + D703F68C62134D846E9AFE6B0B29AD69 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = "../../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/Resources/PrivacyInfo.xcprivacy"; sourceTree = ""; }; + D7B7454BF5334670ECF3A33191A92E6C /* FIRMessagingAPNSInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingAPNSInfo.h; path = FirebaseMessaging/Sources/Token/FIRMessagingAPNSInfo.h; sourceTree = ""; }; + D7D8E0360DD7C3C4C53443E53FB2D047 /* FIRMessagingTokenInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingTokenInfo.m; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenInfo.m; sourceTree = ""; }; + D8080290C8FF379AAFE127072282B83E /* FBLPromise+Retry.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Retry.m"; path = "Sources/FBLPromises/FBLPromise+Retry.m"; sourceTree = ""; }; + D889199081E3C4524D59D648514AF05C /* FirebaseCore-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "FirebaseCore-dummy.m"; sourceTree = ""; }; + D88ABCF86F232D838F567FDACBEB3FD3 /* FIRInstallationsItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsItem.h; path = FirebaseInstallations/Source/Library/FIRInstallationsItem.h; sourceTree = ""; }; + D908E95DE9E1E5FAA4F57148C5FC790B /* GDTCORMetricsMetadata.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORMetricsMetadata.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORMetricsMetadata.m; sourceTree = ""; }; + D95A493523FB2DFA4265B765F8BFA06E /* FIRInstallationsItem+RegisterInstallationAPI.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FIRInstallationsItem+RegisterInstallationAPI.h"; path = "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h"; sourceTree = ""; }; + DA922CF0D0D079AC32082A5020A72150 /* GDTCORDirectorySizeTracker.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORDirectorySizeTracker.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h; sourceTree = ""; }; + DB8C49B0B5734A01DE048CA85F1069EE /* FIRMessagingPubSub.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRMessagingPubSub.m; path = FirebaseMessaging/Sources/FIRMessagingPubSub.m; sourceTree = ""; }; + DB95A71164E10C96C48CA96BB0C2C871 /* FIRApp.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRApp.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h; sourceTree = ""; }; + DD77AADE9BB2391A80E5DE0B44F9B2C7 /* FIRComponentContainer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentContainer.h; path = FirebaseCore/Extension/FIRComponentContainer.h; sourceTree = ""; }; + DD8C8ACC853AF1B657D17AEC50E540A9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + DDAC6D191B54B707F402B200DA9BCCCF /* FirebaseCore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseCore.h; path = FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h; sourceTree = ""; }; + DE16863F43AFC398785AB95591472899 /* FIRInstallationsSingleOperationPromiseCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsSingleOperationPromiseCache.m; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m; sourceTree = ""; }; + DE501C91B85AD9DEF66B570B8F7C637B /* FLTImagePickerPlugin_Test.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FLTImagePickerPlugin_Test.h; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/include/image_picker_ios/FLTImagePickerPlugin_Test.h"; sourceTree = ""; }; + DEF857F1E2D5063DB5343E9A4F23F782 /* GULNetworkInfo.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GULNetworkInfo.m; path = GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m; sourceTree = ""; }; + DF1F5F4906A736BC65D87CBEDAFE1894 /* GDTCORRegistrar.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORRegistrar.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h; sourceTree = ""; }; + DF2202BFB27E7E8B535986D8ACA2A11A /* FLTImagePickerPhotoAssetUtil.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FLTImagePickerPhotoAssetUtil.m; path = "../../../../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources/image_picker_ios/FLTImagePickerPhotoAssetUtil.m"; sourceTree = ""; }; + DF76ABCF8FC780F5A09634D08E40A690 /* FIRInstallationsStoredAuthToken.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsStoredAuthToken.h; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h; sourceTree = ""; }; + E0DF8F36727B0D343DF681ED004FD2E6 /* FlutterLocalNotificationsPlugin.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FlutterLocalNotificationsPlugin.m; path = "../../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios/Classes/FlutterLocalNotificationsPlugin.m"; sourceTree = ""; }; + E18168F03FAF8DF950345F0DB50BFF92 /* GULNetworkInfo.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULNetworkInfo.h; path = GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h; sourceTree = ""; }; + E22BD45F6FB773C33141B618168C4A8F /* FIRTimestamp.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRTimestamp.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h; sourceTree = ""; }; + E2411C6C639146FA21E9291E20EB02BF /* GoogleUtilities.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = GoogleUtilities.release.xcconfig; sourceTree = ""; }; + E29FF4FADCEBFFF58991819DA709FC0E /* FBLPromise+Await.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Await.m"; path = "Sources/FBLPromises/FBLPromise+Await.m"; sourceTree = ""; }; + E2B63D462DB7F827C4B11FD51E4F8E2D /* FirebaseCore */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = FirebaseCore; path = FirebaseCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E2BA5760A60FB76A5D0DA6B6592378C9 /* FIRComponentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRComponentType.h; path = FirebaseCore/Extension/FIRComponentType.h; sourceTree = ""; }; + E5BF9CEDCABEB953A0F74A583477329D /* FIRMessagingAnalytics.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingAnalytics.h; path = FirebaseMessaging/Sources/FIRMessagingAnalytics.h; sourceTree = ""; }; + E61CC707F35A1D8DFF986E0272AE2433 /* FBLPromise.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FBLPromise.h; path = Sources/FBLPromises/include/FBLPromise.h; sourceTree = ""; }; + E6D3C3E840BD79066822FDA834733864 /* GDTCCTCompressionHelper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCCTCompressionHelper.h; path = GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h; sourceTree = ""; }; + E73067A4812023AA71C5F5DE2A7A1549 /* GULLoggerLevel.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GULLoggerLevel.h; path = GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h; sourceTree = ""; }; + E7E682D58A22915DE40E4BC2C50995BF /* NSDictionary+FIRMessaging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+FIRMessaging.h"; path = "FirebaseMessaging/Sources/NSDictionary+FIRMessaging.h"; sourceTree = ""; }; + E8613A3C37426EBD5058C1EACD29B4D3 /* firebase_core-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "firebase_core-umbrella.h"; sourceTree = ""; }; + E8A3A7295F345E685EABEEFE068CCEE6 /* GDTCCTURLSessionDataResponse.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCCTURLSessionDataResponse.h; path = GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h; sourceTree = ""; }; + E9C5F640AD2476216F4F542B0AF5E13C /* Pods-RunnerTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-RunnerTests.modulemap"; sourceTree = ""; }; + E9EDD23A28B53B116FCC2B249E7ABB62 /* GDTCORMetrics.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORMetrics.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORMetrics.m; sourceTree = ""; }; + EAA0F2B1CA18EB072F0B6672F56FF88C /* PromisesObjC-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "PromisesObjC-umbrella.h"; sourceTree = ""; }; + EAA203D51C6952F039B16DA1C6886296 /* GDTCORTransformer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORTransformer.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m; sourceTree = ""; }; + EBF3BFE26470C008E106EB355D9C4277 /* FIRVersion.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRVersion.h; path = FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h; sourceTree = ""; }; + ECE416D5B8F4153F022C16A087BF2E26 /* flutter_local_notifications-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "flutter_local_notifications-dummy.m"; sourceTree = ""; }; + ED62F9AF2BC8736E949B2CB879B6445D /* GDTCOREvent+GDTCCTSupport.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "GDTCOREvent+GDTCCTSupport.h"; path = "GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h"; sourceTree = ""; }; + EDD9A3C2E72FAF155EF4D0403E6D9C3F /* FIRInstallationsLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRInstallationsLogger.m; path = FirebaseInstallations/Source/Library/FIRInstallationsLogger.m; sourceTree = ""; }; + EDE3C6D61BC0AFA10BEE62B82A8CB6BC /* FirebaseMessaging.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FirebaseMessaging.debug.xcconfig; sourceTree = ""; }; + EF5E4FCAEC3D44A5DF86D667C0A1F738 /* GDTCORStorageProtocol.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCORStorageProtocol.h; path = GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h; sourceTree = ""; }; + EFE38C75A3D217CDE7B18F9027CC4F8F /* external_privacy_context.nanopb.c */ = {isa = PBXFileReference; includeInIndex = 1; name = external_privacy_context.nanopb.c; path = GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.c; sourceTree = ""; }; + F0C760C99840E9C0450409DDBC6761BA /* nanopb-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "nanopb-Info.plist"; sourceTree = ""; }; + F0C7EFBFF01CFAAB52BA74E6CB40CE2C /* image_picker_ios-image_picker_ios_privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "image_picker_ios-image_picker_ios_privacy"; path = image_picker_ios_privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + F15F7CD527312C51FC5532AFF29B0CCC /* FIRMessagingTopicOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingTopicOperation.h; path = FirebaseMessaging/Sources/FIRMessagingTopicOperation.h; sourceTree = ""; }; + F1A1B6D700EBB61E205BD7BFC87E2845 /* FIRInstallationsStoredItem.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRInstallationsStoredItem.h; path = FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h; sourceTree = ""; }; + F3047D3277103F27E21BE1D377E7FDA4 /* Heartbeat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Heartbeat.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift; sourceTree = ""; }; + F30DC71EBEC30BD542B7B8BAD2061FB1 /* FBLPromise.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FBLPromise.m; path = Sources/FBLPromises/FBLPromise.m; sourceTree = ""; }; + F3B74672DAE304DCA370B761FBD5B2D7 /* firebase_core */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = firebase_core; path = firebase_core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F4433BBACF71027F05BF2D7ECBC5470A /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; name = LICENSE; path = "../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/LICENSE"; sourceTree = ""; }; + F53C5B35436C00D610665FD9A52DA659 /* ResourceBundle-flutter_local_notifications_privacy-flutter_local_notifications-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-flutter_local_notifications_privacy-flutter_local_notifications-Info.plist"; sourceTree = ""; }; + F62A706AAE45E348C3A5AF903610CBA3 /* GDTCOREvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCOREvent.m; path = GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m; sourceTree = ""; }; + F67BA8239D8A9976F471301DA705FC65 /* GDTCCTCompressionHelper.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCCTCompressionHelper.m; path = GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m; sourceTree = ""; }; + F72DE1533AD7657E655356E31E3A5475 /* FIRHeartbeatLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRHeartbeatLogger.m; path = FirebaseCore/Sources/FIRHeartbeatLogger.m; sourceTree = ""; }; + F73AA961F4AEFF2B46B00AE435DF6BE3 /* GoogleDataTransport-GoogleDataTransport_Privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "GoogleDataTransport-GoogleDataTransport_Privacy"; path = GoogleDataTransport_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + F7DFFA85CEF0CB6E8D3932BE99635EB6 /* FBLPromise+Reduce.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "FBLPromise+Reduce.m"; path = "Sources/FBLPromises/FBLPromise+Reduce.m"; sourceTree = ""; }; + F846B09E79FE5A1BE2108540AD98A6B0 /* FIRMessagingTokenOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingTokenOperation.h; path = FirebaseMessaging/Sources/Token/FIRMessagingTokenOperation.h; sourceTree = ""; }; + F8547457089967DAC30C3130D4EDF7D1 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Runner.release.xcconfig"; sourceTree = ""; }; + F8E3D4F092146A52F08248A9674D2F43 /* FirebaseMessaging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseMessaging.h; path = FirebaseMessaging/Sources/Public/FirebaseMessaging/FirebaseMessaging.h; sourceTree = ""; }; + F9C0C8FF6D363C392626B70C996CB3B9 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = FirebaseCore/Sources/Resources/PrivacyInfo.xcprivacy; sourceTree = ""; }; + FA0D0444FDB3A5A4B215BC95A9FF00B9 /* FirebaseCore.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = FirebaseCore.modulemap; sourceTree = ""; }; + FA725D6547E13C230774CBE70FF3DCD1 /* ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist"; sourceTree = ""; }; + FA8650F57B8928F747DF6C8DAAADBA7A /* GDTCOREndpoints.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCOREndpoints.h; path = GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h; sourceTree = ""; }; + FB0D5A901EA4BB55EB4272787CA2B4B8 /* Firebase.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Firebase.release.xcconfig; sourceTree = ""; }; + FB1460C0D5E3BF3EFFDA6E70D347BD42 /* FIRMessagingExtensionHelper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingExtensionHelper.h; path = FirebaseMessaging/Sources/Public/FirebaseMessaging/FIRMessagingExtensionHelper.h; sourceTree = ""; }; + FB2298AE8D3CC3C6ABB941D9CB1CBA09 /* GDTCCTUploader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCCTUploader.m; path = GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m; sourceTree = ""; }; + FB3E0B1F27EBFF6B4823EDA87587A8A8 /* FIRMessagingLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FIRMessagingLogger.h; path = FirebaseMessaging/Sources/FIRMessagingLogger.h; sourceTree = ""; }; + FDDD8D05205C5EE7B1CC69B162A85388 /* firebase_core-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "firebase_core-dummy.m"; sourceTree = ""; }; + FE20B56087FB4F4CA7131763C35DDC67 /* WeakContainer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WeakContainer.swift; path = FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift; sourceTree = ""; }; + FE714E74EA2B7E26A7EDC9208B5BA435 /* GDTCCTUploader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = GDTCCTUploader.h; path = GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h; sourceTree = ""; }; + FE8579D48A79E1302D02298969B675E6 /* FirebaseMessaging.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = FirebaseMessaging.h; path = FirebaseMessaging/Sources/FirebaseMessaging.h; sourceTree = ""; }; + FF09DBF131ED32352049DD973E63FA75 /* FBLPromise+Race.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "FBLPromise+Race.h"; path = "Sources/FBLPromises/include/FBLPromise+Race.h"; sourceTree = ""; }; + FF44DE1588F3EB44D30CE17C5922D3C3 /* GDTCORDirectorySizeTracker.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = GDTCORDirectorySizeTracker.m; path = GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m; sourceTree = ""; }; + FF8D2EC06176343EF1EACEF6206CC015 /* FIRCurrentDateProvider.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = FIRCurrentDateProvider.m; path = FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m; sourceTree = ""; }; + FFE7D2BB92263A9180243E4881212E9B /* Flutter.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Flutter.debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 011DF66FFEC59ABF67BB667B58689AF2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1118996EB7A1A6AA5BC8EA75EB476CEB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 11A5CD70E56822C606053045D712429E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C47204FDE9B53CBCE9613B73579400F4 /* Foundation.framework in Frameworks */, + 4D01D550A60A382E2944308B17150B8A /* Security.framework in Frameworks */, + E68510190917732CC725615AA847A331 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1B468F5EEF27FF5C76D23AD996BAAC4E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4011B1E1709BDA346CBE3D582E7224ED /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 51B0830A8ADC47C7AAB55DE15719C24A /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 401E66DD45DCC4B0A97659CEE79BE8AC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0BF67FE9A6EEF75C7DF88C5A427D0A43 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4380924F566AA01EB048DC15F9BC6D33 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CEBD84922D2CCEF26C272418EC3EB3A6 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 446C0BC610C7A8EA41CDC32090D4AD1A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 61EC42D4D6F7655085AC323D84ACC658 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8322F80818695D2EB9FAFD859BDF5331 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6786A1D4808E8E2313F71767FF832CE2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7E9C2C14859C36ED6022BB2557B2997F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9D47597085C9D008DCEE9015B4BCAB2D /* Foundation.framework in Frameworks */, + F9A9D2DDE5E2B67AC92E8946EC84006C /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 88B211DE19A8FBCC86252DCF9B408D02 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 08ECE8151E4DFCFE4311F5E4C9B5A3BB /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8B1C5539CF105EC36B6A5B1374605C8F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D1D48F651806972AC979D904A9AD7BD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 966CB1DDB721FCEE4DC8479DF3B8F774 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 369CEECE1E95709A6F0740CAF57DD1B2 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9790929E5B5A7DAC61E22162DCA93710 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A5EAA55959CA9B9269CE684D82D5D79A /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9A50662B13743CE2A849499FACE17ECE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9F8DC547606FBA36D86DF22F4ADCF140 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AE8F16AE7FC4D23ED6EC16D26A1C006C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B2591A99B8C8E4D66AF75F288127F82F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FF0F13E0126A7A0C66E7F2D1B76D38E1 /* Foundation.framework in Frameworks */, + 0CF6202C8A8CA2A354C91B2548BE2E72 /* UIKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B7C2FF4A20ABA1FEAD6C6E13A1B1A0F9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 71ABE471529580AFD720CA76711E5637 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BAD0676965D69323866632F99967FEDD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2315F86A6673F07D6059CA6C0D406A3D /* Foundation.framework in Frameworks */, + F5D07E81A16752CBA1D145854D561752 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BF68AB50D403234129980F774D24C571 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1CF1B04DBE905C2336EA637574DC884A /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E3EA90E72414934EBD7E31E4F20F2E11 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7ACB15EB4D09C7709E1190DCBF5D7B6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 23B81E60D7CC6BBAD1A1F7C4A07D424B /* CoreTelephony.framework in Frameworks */, + 757E9C717CB2D5CA0CC6C6C5A1BE72E2 /* Foundation.framework in Frameworks */, + 4509E9FE5C25CAA4EBD707934BA118E9 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 010437CF98F3CAE2A251EEE2D86CA462 /* Resources */ = { + isa = PBXGroup; + children = ( + 77574C1B35FAEFA284EB091A05D3777F /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + 01E6C1BC46C650C58003A771DA7F3D74 /* GoogleUtilities */ = { + isa = PBXGroup; + children = ( + 8EA27CE9AF869CC39B010080517297D4 /* AppDelegateSwizzler */, + 042CC5E89A592195FEAD79B04CB91D3F /* Environment */, + D6950E1D8D601AFE0B695E022F951E53 /* Logger */, + A6E09B2AF90AEEDCDC9EF2CBF76B3411 /* Network */, + 3F07140EA42433412891755478890D8A /* NSData+zlib */, + 1BB554E7E4E7844BBFEAB15DC345A8E2 /* Privacy */, + 0AC49336590F47FE41C397AEE0D02D99 /* Reachability */, + A0297AAA9C907D92FA5B161E1A5F2A03 /* Support Files */, + 887A8D978BD292708C49B2B84961764E /* UserDefaults */, + ); + name = GoogleUtilities; + path = GoogleUtilities; + sourceTree = ""; + }; + 02AD19C491229E14D9AC48C0A9B3C116 /* image_picker_ios */ = { + isa = PBXGroup; + children = ( + 88ADD3E5BF542DA910365A2BBD9FC7E5 /* Sources */, + ); + name = image_picker_ios; + path = image_picker_ios; + sourceTree = ""; + }; + 03892974EADB2462B78100DF51B8E14C /* ios */ = { + isa = PBXGroup; + children = ( + 7252FF044C4EC9594CBF65448601DBC8 /* .symlinks */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; + 038A202E602B16CD5E8DEF95B7FFD5E3 /* firebase_messaging */ = { + isa = PBXGroup; + children = ( + 546099FE185C6C86BAA40B2CA9313B06 /* Sources */, + ); + name = firebase_messaging; + path = firebase_messaging; + sourceTree = ""; + }; + 042CC5E89A592195FEAD79B04CB91D3F /* Environment */ = { + isa = PBXGroup; + children = ( + 9EA4EC1164AD4A64AD408A4F74ECCD8B /* GULAppEnvironmentUtil.h */, + ABA0FD5A71EE712584651CF55F1558E6 /* GULAppEnvironmentUtil.m */, + 91281858E7C5C6A953ACFCCB0F0E8759 /* GULKeychainStorage.h */, + 942ACCA965CADB64D429066DA899D930 /* GULKeychainStorage.m */, + 081DB68F10FD71B7A8E743FC93039FCC /* GULKeychainUtils.h */, + 9121522B9B5A12545EBB589A83BD8F78 /* GULKeychainUtils.m */, + E18168F03FAF8DF950345F0DB50BFF92 /* GULNetworkInfo.h */, + DEF857F1E2D5063DB5343E9A4F23F782 /* GULNetworkInfo.m */, + 422185136707E9DE2A78DC226625C9D5 /* IsAppEncrypted.h */, + 26B9F97490E01D18CE5B3F13AF177F32 /* IsAppEncrypted.m */, + ); + name = Environment; + sourceTree = ""; + }; + 0564EDF30F71479955FEC381DC94500D /* .. */ = { + isa = PBXGroup; + children = ( + D0CD2303C269E3757FD8DBDBD8299345 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 068B2F0C08B1FBB835CD4D5EBEA03418 /* Gradi_25Fall */ = { + isa = PBXGroup; + children = ( + 20C189E11704D375F7115AF4A5D1723A /* frontend */, + ); + name = Gradi_25Fall; + path = Gradi_25Fall; + sourceTree = ""; + }; + 072702053E8A7D816FB4305AA3AC54BA /* .. */ = { + isa = PBXGroup; + children = ( + 996F6D3B99D3E763D7B0888BDDC456F0 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 0AC49336590F47FE41C397AEE0D02D99 /* Reachability */ = { + isa = PBXGroup; + children = ( + 5F7961550B6D6E457B016978E275F440 /* GULReachabilityChecker.h */, + 28C991FA4F9E8DB769F528C9B6AB0F23 /* GULReachabilityChecker.m */, + 007C2472BFF7E2E14B4BF86E9A99997B /* GULReachabilityChecker+Internal.h */, + D436772E65625479E300E56250E3F274 /* GULReachabilityMessageCode.h */, + ); + name = Reachability; + sourceTree = ""; + }; + 0B7A2D1A3D25C1DDAB1089A6142632B3 /* Development Pods */ = { + isa = PBXGroup; + children = ( + 7E10AB6911662D156241042477BB5AA5 /* firebase_core */, + 626C6BC88BC7922AE2D07A0F6F7419D1 /* firebase_messaging */, + CE1D651CC79FC7514D64896550215ED9 /* Flutter */, + 25130974564B40BBB7EDD61AD666256F /* flutter_local_notifications */, + 9A2B0F336F46F2786031FCCB2185A4E6 /* image_picker_ios */, + ); + name = "Development Pods"; + sourceTree = ""; + }; + 0E3F727B67A23B15C2D58D37573D4BAA /* Support Files */ = { + isa = PBXGroup; + children = ( + 546407E1AE82F5A543FB0FF08CFB6A93 /* flutter_local_notifications.modulemap */, + ECE416D5B8F4153F022C16A087BF2E26 /* flutter_local_notifications-dummy.m */, + 8A079A9004A27A365C06CB4DA95B4015 /* flutter_local_notifications-Info.plist */, + CF25197F3272BC4554DD1795F4C0D9BE /* flutter_local_notifications-prefix.pch */, + C76A440189B37018CF064EDA9E1007B9 /* flutter_local_notifications-umbrella.h */, + 2E3135844263DBDB97D0179BDAB2CB68 /* flutter_local_notifications.debug.xcconfig */, + 75D435FE4E37C337A7F1C57E230D8EBD /* flutter_local_notifications.release.xcconfig */, + F53C5B35436C00D610665FD9A52DA659 /* ResourceBundle-flutter_local_notifications_privacy-flutter_local_notifications-Info.plist */, + ); + name = "Support Files"; + path = "../../../../Pods/Target Support Files/flutter_local_notifications"; + sourceTree = ""; + }; + 0F78B694F96996258D046C0DF40E5C09 /* .. */ = { + isa = PBXGroup; + children = ( + 640D55DEBDF47536D1901AFA742A8014 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 106DEECDE2DA0C490E6087ED6F4FED4C /* FirebaseCoreInternal */ = { + isa = PBXGroup; + children = ( + 2428D4B9A1ADDA45215CD1FC1F3207AD /* _ObjC_HeartbeatController.swift */, + 3EA71D30421D81D90A45FD77D6FB2976 /* _ObjC_HeartbeatsPayload.swift */, + 2C0DF8FF5022D896FDA41D434C0F6EF5 /* AtomicBox.swift */, + 192ABD450F0C793BE1E734A176E27E26 /* FIRAllocatedUnfairLock.swift */, + F3047D3277103F27E21BE1D377E7FDA4 /* Heartbeat.swift */, + 3D7A14EF7C31BD4B3BC7F920226167FC /* HeartbeatController.swift */, + 9608F18BDF2DDE520187B9B5D6E6D2A4 /* HeartbeatLoggingTestUtils.swift */, + B3B80750D3B364B9E166CCEB905EACF7 /* HeartbeatsBundle.swift */, + 35B82E32D28724379DF7521589FEBFE2 /* HeartbeatsPayload.swift */, + 9B48F659C78E38331874678992458C9B /* HeartbeatStorage.swift */, + 2DC9C663B1C9C9C7D6D450E2475A8960 /* RingBuffer.swift */, + 3AEB19A22ADF808E67367F1FB5B2A554 /* Storage.swift */, + 2FE54C96AAFD6CECAA849DB5EA8452F1 /* StorageFactory.swift */, + FE20B56087FB4F4CA7131763C35DDC67 /* WeakContainer.swift */, + 4205EC1576CEFC99710A44F705A0B24E /* Resources */, + EEE40ED8800AF29392D5F3DB397E437E /* Support Files */, + ); + name = FirebaseCoreInternal; + path = FirebaseCoreInternal; + sourceTree = ""; + }; + 1171DE98DC8BFDE97314C5CFA6B65A25 /* decode */ = { + isa = PBXGroup; + children = ( + ); + name = decode; + sourceTree = ""; + }; + 11EDC8C54BDDFE46D87B622832031355 /* image_picker_ios */ = { + isa = PBXGroup; + children = ( + 8227F277A10DEFE09506DB03A9348E6A /* ios */, + ); + name = image_picker_ios; + path = image_picker_ios; + sourceTree = ""; + }; + 11FB3604814327D721D866E109919B4C /* Pod */ = { + isa = PBXGroup; + children = ( + 2C83B649D5208B12A39151A858969DD4 /* firebase_messaging.podspec */, + 8E9255CA321EDC93153298BF92D5B4C9 /* LICENSE */, + ); + name = Pod; + sourceTree = ""; + }; + 13C7A252E42C4312E34367588AE6074D /* firebase_core */ = { + isa = PBXGroup; + children = ( + 811763FF1481B539C26618E884EACCA7 /* Sources */, + ); + name = firebase_core; + path = firebase_core; + sourceTree = ""; + }; + 170901C7DA9C8811141BAD0CB1DF4F14 /* Resources */ = { + isa = PBXGroup; + children = ( + F9C0C8FF6D363C392626B70C996CB3B9 /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + 17FD1F93622B9F7ADA7B67952EAAB5AB /* Sources */ = { + isa = PBXGroup; + children = ( + 8E62AF06AF6C5C83EA8CA339861DEE5A /* image_picker_ios */, + ); + name = Sources; + path = Sources; + sourceTree = ""; + }; + 18E7554E08076502F4B8EB0472F2A8B3 /* firebase_core */ = { + isa = PBXGroup; + children = ( + 5FE570758D07A5EE6A12AF7E45FFC15B /* dummy.m */, + 28DDAFBBF7DC1837B7CB4B7401725191 /* FLTFirebaseCorePlugin.m */, + 2E7BEB959A6F7D8070CB1E6B209A8C76 /* FLTFirebasePlugin.m */, + 6CACAF5FAD3F5001091F6F489F1D22AC /* FLTFirebasePluginRegistry.m */, + 44B37CE36850E344D08C7C42DC1B036A /* messages.g.m */, + 97278A68689DB1017EE68A044F167235 /* include */, + ); + name = firebase_core; + path = firebase_core; + sourceTree = ""; + }; + 1AAE3A40D6719B95FE0AFD52269B7E79 /* .. */ = { + isa = PBXGroup; + children = ( + CEBEE4F9E64989571C12CD23F0380A71 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 1BB554E7E4E7844BBFEAB15DC345A8E2 /* Privacy */ = { + isa = PBXGroup; + children = ( + 88690D02C79945D5C7D3734B69CEDD6D /* Resources */, + ); + name = Privacy; + sourceTree = ""; + }; + 1BDF8B9451D07E33650D525677D6F0B8 /* encode */ = { + isa = PBXGroup; + children = ( + ); + name = encode; + sourceTree = ""; + }; + 1D23D894C209415D176E75771CCB8089 /* .. */ = { + isa = PBXGroup; + children = ( + A7074DA0EFA4C143E1AC4D6F03E7C3FD /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 20636934091401CBB21CB77E629AF4C6 /* Pods-RunnerTests */ = { + isa = PBXGroup; + children = ( + E9C5F640AD2476216F4F542B0AF5E13C /* Pods-RunnerTests.modulemap */, + 8A432929F7E93D3E1AA06A4A8668C699 /* Pods-RunnerTests-acknowledgements.markdown */, + 3E249AAAE8E92B5750DB3E8ADB534D8F /* Pods-RunnerTests-acknowledgements.plist */, + 8758A56177F57A2EE30894AA6F81B31A /* Pods-RunnerTests-dummy.m */, + 817671F15D4B947F617BD4EE8ACFC278 /* Pods-RunnerTests-Info.plist */, + 2CB04EB554430E41E5A19EDE6D62C9F2 /* Pods-RunnerTests-umbrella.h */, + DD8C8ACC853AF1B657D17AEC50E540A9 /* Pods-RunnerTests.debug.xcconfig */, + 1FC96341216BBB5BBE3744FB1F35DEEE /* Pods-RunnerTests.profile.xcconfig */, + 1ADB61306F50F60E65BED44878011822 /* Pods-RunnerTests.release.xcconfig */, + ); + name = "Pods-RunnerTests"; + path = "Target Support Files/Pods-RunnerTests"; + sourceTree = ""; + }; + 20C189E11704D375F7115AF4A5D1723A /* frontend */ = { + isa = PBXGroup; + children = ( + 392E5232C3A578AE5EF4498FD2F05F63 /* ios */, + ); + name = frontend; + path = frontend; + sourceTree = ""; + }; + 238B00F2E6FF73F4ABE5EF61426D4B11 /* .. */ = { + isa = PBXGroup; + children = ( + 1D23D894C209415D176E75771CCB8089 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 239126CA47E44407F16B4613708F765A /* FirebaseMessaging */ = { + isa = PBXGroup; + children = ( + B06CC20D8B264C65422A00B2ECA1BC21 /* FIRAnalyticsInterop.h */, + 2253E23F9EAEA9EE71A0073BE86B5E16 /* FIRAnalyticsInteropListener.h */, + 197CD7DF8C5D74CD76AFB946CABF0B91 /* FIRAppInternal.h */, + B543F786F7AC662A9B3B4A59604BE673 /* FIRComponent.h */, + 4E86D9F1294ECE2C483FD6166223BD86 /* FIRComponentContainer.h */, + BE28E7364E1EFEE4FDCAE35B7550F06D /* FIRComponentType.h */, + AADC5B5B4544956F7DD190C8434971BB /* FirebaseCoreInternal.h */, + CCFCE0BE21B0FC0352C603586D9642FD /* FirebaseInstallationsInternal.h */, + FE8579D48A79E1302D02298969B675E6 /* FirebaseMessaging.h */, + F8E3D4F092146A52F08248A9674D2F43 /* FirebaseMessaging.h */, + 08579575396173B32867108F604F151C /* FIRHeartbeatLogger.h */, + AC37499B722B10926F29985F2F626B61 /* FIRInteropEventNames.h */, + 425208C5EBD0D6B01AB909862DE50BAA /* FIRInteropParameterNames.h */, + 5D75104223B5E3CD6623422BDAF96AC4 /* FIRLibrary.h */, + 6AAFE120840A05E53C241E4B7F3C64E8 /* FIRLogger.h */, + 4EC3E7E7FF9E0F3BF5F8FBF7A3BBF8DB /* FIRMessaging.h */, + B0ECBAFC8D346176B5C9430AAC93D937 /* FIRMessaging.m */, + BD0A6B8D25BE47384E9E9BDED1204071 /* FIRMessaging+ExtensionHelper.h */, + CD22F9E01ED5FA1020DE6283E509A9CE /* FIRMessaging+ExtensionHelper.m */, + 8E8FEF536CAF0C03226B8AE23FE454C1 /* FIRMessaging_Private.h */, + E5BF9CEDCABEB953A0F74A583477329D /* FIRMessagingAnalytics.h */, + 554D791CC412A5751A7D867492682EB9 /* FIRMessagingAnalytics.m */, + D7B7454BF5334670ECF3A33191A92E6C /* FIRMessagingAPNSInfo.h */, + 922274B4EC30676D7427163E9BB88BDB /* FIRMessagingAPNSInfo.m */, + 4A975AC758C10E2751E29D23149C3F8A /* FIRMessagingAuthKeychain.h */, + 6F530CD2447E7BB4E8F245B5578D0E43 /* FIRMessagingAuthKeychain.m */, + 65E68F8C9B22A7FF7F1B3F3948BBB254 /* FIRMessagingAuthService.h */, + 94EBBDCB1362A8DB35DD72A83BCE41D5 /* FIRMessagingAuthService.m */, + CB675655530559C4E017C19318F89546 /* FIRMessagingBackupExcludedPlist.h */, + 0A7219D1FBE5F86E63958153ED0BF377 /* FIRMessagingBackupExcludedPlist.m */, + 89E70F54AFC72D650C16A032C725BCD9 /* FIRMessagingCheckinPreferences.h */, + 2E99CA1C85E12A4F6F18BC1B1CBF6DAB /* FIRMessagingCheckinPreferences.m */, + 645C467BE75EA8292CD0BAC07F1DD5A5 /* FIRMessagingCheckinService.h */, + D6891EE2C0F69454EAE3D9E045FE3E1A /* FIRMessagingCheckinService.m */, + 62E4E821E9D7CB7F725D9FF9D5C20D14 /* FIRMessagingCheckinStore.h */, + D4380D9849871F7D36C7E7CBA98E87EA /* FIRMessagingCheckinStore.m */, + CF172E90C36C492AB298888A29405014 /* FIRMessagingCode.h */, + 293CA810B9F9A627CF1B04985BBABB47 /* FIRMessagingConstants.h */, + 403BA008E85450C1AAAEF7B741D81AA3 /* FIRMessagingConstants.m */, + 99065A5299D40284C591F13F428CCA1A /* FIRMessagingContextManagerService.h */, + A2DC8CBC904B18E1936ED362DFA6CCB2 /* FIRMessagingContextManagerService.m */, + B2FEF990F569E7CC05C3AFED1D83F505 /* FIRMessagingDefines.h */, + FB1460C0D5E3BF3EFFDA6E70D347BD42 /* FIRMessagingExtensionHelper.h */, + 6A3F9414556C6E7943F21A35632157C2 /* FIRMessagingExtensionHelper.m */, + C0C2B36D833E272B8DEBDB540B84847A /* FIRMessagingInterop.h */, + 673C3318F9A1D81116EEE5349A511A7F /* FIRMessagingKeychain.h */, + 026994D707584EFF3A96BC447ACB8B4B /* FIRMessagingKeychain.m */, + FB3E0B1F27EBFF6B4823EDA87587A8A8 /* FIRMessagingLogger.h */, + 50F392EB97CBED8788C50990F6BAB160 /* FIRMessagingLogger.m */, + 067B1A306E1D71331FFB0C7B4842C96D /* FIRMessagingPendingTopicsList.h */, + AAF898F203112836152F0FEF6B14DF2B /* FIRMessagingPendingTopicsList.m */, + 905E98607B71266F977964D0380B9E8F /* FIRMessagingPersistentSyncMessage.h */, + 8A65DC251AC8459E96CF62A9A28D7FA9 /* FIRMessagingPersistentSyncMessage.m */, + BF34DE84DA4E4042C6880D4E5D0F35DC /* FIRMessagingPubSub.h */, + DB8C49B0B5734A01DE048CA85F1069EE /* FIRMessagingPubSub.m */, + 8DA801B2D8F4EC374CCF24A7CAA24A5D /* FIRMessagingRemoteNotificationsProxy.h */, + 8634CC3175F30B9D18008895B3D338AC /* FIRMessagingRemoteNotificationsProxy.m */, + 4044D1DCE0CEDBE513D95BE2120704F9 /* FIRMessagingRmqManager.h */, + 6EF1D0E06F214361137D35D1ED4EDE67 /* FIRMessagingRmqManager.m */, + A68052862F5BAE7158CA697BF80807F4 /* FIRMessagingSyncMessageManager.h */, + 936ACF7D90A1E6DAEEA75462AC5C9CCC /* FIRMessagingSyncMessageManager.m */, + 310D0CD7273827DB2A2442B0149E6B9F /* FIRMessagingTokenDeleteOperation.h */, + 6D76A6F64A9F9AC8C80C62153642E906 /* FIRMessagingTokenDeleteOperation.m */, + 5A4ADC3E70449C2D6DDAD177ABCBBB5F /* FIRMessagingTokenFetchOperation.h */, + 1CFEE5BEEE3B72CCB9414344913144FD /* FIRMessagingTokenFetchOperation.m */, + 445871E06F8049863AA09E1A3C325E3E /* FIRMessagingTokenInfo.h */, + D7D8E0360DD7C3C4C53443E53FB2D047 /* FIRMessagingTokenInfo.m */, + B5D20E78EE54D5C48ACEEDD6D89CEA6B /* FIRMessagingTokenManager.h */, + 90E4953F898CE5FB797B791B5411722B /* FIRMessagingTokenManager.m */, + F846B09E79FE5A1BE2108540AD98A6B0 /* FIRMessagingTokenOperation.h */, + 066B519E3C90539086F1B9869EDBEB8A /* FIRMessagingTokenOperation.m */, + BDF87156BDDD108EE55A558C722D79EA /* FIRMessagingTokenStore.h */, + 49A6AF4F7D6CCA75CB3493CBDFEAE6FD /* FIRMessagingTokenStore.m */, + F15F7CD527312C51FC5532AFF29B0CCC /* FIRMessagingTopicOperation.h */, + C150D02EC9C5D375CA88FE501C84AC6D /* FIRMessagingTopicOperation.m */, + 78F891CC63C36BCCAE34673B49F6DD9D /* FIRMessagingTopicsCommon.h */, + 10CFAF9FFD1CC96384F77C2950681BD4 /* FIRMessagingUtilities.h */, + 5FEB5CEB94D970450A0BBA5577A80F61 /* FIRMessagingUtilities.m */, + 50D270FC2FB999A0D0BA29B73B9B2DFB /* me.nanopb.c */, + BFD12588B0D0F7405A96DE2EA7396A34 /* me.nanopb.h */, + E7E682D58A22915DE40E4BC2C50995BF /* NSDictionary+FIRMessaging.h */, + CB5EA4244DC66422A84FB2F4C7803614 /* NSDictionary+FIRMessaging.m */, + C801FDA12C657DA4D652A2352A705D04 /* NSError+FIRMessaging.h */, + 8664F6601EE686C6DBC6F3C7E5078272 /* NSError+FIRMessaging.m */, + E126A175BF3004CF1E089C748D21DC2D /* Resources */, + 64E090B161FEA3CA30DD6DB36FEB27D0 /* Support Files */, + ); + name = FirebaseMessaging; + path = FirebaseMessaging; + sourceTree = ""; + }; + 24C9F01C39523E87C1F779CA10A131CF /* .. */ = { + isa = PBXGroup; + children = ( + 2CE83257B547FD4380584185AB4BC8EF /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 2503F4B653440C1110DC9F5ED308B677 /* include */ = { + isa = PBXGroup; + children = ( + 042074816A9B5A4CFF2C78D349B025D7 /* FLTFirebaseMessagingPlugin.h */, + ); + name = include; + path = include; + sourceTree = ""; + }; + 25130974564B40BBB7EDD61AD666256F /* flutter_local_notifications */ = { + isa = PBXGroup; + children = ( + 55A10D4F45585E787393BB9B70ABFFFF /* .. */, + 9D2E1E1C7145B541B3916B3F99D3F5CA /* Pod */, + 0E3F727B67A23B15C2D58D37573D4BAA /* Support Files */, + ); + name = flutter_local_notifications; + path = ../.symlinks/plugins/flutter_local_notifications/ios; + sourceTree = ""; + }; + 2695EAFDFE6832EBA83F688A20975B2D /* plugins */ = { + isa = PBXGroup; + children = ( + 11EDC8C54BDDFE46D87B622832031355 /* image_picker_ios */, + ); + name = plugins; + path = plugins; + sourceTree = ""; + }; + 26EDF2E63D80ED46E863FF49505A3210 /* Pod */ = { + isa = PBXGroup; + children = ( + 4E92F5C34E3AB0C48D354F7CA1455254 /* image_picker_ios.podspec */, + BEF781DC1D6001BD3E1397BCE96B912B /* ImagePickerPlugin.modulemap */, + F4433BBACF71027F05BF2D7ECBC5470A /* LICENSE */, + ); + name = Pod; + sourceTree = ""; + }; + 26EF3C6B2AB54AD278915C8BB210C435 /* Resources */ = { + isa = PBXGroup; + children = ( + 18360B97FCA68E6CB98056F40009B735 /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + path = Resources; + sourceTree = ""; + }; + 2B731F5E51D8CEB6445C2DF2D93956CF /* image_picker_ios */ = { + isa = PBXGroup; + children = ( + 17FD1F93622B9F7ADA7B67952EAAB5AB /* Sources */, + ); + name = image_picker_ios; + path = image_picker_ios; + sourceTree = ""; + }; + 2CE83257B547FD4380584185AB4BC8EF /* .. */ = { + isa = PBXGroup; + children = ( + CFCA555F85107F110450F883F20048E4 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 308B0B8D196DF824F29C7F5CD4A11829 /* .. */ = { + isa = PBXGroup; + children = ( + 37B782C9CB5AC1728834E3273682260F /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 37B782C9CB5AC1728834E3273682260F /* .. */ = { + isa = PBXGroup; + children = ( + 651DE67511DB7BBB06B1413133CC3BFC /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 392E5232C3A578AE5EF4498FD2F05F63 /* ios */ = { + isa = PBXGroup; + children = ( + D54824FDBF878417287BC199618E7FB9 /* .symlinks */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; + 3C3903F38477F218159F2194FBAD0386 /* nanopb */ = { + isa = PBXGroup; + children = ( + 2857105885BD433FDC1DF8F4846851DC /* pb.h */, + C020E1647C73F291B7B8232080B21AB5 /* pb_common.c */, + B94BEE8D0E30393C9D4D6CBA57B8D263 /* pb_common.h */, + 499A09DE888645CBC456DD808F91F0C0 /* pb_decode.c */, + 635395842F105EACF3067D6B54D82C8F /* pb_decode.h */, + 35414041146136B679F51AE9058D762F /* pb_encode.c */, + AE06A6A60D50DA808B0072CE08DCC3E5 /* pb_encode.h */, + 1171DE98DC8BFDE97314C5CFA6B65A25 /* decode */, + 1BDF8B9451D07E33650D525677D6F0B8 /* encode */, + B0C4D7E3847F904A678EBF4CE99D7BE1 /* Resources */, + 53A57B65B0DDDDA422CF128E6B5094F7 /* Support Files */, + ); + name = nanopb; + path = nanopb; + sourceTree = ""; + }; + 3F07140EA42433412891755478890D8A /* NSData+zlib */ = { + isa = PBXGroup; + children = ( + 11E183230D34CC5B062D1D1049A366B6 /* GULNSData+zlib.h */, + 07CF8CA0F334DC28EDEC31A017D7EB45 /* GULNSData+zlib.m */, + ); + name = "NSData+zlib"; + sourceTree = ""; + }; + 3FBF536927667C1BEFFBB1B679439A45 /* .. */ = { + isa = PBXGroup; + children = ( + F5C2DC2EB3A1CCED15630C277EC08433 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 3FEFC261A57F68B0C1BDF5FAE3DDA815 /* image_picker_ios */ = { + isa = PBXGroup; + children = ( + 26EF3C6B2AB54AD278915C8BB210C435 /* Resources */, + ); + name = image_picker_ios; + path = image_picker_ios; + sourceTree = ""; + }; + 40BA3CE99B40EB9FFD5FE42DA1B159AE /* frontend */ = { + isa = PBXGroup; + children = ( + 8C006DE1F537DE474BBAFC07483B4561 /* ios */, + ); + name = frontend; + path = frontend; + sourceTree = ""; + }; + 4205EC1576CEFC99710A44F705A0B24E /* Resources */ = { + isa = PBXGroup; + children = ( + D655DF7B1D831EAF390B40308E74B9A4 /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + 48784BA740BD93553321C337ADC29C92 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + F733C06013DDD6E5B5E1694C37DDB5BD /* Pods-Runner */, + 20636934091401CBB21CB77E629AF4C6 /* Pods-RunnerTests */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 4973F4DE4CB366F749AEC1660E93969C /* Support Files */ = { + isa = PBXGroup; + children = ( + FFE7D2BB92263A9180243E4881212E9B /* Flutter.debug.xcconfig */, + 5F2A42EA92F0EA92CF755046DDC08290 /* Flutter.release.xcconfig */, + ); + name = "Support Files"; + path = "../Pods/Target Support Files/Flutter"; + sourceTree = ""; + }; + 499EAB2CFF652CEEC9F1CFB7371FDC99 /* Gradi_25Fall */ = { + isa = PBXGroup; + children = ( + A0A5892257DF58F3F55622E27B78B20C /* frontend */, + ); + name = Gradi_25Fall; + path = Gradi_25Fall; + sourceTree = ""; + }; + 4BBCFA36EBC24795ADD06DB69A34C626 /* .symlinks */ = { + isa = PBXGroup; + children = ( + 2695EAFDFE6832EBA83F688A20975B2D /* plugins */, + ); + name = .symlinks; + path = .symlinks; + sourceTree = ""; + }; + 4C41FF691048CC7B854D238D94F30599 /* .. */ = { + isa = PBXGroup; + children = ( + A7C5508B5A0F67A86FAEE734358A7E7B /* .. */, + ); + name = ..; + path = "../../../../../../../../.pub-cache/hosted/pub.dev/firebase_messaging-15.2.10/ios/firebase_messaging/Sources"; + sourceTree = ""; + }; + 4ECF93295DFC0799FAF8A3A46C5B789D /* GoogleDataTransport */ = { + isa = PBXGroup; + children = ( + C91F16BB997A1432E3E845FB58E5419A /* cct.nanopb.c */, + 478136BE01D032987B5DF1FB1694472C /* cct.nanopb.h */, + 425AB8995EF76A7A41250B2B39B918A9 /* client_metrics.nanopb.c */, + 37264F9F27D2E16057E0E305FA5BCCCB /* client_metrics.nanopb.h */, + 4F4B9BE06777680B5A22621207B01882 /* compliance.nanopb.c */, + 5CB3716BCB4F04E1DFCEA30BECF2BC60 /* compliance.nanopb.h */, + 0644B8CAE7E33A4B091322FB566D2BBA /* external_prequest_context.nanopb.c */, + 76C1F6C5D89AD24DC65E947B2C95504E /* external_prequest_context.nanopb.h */, + EFE38C75A3D217CDE7B18F9027CC4F8F /* external_privacy_context.nanopb.c */, + 466AEE01B8DBE6158A57A5141A851070 /* external_privacy_context.nanopb.h */, + E6D3C3E840BD79066822FDA834733864 /* GDTCCTCompressionHelper.h */, + F67BA8239D8A9976F471301DA705FC65 /* GDTCCTCompressionHelper.m */, + B4671189B401A63804AEDF5B26C05A56 /* GDTCCTNanopbHelpers.h */, + CE9BD927B75EFA6B4F63E3EF7F76C142 /* GDTCCTNanopbHelpers.m */, + FE714E74EA2B7E26A7EDC9208B5BA435 /* GDTCCTUploader.h */, + FB2298AE8D3CC3C6ABB941D9CB1CBA09 /* GDTCCTUploader.m */, + CF05C45883497B3E21CA51BF8DE0F678 /* GDTCCTUploadOperation.h */, + CCF6202512922098E47F97220393B797 /* GDTCCTUploadOperation.m */, + E8A3A7295F345E685EABEEFE068CCEE6 /* GDTCCTURLSessionDataResponse.h */, + 2B2C2824B00198C89C8796514A539E69 /* GDTCCTURLSessionDataResponse.m */, + B49E2EBD1B89DC348FB58AD368278DA1 /* GDTCORAssert.h */, + 317558E06CC941F96264F2804571871D /* GDTCORAssert.m */, + 965331C3BB09EADB3C0D9516C974726B /* GDTCORClock.h */, + 9B06B15554EC98005C5A2A6E4F9A4503 /* GDTCORClock.m */, + A5F3FE81EB27FB2162597E4C38CF7A2B /* GDTCORConsoleLogger.h */, + B6E1889709D64FDA47F85E4DA3319BCE /* GDTCORConsoleLogger.m */, + DA922CF0D0D079AC32082A5020A72150 /* GDTCORDirectorySizeTracker.h */, + FF44DE1588F3EB44D30CE17C5922D3C3 /* GDTCORDirectorySizeTracker.m */, + FA8650F57B8928F747DF6C8DAAADBA7A /* GDTCOREndpoints.h */, + 597586DD100925D126C1C463DD575398 /* GDTCOREndpoints.m */, + 8C201419AAEB1684E8D3357D88541EC5 /* GDTCOREndpoints_Private.h */, + 37EF8E7FBD37768317274AA49494D9D7 /* GDTCOREvent.h */, + F62A706AAE45E348C3A5AF903610CBA3 /* GDTCOREvent.m */, + ED62F9AF2BC8736E949B2CB879B6445D /* GDTCOREvent+GDTCCTSupport.h */, + BD2F62558CF728467E423DE871BCE8A8 /* GDTCOREvent+GDTCCTSupport.m */, + CB9C404F2038079531D51B37205F6FA6 /* GDTCOREvent+GDTMetricsSupport.h */, + 5973651CFCFFEC1F7B81A2D131B46CCA /* GDTCOREvent+GDTMetricsSupport.m */, + 6ED2F58D2160FEAAC3E745D0085755B1 /* GDTCOREvent_Private.h */, + 7E173B14DD49E212545D1962FACBA586 /* GDTCOREventDataObject.h */, + 78A647CF2AA2FEDD71CFDAB7BAA6CB01 /* GDTCOREventDropReason.h */, + D56C33CE6C883DF8D154067576FC8FCB /* GDTCOREventTransformer.h */, + CCB99A06CCC77919B7446EEF57659E87 /* GDTCORFlatFileStorage.h */, + 551651297586403CD2F85A86DB9035D4 /* GDTCORFlatFileStorage.m */, + 601B9BE94C9A2AEB8E3FAF0E5B8480B1 /* GDTCORFlatFileStorage+Promises.h */, + 18A6D34071FD583FE9C58FCE5CF837F8 /* GDTCORFlatFileStorage+Promises.m */, + 600AC3F60588265C01A074792402E2BC /* GDTCORLifecycle.h */, + 03408913A9DA374E2493D330A980E8CC /* GDTCORLifecycle.m */, + 4E74DC0FD5217C11B99B434ACE6CD425 /* GDTCORLogSourceMetrics.h */, + C23D989186917D690D6E35EAEE950DAC /* GDTCORLogSourceMetrics.m */, + A6B1DDCFBD3CF418AC193FE5F753B7A0 /* GDTCORMetrics.h */, + E9EDD23A28B53B116FCC2B249E7ABB62 /* GDTCORMetrics.m */, + 986A3F2324959A8B87BB0F95403C0DB4 /* GDTCORMetrics+GDTCCTSupport.h */, + 8E0EE42F5223017E57B7B7D51B4CF1B4 /* GDTCORMetrics+GDTCCTSupport.m */, + 8C31E883DF59327EFA2F3C02699CCA15 /* GDTCORMetricsController.h */, + 1F498270700E31C3494045615D8186A7 /* GDTCORMetricsController.m */, + 481E832C9E13CB11704E3B80B0A61F8A /* GDTCORMetricsControllerProtocol.h */, + 03AE6CA1DBA607C545A3B791D8E2AF51 /* GDTCORMetricsMetadata.h */, + D908E95DE9E1E5FAA4F57148C5FC790B /* GDTCORMetricsMetadata.m */, + B371BCA4519038B554B5CE8AE4330B6C /* GDTCORPlatform.h */, + D1E3607447AF036E85C9F1FF89B9B44E /* GDTCORPlatform.m */, + C586DD178A496B2B6864BA1A72B66182 /* GDTCORProductData.h */, + 6308A2BF48F37BFCC2D67C547F4FFC31 /* GDTCORProductData.m */, + 850D0BDD3B07A173617227FD60A6231C /* GDTCORReachability.h */, + 1B11C51237E5D56456A68EABAE481D91 /* GDTCORReachability.m */, + 936F09821C7EE0C3CD7F82890DB3A2CD /* GDTCORReachability_Private.h */, + DF1F5F4906A736BC65D87CBEDAFE1894 /* GDTCORRegistrar.h */, + 053E79D285ED081E8D3A467E9057432F /* GDTCORRegistrar.m */, + 20AF87A6F49B0CEA59EC599CAEDFD41A /* GDTCORRegistrar_Private.h */, + C9232E4B48A37102EEF6856FD90C953A /* GDTCORStorageEventSelector.h */, + AC70B4B71CC9B390381A08D1429D6519 /* GDTCORStorageEventSelector.m */, + 16F47DBFD334E095900DAD45D515CFE7 /* GDTCORStorageMetadata.h */, + 381BA5E61A58F61BC2D25A380396C078 /* GDTCORStorageMetadata.m */, + EF5E4FCAEC3D44A5DF86D667C0A1F738 /* GDTCORStorageProtocol.h */, + 424A93A150F9A2832A97CB7932DD2206 /* GDTCORStorageSizeBytes.h */, + B512FE666020CE015DAEDEB8CBABCAAB /* GDTCORTargets.h */, + 3F24A03162482FB4B37596AA1170AA70 /* GDTCORTransformer.h */, + EAA203D51C6952F039B16DA1C6886296 /* GDTCORTransformer.m */, + B938FBAF03B6ED7A749BE73D476B7B15 /* GDTCORTransformer_Private.h */, + 3431FD1E5FCA48FEF6E835D77FC47AE9 /* GDTCORTransport.h */, + 5849D105D1C2834E540A65AE4ABE3C27 /* GDTCORTransport.m */, + AA3D5E76E8D7DF4C02A1061D71983979 /* GDTCORTransport_Private.h */, + 8FD58877AD51D8F920444C2D00B20F3D /* GDTCORUploadBatch.h */, + 49AE84DBBAD701EE2CB8545AAC680E6E /* GDTCORUploadBatch.m */, + BDCA34BFBDAE2A8CD8404ECE64D14D00 /* GDTCORUploadCoordinator.h */, + D2DBBD201333C23533BD538E84DA3E09 /* GDTCORUploadCoordinator.m */, + B60A2D97A08A79D950561A5CC0A9494B /* GDTCORUploader.h */, + 83C495C7955782B478F1F6B5A9B7E1CF /* GoogleDataTransport.h */, + 8D5A758593DC540CC73AAB4FE11A2591 /* Resources */, + 7624A94AF39AE57C3F2455C6013BC99D /* Support Files */, + ); + name = GoogleDataTransport; + path = GoogleDataTransport; + sourceTree = ""; + }; + 53A57B65B0DDDDA422CF128E6B5094F7 /* Support Files */ = { + isa = PBXGroup; + children = ( + 7DD9D9497462C5FEAB0716591373B13F /* nanopb.modulemap */, + 362A936B488A8BC83F35FE595CF39E60 /* nanopb-dummy.m */, + F0C760C99840E9C0450409DDBC6761BA /* nanopb-Info.plist */, + 00A8890A6B80A0582F6CAFA39FA57375 /* nanopb-prefix.pch */, + 1113950F760FBB488BA6EFD6F5B7B649 /* nanopb-umbrella.h */, + 1792230F1C96C80BBCBE1F3E25A86437 /* nanopb.debug.xcconfig */, + 0C6A42B0370A0BB6545A0CCA144AF3F4 /* nanopb.release.xcconfig */, + A627709EDE767EA9D58552E6AD1A466D /* ResourceBundle-nanopb_Privacy-nanopb-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/nanopb"; + sourceTree = ""; + }; + 546099FE185C6C86BAA40B2CA9313B06 /* Sources */ = { + isa = PBXGroup; + children = ( + EA3FD3C1C68A16D9A0908CF45B76B3E8 /* firebase_messaging */, + ); + name = Sources; + path = Sources; + sourceTree = ""; + }; + 555DDB2A307A47C84C0711DA4FF9F85C /* Documents */ = { + isa = PBXGroup; + children = ( + 6CD5117C68B2B1188F12EEBB9ADBE895 /* Gradi_25Fall */, + ); + name = Documents; + path = Documents; + sourceTree = ""; + }; + 55A10D4F45585E787393BB9B70ABFFFF /* .. */ = { + isa = PBXGroup; + children = ( + 8D3811DCCAF654615C545B955A80B1D9 /* .. */, + ); + name = ..; + path = "../../../../../../../../.pub-cache/hosted/pub.dev/flutter_local_notifications-18.0.1/ios"; + sourceTree = ""; + }; + 5798B066162366492E73AA9AD1FFBCCE /* .. */ = { + isa = PBXGroup; + children = ( + 806D2D7819C0A9670EA28E3E64FBC4A9 /* .. */, + 979DA65FF455BE8753D22CE503383BE9 /* Documents */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 5B170184515982BFC0833E995151271B /* Support Files */ = { + isa = PBXGroup; + children = ( + FA0D0444FDB3A5A4B215BC95A9FF00B9 /* FirebaseCore.modulemap */, + D889199081E3C4524D59D648514AF05C /* FirebaseCore-dummy.m */, + 896D97FE0D7AA3609F1D1DB35572DC14 /* FirebaseCore-Info.plist */, + AC350D7331C62B3D5200AEB896375605 /* FirebaseCore-umbrella.h */, + 490691048F9A43D41B5F491C8D800AA6 /* FirebaseCore.debug.xcconfig */, + 9D925A34FCE9DF5AF00DD4BB47713016 /* FirebaseCore.release.xcconfig */, + 5D72A05D5CC2A779BBB1D8F916B0FF1A /* ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseCore"; + sourceTree = ""; + }; + 626C6BC88BC7922AE2D07A0F6F7419D1 /* firebase_messaging */ = { + isa = PBXGroup; + children = ( + 4C41FF691048CC7B854D238D94F30599 /* .. */, + 11FB3604814327D721D866E109919B4C /* Pod */, + 9B6D0117D7D50B6A72A82D49402C7DB5 /* Support Files */, + ); + name = firebase_messaging; + path = ../.symlinks/plugins/firebase_messaging/ios; + sourceTree = ""; + }; + 640D55DEBDF47536D1901AFA742A8014 /* .. */ = { + isa = PBXGroup; + children = ( + 238B00F2E6FF73F4ABE5EF61426D4B11 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 64E090B161FEA3CA30DD6DB36FEB27D0 /* Support Files */ = { + isa = PBXGroup; + children = ( + 8976EF86AC0380FF046DC73A94C240D5 /* FirebaseMessaging.modulemap */, + 8C334D9E95131AD50108A1C67E238989 /* FirebaseMessaging-dummy.m */, + 20A4EB78766C836C5E6356204E56EB54 /* FirebaseMessaging-Info.plist */, + 50F613F74218D55303469A0613633B7E /* FirebaseMessaging-umbrella.h */, + EDE3C6D61BC0AFA10BEE62B82A8CB6BC /* FirebaseMessaging.debug.xcconfig */, + 00817846E0BC0BA43768612211393B49 /* FirebaseMessaging.release.xcconfig */, + 02B09E1438E8A0C58CFD12510B6FB36E /* ResourceBundle-FirebaseMessaging_Privacy-FirebaseMessaging-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseMessaging"; + sourceTree = ""; + }; + 651DE67511DB7BBB06B1413133CC3BFC /* .. */ = { + isa = PBXGroup; + children = ( + A0AC25D64152BD8169DE2789DF5A5F7C /* Documents */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 66647F7932D5D6F4753C341F81B4BF11 /* CoreOnly */ = { + isa = PBXGroup; + children = ( + 5AD9D505359BA32ED31F62F46E5FA68D /* Firebase.h */, + ); + name = CoreOnly; + sourceTree = ""; + }; + 669F78689DB46140972316A4CA284CEB /* .. */ = { + isa = PBXGroup; + children = ( + 0564EDF30F71479955FEC381DC94500D /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 6C1514730C3D1CDEB70C442A1132B8D5 /* firebase_core */ = { + isa = PBXGroup; + children = ( + B279B373CD06EEF86B1A2F783F379C53 /* ios */, + ); + name = firebase_core; + path = firebase_core; + sourceTree = ""; + }; + 6CD5117C68B2B1188F12EEBB9ADBE895 /* Gradi_25Fall */ = { + isa = PBXGroup; + children = ( + 40BA3CE99B40EB9FFD5FE42DA1B159AE /* frontend */, + ); + name = Gradi_25Fall; + path = Gradi_25Fall; + sourceTree = ""; + }; + 6E445044AF891F278034B36FC558610D /* flutter_local_notifications */ = { + isa = PBXGroup; + children = ( + C5FB9D9D618277A84A28B82F53E25757 /* ios */, + ); + name = flutter_local_notifications; + path = flutter_local_notifications; + sourceTree = ""; + }; + 6E7D4BDD596A694F58C40911CFB888AB /* Classes */ = { + isa = PBXGroup; + children = ( + 1A0F986347F2F1609FFC4F0D31B89630 /* ActionEventSink.h */, + 895B93138E15C0598E60030F41FD9104 /* ActionEventSink.m */, + 9BB83D91F5873A1F19C583E5BC73CB30 /* Converters.h */, + 7C871D09740CE9D74171701136D65B99 /* Converters.m */, + 45E5FA6F52D158F4FB3C4CBC66E449BC /* FlutterEngineManager.h */, + 0449AF94882DAC62AA57B3FD5760D8B0 /* FlutterEngineManager.m */, + 490DC0C7050C99937B5FAA5B60745755 /* FlutterLocalNotificationsPlugin.h */, + E0DF8F36727B0D343DF681ED004FD2E6 /* FlutterLocalNotificationsPlugin.m */, + ); + name = Classes; + path = Classes; + sourceTree = ""; + }; + 7252FF044C4EC9594CBF65448601DBC8 /* .symlinks */ = { + isa = PBXGroup; + children = ( + A5D58DB2607BD6490D7A832B247F6C07 /* plugins */, + ); + name = .symlinks; + path = .symlinks; + sourceTree = ""; + }; + 7512F727C3F97C04B3EDF1F3CDF6AB4C /* Pod */ = { + isa = PBXGroup; + children = ( + 95C81102A4DAA71473683800CEF5618C /* Flutter.podspec */, + ); + name = Pod; + sourceTree = ""; + }; + 7624A94AF39AE57C3F2455C6013BC99D /* Support Files */ = { + isa = PBXGroup; + children = ( + 71C8A4AF101980DA93A8A45F8C55DFA2 /* GoogleDataTransport.modulemap */, + BB67577D73012DFE877DCAA6A5A0CFBD /* GoogleDataTransport-dummy.m */, + 75A09089BD5480957D6E683E7B8EEEFA /* GoogleDataTransport-Info.plist */, + B2387C526D96360EC27318C6A56C9530 /* GoogleDataTransport-umbrella.h */, + 5D9309B998555FFB2544D65E50F4A2F9 /* GoogleDataTransport.debug.xcconfig */, + 7658FDF5AEDDE8CAA80B12334DDD9D37 /* GoogleDataTransport.release.xcconfig */, + FA725D6547E13C230774CBE70FF3DCD1 /* ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/GoogleDataTransport"; + sourceTree = ""; + }; + 7E10AB6911662D156241042477BB5AA5 /* firebase_core */ = { + isa = PBXGroup; + children = ( + A68143BA5E389A599AC71B36F2C19C1D /* .. */, + 892D5B46E901293D03E5AB83B9BE1F42 /* Pod */, + 9942C1574A605B878A1D43B799D95660 /* Support Files */, + ); + name = firebase_core; + path = ../.symlinks/plugins/firebase_core/ios; + sourceTree = ""; + }; + 806D2D7819C0A9670EA28E3E64FBC4A9 /* .. */ = { + isa = PBXGroup; + children = ( + EE41A2B0C091AD29E62B883D7F8AD6AC /* Documents */, + ); + name = ..; + path = .; + sourceTree = ""; + }; + 811763FF1481B539C26618E884EACCA7 /* Sources */ = { + isa = PBXGroup; + children = ( + 18E7554E08076502F4B8EB0472F2A8B3 /* firebase_core */, + ); + name = Sources; + path = Sources; + sourceTree = ""; + }; + 8227F277A10DEFE09506DB03A9348E6A /* ios */ = { + isa = PBXGroup; + children = ( + 2B731F5E51D8CEB6445C2DF2D93956CF /* image_picker_ios */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; + 833AE2029D5B5A82A98C77B351D1C67C /* FirebaseCore */ = { + isa = PBXGroup; + children = ( + 77E4E0DF346BC55702A7F97C83759EB7 /* FIRAnalyticsConfiguration.h */, + AAD8085D8AFEEB3417EF649424648779 /* FIRAnalyticsConfiguration.m */, + DB95A71164E10C96C48CA96BB0C2C871 /* FIRApp.h */, + 6A10DCC568131817410FB1AEF9178715 /* FIRApp.m */, + 0D4A46F116BFFAE9C3ECDC7EF00A6E6A /* FIRAppInternal.h */, + 778F816687F31D011CF7B8600D15C99C /* FIRBundleUtil.h */, + 194D87AC7FA8ACD1ADC48E9094B1DD8F /* FIRBundleUtil.m */, + BCAEF4B6CC33BA3FDC7A5EFC1081A150 /* FIRComponent.h */, + 52D6E9B0E720A5CC03B91F3CCE939F1D /* FIRComponent.m */, + 8E186EAC5470DCC01B54AD829AB67040 /* FIRComponentContainer.h */, + 8D630B865AE0C8F8420AEEA5D9729BEA /* FIRComponentContainer.m */, + 17FF3FD8C34AE6E60B8CAEBA719DEA21 /* FIRComponentContainerInternal.h */, + 2F3048B48A2FE22ED08DA327695BC2D9 /* FIRComponentType.h */, + 9896FC50EDA315757C5C60709679C840 /* FIRComponentType.m */, + 93320CABD301A5AEBACABF6E8637270F /* FIRConfiguration.h */, + 8D10767A89F4C2717508593913943165 /* FIRConfiguration.m */, + 656C5FB7BFF6EBCF232183D77650236F /* FIRConfigurationInternal.h */, + DDAC6D191B54B707F402B200DA9BCCCF /* FirebaseCore.h */, + 1597161DD3BB968D29E7B45448AA14CB /* FirebaseCoreInternal.h */, + B6A067FEC2F7D21562E67BC5305FB65D /* FIRFirebaseUserAgent.h */, + 94449CA47C2641CC67085CB779439A41 /* FIRFirebaseUserAgent.m */, + 92999C4A70B803D6BB4A68BBA0D010FE /* FIRHeartbeatLogger.h */, + F72DE1533AD7657E655356E31E3A5475 /* FIRHeartbeatLogger.m */, + B813F4D2F842FDC08628BEC65FF4ED40 /* FIRLibrary.h */, + B2CC463A480A8EE4BB1C8BAB7EC6A811 /* FIRLogger.h */, + 70B2477B7080994FF019740F97FDA027 /* FIRLogger.m */, + 7A4D3DB3BE1854CAF9DDABE31710F76C /* FIRLoggerLevel.h */, + 739528119751A21100A633EC4AFD6198 /* FIROptions.h */, + 5AA41421D42B0E9F83F0034ED34A520D /* FIROptions.m */, + 9AC7C482E6D07C1D873A78BAD801C86A /* FIROptionsInternal.h */, + E22BD45F6FB773C33141B618168C4A8F /* FIRTimestamp.h */, + A28ECC14C6767FD5BF201D0A0585F63A /* FIRTimestamp.m */, + 06FEAB1B0AE18AA2E6311F4327D6F2D0 /* FIRTimestampInternal.h */, + EBF3BFE26470C008E106EB355D9C4277 /* FIRVersion.h */, + 9B0344A89EE65F8D04A56A2B0A15E832 /* FIRVersion.m */, + 170901C7DA9C8811141BAD0CB1DF4F14 /* Resources */, + 5B170184515982BFC0833E995151271B /* Support Files */, + ); + name = FirebaseCore; + path = FirebaseCore; + sourceTree = ""; + }; + 83AFB96A08073A251C90AFD614DC5FC8 /* Resources */ = { + isa = PBXGroup; + children = ( + D703F68C62134D846E9AFE6B0B29AD69 /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + path = Resources; + sourceTree = ""; + }; + 83D787180AF061194BA0546C2D89317C /* ios */ = { + isa = PBXGroup; + children = ( + EA5A45D7768C919A51F9CCBED76EBBC5 /* .symlinks */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; + 88690D02C79945D5C7D3734B69CEDD6D /* Resources */ = { + isa = PBXGroup; + children = ( + 2D8EA9E33C58DFF057693997F6C8D831 /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + 887A8D978BD292708C49B2B84961764E /* UserDefaults */ = { + isa = PBXGroup; + children = ( + 3A46168EEE10D0596CA807ED75B57AAC /* GULUserDefaults.h */, + AAD3BC28C09DA52886D6B8681F7F5FBD /* GULUserDefaults.m */, + ); + name = UserDefaults; + sourceTree = ""; + }; + 88ADD3E5BF542DA910365A2BBD9FC7E5 /* Sources */ = { + isa = PBXGroup; + children = ( + 3FEFC261A57F68B0C1BDF5FAE3DDA815 /* image_picker_ios */, + ); + name = Sources; + path = Sources; + sourceTree = ""; + }; + 88B2EBC8E7E9601DE0F173B6872F2C01 /* Documents */ = { + isa = PBXGroup; + children = ( + EB257A81BCCE619200312B3F737CDBF2 /* Gradi_25Fall */, + ); + name = Documents; + path = Documents; + sourceTree = ""; + }; + 892D5B46E901293D03E5AB83B9BE1F42 /* Pod */ = { + isa = PBXGroup; + children = ( + 832AE400756F88C7AF9B23A8DE12970F /* firebase_core.podspec */, + 5DBD8A865F7372556F04F54BEEBC7ADC /* LICENSE */, + ); + name = Pod; + sourceTree = ""; + }; + 8958D0EB294B8D07034B3CEDC6550C78 /* ios */ = { + isa = PBXGroup; + children = ( + 4BBCFA36EBC24795ADD06DB69A34C626 /* .symlinks */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; + 8B2588051B6C66F803D15CD77949F784 /* .. */ = { + isa = PBXGroup; + children = ( + 24C9F01C39523E87C1F779CA10A131CF /* .. */, + ); + name = ..; + path = "../../../../../../../../.pub-cache/hosted/pub.dev/image_picker_ios-0.8.13+1/ios/image_picker_ios/Sources"; + sourceTree = ""; + }; + 8C006DE1F537DE474BBAFC07483B4561 /* ios */ = { + isa = PBXGroup; + children = ( + A379E1B91B49EB3274A0E493E3A5ED9E /* .symlinks */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; + 8D3811DCCAF654615C545B955A80B1D9 /* .. */ = { + isa = PBXGroup; + children = ( + D1443A91868AEE5CB811A9FF42E816AF /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 8D5A758593DC540CC73AAB4FE11A2591 /* Resources */ = { + isa = PBXGroup; + children = ( + 6B31EC9A7B428F4713B87CE4DF630775 /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + 8E62AF06AF6C5C83EA8CA339861DEE5A /* image_picker_ios */ = { + isa = PBXGroup; + children = ( + B62F8176908F7C7B39EEA7BA2DF3C364 /* FLTImagePickerImageUtil.m */, + C7C11EC9AC85A39FC2DA6B03D4EA2A36 /* FLTImagePickerMetaDataUtil.m */, + DF2202BFB27E7E8B535986D8ACA2A11A /* FLTImagePickerPhotoAssetUtil.m */, + 36D1D380AC0FAE1558B1433A94C5939C /* FLTImagePickerPlugin.m */, + 1F1B1A3CB7EF62D9C362CFF5A14098E7 /* FLTPHPickerSaveImageToPathOperation.m */, + A1BD49BD040680F98EB5578FF93E0C8B /* messages.g.m */, + DBFD9B36B592F2BE68C9957073A188DB /* include */, + ); + name = image_picker_ios; + path = image_picker_ios; + sourceTree = ""; + }; + 8EA27CE9AF869CC39B010080517297D4 /* AppDelegateSwizzler */ = { + isa = PBXGroup; + children = ( + CCC1B87A6B369D883DC59DA1A876FB48 /* GULAppDelegateSwizzler.h */, + 1EA7FEFB5AC53EBAF907B0E73D03959D /* GULAppDelegateSwizzler.m */, + 71CDF1D9C3D3B35FD852BBFCF671E4B6 /* GULAppDelegateSwizzler_Private.h */, + 4B0C1FD0FEE536657E3F3752322EE5F6 /* GULApplication.h */, + A17B442DCEB9C47D544B82CE2BFDB986 /* GULLoggerCodes.h */, + 35E25A842CB04F9B78FCBA6BF7F0C5CA /* GULSceneDelegateSwizzler.h */, + 1C6CB67271C76EA4A1308844DF06B701 /* GULSceneDelegateSwizzler.m */, + 00830C5FFBF7D722EFA837254CFA5443 /* GULSceneDelegateSwizzler_Private.h */, + ); + name = AppDelegateSwizzler; + sourceTree = ""; + }; + 93790D9FDD2F9CEA5D2CD6FFAD4D2184 /* ios */ = { + isa = PBXGroup; + children = ( + 038A202E602B16CD5E8DEF95B7FFD5E3 /* firebase_messaging */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; + 940D76968AE4062621B5A6A5ED97E14C /* firebase_core */ = { + isa = PBXGroup; + children = ( + 0F83DB803875BEAAF3F411BC01D3472E /* dummy.h */, + 307006891C36268C3ABD5CA9F826AFC0 /* FLTFirebaseCorePlugin.h */, + 79F077D532D1FC3E22DAC2178F2B93DF /* FLTFirebasePlugin.h */, + B04FDD8DDB07A0183A4E103A9D101302 /* FLTFirebasePluginRegistry.h */, + A502B0A40F92792DB2223688F14EF403 /* messages.g.h */, + ); + name = firebase_core; + path = firebase_core; + sourceTree = ""; + }; + 97278A68689DB1017EE68A044F167235 /* include */ = { + isa = PBXGroup; + children = ( + 940D76968AE4062621B5A6A5ED97E14C /* firebase_core */, + ); + name = include; + path = include; + sourceTree = ""; + }; + 979DA65FF455BE8753D22CE503383BE9 /* Documents */ = { + isa = PBXGroup; + children = ( + F8555CE790C1C8A5532937169BFFE3DD /* Gradi_25Fall */, + ); + name = Documents; + path = Documents; + sourceTree = ""; + }; + 9942C1574A605B878A1D43B799D95660 /* Support Files */ = { + isa = PBXGroup; + children = ( + 3D91810E20A5CC45F9D6656F71A636BD /* firebase_core.modulemap */, + FDDD8D05205C5EE7B1CC69B162A85388 /* firebase_core-dummy.m */, + 67D3334469F5EF9F0C72503D6E4DE412 /* firebase_core-Info.plist */, + A7CC628CA6581A6F7BDABA0490622A6B /* firebase_core-prefix.pch */, + E8613A3C37426EBD5058C1EACD29B4D3 /* firebase_core-umbrella.h */, + 3F9429AEFF528448C4A75318298FA20A /* firebase_core.debug.xcconfig */, + 9D929313305FB6B3C350F1CCF65FFEA9 /* firebase_core.release.xcconfig */, + ); + name = "Support Files"; + path = "../../../../Pods/Target Support Files/firebase_core"; + sourceTree = ""; + }; + 996F6D3B99D3E763D7B0888BDDC456F0 /* .. */ = { + isa = PBXGroup; + children = ( + 5798B066162366492E73AA9AD1FFBCCE /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 9A2B0F336F46F2786031FCCB2185A4E6 /* image_picker_ios */ = { + isa = PBXGroup; + children = ( + 8B2588051B6C66F803D15CD77949F784 /* .. */, + 26EDF2E63D80ED46E863FF49505A3210 /* Pod */, + D529BED0E737A5BC91E30F7F579434E9 /* Support Files */, + ); + name = image_picker_ios; + path = ../.symlinks/plugins/image_picker_ios/ios; + sourceTree = ""; + }; + 9AC8FB3816FAC566415BEB71670DDEAC /* Support Files */ = { + isa = PBXGroup; + children = ( + 7F9B3EFD7A0DCF699AA75614DCFE5FFE /* PromisesObjC.modulemap */, + 1C613D4CE88F0AF4F9A718CB8F6CB748 /* PromisesObjC-dummy.m */, + 27F45BB476A5698F78222A71E4F39AE1 /* PromisesObjC-Info.plist */, + EAA0F2B1CA18EB072F0B6672F56FF88C /* PromisesObjC-umbrella.h */, + 8117DDCAB0947EC036DA8BE1D942F629 /* PromisesObjC.debug.xcconfig */, + B6937D9D9C997E2BA32C1EA4575FD8BA /* PromisesObjC.release.xcconfig */, + 405713E74388D08C5EA84CD978C15709 /* ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/PromisesObjC"; + sourceTree = ""; + }; + 9B6D0117D7D50B6A72A82D49402C7DB5 /* Support Files */ = { + isa = PBXGroup; + children = ( + 6814315BA51938939FB36210B07A40D5 /* firebase_messaging.modulemap */, + 4C05080F60D04271D75AD4FB3A338D84 /* firebase_messaging-dummy.m */, + 969F41146FA5CA010B9D53DA3F128112 /* firebase_messaging-Info.plist */, + 42090CBE9D81332CD5F6058E81F380CC /* firebase_messaging-prefix.pch */, + 1F41AF401ECD6D59105FD217BFA68A35 /* firebase_messaging-umbrella.h */, + 6D057386278D6ACF2F30795937A5D7B6 /* firebase_messaging.debug.xcconfig */, + ADD75767BCDDF56305838AA3576C0D6A /* firebase_messaging.release.xcconfig */, + AA24167E8696ACD1B99C485B3A3EBF8F /* ResourceBundle-firebase_messaging_Privacy-firebase_messaging-Info.plist */, + ); + name = "Support Files"; + path = "../../../../Pods/Target Support Files/firebase_messaging"; + sourceTree = ""; + }; + 9D2E1E1C7145B541B3916B3F99D3F5CA /* Pod */ = { + isa = PBXGroup; + children = ( + 73215A0276358893231379269AE806A0 /* flutter_local_notifications.podspec */, + 4410AC3B578C5D7B3CC7EFF95034B347 /* LICENSE */, + ); + name = Pod; + sourceTree = ""; + }; + 9F075856BE98B1550012512D4D169BAC /* frontend */ = { + isa = PBXGroup; + children = ( + 03892974EADB2462B78100DF51B8E14C /* ios */, + ); + name = frontend; + path = frontend; + sourceTree = ""; + }; + A0297AAA9C907D92FA5B161E1A5F2A03 /* Support Files */ = { + isa = PBXGroup; + children = ( + 029E5A0553893B0C6A0A8FC483F5F56E /* GoogleUtilities.modulemap */, + 4790FE35CCE78F042C4976E095FC08E7 /* GoogleUtilities-dummy.m */, + 5C482693DD66F9BCB854CF7C4D8DDB90 /* GoogleUtilities-Info.plist */, + 5215464BB80A41FB505019E963220AE0 /* GoogleUtilities-umbrella.h */, + 7D0ECCE4F5783E4482638C77ECFF4F5B /* GoogleUtilities.debug.xcconfig */, + E2411C6C639146FA21E9291E20EB02BF /* GoogleUtilities.release.xcconfig */, + 94918A4BBE2FA240BB3A089559EE38F4 /* ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/GoogleUtilities"; + sourceTree = ""; + }; + A0A5892257DF58F3F55622E27B78B20C /* frontend */ = { + isa = PBXGroup; + children = ( + 83D787180AF061194BA0546C2D89317C /* ios */, + ); + name = frontend; + path = frontend; + sourceTree = ""; + }; + A0AC25D64152BD8169DE2789DF5A5F7C /* Documents */ = { + isa = PBXGroup; + children = ( + 068B2F0C08B1FBB835CD4D5EBEA03418 /* Gradi_25Fall */, + ); + name = Documents; + path = Documents; + sourceTree = ""; + }; + A2C84E137E72B1BCC25B0A7F44436F85 /* FirebaseInstallations */ = { + isa = PBXGroup; + children = ( + 202227937DC19626B6162B984AC7B94B /* FIRAppInternal.h */, + 9FFE58E8153EEA5BBD4ADEA1792F2C39 /* FIRComponent.h */, + DD77AADE9BB2391A80E5DE0B44F9B2C7 /* FIRComponentContainer.h */, + E2BA5760A60FB76A5D0DA6B6592378C9 /* FIRComponentType.h */, + 87934EF8F3D60D9A8C773E4D2A0BA3B3 /* FIRCurrentDateProvider.h */, + FF8D2EC06176343EF1EACEF6206CC015 /* FIRCurrentDateProvider.m */, + 886C3E05AA567BEB1219A0D5E1FD0E26 /* FirebaseCoreInternal.h */, + B646BBDFE3CEA2C26F26ADD034CD74D7 /* FirebaseInstallations.h */, + 3BE9CF5E1CA26178487BCD7E48951DE8 /* FirebaseInstallationsInternal.h */, + 8E3D3451D357BAC83914C1402577267F /* FIRHeartbeatLogger.h */, + D129CBF9B6659C2212C9D0E35165E9E3 /* FIRInstallations.h */, + 6A03990672E97F082CE5D42C4DA88AE3 /* FIRInstallations.m */, + 72E84C770071D5A1531FAE5D14D85044 /* FIRInstallationsAPIService.h */, + A773AD7AC2BDC4D59F7D44F165DDE579 /* FIRInstallationsAPIService.m */, + 38E268C4172837796B505246635355EA /* FIRInstallationsAuthTokenResult.h */, + 2E3C1BE5EE5B7F7FE8218A78F05F362D /* FIRInstallationsAuthTokenResult.m */, + 33FC9CF96CA23D0419B6024FA5B7B9CE /* FIRInstallationsAuthTokenResultInternal.h */, + 55086D223D9FF08447F190FF4EC56B2B /* FIRInstallationsBackoffController.h */, + AB598EB2A3C10C454BDF7F082CBF13E2 /* FIRInstallationsBackoffController.m */, + 74253B13C3296B401730EDF3CA4B17C1 /* FIRInstallationsErrors.h */, + 7BB7063CC89B497ABCC22BCC4F19BA33 /* FIRInstallationsErrorUtil.h */, + 71BEE6C7B8B888271C132B6206500966 /* FIRInstallationsErrorUtil.m */, + 45CF41DF5693A36FD86A879BE06D0382 /* FIRInstallationsHTTPError.h */, + C40988385EFE5D8754088D1EBBDF7BAD /* FIRInstallationsHTTPError.m */, + CF581185566FAB365575D1B37BF1296C /* FIRInstallationsIDController.h */, + 044C8F52069D02324E0E1334EC92CBC8 /* FIRInstallationsIDController.m */, + 07C6B8ABF0A5FBF262DEA5F49AEAFD28 /* FIRInstallationsIIDStore.h */, + BEF18B32324D7103B23F4A901C785607 /* FIRInstallationsIIDStore.m */, + A06777B4DB78BB55C72E6640E8BA41DE /* FIRInstallationsIIDTokenStore.h */, + B5BCF95BE69FDCDB288B6DD2D650398F /* FIRInstallationsIIDTokenStore.m */, + D88ABCF86F232D838F567FDACBEB3FD3 /* FIRInstallationsItem.h */, + 72C335FC7A27042501497C43922F7C50 /* FIRInstallationsItem.m */, + D95A493523FB2DFA4265B765F8BFA06E /* FIRInstallationsItem+RegisterInstallationAPI.h */, + 3B5F7F6DD4538CB6DE8986871A2965EA /* FIRInstallationsItem+RegisterInstallationAPI.m */, + 4213C92093942202692742B0F6E8A372 /* FIRInstallationsLogger.h */, + EDD9A3C2E72FAF155EF4D0403E6D9C3F /* FIRInstallationsLogger.m */, + 51E163742B3DECE034022C24CEA961D7 /* FIRInstallationsSingleOperationPromiseCache.h */, + DE16863F43AFC398785AB95591472899 /* FIRInstallationsSingleOperationPromiseCache.m */, + 29D1AD200DC6E547E00A68ED01A09C6D /* FIRInstallationsStatus.h */, + C2758FE22DBE0DF635FED68706680916 /* FIRInstallationsStore.h */, + 073788DD1F3BA0D6A1E4F105FEE47626 /* FIRInstallationsStore.m */, + DF76ABCF8FC780F5A09634D08E40A690 /* FIRInstallationsStoredAuthToken.h */, + 9E39F1849E3712A9D9DFEB11809CD4F8 /* FIRInstallationsStoredAuthToken.m */, + F1A1B6D700EBB61E205BD7BFC87E2845 /* FIRInstallationsStoredItem.h */, + 905B7DD657BA252E11F011C073B15B04 /* FIRInstallationsStoredItem.m */, + 28BF0A4825F5A1C942E39489A06D32FF /* FIRLibrary.h */, + BA0D0C8AF5CDA0A632B05B589AF94132 /* FIRLogger.h */, + 010437CF98F3CAE2A251EEE2D86CA462 /* Resources */, + F5C65A267A7D762B820506E9ACE73F20 /* Support Files */, + ); + name = FirebaseInstallations; + path = FirebaseInstallations; + sourceTree = ""; + }; + A379E1B91B49EB3274A0E493E3A5ED9E /* .symlinks */ = { + isa = PBXGroup; + children = ( + C6833CCC9E60B1256F9EF961FDAC3E99 /* plugins */, + ); + name = .symlinks; + path = .symlinks; + sourceTree = ""; + }; + A5D58DB2607BD6490D7A832B247F6C07 /* plugins */ = { + isa = PBXGroup; + children = ( + 6C1514730C3D1CDEB70C442A1132B8D5 /* firebase_core */, + ); + name = plugins; + path = plugins; + sourceTree = ""; + }; + A68143BA5E389A599AC71B36F2C19C1D /* .. */ = { + isa = PBXGroup; + children = ( + 3FBF536927667C1BEFFBB1B679439A45 /* .. */, + ); + name = ..; + path = "../../../../../../../../.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ios/firebase_core/Sources"; + sourceTree = ""; + }; + A6E09B2AF90AEEDCDC9EF2CBF76B3411 /* Network */ = { + isa = PBXGroup; + children = ( + CF3313E1A4AAD2C8C90168A130ED02C8 /* GULMutableDictionary.h */, + 27BAF00DDE21BC901CDDFBC3E0E51ACB /* GULMutableDictionary.m */, + 8AEEA5FC7114C4A84FE61786766702D8 /* GULNetwork.h */, + 4D28E6CD2A57E7F53F190E76FDADBD54 /* GULNetwork.m */, + 12CE4326B05B13F9BDF9FDD0DEC5EEF6 /* GULNetworkConstants.h */, + 4CFB397A9898BDBB88BBCFFC0548617D /* GULNetworkConstants.m */, + D2C205268B2949B720B83A78AA2A2F6C /* GULNetworkInternal.h */, + 92A5185EE87E3B7A214986492CCC6B06 /* GULNetworkLoggerProtocol.h */, + 7B07CCA749AC3691235E002653AA08F8 /* GULNetworkMessageCode.h */, + A15DFB7CC7A259F61E840FBA0257AABA /* GULNetworkURLSession.h */, + B1DA64C7F3DEAD8DF2E9C85AFE1682E7 /* GULNetworkURLSession.m */, + ); + name = Network; + sourceTree = ""; + }; + A7074DA0EFA4C143E1AC4D6F03E7C3FD /* .. */ = { + isa = PBXGroup; + children = ( + 88B2EBC8E7E9601DE0F173B6872F2C01 /* Documents */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + A72F646A07048F77582F0AE2C6F505B7 /* image_picker_ios */ = { + isa = PBXGroup; + children = ( + 93E585DF573298497CD9445A79B513D8 /* FLTImagePickerImageUtil.h */, + 9245949F7AF50C5640000F79C1110624 /* FLTImagePickerMetaDataUtil.h */, + 252ED5705010489B5DDE7E1A4E37EF6E /* FLTImagePickerPhotoAssetUtil.h */, + 00FFDE3AE7E0091D819430E2EA48408E /* FLTImagePickerPlugin.h */, + DE501C91B85AD9DEF66B570B8F7C637B /* FLTImagePickerPlugin_Test.h */, + 857B278AF026E36C0BD658D6411E29FA /* FLTPHPickerSaveImageToPathOperation.h */, + 20CFA7FEC659CB53FA77B7DB18BB054C /* messages.g.h */, + ); + name = image_picker_ios; + path = image_picker_ios; + sourceTree = ""; + }; + A7C5508B5A0F67A86FAEE734358A7E7B /* .. */ = { + isa = PBXGroup; + children = ( + 1AAE3A40D6719B95FE0AFD52269B7E79 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + B0C4D7E3847F904A678EBF4CE99D7BE1 /* Resources */ = { + isa = PBXGroup; + children = ( + BDFC14A8280221C515A9AFE2CE99D65B /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + B279B373CD06EEF86B1A2F783F379C53 /* ios */ = { + isa = PBXGroup; + children = ( + 13C7A252E42C4312E34367588AE6074D /* firebase_core */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; + B8BF34FB8DEE6BFA572B6E1D571B166A /* frontend */ = { + isa = PBXGroup; + children = ( + 8958D0EB294B8D07034B3CEDC6550C78 /* ios */, + ); + name = frontend; + path = frontend; + sourceTree = ""; + }; + B94D7768568A9992200DB461E8CF687F /* Frameworks */ = { + isa = PBXGroup; + children = ( + D4C766B4E2421A5A213D0DC5507C0EB6 /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + BE1941B9061DA527DE930E6F23B39B62 /* Products */ = { + isa = PBXGroup; + children = ( + F3B74672DAE304DCA370B761FBD5B2D7 /* firebase_core */, + 626B91FA30530F8DA0D892C01BC22133 /* firebase_messaging */, + 75CF387A098437DDEB77C4DD2B48D012 /* firebase_messaging-firebase_messaging_Privacy */, + E2B63D462DB7F827C4B11FD51E4F8E2D /* FirebaseCore */, + 8BB937B1C0DFFCF92F41861C2BC54DDA /* FirebaseCore-FirebaseCore_Privacy */, + 148D0F9E8C7373FEAF40D800FC5F1BAA /* FirebaseCoreInternal */, + 4DB03FD262B678178A44272143846563 /* FirebaseCoreInternal-FirebaseCoreInternal_Privacy */, + 13C8C8B254851998F9289F71229B28A2 /* FirebaseInstallations */, + 47C581450CDB4A6111CB97EEE0711A8C /* FirebaseInstallations-FirebaseInstallations_Privacy */, + 5B654B4B042BA7DC93766943A643E42B /* FirebaseMessaging */, + B0B6501341FD6783C6874C54AB31A9CF /* FirebaseMessaging-FirebaseMessaging_Privacy */, + D2818DB76C14B8736924E987E37A9823 /* flutter_local_notifications */, + 513486288D9850EF657161C39358ED93 /* flutter_local_notifications-flutter_local_notifications_privacy */, + 856B5CD56F194FAD26EA91620B66D614 /* GoogleDataTransport */, + F73AA961F4AEFF2B46B00AE435DF6BE3 /* GoogleDataTransport-GoogleDataTransport_Privacy */, + B43874C6CBB50E7134FBEC24BABFE14F /* GoogleUtilities */, + 44E291D18340EAC3F761346198515323 /* GoogleUtilities-GoogleUtilities_Privacy */, + 768975E636D1D2FB85622FB67DB04E5A /* image_picker_ios */, + F0C7EFBFF01CFAAB52BA74E6CB40CE2C /* image_picker_ios-image_picker_ios_privacy */, + 06FC5C9CF96D60C50FCD47D339C91951 /* nanopb */, + 3227F3FC45681D7CEE5D1355A532398A /* nanopb-nanopb_Privacy */, + 669E8F25E1897672BDB80B7EB784DA24 /* Pods-Runner */, + 6C3345B1B3CAEDF5B03B1F731FDC492E /* Pods-RunnerTests */, + 3347A1AB6546F0A3977529B8F199DC41 /* PromisesObjC */, + 3F238BB22C5201CE689CAF2F766AED95 /* PromisesObjC-FBLPromises_Privacy */, + ); + name = Products; + sourceTree = ""; + }; + C5FB9D9D618277A84A28B82F53E25757 /* ios */ = { + isa = PBXGroup; + children = ( + 6E7D4BDD596A694F58C40911CFB888AB /* Classes */, + 83AFB96A08073A251C90AFD614DC5FC8 /* Resources */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; + C6833CCC9E60B1256F9EF961FDAC3E99 /* plugins */ = { + isa = PBXGroup; + children = ( + CB5E2046555C057A0F9FA789B9C71AF5 /* firebase_messaging */, + ); + name = plugins; + path = plugins; + sourceTree = ""; + }; + CB5E2046555C057A0F9FA789B9C71AF5 /* firebase_messaging */ = { + isa = PBXGroup; + children = ( + 93790D9FDD2F9CEA5D2CD6FFAD4D2184 /* ios */, + ); + name = firebase_messaging; + path = firebase_messaging; + sourceTree = ""; + }; + CC89A1664361092E042FF2CB61BE0BC9 /* Firebase */ = { + isa = PBXGroup; + children = ( + 66647F7932D5D6F4753C341F81B4BF11 /* CoreOnly */, + D6E7F90BAF1B029576573CD27D54A0EF /* Support Files */, + ); + name = Firebase; + path = Firebase; + sourceTree = ""; + }; + CD1E0EAC4D69A09B7735D998390CF366 /* plugins */ = { + isa = PBXGroup; + children = ( + 6E445044AF891F278034B36FC558610D /* flutter_local_notifications */, + ); + name = plugins; + path = plugins; + sourceTree = ""; + }; + CE1D651CC79FC7514D64896550215ED9 /* Flutter */ = { + isa = PBXGroup; + children = ( + 7512F727C3F97C04B3EDF1F3CDF6AB4C /* Pod */, + 4973F4DE4CB366F749AEC1660E93969C /* Support Files */, + ); + name = Flutter; + path = ../Flutter; + sourceTree = ""; + }; + CEBEE4F9E64989571C12CD23F0380A71 /* .. */ = { + isa = PBXGroup; + children = ( + E9414DDC1343D9D8667EB07CD12CC8F5 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + 0B7A2D1A3D25C1DDAB1089A6142632B3 /* Development Pods */, + B94D7768568A9992200DB461E8CF687F /* Frameworks */, + F3A17D620F401C88632D862857C8B016 /* Pods */, + BE1941B9061DA527DE930E6F23B39B62 /* Products */, + 48784BA740BD93553321C337ADC29C92 /* Targets Support Files */, + ); + sourceTree = ""; + }; + CFCA555F85107F110450F883F20048E4 /* .. */ = { + isa = PBXGroup; + children = ( + ED6F830771106F996DF775E049C7BAE0 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + D0CD2303C269E3757FD8DBDBD8299345 /* .. */ = { + isa = PBXGroup; + children = ( + 555DDB2A307A47C84C0711DA4FF9F85C /* Documents */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + D1443A91868AEE5CB811A9FF42E816AF /* .. */ = { + isa = PBXGroup; + children = ( + 308B0B8D196DF824F29C7F5CD4A11829 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + D4C766B4E2421A5A213D0DC5507C0EB6 /* iOS */ = { + isa = PBXGroup; + children = ( + 3C0783D1DCE2D70C01DE8F66368E3525 /* CoreTelephony.framework */, + 411C572D658946450319E3438E61FBCC /* Foundation.framework */, + 619E6A45528E9255637879488FB26EDF /* Security.framework */, + B193AA1062E3BDA9FD9F681F8B33A4FB /* SystemConfiguration.framework */, + 21D9E6AABF6D4CF5BC663A230EF53A42 /* UIKit.framework */, + ); + name = iOS; + sourceTree = ""; + }; + D529BED0E737A5BC91E30F7F579434E9 /* Support Files */ = { + isa = PBXGroup; + children = ( + 0C55AD722325AEB399EE8A894204E0C7 /* image_picker_ios.modulemap */, + 6EDDBD54960ABBA9D0898075ADB7A56C /* image_picker_ios-dummy.m */, + 707F66161F44DCDEE17FC7C063562F45 /* image_picker_ios-Info.plist */, + 43761187E271796633E239446DAD0EB1 /* image_picker_ios-prefix.pch */, + 6C16E4E43B9D4F77B6DB7BB1766F356E /* image_picker_ios.debug.xcconfig */, + B903D4DE875B151937BA3E87E4A04205 /* image_picker_ios.release.xcconfig */, + 957B5DFE330996813A28975B2930348E /* ResourceBundle-image_picker_ios_privacy-image_picker_ios-Info.plist */, + ); + name = "Support Files"; + path = "../../../../Pods/Target Support Files/image_picker_ios"; + sourceTree = ""; + }; + D54824FDBF878417287BC199618E7FB9 /* .symlinks */ = { + isa = PBXGroup; + children = ( + CD1E0EAC4D69A09B7735D998390CF366 /* plugins */, + ); + name = .symlinks; + path = .symlinks; + sourceTree = ""; + }; + D6950E1D8D601AFE0B695E022F951E53 /* Logger */ = { + isa = PBXGroup; + children = ( + 4AD9F2841591395962459F34DBA6F234 /* GULLogger.h */, + C94ADD90B6B07B25ED550BCBE0EC2FB7 /* GULLogger.m */, + E73067A4812023AA71C5F5DE2A7A1549 /* GULLoggerLevel.h */, + ); + name = Logger; + sourceTree = ""; + }; + D6E7F90BAF1B029576573CD27D54A0EF /* Support Files */ = { + isa = PBXGroup; + children = ( + 97EF58920BA75188BEFB815F403ECFD7 /* Firebase.debug.xcconfig */, + FB0D5A901EA4BB55EB4272787CA2B4B8 /* Firebase.release.xcconfig */, + ); + name = "Support Files"; + path = "../Target Support Files/Firebase"; + sourceTree = ""; + }; + D7AAA9FB8BD133A2694FD5FDC35EDA78 /* image_picker_ios */ = { + isa = PBXGroup; + children = ( + F937DD50B5CE6D00B8915E003ED547DA /* ios */, + ); + name = image_picker_ios; + path = image_picker_ios; + sourceTree = ""; + }; + DBFD9B36B592F2BE68C9957073A188DB /* include */ = { + isa = PBXGroup; + children = ( + 3ABA51F489706FFEBF9DE0135C0C0FCA /* image_picker_ios-umbrella.h */, + A72F646A07048F77582F0AE2C6F505B7 /* image_picker_ios */, + ); + name = include; + path = include; + sourceTree = ""; + }; + E126A175BF3004CF1E089C748D21DC2D /* Resources */ = { + isa = PBXGroup; + children = ( + 3E39342DADE8E8CA6D1D925BCFF34D3C /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + E582E06AB50F2F87EFCE00F6E231689B /* PromisesObjC */ = { + isa = PBXGroup; + children = ( + E61CC707F35A1D8DFF986E0272AE2433 /* FBLPromise.h */, + F30DC71EBEC30BD542B7B8BAD2061FB1 /* FBLPromise.m */, + C00EBC7A4974174FA9C5F1FBAA0E7308 /* FBLPromise+All.h */, + B25ED3E90C5098A71F9E5478214441B0 /* FBLPromise+All.m */, + 5551C50E78F600068DECA3941CFDC868 /* FBLPromise+Always.h */, + A67F9CA5CA48ED7EC5EC8BDCEBA8414F /* FBLPromise+Always.m */, + 9867C191C8BCE953F2C1239417D48C59 /* FBLPromise+Any.h */, + 511BBAD2CBB8A874EDF7B10BE3A86FB5 /* FBLPromise+Any.m */, + 27C6F7D9AFD28A5F991FCC1ADF5594EF /* FBLPromise+Async.h */, + 98DB6F70F9386301F5C36CD6C1299D73 /* FBLPromise+Async.m */, + 1878E7A7CE833995A4A9C1C8C5241E9F /* FBLPromise+Await.h */, + E29FF4FADCEBFFF58991819DA709FC0E /* FBLPromise+Await.m */, + B4BBEFB2C73F81F446CAC134CC2546E4 /* FBLPromise+Catch.h */, + D0E98CC50462D87B324B0B4B3C712778 /* FBLPromise+Catch.m */, + 00D77329FD54061BC8C4922FDEED6DF9 /* FBLPromise+Delay.h */, + CE08696E0972B7E5F2A377E2874A05FE /* FBLPromise+Delay.m */, + 727E3D670FEDA09567F4E93499135B7E /* FBLPromise+Do.h */, + 4D78F29C73286A17F514D3070039F716 /* FBLPromise+Do.m */, + FF09DBF131ED32352049DD973E63FA75 /* FBLPromise+Race.h */, + 916ED4F015F6F56B913472172EB23B0D /* FBLPromise+Race.m */, + 9EFF6746B2289C5FD36C9BC6742995F1 /* FBLPromise+Recover.h */, + 7ECD27E226247CC6BEE22DBFBF905F60 /* FBLPromise+Recover.m */, + B83C30F28A2D3A9276FE5DE6F46E1766 /* FBLPromise+Reduce.h */, + F7DFFA85CEF0CB6E8D3932BE99635EB6 /* FBLPromise+Reduce.m */, + AF370489BA290D16F746A5FC144C8ED5 /* FBLPromise+Retry.h */, + D8080290C8FF379AAFE127072282B83E /* FBLPromise+Retry.m */, + D3CBFEF9C55D8B8C77DC8B0311BBB9CE /* FBLPromise+Testing.h */, + 6B6B934456F9D9272269319603A5F9C3 /* FBLPromise+Testing.m */, + C521DDFFCA95CC5736F10248D9812971 /* FBLPromise+Then.h */, + 919FA6048D25DD3D403B87F067045348 /* FBLPromise+Then.m */, + A38E222418E1BD45495FCA32F1873620 /* FBLPromise+Timeout.h */, + 01C21144A7A96E0CDBABE621D3EC79CD /* FBLPromise+Timeout.m */, + 34E0FF48D6D2CD42238C1A65D59CED2F /* FBLPromise+Validate.h */, + 2AEADD8988B976B2FC825995D7A877AD /* FBLPromise+Validate.m */, + 545009CB939B8FA897EBC1023E6DA94C /* FBLPromise+Wrap.h */, + 1FC1F7D9B41F4C5EC44785ED4449DABD /* FBLPromise+Wrap.m */, + 12C8D8D85F32CD7F51280DC4963FA9A0 /* FBLPromiseError.h */, + 1D5E75344C12FBE305143C4EE160EF82 /* FBLPromiseError.m */, + 84F8E1FB429C5EB93170E449E74D75B1 /* FBLPromisePrivate.h */, + 2EB64290BD8F25183F5F3B6E893CEC55 /* FBLPromises.h */, + E94BDF76D5F3242FDBE6B150524597A7 /* Resources */, + 9AC8FB3816FAC566415BEB71670DDEAC /* Support Files */, + ); + name = PromisesObjC; + path = PromisesObjC; + sourceTree = ""; + }; + E9414DDC1343D9D8667EB07CD12CC8F5 /* .. */ = { + isa = PBXGroup; + children = ( + 669F78689DB46140972316A4CA284CEB /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + E94BDF76D5F3242FDBE6B150524597A7 /* Resources */ = { + isa = PBXGroup; + children = ( + 5F79E91E59676DD40F34E8E5DEFC6A9E /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + sourceTree = ""; + }; + EA3FD3C1C68A16D9A0908CF45B76B3E8 /* firebase_messaging */ = { + isa = PBXGroup; + children = ( + 85297D57D31AF535B35107FA3534855A /* FLTFirebaseMessagingPlugin.m */, + 2503F4B653440C1110DC9F5ED308B677 /* include */, + ); + name = firebase_messaging; + path = firebase_messaging; + sourceTree = ""; + }; + EA5A45D7768C919A51F9CCBED76EBBC5 /* .symlinks */ = { + isa = PBXGroup; + children = ( + EEBD451B7354687013DDC2A5C83FF3CF /* plugins */, + ); + name = .symlinks; + path = .symlinks; + sourceTree = ""; + }; + EB257A81BCCE619200312B3F737CDBF2 /* Gradi_25Fall */ = { + isa = PBXGroup; + children = ( + 9F075856BE98B1550012512D4D169BAC /* frontend */, + ); + name = Gradi_25Fall; + path = Gradi_25Fall; + sourceTree = ""; + }; + ED6F830771106F996DF775E049C7BAE0 /* .. */ = { + isa = PBXGroup; + children = ( + 072702053E8A7D816FB4305AA3AC54BA /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + EE41A2B0C091AD29E62B883D7F8AD6AC /* Documents */ = { + isa = PBXGroup; + children = ( + 499EAB2CFF652CEEC9F1CFB7371FDC99 /* Gradi_25Fall */, + ); + name = Documents; + path = Documents; + sourceTree = ""; + }; + EEBD451B7354687013DDC2A5C83FF3CF /* plugins */ = { + isa = PBXGroup; + children = ( + D7AAA9FB8BD133A2694FD5FDC35EDA78 /* image_picker_ios */, + ); + name = plugins; + path = plugins; + sourceTree = ""; + }; + EEE40ED8800AF29392D5F3DB397E437E /* Support Files */ = { + isa = PBXGroup; + children = ( + A98F7B52E50AE5E6285A9A90E0429AFF /* FirebaseCoreInternal.modulemap */, + BA6F9C82EF49DC1505AB92789AC3C133 /* FirebaseCoreInternal-dummy.m */, + 5933B364C8A4BF4E4CED5DF0016F175F /* FirebaseCoreInternal-Info.plist */, + 836799D7AEDE4394FF12B9184A5D77E7 /* FirebaseCoreInternal-prefix.pch */, + BD75CD0508AD16FB45C1DD6842B85A77 /* FirebaseCoreInternal-umbrella.h */, + 78CF3937473E3F59F7E47C945F33DB50 /* FirebaseCoreInternal.debug.xcconfig */, + 279906FE251A2F87816561487A4BBB08 /* FirebaseCoreInternal.release.xcconfig */, + 12F5C151D4D75DC95504E85575964C8C /* ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseCoreInternal"; + sourceTree = ""; + }; + F3A17D620F401C88632D862857C8B016 /* Pods */ = { + isa = PBXGroup; + children = ( + CC89A1664361092E042FF2CB61BE0BC9 /* Firebase */, + 833AE2029D5B5A82A98C77B351D1C67C /* FirebaseCore */, + 106DEECDE2DA0C490E6087ED6F4FED4C /* FirebaseCoreInternal */, + A2C84E137E72B1BCC25B0A7F44436F85 /* FirebaseInstallations */, + 239126CA47E44407F16B4613708F765A /* FirebaseMessaging */, + 4ECF93295DFC0799FAF8A3A46C5B789D /* GoogleDataTransport */, + 01E6C1BC46C650C58003A771DA7F3D74 /* GoogleUtilities */, + 3C3903F38477F218159F2194FBAD0386 /* nanopb */, + E582E06AB50F2F87EFCE00F6E231689B /* PromisesObjC */, + ); + name = Pods; + sourceTree = ""; + }; + F5C2DC2EB3A1CCED15630C277EC08433 /* .. */ = { + isa = PBXGroup; + children = ( + 0F78B694F96996258D046C0DF40E5C09 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + F5C65A267A7D762B820506E9ACE73F20 /* Support Files */ = { + isa = PBXGroup; + children = ( + 908FF3C2F86633C7AE8EB9F4F1E80B9C /* FirebaseInstallations.modulemap */, + 93CE9B2E15F0CFDDF3305716F26E8467 /* FirebaseInstallations-dummy.m */, + 925C2D5A764E37386204B256CA65AB8B /* FirebaseInstallations-Info.plist */, + 4F58BAB8D1B897095AA76F603F58EBFD /* FirebaseInstallations-umbrella.h */, + 8D8A24088A30A466B083BC03A5AE1101 /* FirebaseInstallations.debug.xcconfig */, + 618D7CDD1897742A6C54A37FFB4D0219 /* FirebaseInstallations.release.xcconfig */, + BD3BD1D65B117C25A6F2FA906D597A39 /* ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist */, + ); + name = "Support Files"; + path = "../Target Support Files/FirebaseInstallations"; + sourceTree = ""; + }; + F733C06013DDD6E5B5E1694C37DDB5BD /* Pods-Runner */ = { + isa = PBXGroup; + children = ( + 0D351F23C38290B0C3B49DC7310E8B45 /* Pods-Runner.modulemap */, + A8FDBAA5DB30273D3A49EC23FF64001E /* Pods-Runner-acknowledgements.markdown */, + 45E120F4A9F7D13802BA4D4E76E24EFC /* Pods-Runner-acknowledgements.plist */, + 4CB131F3BC1D6D2C79680B59CF30EF6B /* Pods-Runner-dummy.m */, + CFA56F7544C7A03823E1D2D749934BFC /* Pods-Runner-frameworks.sh */, + 16754451CC068C973247E72B5EACF78C /* Pods-Runner-Info.plist */, + 7FA1EE3150AB7E2D7A76E646E7CA6C1E /* Pods-Runner-resources.sh */, + BCC84BDE7260B712B097666E169A193C /* Pods-Runner-umbrella.h */, + 2F0908B8A5026151E2800777E4B17F20 /* Pods-Runner.debug.xcconfig */, + 2B3AF9D90D4B088422687FFF4641CBC3 /* Pods-Runner.profile.xcconfig */, + F8547457089967DAC30C3130D4EDF7D1 /* Pods-Runner.release.xcconfig */, + ); + name = "Pods-Runner"; + path = "Target Support Files/Pods-Runner"; + sourceTree = ""; + }; + F8555CE790C1C8A5532937169BFFE3DD /* Gradi_25Fall */ = { + isa = PBXGroup; + children = ( + B8BF34FB8DEE6BFA572B6E1D571B166A /* frontend */, + ); + name = Gradi_25Fall; + path = Gradi_25Fall; + sourceTree = ""; + }; + F937DD50B5CE6D00B8915E003ED547DA /* ios */ = { + isa = PBXGroup; + children = ( + 02AD19C491229E14D9AC48C0A9B3C116 /* image_picker_ios */, + ); + name = ios; + path = ios; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 0E5EA2EC4B601D99DEF81F43EB8CABD4 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 09ED7C9E0D2AD0089F0A963AB722D00F /* Pods-Runner-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 12CAA56F4981E34F8AAE18C1B78557E3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 009AE534528CDDAE7E5E5BEC0E83981A /* nanopb-umbrella.h in Headers */, + 0587C0EEAEB4C3D21491C6EE0A620178 /* pb.h in Headers */, + D25A30EC156A63A0BAA6C9D733BD2834 /* pb_common.h in Headers */, + 2513C5C0DB00539C0026FA3729A6D2C5 /* pb_decode.h in Headers */, + 1F4B7B2479B0430452AA32F8218495A9 /* pb_encode.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1B2FB06F551FA0077084A2BEFC32E626 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 9F60D4B837062AF7F00AF5870E7F08F9 /* cct.nanopb.h in Headers */, + 7569264A765ABBC5B22A8D1FEA13BDD0 /* client_metrics.nanopb.h in Headers */, + C9E3A70F5A9E32DBF7A2CB44A76DE9C1 /* compliance.nanopb.h in Headers */, + 3648AB694DB575E7E60E787F307CCF2D /* external_prequest_context.nanopb.h in Headers */, + 3FEA9D3B888B3980702E68214ABADA5E /* external_privacy_context.nanopb.h in Headers */, + 91F80BDF63CDDEA0D3487E227DF9FF5B /* GDTCCTCompressionHelper.h in Headers */, + 493D43EF0F30335CA5779D3C6A065588 /* GDTCCTNanopbHelpers.h in Headers */, + 9F8F96C7051EF3BDBDC764B07A37E130 /* GDTCCTUploader.h in Headers */, + 1A438F3B4C0C2739358FF5DAD9F5A4C1 /* GDTCCTUploadOperation.h in Headers */, + B06F806AC06F78F2ADCE0159B115705F /* GDTCCTURLSessionDataResponse.h in Headers */, + EEB114A1198D178FB1C6C8BC5B2DB442 /* GDTCORAssert.h in Headers */, + 72FA74901D64A09C1F55D8DF8F52B176 /* GDTCORClock.h in Headers */, + E6C95844ACBB8AA73161C5E7AA4D689E /* GDTCORConsoleLogger.h in Headers */, + D30890C71943B3623755D4EC78F004CF /* GDTCORDirectorySizeTracker.h in Headers */, + F2852D062145348D0706025C88866693 /* GDTCOREndpoints.h in Headers */, + 6323383CC1216A37D613D2608C001940 /* GDTCOREndpoints_Private.h in Headers */, + 7FC7DADC5F23D90E94F19D4A71444D35 /* GDTCOREvent.h in Headers */, + 1CC94C695A8D7E61B92E44ED84B88D50 /* GDTCOREvent+GDTCCTSupport.h in Headers */, + 5E43A31995CAC5C41E291FD562CBB823 /* GDTCOREvent+GDTMetricsSupport.h in Headers */, + 0DD0CC775C037EE7BAA4BA1497D15EDB /* GDTCOREvent_Private.h in Headers */, + 544280ADC86CD3645E5CA2495F18D452 /* GDTCOREventDataObject.h in Headers */, + 40754B9673CD03A705FFDD2734E0181A /* GDTCOREventDropReason.h in Headers */, + 2C08D6A1AB540EA72D250B54E8CF9C3D /* GDTCOREventTransformer.h in Headers */, + 11C2E0C3CE9E7BBD53FF9A879ADFC54F /* GDTCORFlatFileStorage.h in Headers */, + C741E544E6FEE0679FB092AD4568DC76 /* GDTCORFlatFileStorage+Promises.h in Headers */, + C3F511EA3E1AF5A8CDD921D6C96F35BF /* GDTCORLifecycle.h in Headers */, + 1F07E5C1F822DD99C54C88E97A974058 /* GDTCORLogSourceMetrics.h in Headers */, + E63CDE7BF4ABF68C58E0110698286A53 /* GDTCORMetrics.h in Headers */, + 0DFBDA661534DFF7B7161F3D9A36C1A3 /* GDTCORMetrics+GDTCCTSupport.h in Headers */, + CA90913666ED773FD6C6B148EBF1C9B8 /* GDTCORMetricsController.h in Headers */, + A9B88AF4BF6260F8378F14F7506ECF89 /* GDTCORMetricsControllerProtocol.h in Headers */, + 3B56BCBA48E035A238B77B3A225EC6AC /* GDTCORMetricsMetadata.h in Headers */, + D87051785D72FCC6749E51472EBADF70 /* GDTCORPlatform.h in Headers */, + 9A3021D76E2B754738B65ADC8ED11181 /* GDTCORProductData.h in Headers */, + A2BAEBCD6D1CAAEC9BCFAE3DC4819C14 /* GDTCORReachability.h in Headers */, + D1CA3597FB8047DFC7BCE711E7E91C63 /* GDTCORReachability_Private.h in Headers */, + CDE19547447CB737FC76C275C88BB7D6 /* GDTCORRegistrar.h in Headers */, + 7D3F85C5EA471C4551F2BD8A5009B52A /* GDTCORRegistrar_Private.h in Headers */, + 7AD65DC99362610A75A7E598EE6F5F33 /* GDTCORStorageEventSelector.h in Headers */, + 3D8C0E872A44DAB97F4DED0B0C32DD85 /* GDTCORStorageMetadata.h in Headers */, + 09E8AEF6A2333C2AF970994B5A4F81AB /* GDTCORStorageProtocol.h in Headers */, + 7B57B2EAB92952ABE214A49A637CCB82 /* GDTCORStorageSizeBytes.h in Headers */, + D68DEFDF612A8135C271A428204DAC30 /* GDTCORTargets.h in Headers */, + AE45411B1C58FC1EE4F48E723CB6CA14 /* GDTCORTransformer.h in Headers */, + 276A96E8DFA740171098223E83C76817 /* GDTCORTransformer_Private.h in Headers */, + 2DC132ABBFF98D1617F6BFB15928CA0B /* GDTCORTransport.h in Headers */, + CB37C4826B004B6D04CB0DA533B257E3 /* GDTCORTransport_Private.h in Headers */, + 0B26180FB07A238EB65995A651441012 /* GDTCORUploadBatch.h in Headers */, + CAB72AF2BCBA56C4E6D5BDA273941399 /* GDTCORUploadCoordinator.h in Headers */, + BDA978C9EAD726C618B126E9839199E3 /* GDTCORUploader.h in Headers */, + 21BEF5DA11B1DBC9D7DBAA2032842F13 /* GoogleDataTransport.h in Headers */, + 91B90D51F260BB17A2EB29F9D3CE4C9E /* GoogleDataTransport-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2C8E56B683C60849A65BE80C0F4ADE2A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 9270C74C406F0F608346E1E9B2F1535C /* FBLPromise.h in Headers */, + AC19EF1EBF438BA93F976199EC9C357B /* FBLPromise+All.h in Headers */, + F084F5844715E1103AF57EB0EBF82AC2 /* FBLPromise+Always.h in Headers */, + F98570EE85F37E3B97540660F9CE9061 /* FBLPromise+Any.h in Headers */, + D970FF5E30342365D35A8EA77860069A /* FBLPromise+Async.h in Headers */, + 4A94139A1289CE6297ABC9EAFD4E37BC /* FBLPromise+Await.h in Headers */, + 750D0629F1E212AAEBC050275771A101 /* FBLPromise+Catch.h in Headers */, + 499E1800B68C714B4BB042E76C79FD66 /* FBLPromise+Delay.h in Headers */, + 3C5C68623B8428B3C9A15638A80B7048 /* FBLPromise+Do.h in Headers */, + BDAFAC271C65BB7F19F10CDB115403DE /* FBLPromise+Race.h in Headers */, + D1C210F4F9DABF8892209A992A62D323 /* FBLPromise+Recover.h in Headers */, + 0785621278D71B1DE67F4BAC1E860E69 /* FBLPromise+Reduce.h in Headers */, + 68C3CA9A7A088553FEDF725120477E7A /* FBLPromise+Retry.h in Headers */, + 7457CF2B4D9B476CF1318103FE7830F2 /* FBLPromise+Testing.h in Headers */, + 0F5A053CBEC500A7E84633E29A32651B /* FBLPromise+Then.h in Headers */, + 07BCEFB4A881BEAD7733853378252048 /* FBLPromise+Timeout.h in Headers */, + 0D2872C9FF381C30DE475A675AED4C67 /* FBLPromise+Validate.h in Headers */, + 8EE9C67DDCF4CEE8B4DD33A27410CB22 /* FBLPromise+Wrap.h in Headers */, + 3638C218BDFEFC0C5484CC46569BDC0A /* FBLPromiseError.h in Headers */, + 1E678DEABDD346FA91C6A0503F1E8789 /* FBLPromisePrivate.h in Headers */, + 87586DAA45B3C853A2C09663187F2D56 /* FBLPromises.h in Headers */, + 91F8E57F87FED95335A57C5C724CEA07 /* PromisesObjC-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4204571A0B75FA667DA483210F248E0F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7B044EC231D1AF36640ACEC0023E63E8 /* FIRAnalyticsInterop.h in Headers */, + 9D703371D3CD787AE857A36BEDEE2AA7 /* FIRAnalyticsInteropListener.h in Headers */, + 1B94F23129421A5CC48403B8178218F8 /* FIRAppInternal.h in Headers */, + D59044973DC2A2F2C10E17DC826A1E85 /* FIRComponent.h in Headers */, + 842329951AFD13954BF159C504EED836 /* FIRComponentContainer.h in Headers */, + 67F5C250302A291A794C510EAE9F863B /* FIRComponentType.h in Headers */, + EE6FD1E0FC78308189FCECE05EC4D332 /* FirebaseCoreInternal.h in Headers */, + F39765586A881C4E7171A53A4BA8BD47 /* FirebaseInstallationsInternal.h in Headers */, + 37C4392EA3367F629410DAC46D87AA4A /* FirebaseMessaging.h in Headers */, + ACF4F3EE73B67DE6C5F84E2E126331C9 /* FirebaseMessaging.h in Headers */, + C0DA634B37A4964EC148F3CFBCF55AE7 /* FirebaseMessaging-umbrella.h in Headers */, + 9154C7945BC9328823005BD246F0F4BA /* FIRHeartbeatLogger.h in Headers */, + 5D916C6AF9F15F17055C7EA9D2DA73D8 /* FIRInteropEventNames.h in Headers */, + 16D77ED94360918B9B6C001B243A1D6C /* FIRInteropParameterNames.h in Headers */, + 438A690FC09DEE64359AB9D6F43A9FF4 /* FIRLibrary.h in Headers */, + 18DB9163B1CC2366698518359F84871B /* FIRLogger.h in Headers */, + 84EAD76FFB65566ABC8E5903AB04AD0C /* FIRMessaging.h in Headers */, + 0C6E2C0C66F1050EBD6675CD2CF943AF /* FIRMessaging+ExtensionHelper.h in Headers */, + AC1ADE881BF50CD7ABABA58EB080B629 /* FIRMessaging_Private.h in Headers */, + B5FCC5B73EA83034C63477419EC69BE7 /* FIRMessagingAnalytics.h in Headers */, + 7304F433C6347EB07D4142B01875E1F1 /* FIRMessagingAPNSInfo.h in Headers */, + 61D8E48C8F979AB44479550A3F40E672 /* FIRMessagingAuthKeychain.h in Headers */, + BEAC8F429499100F442589D4AACA6D50 /* FIRMessagingAuthService.h in Headers */, + 64BFAE5154200351C22E8E9DFCBA9519 /* FIRMessagingBackupExcludedPlist.h in Headers */, + 275ECCAB21ADAB686EE232016D4F92FE /* FIRMessagingCheckinPreferences.h in Headers */, + 285E16ED3A35B853639E6100AFCEFBCF /* FIRMessagingCheckinService.h in Headers */, + 98B873497D2CAB99A2FD1A57455067AE /* FIRMessagingCheckinStore.h in Headers */, + 9B4E040836612266D4738000DCD0BB46 /* FIRMessagingCode.h in Headers */, + 751479F72F20B4861E68ABD6C985F2ED /* FIRMessagingConstants.h in Headers */, + 6A7F71291F8499AE4C5EA03A137948D9 /* FIRMessagingContextManagerService.h in Headers */, + 80FBAA97526FE8395E5745B3D5FD9BFA /* FIRMessagingDefines.h in Headers */, + 1B60A4B1E41A656934200C3CCAE63D4B /* FIRMessagingExtensionHelper.h in Headers */, + 6B64390E7A14853A1204E075A2C12033 /* FIRMessagingInterop.h in Headers */, + 19149081E4D94571DA14231CBEB5B69B /* FIRMessagingKeychain.h in Headers */, + D6E56A02CA701D7DF1A692667B5163BD /* FIRMessagingLogger.h in Headers */, + E4E105868F5E9B636CDCDC5296FEB98A /* FIRMessagingPendingTopicsList.h in Headers */, + 472479E65845A87D981A2DEE1A85214D /* FIRMessagingPersistentSyncMessage.h in Headers */, + D22276343FBA6C2562BE9AB3A5620041 /* FIRMessagingPubSub.h in Headers */, + F934DFC104F5662200123E6AA5E2A207 /* FIRMessagingRemoteNotificationsProxy.h in Headers */, + 53DC0DA5AD85987E2AC963F80B89ADE7 /* FIRMessagingRmqManager.h in Headers */, + F6F533DB29E1D3E34B55A0052FEDE521 /* FIRMessagingSyncMessageManager.h in Headers */, + 404A66D9391BC3DD7D99828504E2BDF5 /* FIRMessagingTokenDeleteOperation.h in Headers */, + A838944C074357D7A1770D93C190BE46 /* FIRMessagingTokenFetchOperation.h in Headers */, + 4D0780433AAE191F9E90337E264A5BD8 /* FIRMessagingTokenInfo.h in Headers */, + 384C25A1E858BA823349DED7C0D94DCC /* FIRMessagingTokenManager.h in Headers */, + 897899B6759269070488C811DEB03E42 /* FIRMessagingTokenOperation.h in Headers */, + 0B06543A58DA0D4CBDC34716A1E19AE4 /* FIRMessagingTokenStore.h in Headers */, + BA84AE2395BC044BF80418CD6030E54B /* FIRMessagingTopicOperation.h in Headers */, + A7FBF0C702FEC57796B4C65CD6C0EF44 /* FIRMessagingTopicsCommon.h in Headers */, + 6ED29C09EB0823C0305A238D34A3CC3A /* FIRMessagingUtilities.h in Headers */, + 54A0EBF36971E9AC4B2E9011816EAE7F /* me.nanopb.h in Headers */, + B74DE84140BDE18B1242DD0D620DFAC0 /* NSDictionary+FIRMessaging.h in Headers */, + C11F71971DA2059D684AD5816443A802 /* NSError+FIRMessaging.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 734660C1C2C0F8FD0D664F521FA1F77A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E532F0A39000EBA4FEC76E115C32030E /* GoogleUtilities-umbrella.h in Headers */, + A9455B109C5A7FB8C5E6D1AE2CFB6619 /* GULAppDelegateSwizzler.h in Headers */, + ACC60E8A6204093A2A5B71497385FA7A /* GULAppDelegateSwizzler_Private.h in Headers */, + 7AC356CA025D0FEF92051678F0A18AFC /* GULAppEnvironmentUtil.h in Headers */, + 61F8891E091E3B6588E727E00DF94770 /* GULApplication.h in Headers */, + 72D7E53AE93FAA6CF9BA9301EAC7E6B0 /* GULKeychainStorage.h in Headers */, + EEECBF4E927482BAF8199FD81F79C1BD /* GULKeychainUtils.h in Headers */, + 5C0814943AFDA883ABE9FBA93D14BA07 /* GULLogger.h in Headers */, + 61CBAEADE7CDDF9E6DA1B468C2180BC1 /* GULLoggerCodes.h in Headers */, + 6AEDFFDC5780162138E8D7DE0698F649 /* GULLoggerLevel.h in Headers */, + 4B8187E18881BD774BD62686E71527FD /* GULMutableDictionary.h in Headers */, + 8C5951DCC3226AA3B75DA1618216B15B /* GULNetwork.h in Headers */, + E700869F7CD4BC498C4C22937E0848D0 /* GULNetworkConstants.h in Headers */, + 5382B2C6ACF2D1F0F1711E71EFBCA736 /* GULNetworkInfo.h in Headers */, + 0F06FE337A62AFA36D005589967BC90D /* GULNetworkInternal.h in Headers */, + 00A8EF145409B6264F85D45182E6F11C /* GULNetworkLoggerProtocol.h in Headers */, + 89DC4CFE4B7E8EEB8DD6933AA505B5BB /* GULNetworkMessageCode.h in Headers */, + 49645BA65DD9ED60A716A4BCA65C7D49 /* GULNetworkURLSession.h in Headers */, + 40122AC85B3F1699C34744E7EDA39C8A /* GULNSData+zlib.h in Headers */, + DCC14056D1B279416B8245E7D21BB970 /* GULReachabilityChecker.h in Headers */, + 979FC74FB51633CCE1283ED32A496BEF /* GULReachabilityChecker+Internal.h in Headers */, + DBD16C9FE34200CFBE4750E049F73595 /* GULReachabilityMessageCode.h in Headers */, + AF98A71F63A1C7C96F6F5276B6C6E294 /* GULSceneDelegateSwizzler.h in Headers */, + 5DA5FA0CB3AEE2A705640929B960522B /* GULSceneDelegateSwizzler_Private.h in Headers */, + 1CF9D1DC095D24970CFC8E135F7616D3 /* GULUserDefaults.h in Headers */, + 220954F9E123D8C3938D1B7630C6FD5C /* IsAppEncrypted.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7458FB28F60AC8C18BC9DF5C2AE604BC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 58AD4E1DE1536902C995397B3D3C07F9 /* ActionEventSink.h in Headers */, + 931DB7CBE666982D4227D56B4D4B48F1 /* Converters.h in Headers */, + 5019D7BE0BF1B9EC313A35D344349DFE /* flutter_local_notifications-umbrella.h in Headers */, + D122EC7B51B97CE4665506DDA02C4257 /* FlutterEngineManager.h in Headers */, + 17C6DA08C7213732A9978A61551D596A /* FlutterLocalNotificationsPlugin.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 77C4610B8C3FE989CEF894E346FFC87A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 239863429DD644D3C8FD31BB9592B347 /* dummy.h in Headers */, + C0B9117B0CE538886275E248E19346B7 /* firebase_core-umbrella.h in Headers */, + FCC88198892649F6D51E02FD2E2918D5 /* FLTFirebaseCorePlugin.h in Headers */, + D2C4E19D3184A18BA88FEB3DB9C25680 /* FLTFirebasePlugin.h in Headers */, + D0B5A819F9DF9C4D282A62A3E745EA32 /* FLTFirebasePluginRegistry.h in Headers */, + A375B78D2AD54614602D49E5984931F4 /* messages.g.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8DF624C37333AC9C22805D69B6FA9442 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3A706CF97C1EDA8D155C153CBD7121A6 /* FirebaseCoreInternal-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9CB3573ED4594644C08E9EDDDCF3A99D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8242A992829FEFFA2B3781F60F01EDC5 /* FIRAnalyticsConfiguration.h in Headers */, + 6E7EBB4FDEFFA4EEF8A7E57AF5B3A94F /* FIRApp.h in Headers */, + BD07A6D1833C206CCDF7F92845225991 /* FIRAppInternal.h in Headers */, + 8D8A6A88D28463F025D2C1A1545BFE99 /* FIRBundleUtil.h in Headers */, + 99B920AA9E73B9F4F7AE1C5AF4E69DC2 /* FIRComponent.h in Headers */, + 620C4EDB9C0FA59FAD2487301B386B82 /* FIRComponentContainer.h in Headers */, + 9212CB7F5D22BEA7CAFC45714545EAD3 /* FIRComponentContainerInternal.h in Headers */, + C4D47F5765D8F5C5CD1D4F86E89DA8AF /* FIRComponentType.h in Headers */, + 2490496B11F00A0DA461D6CE37BE903E /* FIRConfiguration.h in Headers */, + 9443B33116703E1817AA29E6DBCBEBC8 /* FIRConfigurationInternal.h in Headers */, + 9BD72C002DD685377F9BDF27B04C1DB6 /* FirebaseCore.h in Headers */, + 7E621877E882B58DA8C15C788BDEA6C7 /* FirebaseCore-umbrella.h in Headers */, + B576B9C541C214280BF77606E022B14A /* FirebaseCoreInternal.h in Headers */, + 7851CFF4F7E792321144B8939167E84B /* FIRFirebaseUserAgent.h in Headers */, + 60409D502F9E75B6BA3A7FC9F697E90C /* FIRHeartbeatLogger.h in Headers */, + E735396838D12795BB9F1B0F8C0E4B25 /* FIRLibrary.h in Headers */, + B731645D792DAE16A62DA50AC1245AC0 /* FIRLogger.h in Headers */, + 688490CB29644F8758A46C3C042F10CB /* FIRLoggerLevel.h in Headers */, + E37D698A247D3F60BFCF14A6E5ACAFD0 /* FIROptions.h in Headers */, + DFE6EBE75E9A7639156E22E266C5E32D /* FIROptionsInternal.h in Headers */, + E15444EFB3802537E7C30B3D687BD68C /* FIRTimestamp.h in Headers */, + BEC9964729B6B2C2017EB6BF664DDBCC /* FIRTimestampInternal.h in Headers */, + 31669F21EC4AA5BBB6DD01B51612CDEB /* FIRVersion.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + ABB8D2A0B00BBB06C4066C8B11BED0AC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 88F2E9580ADEE4C0B0FA25B82AFE5A9F /* FLTImagePickerImageUtil.h in Headers */, + 215495EF2965BB009E9A6C9E224651BB /* FLTImagePickerMetaDataUtil.h in Headers */, + 74601E4C287C1065C3FC68008551691F /* FLTImagePickerPhotoAssetUtil.h in Headers */, + 22BD42F0338D295125A9731250A8215B /* FLTImagePickerPlugin.h in Headers */, + 5D89D22A2709CE7E0BB89B03B7423628 /* FLTImagePickerPlugin_Test.h in Headers */, + DB6FA7F9C81D6A05761CEF5A9BC11E56 /* FLTPHPickerSaveImageToPathOperation.h in Headers */, + 074401DD0ECBA53E57075F84BDE3C310 /* image_picker_ios-umbrella.h in Headers */, + D5644BFA4BACB8E7C3E53FC0C6323E05 /* messages.g.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DE243339F7DDAB0EC6DEB58F40872A9D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 6CF412935C7B90C13242614A2BC4261E /* FIRAppInternal.h in Headers */, + 9478BF72A1EB6C4A947C9BD449A9BDBA /* FIRComponent.h in Headers */, + 6EB1422201E4BC496256783843401BE9 /* FIRComponentContainer.h in Headers */, + B6A5387072A26F8F7F51DA746CDE80E5 /* FIRComponentType.h in Headers */, + 06237A16A8BAC89D177AF533730FDBB8 /* FIRCurrentDateProvider.h in Headers */, + FC08C647E5AD9FB89636C914A2520EC6 /* FirebaseCoreInternal.h in Headers */, + 80DFF208DB00F875CDF7A0871CFEB350 /* FirebaseInstallations.h in Headers */, + 78EF505756B7A2E9E0BBB07E44B01248 /* FirebaseInstallations-umbrella.h in Headers */, + 2C0E76791D2814239B3C5B93F6F11DD0 /* FirebaseInstallationsInternal.h in Headers */, + 934946C3A556F12CA77F218649CDA697 /* FIRHeartbeatLogger.h in Headers */, + 7F79644506B07B238B26434BFB71DC75 /* FIRInstallations.h in Headers */, + 6A61C6D8BA03B9675E35694AA7BFFD00 /* FIRInstallationsAPIService.h in Headers */, + 19FFA03079E30FBB6884BCAC56DD2132 /* FIRInstallationsAuthTokenResult.h in Headers */, + E13FBC9788A0862DC162AC67FD55AFB9 /* FIRInstallationsAuthTokenResultInternal.h in Headers */, + F8FF1998A797C15F68434F157B9B5D1C /* FIRInstallationsBackoffController.h in Headers */, + 4DE6C1CFFCD152E770A1433419AD8E34 /* FIRInstallationsErrors.h in Headers */, + 36751170F570E5241CC3A11282BD0341 /* FIRInstallationsErrorUtil.h in Headers */, + 816A43F3F940EA10A0E082CCE3C2784D /* FIRInstallationsHTTPError.h in Headers */, + 158E75642E31997D32F8CAA6ED8C3D69 /* FIRInstallationsIDController.h in Headers */, + E78EB8DAE38E6379F08424C3F42C53E7 /* FIRInstallationsIIDStore.h in Headers */, + F07AD4215638DC0BB6294D26F724455F /* FIRInstallationsIIDTokenStore.h in Headers */, + 9DD757379090CA5206E073BE4F5E3457 /* FIRInstallationsItem.h in Headers */, + BB694DA12F8A49C9D40D2C3FE43D9AC4 /* FIRInstallationsItem+RegisterInstallationAPI.h in Headers */, + F117AE9AFD9CA0918457364B5224BA7D /* FIRInstallationsLogger.h in Headers */, + 19451FEC797AB117546FEC0D36D8AB36 /* FIRInstallationsSingleOperationPromiseCache.h in Headers */, + 2C1B8D99B5F7257C2F90DDFF8CBB76F3 /* FIRInstallationsStatus.h in Headers */, + 4475763B57CBB56D34AD86A90F7498D5 /* FIRInstallationsStore.h in Headers */, + F354E23D48F280BED18EE1E7109BC0EF /* FIRInstallationsStoredAuthToken.h in Headers */, + 2CC677CAF6F511B9D0BC37FAFF3A3A63 /* FIRInstallationsStoredItem.h in Headers */, + 5507D046C4E8455B1CBA2B9E80B627DA /* FIRLibrary.h in Headers */, + 4060F7F3B3994466089B08C6B344FE1B /* FIRLogger.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E3BA34355E381CBF076CDBE8B3D019E5 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 73D7985E3D8DA2E28A794979EDD4A1CB /* firebase_messaging-umbrella.h in Headers */, + 34C107B2B498E0E9938E09AD436D7C20 /* FLTFirebaseMessagingPlugin.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FC4DA9BD27A4914E75F803590E4C4B8B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + EB2DC96CDCF638AB89007D2DB0F3119A /* Pods-RunnerTests-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 1001C16510D946B47CFF8B19DBC0B787 /* FirebaseCore-FirebaseCore_Privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = A5B701584A7226F4EA1D22F8A8C3212C /* Build configuration list for PBXNativeTarget "FirebaseCore-FirebaseCore_Privacy" */; + buildPhases = ( + 4164EACC29BB2CA05655CCAC9E955877 /* Sources */, + 011DF66FFEC59ABF67BB667B58689AF2 /* Frameworks */, + 9F2A213061BBCC007B30472BEEAB67EB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "FirebaseCore-FirebaseCore_Privacy"; + productName = FirebaseCore_Privacy; + productReference = 8BB937B1C0DFFCF92F41861C2BC54DDA /* FirebaseCore-FirebaseCore_Privacy */; + productType = "com.apple.product-type.bundle"; + }; + 1BFBEDBF7E03729D43C96530EE190825 /* PromisesObjC-FBLPromises_Privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = F415E1450AA4CE65860E7ADC0DD4E41B /* Build configuration list for PBXNativeTarget "PromisesObjC-FBLPromises_Privacy" */; + buildPhases = ( + 3077D4C072B5555EB5D43BA45E694885 /* Sources */, + 9A50662B13743CE2A849499FACE17ECE /* Frameworks */, + 7F0A7510B30C0682145ACC058656CF53 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "PromisesObjC-FBLPromises_Privacy"; + productName = FBLPromises_Privacy; + productReference = 3F238BB22C5201CE689CAF2F766AED95 /* PromisesObjC-FBLPromises_Privacy */; + productType = "com.apple.product-type.bundle"; + }; + 21FB29F43C8A2A81ABFE8C478370070E /* FirebaseMessaging-FirebaseMessaging_Privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = D833327BDF1E3BCD88C1AB96DD27BB16 /* Build configuration list for PBXNativeTarget "FirebaseMessaging-FirebaseMessaging_Privacy" */; + buildPhases = ( + A2D59A8FCD82492D4F829B09CF2FB789 /* Sources */, + 446C0BC610C7A8EA41CDC32090D4AD1A /* Frameworks */, + 9F6DE6C699266DE7B5941C3E872B4879 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "FirebaseMessaging-FirebaseMessaging_Privacy"; + productName = FirebaseMessaging_Privacy; + productReference = B0B6501341FD6783C6874C54AB31A9CF /* FirebaseMessaging-FirebaseMessaging_Privacy */; + productType = "com.apple.product-type.bundle"; + }; + 25E9E9A17BC3F670357D7385C521E48E /* FirebaseCoreInternal */ = { + isa = PBXNativeTarget; + buildConfigurationList = FA208D28700E3A65EA795BE0320525EA /* Build configuration list for PBXNativeTarget "FirebaseCoreInternal" */; + buildPhases = ( + 8DF624C37333AC9C22805D69B6FA9442 /* Headers */, + 5CB2457BCDFFA93F73BECE4B035AF4A2 /* Sources */, + 966CB1DDB721FCEE4DC8479DF3B8F774 /* Frameworks */, + A3CACFAB5ADDA7D54B8A8224285DD11D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + C9E65B124DC872E1B3548F41A8D0FC11 /* PBXTargetDependency */, + 8B95663B5F60A2335323E03400082A15 /* PBXTargetDependency */, + ); + name = FirebaseCoreInternal; + productName = FirebaseCoreInternal; + productReference = 148D0F9E8C7373FEAF40D800FC5F1BAA /* FirebaseCoreInternal */; + productType = "com.apple.product-type.framework"; + }; + 2949783F7EDB27AD4666B5427B63DC79 /* FirebaseCoreInternal-FirebaseCoreInternal_Privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 338130EB3FC87F51A0A88EE26D25D074 /* Build configuration list for PBXNativeTarget "FirebaseCoreInternal-FirebaseCoreInternal_Privacy" */; + buildPhases = ( + 4B11328CF790813DD1A575CB9BA2CA7A /* Sources */, + 8D1D48F651806972AC979D904A9AD7BD /* Frameworks */, + 9F584252E775DF897EF7DC5DC9BA7D19 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "FirebaseCoreInternal-FirebaseCoreInternal_Privacy"; + productName = FirebaseCoreInternal_Privacy; + productReference = 4DB03FD262B678178A44272143846563 /* FirebaseCoreInternal-FirebaseCoreInternal_Privacy */; + productType = "com.apple.product-type.bundle"; + }; + 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */ = { + isa = PBXNativeTarget; + buildConfigurationList = DD3CE85025D7A56421ADB3E62D3F3DA7 /* Build configuration list for PBXNativeTarget "PromisesObjC" */; + buildPhases = ( + 2C8E56B683C60849A65BE80C0F4ADE2A /* Headers */, + 3D82D56BAAE6C78EC060D453882ECFC8 /* Sources */, + 4011B1E1709BDA346CBE3D582E7224ED /* Frameworks */, + DEFAD4CF2425033373B12CC9A63EE779 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + D82107409C69EEE8FC243BCF5B94F6BD /* PBXTargetDependency */, + ); + name = PromisesObjC; + productName = FBLPromises; + productReference = 3347A1AB6546F0A3977529B8F199DC41 /* PromisesObjC */; + productType = "com.apple.product-type.framework"; + }; + 3232F0C0E7C65B232832393F9ADDD8C3 /* Pods-RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D52099AA1537D0F3745166E1889F6CA3 /* Build configuration list for PBXNativeTarget "Pods-RunnerTests" */; + buildPhases = ( + FC4DA9BD27A4914E75F803590E4C4B8B /* Headers */, + 001CCB0FEA80CD1C6BF534C6D9C6283A /* Sources */, + 4380924F566AA01EB048DC15F9BC6D33 /* Frameworks */, + 4A765108DEAFDEBF078F71CDDBE3414E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 80986EF8DBD794A5118CAB08EB42F6E3 /* PBXTargetDependency */, + ); + name = "Pods-RunnerTests"; + productName = Pods_RunnerTests; + productReference = 6C3345B1B3CAEDF5B03B1F731FDC492E /* Pods-RunnerTests */; + productType = "com.apple.product-type.framework"; + }; + 3EB14444A17F9D4F1F697F7C1FF32245 /* FirebaseInstallations-FirebaseInstallations_Privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6596288413C6F6B681EBF266486DE2A1 /* Build configuration list for PBXNativeTarget "FirebaseInstallations-FirebaseInstallations_Privacy" */; + buildPhases = ( + 929C144419D21D1CA1DE9441530CBC7A /* Sources */, + 1118996EB7A1A6AA5BC8EA75EB476CEB /* Frameworks */, + BAEC70D60885D296F66B9699520CB6D1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "FirebaseInstallations-FirebaseInstallations_Privacy"; + productName = FirebaseInstallations_Privacy; + productReference = 47C581450CDB4A6111CB97EEE0711A8C /* FirebaseInstallations-FirebaseInstallations_Privacy */; + productType = "com.apple.product-type.bundle"; + }; + 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */ = { + isa = PBXNativeTarget; + buildConfigurationList = 16DD5A8F60AB91B2757F7AAB20D27667 /* Build configuration list for PBXNativeTarget "FirebaseCore" */; + buildPhases = ( + 9CB3573ED4594644C08E9EDDDCF3A99D /* Headers */, + 688BA826FFAD96E89DFCC82DF3D24906 /* Sources */, + B2591A99B8C8E4D66AF75F288127F82F /* Frameworks */, + C86C23B589C8EEE21FB71748E69B4CC3 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 73EFE5FFFB400190D960221C166CC0D8 /* PBXTargetDependency */, + 72A36FA49A29DFA754257CC533D9471E /* PBXTargetDependency */, + 4C09BF1AFA89E841993276CF0342B9B3 /* PBXTargetDependency */, + ); + name = FirebaseCore; + productName = FirebaseCore; + productReference = E2B63D462DB7F827C4B11FD51E4F8E2D /* FirebaseCore */; + productType = "com.apple.product-type.framework"; + }; + 55522A91938FF505CFEBEAD2DD85AE2D /* nanopb-nanopb_Privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 25571F03D4736F86E7D5D1363783468B /* Build configuration list for PBXNativeTarget "nanopb-nanopb_Privacy" */; + buildPhases = ( + 180A7C8901359640DC134E93ED4CD3BD /* Sources */, + 1B468F5EEF27FF5C76D23AD996BAAC4E /* Frameworks */, + 19872ECFB8F626C82A70E439FBBB6428 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "nanopb-nanopb_Privacy"; + productName = nanopb_Privacy; + productReference = 3227F3FC45681D7CEE5D1355A532398A /* nanopb-nanopb_Privacy */; + productType = "com.apple.product-type.bundle"; + }; + 5895B432FE4D2F6826C8FF25A09DB6D2 /* FirebaseMessaging */ = { + isa = PBXNativeTarget; + buildConfigurationList = B36E02CAB92E20E1B6C0F3F7684B23EE /* Build configuration list for PBXNativeTarget "FirebaseMessaging" */; + buildPhases = ( + 4204571A0B75FA667DA483210F248E0F /* Headers */, + AA845A7517D3B39DABE672F95557CE16 /* Sources */, + BAD0676965D69323866632F99967FEDD /* Frameworks */, + 18F3E745C1B9D07E2F767D0CAFE0A452 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 84FB2E490719510A066EE6188A4A4EF1 /* PBXTargetDependency */, + 8B1027366C2D676EE573B263C412D596 /* PBXTargetDependency */, + D14D86C928DA86CF300718D1228D2887 /* PBXTargetDependency */, + C4AC5F561C9A462DCEAC9DEFB1DAB202 /* PBXTargetDependency */, + 43A4DFA831ABC1D8C3E6D228E330BBF9 /* PBXTargetDependency */, + ED7FC5BAE4BADD9FBE87E8C470DF7280 /* PBXTargetDependency */, + ); + name = FirebaseMessaging; + productName = FirebaseMessaging; + productReference = 5B654B4B042BA7DC93766943A643E42B /* FirebaseMessaging */; + productType = "com.apple.product-type.framework"; + }; + 5C0371EE948D0357B8EE0E34ABB44BF0 /* GoogleDataTransport */ = { + isa = PBXNativeTarget; + buildConfigurationList = E62B9E5503856CC7A80E2ECC1748C89C /* Build configuration list for PBXNativeTarget "GoogleDataTransport" */; + buildPhases = ( + 1B2FB06F551FA0077084A2BEFC32E626 /* Headers */, + 7DE3BF0C370F8B10754A58A74D2CA5EA /* Sources */, + F7ACB15EB4D09C7709E1190DCBF5D7B6 /* Frameworks */, + E927839ADF53653668A90CA4C5B6ABDC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + A8EAC6D6E4AF36FED65E29228ACE36B1 /* PBXTargetDependency */, + 664C337C40D2B840B761FA06AA362A8E /* PBXTargetDependency */, + C2E948A82861BA076D785707AB845988 /* PBXTargetDependency */, + ); + name = GoogleDataTransport; + productName = GoogleDataTransport; + productReference = 856B5CD56F194FAD26EA91620B66D614 /* GoogleDataTransport */; + productType = "com.apple.product-type.framework"; + }; + 5FF1A58DEEC5DB749FCD6C120B97CC82 /* GoogleUtilities-GoogleUtilities_Privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9891BD206978E995A3D1B39280730E93 /* Build configuration list for PBXNativeTarget "GoogleUtilities-GoogleUtilities_Privacy" */; + buildPhases = ( + 5BC03BD9DFFC25AA4E53B4B466A16173 /* Sources */, + 8B1C5539CF105EC36B6A5B1374605C8F /* Frameworks */, + EEAA77D0BE6E9FA5C05E32B595EA4B58 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "GoogleUtilities-GoogleUtilities_Privacy"; + productName = GoogleUtilities_Privacy; + productReference = 44E291D18340EAC3F761346198515323 /* GoogleUtilities-GoogleUtilities_Privacy */; + productType = "com.apple.product-type.bundle"; + }; + 743B1C5626A92F8FC4AFBE2602CA840F /* flutter_local_notifications-flutter_local_notifications_privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = D29D81EAA2B56AA0D77047034F77C3F2 /* Build configuration list for PBXNativeTarget "flutter_local_notifications-flutter_local_notifications_privacy" */; + buildPhases = ( + 6242DB25FF042E4874C8AC35BAB232F6 /* Sources */, + 6786A1D4808E8E2313F71767FF832CE2 /* Frameworks */, + 053B5AA80707924B66098D3738557F0E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "flutter_local_notifications-flutter_local_notifications_privacy"; + productName = flutter_local_notifications_privacy; + productReference = 513486288D9850EF657161C39358ED93 /* flutter_local_notifications-flutter_local_notifications_privacy */; + productType = "com.apple.product-type.bundle"; + }; + 845DF30C6C93A1F35C6DCEBAFECA8F8A /* image_picker_ios */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4B1508164EFB91BCA6B7DFAAAE1EDDF9 /* Build configuration list for PBXNativeTarget "image_picker_ios" */; + buildPhases = ( + ABB8D2A0B00BBB06C4066C8B11BED0AC /* Headers */, + A4DD926A06AEB5F3B2521297C2FCF9FA /* Sources */, + B7C2FF4A20ABA1FEAD6C6E13A1B1A0F9 /* Frameworks */, + E068C7E9C4F7A1B731D2D2A12E421A00 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 8F9268222E7F350FF069975274F2941E /* PBXTargetDependency */, + 92FF942C4FCB632500DD32D523575520 /* PBXTargetDependency */, + ); + name = image_picker_ios; + productName = image_picker_ios; + productReference = 768975E636D1D2FB85622FB67DB04E5A /* image_picker_ios */; + productType = "com.apple.product-type.framework"; + }; + 87803597EB3F20FC46472B85392EC4FD /* FirebaseInstallations */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5FA5B327F6D79B0503F3F3AC10FABE44 /* Build configuration list for PBXNativeTarget "FirebaseInstallations" */; + buildPhases = ( + DE243339F7DDAB0EC6DEB58F40872A9D /* Headers */, + 3195E549D7E1C4DC9C1E988BC062A131 /* Sources */, + 7E9C2C14859C36ED6022BB2557B2997F /* Frameworks */, + 2A4C54BB3FE7CEF5AFF54CD8EF0AED0B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 7DE3F59D32E758D449D9B22688C05CA9 /* PBXTargetDependency */, + B67F50CE988161665B2AB017B92A657F /* PBXTargetDependency */, + 8D5ABA0387D4D65424317F9CDC9D49D0 /* PBXTargetDependency */, + 50579E6A41DA8125ACDED4083FC9BAA1 /* PBXTargetDependency */, + ); + name = FirebaseInstallations; + productName = FirebaseInstallations; + productReference = 13C8C8B254851998F9289F71229B28A2 /* FirebaseInstallations */; + productType = "com.apple.product-type.framework"; + }; + 8B74B458B450D74B75744B87BD747314 /* Pods-Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = D9B3D27CA537F94301490675549265C6 /* Build configuration list for PBXNativeTarget "Pods-Runner" */; + buildPhases = ( + 0E5EA2EC4B601D99DEF81F43EB8CABD4 /* Headers */, + C244765427CE0A229C81D754AA6E54FA /* Sources */, + 61EC42D4D6F7655085AC323D84ACC658 /* Frameworks */, + CA051C0BF7A45D09061D914E5231CCAB /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + BA47C823EA60AD852C65E2F339DCCAC7 /* PBXTargetDependency */, + 5C92AD7A173EFF92E4092C6AF37EFDC0 /* PBXTargetDependency */, + 2869380D030F1BD3D7B625D9B5E0D28A /* PBXTargetDependency */, + 3C9D6B3C27DE7FAC798F9E8ED42E6D48 /* PBXTargetDependency */, + 2CCFEE512E4639C3C0E902E42B230B2A /* PBXTargetDependency */, + 3E403294D2A189101DB7574D84F616C3 /* PBXTargetDependency */, + CBC35C781EA13C1D19EFDF9EE9EB96C2 /* PBXTargetDependency */, + 0EE01B0D211874C6816F991E8BE40CDE /* PBXTargetDependency */, + 10CB25F83A43C843C01E22489D47DEE4 /* PBXTargetDependency */, + BE67F450DB9D82F4A23F1D9332169775 /* PBXTargetDependency */, + AC7895442E8ED9F65E03479BA0B36FD9 /* PBXTargetDependency */, + 63F5DF323ED73744380ABA257B338150 /* PBXTargetDependency */, + 0E8E2C4456F612F10A156A69D326BEEE /* PBXTargetDependency */, + BF273C1C9950BF7782C02342D2E52334 /* PBXTargetDependency */, + ); + name = "Pods-Runner"; + productName = Pods_Runner; + productReference = 669E8F25E1897672BDB80B7EB784DA24 /* Pods-Runner */; + productType = "com.apple.product-type.framework"; + }; + 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */ = { + isa = PBXNativeTarget; + buildConfigurationList = B5736ABBC2B983C7339FD9E4C90C933E /* Build configuration list for PBXNativeTarget "GoogleUtilities" */; + buildPhases = ( + 734660C1C2C0F8FD0D664F521FA1F77A /* Headers */, + 5805886CD3E75C0CDC32E1992976601F /* Sources */, + 11A5CD70E56822C606053045D712429E /* Frameworks */, + AC9F275D873001D4C3EE03078FA5A71B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 02CDDA9B79E3AF65C46C03A75053ECF3 /* PBXTargetDependency */, + ); + name = GoogleUtilities; + productName = GoogleUtilities; + productReference = B43874C6CBB50E7134FBEC24BABFE14F /* GoogleUtilities */; + productType = "com.apple.product-type.framework"; + }; + A450BF39E3E5256209A256E278D71BFD /* image_picker_ios-image_picker_ios_privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 52D03D1C0585986A645E6E4DA0F5A0BD /* Build configuration list for PBXNativeTarget "image_picker_ios-image_picker_ios_privacy" */; + buildPhases = ( + 6A3D605B13C8FDD80991B363F0D7AAEA /* Sources */, + 9F8DC547606FBA36D86DF22F4ADCF140 /* Frameworks */, + 5095725760E9EC2D3764003C41981EF4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "image_picker_ios-image_picker_ios_privacy"; + productName = image_picker_ios_privacy; + productReference = F0C7EFBFF01CFAAB52BA74E6CB40CE2C /* image_picker_ios-image_picker_ios_privacy */; + productType = "com.apple.product-type.bundle"; + }; + B92347C3E503ADBA2F0EF79DE5320B2D /* firebase_messaging */ = { + isa = PBXNativeTarget; + buildConfigurationList = A742CB9DC752699A7ADA6C62CF5707F9 /* Build configuration list for PBXNativeTarget "firebase_messaging" */; + buildPhases = ( + E3BA34355E381CBF076CDBE8B3D019E5 /* Headers */, + 761631FC2975B85862D0966D173A4AB9 /* Sources */, + BF68AB50D403234129980F774D24C571 /* Frameworks */, + A3469B6B7FE128D2F78F4020FE7D9C21 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 7D9F786F238F8E30338A94B55FBDEF94 /* PBXTargetDependency */, + 7C28218E9F953EE5E7CC0EA152EE3F7B /* PBXTargetDependency */, + F1D853F524E23D8D4413930C90692190 /* PBXTargetDependency */, + 8EE224A90E1681309C71D34E509A520B /* PBXTargetDependency */, + ); + name = firebase_messaging; + productName = firebase_messaging; + productReference = 626B91FA30530F8DA0D892C01BC22133 /* firebase_messaging */; + productType = "com.apple.product-type.framework"; + }; + D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */ = { + isa = PBXNativeTarget; + buildConfigurationList = 594BD1BA1D4D0F671BC521421AC4390C /* Build configuration list for PBXNativeTarget "nanopb" */; + buildPhases = ( + 12CAA56F4981E34F8AAE18C1B78557E3 /* Headers */, + 49245C63FE0D1E6C00351D475AD72C7E /* Sources */, + 401E66DD45DCC4B0A97659CEE79BE8AC /* Frameworks */, + E6856A0E8015A8DE8BA53C5A5973E1BC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 266761D37A9A8C9A937AC06A6A7D2335 /* PBXTargetDependency */, + ); + name = nanopb; + productName = nanopb; + productReference = 06FC5C9CF96D60C50FCD47D339C91951 /* nanopb */; + productType = "com.apple.product-type.framework"; + }; + DAA3DF4B8C2F11E7A1764EF4EC560AC8 /* firebase_core */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5678139697F427A1F6A8CE2EFE1109D4 /* Build configuration list for PBXNativeTarget "firebase_core" */; + buildPhases = ( + 77C4610B8C3FE989CEF894E346FFC87A /* Headers */, + 0BFCF4A443028CAB6B6B22EA5D64ACFA /* Sources */, + 88B211DE19A8FBCC86252DCF9B408D02 /* Frameworks */, + C349420CE80891679D8DF618915537D1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + CCC08443CD338CE1211FCE38A0FE8A95 /* PBXTargetDependency */, + 1F89C870864A29E3B8BFCA4094B80944 /* PBXTargetDependency */, + ); + name = firebase_core; + productName = firebase_core; + productReference = F3B74672DAE304DCA370B761FBD5B2D7 /* firebase_core */; + productType = "com.apple.product-type.framework"; + }; + DD0D41A9315A48004E57F4F0E54095F1 /* GoogleDataTransport-GoogleDataTransport_Privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5F381D5E26CE1B96CEC0BA50A1F94D0F /* Build configuration list for PBXNativeTarget "GoogleDataTransport-GoogleDataTransport_Privacy" */; + buildPhases = ( + 9DFEE358E55506508337C75CA758ED08 /* Sources */, + E3EA90E72414934EBD7E31E4F20F2E11 /* Frameworks */, + EFE3D92049B8DDC79C4E378C8E84E960 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "GoogleDataTransport-GoogleDataTransport_Privacy"; + productName = GoogleDataTransport_Privacy; + productReference = F73AA961F4AEFF2B46B00AE435DF6BE3 /* GoogleDataTransport-GoogleDataTransport_Privacy */; + productType = "com.apple.product-type.bundle"; + }; + DF331B019C7101D6AF15978FDCEC828E /* firebase_messaging-firebase_messaging_Privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9A05DFC822D8BC454D903BCEAD22B415 /* Build configuration list for PBXNativeTarget "firebase_messaging-firebase_messaging_Privacy" */; + buildPhases = ( + CB8A4DBE8446DC7AC0B546C07E10BA80 /* Sources */, + AE8F16AE7FC4D23ED6EC16D26A1C006C /* Frameworks */, + 9343D002827BA03838CAA648B2D1C8F4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "firebase_messaging-firebase_messaging_Privacy"; + productName = firebase_messaging_Privacy; + productReference = 75CF387A098437DDEB77C4DD2B48D012 /* firebase_messaging-firebase_messaging_Privacy */; + productType = "com.apple.product-type.bundle"; + }; + F64AA263B9D7877A7D58823DEF7F113B /* flutter_local_notifications */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0D939566A978AA1625D9977E74EC39C1 /* Build configuration list for PBXNativeTarget "flutter_local_notifications" */; + buildPhases = ( + 7458FB28F60AC8C18BC9DF5C2AE604BC /* Headers */, + EA88393D746FF0BFF123E4DB86ACA2AF /* Sources */, + 9790929E5B5A7DAC61E22162DCA93710 /* Frameworks */, + 0B85BDE822A0E2989ACC5A1C6D8E6CD0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + FCEF46B0022F39DDD0C6F3BDB924C78F /* PBXTargetDependency */, + 73520F9868C9E014FC60A288F8B0D9A3 /* PBXTargetDependency */, + ); + name = flutter_local_notifications; + productName = flutter_local_notifications; + productReference = D2818DB76C14B8736924E987E37A9823 /* flutter_local_notifications */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1600; + LastUpgradeCheck = 1600; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + minimizedProjectReferenceProxies = 0; + preferredProjectObjectVersion = 77; + productRefGroup = BE1941B9061DA527DE930E6F23B39B62 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 072CEA044D2EF26F03496D5996BBF59F /* Firebase */, + DAA3DF4B8C2F11E7A1764EF4EC560AC8 /* firebase_core */, + B92347C3E503ADBA2F0EF79DE5320B2D /* firebase_messaging */, + DF331B019C7101D6AF15978FDCEC828E /* firebase_messaging-firebase_messaging_Privacy */, + 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */, + 1001C16510D946B47CFF8B19DBC0B787 /* FirebaseCore-FirebaseCore_Privacy */, + 25E9E9A17BC3F670357D7385C521E48E /* FirebaseCoreInternal */, + 2949783F7EDB27AD4666B5427B63DC79 /* FirebaseCoreInternal-FirebaseCoreInternal_Privacy */, + 87803597EB3F20FC46472B85392EC4FD /* FirebaseInstallations */, + 3EB14444A17F9D4F1F697F7C1FF32245 /* FirebaseInstallations-FirebaseInstallations_Privacy */, + 5895B432FE4D2F6826C8FF25A09DB6D2 /* FirebaseMessaging */, + 21FB29F43C8A2A81ABFE8C478370070E /* FirebaseMessaging-FirebaseMessaging_Privacy */, + 1EFDDC32A34D56D411E640A81DCD9E73 /* Flutter */, + F64AA263B9D7877A7D58823DEF7F113B /* flutter_local_notifications */, + 743B1C5626A92F8FC4AFBE2602CA840F /* flutter_local_notifications-flutter_local_notifications_privacy */, + 5C0371EE948D0357B8EE0E34ABB44BF0 /* GoogleDataTransport */, + DD0D41A9315A48004E57F4F0E54095F1 /* GoogleDataTransport-GoogleDataTransport_Privacy */, + 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */, + 5FF1A58DEEC5DB749FCD6C120B97CC82 /* GoogleUtilities-GoogleUtilities_Privacy */, + 845DF30C6C93A1F35C6DCEBAFECA8F8A /* image_picker_ios */, + A450BF39E3E5256209A256E278D71BFD /* image_picker_ios-image_picker_ios_privacy */, + D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */, + 55522A91938FF505CFEBEAD2DD85AE2D /* nanopb-nanopb_Privacy */, + 8B74B458B450D74B75744B87BD747314 /* Pods-Runner */, + 3232F0C0E7C65B232832393F9ADDD8C3 /* Pods-RunnerTests */, + 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */, + 1BFBEDBF7E03729D43C96530EE190825 /* PromisesObjC-FBLPromises_Privacy */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 053B5AA80707924B66098D3738557F0E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C2447EC9582F167F7131165BF09E9246 /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0B85BDE822A0E2989ACC5A1C6D8E6CD0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 586072F26AEE6AB93375562DC6D3D54A /* flutter_local_notifications-flutter_local_notifications_privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 18F3E745C1B9D07E2F767D0CAFE0A452 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F91B5A5C597C72F11B80B16E41167055 /* FirebaseMessaging-FirebaseMessaging_Privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 19872ECFB8F626C82A70E439FBBB6428 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 90FD76ED3DF523463354549A94AE5A06 /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2A4C54BB3FE7CEF5AFF54CD8EF0AED0B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AF5E6A1F926F94BFB5389039FD0B871C /* FirebaseInstallations-FirebaseInstallations_Privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4A765108DEAFDEBF078F71CDDBE3414E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5095725760E9EC2D3764003C41981EF4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 761C30A7606CD20926EB925556278C83 /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7F0A7510B30C0682145ACC058656CF53 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1683F46BFD010E525F099B091E72C3CE /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9343D002827BA03838CAA648B2D1C8F4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9F2A213061BBCC007B30472BEEAB67EB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 56BE3DD72BA291E2CE00ED26A89B22A0 /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9F584252E775DF897EF7DC5DC9BA7D19 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 65A63308DC9D8A29BDC2566DC596C6BF /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9F6DE6C699266DE7B5941C3E872B4879 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 75401C13C09D439800C91514D75E6F32 /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A3469B6B7FE128D2F78F4020FE7D9C21 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A3CACFAB5ADDA7D54B8A8224285DD11D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1592FC1F961CCC2F8FDAE4DE102C2A8D /* FirebaseCoreInternal-FirebaseCoreInternal_Privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AC9F275D873001D4C3EE03078FA5A71B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0C3010023CDB0908759D6B5C1E5E63FA /* GoogleUtilities-GoogleUtilities_Privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BAEC70D60885D296F66B9699520CB6D1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 56F29D607373445789154C630E5B4804 /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C349420CE80891679D8DF618915537D1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C86C23B589C8EEE21FB71748E69B4CC3 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0C0796C7D48DD78256A8FEEB7413F6D0 /* FirebaseCore-FirebaseCore_Privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CA051C0BF7A45D09061D914E5231CCAB /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DEFAD4CF2425033373B12CC9A63EE779 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7F3BE46873691FC48F3DF3A5D7E20126 /* PromisesObjC-FBLPromises_Privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E068C7E9C4F7A1B731D2D2A12E421A00 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3F197F4F335A992690C00BE47D82C02E /* image_picker_ios-image_picker_ios_privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E6856A0E8015A8DE8BA53C5A5973E1BC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F0CD29D00D4DE451539A6D01D2F2E7F9 /* nanopb-nanopb_Privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E927839ADF53653668A90CA4C5B6ABDC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 76BC09C29C6545ADE3608271AED0555B /* GoogleDataTransport-GoogleDataTransport_Privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EEAA77D0BE6E9FA5C05E32B595EA4B58 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 297DEA43F5E592D731A47F1A5C0B413C /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EFE3D92049B8DDC79C4E378C8E84E960 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A5892FC1D4BD280BA38213030D30A2D /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 001CCB0FEA80CD1C6BF534C6D9C6283A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B375EA128E6579366091BAA390BBDD34 /* Pods-RunnerTests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0BFCF4A443028CAB6B6B22EA5D64ACFA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E1E1270BD9A3CB344C4B31B44C3E502D /* dummy.m in Sources */, + 571BF6B1BB079A51BAFBB50CEE883CDA /* firebase_core-dummy.m in Sources */, + 7EE849AB55EC83CAC57754C57BD49F1B /* FLTFirebaseCorePlugin.m in Sources */, + EB4605DE8A17BB46F9DD0032A62CE6A2 /* FLTFirebasePlugin.m in Sources */, + 8FA9812545B4E33A5F1FCE78D2E7958E /* FLTFirebasePluginRegistry.m in Sources */, + 2DC9FB7E7BDB2C5F1F4A53856E6C2AFC /* messages.g.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 180A7C8901359640DC134E93ED4CD3BD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3077D4C072B5555EB5D43BA45E694885 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3195E549D7E1C4DC9C1E988BC062A131 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 06618627DDD00F3992F51FBAAEF7B5BC /* FIRCurrentDateProvider.m in Sources */, + D3CA68DFBD6760ECAB9662C2E4459EDA /* FirebaseInstallations-dummy.m in Sources */, + BFD528F6A70B42CAE79FBD2B41427A1A /* FIRInstallations.m in Sources */, + 61CEBE947F27DD5E937A541ACFAC757E /* FIRInstallationsAPIService.m in Sources */, + 5A5B4E3D28CC29759858A1512AC0E4D6 /* FIRInstallationsAuthTokenResult.m in Sources */, + 8A8D2FD34936A0F16995CABAE682BB69 /* FIRInstallationsBackoffController.m in Sources */, + 8B8DCB001A1BDF664F9FD7D72AF7DAE3 /* FIRInstallationsErrorUtil.m in Sources */, + 190F94C0F26BE05ED84B38273B61E3AE /* FIRInstallationsHTTPError.m in Sources */, + EF4F910815C5A3FDB124F1468E180A7C /* FIRInstallationsIDController.m in Sources */, + 9E3E5D5CDB90A05026A0C1992F892580 /* FIRInstallationsIIDStore.m in Sources */, + 993E450FBC85DC9A0FB759FCFD8C1228 /* FIRInstallationsIIDTokenStore.m in Sources */, + 7CE8A75DC1A2B02DC6CFE116AF26CF83 /* FIRInstallationsItem.m in Sources */, + BDD0240723D11CC1C424FCAE1CE8D881 /* FIRInstallationsItem+RegisterInstallationAPI.m in Sources */, + B201F1BAE6C0AC68CE89122CC62192F3 /* FIRInstallationsLogger.m in Sources */, + 7F7997025ACDAAA3F86F2BE4545FF616 /* FIRInstallationsSingleOperationPromiseCache.m in Sources */, + E05B14440006C13142B1D6600528233E /* FIRInstallationsStore.m in Sources */, + 26027AD6D367CD1788F3332165FEAA7A /* FIRInstallationsStoredAuthToken.m in Sources */, + 4AC8EF6AF50C4384AD13CBE73D88A6E9 /* FIRInstallationsStoredItem.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3D82D56BAAE6C78EC060D453882ECFC8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8C68316D150BEDFBDCA3EFCD82BA49F5 /* FBLPromise.m in Sources */, + 0E3F8A6978592652C2EA5EF3A75C0727 /* FBLPromise+All.m in Sources */, + 2182B73EA7F410DC5AA130F5E501E496 /* FBLPromise+Always.m in Sources */, + 46571670CA3978B72CFB440F1228CE28 /* FBLPromise+Any.m in Sources */, + 99B415F3939EB6DCE907A67B7178F172 /* FBLPromise+Async.m in Sources */, + 4B190AD25B05A37B843797054274323E /* FBLPromise+Await.m in Sources */, + 70760F93398A854AA6EC92A099F31B46 /* FBLPromise+Catch.m in Sources */, + FF7B53EF3C76928B265DE076684235AD /* FBLPromise+Delay.m in Sources */, + CAACD4CA74C961236A37792C8A4BFBC2 /* FBLPromise+Do.m in Sources */, + 07C770B6244A7D148CEDC70E279CC0D1 /* FBLPromise+Race.m in Sources */, + C2F85245D2701CC4F30C979C51259C31 /* FBLPromise+Recover.m in Sources */, + 7789C9324F79D1A739BF260EB7CB46B4 /* FBLPromise+Reduce.m in Sources */, + E95E65AE1524C8F63325E910CEFEFCFB /* FBLPromise+Retry.m in Sources */, + E63FE480CF9EFC9E296EF362F05EE98D /* FBLPromise+Testing.m in Sources */, + D256D5171D913FE559EFA69FE4F385E4 /* FBLPromise+Then.m in Sources */, + 1D845CA31916DB3CA63E5B76BC4FBE46 /* FBLPromise+Timeout.m in Sources */, + B2990D3BC02A58DE4814C1ADF56C8C18 /* FBLPromise+Validate.m in Sources */, + 13CA40B9275CF297C782BE9486ADB6F2 /* FBLPromise+Wrap.m in Sources */, + EE135FF14BFA3B4F66801408C125B41F /* FBLPromiseError.m in Sources */, + 00CE183CDBD142197C384084C51D478D /* PromisesObjC-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4164EACC29BB2CA05655CCAC9E955877 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 49245C63FE0D1E6C00351D475AD72C7E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D1756998759D2A6BB960AA128C43129 /* nanopb-dummy.m in Sources */, + 9B476394CDE8C9CF8D586BC575A19D32 /* pb_common.c in Sources */, + C9926BF1ECE48D4F5608B85D23172F58 /* pb_decode.c in Sources */, + A81C7E40BB1B12D81377B6E4943E0221 /* pb_encode.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4B11328CF790813DD1A575CB9BA2CA7A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5805886CD3E75C0CDC32E1992976601F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C56E771DC3DBD1A7F38FFB5073511D74 /* GoogleUtilities-dummy.m in Sources */, + 2F8291AB02BA74E440205A516575FA08 /* GULAppDelegateSwizzler.m in Sources */, + 94E3463FFBB12FD10087C2F2B27C2DCD /* GULAppEnvironmentUtil.m in Sources */, + F9996DFB48D26874343B0BADAC5AE7F2 /* GULKeychainStorage.m in Sources */, + D258FE513187AFE11388A56510D83AA7 /* GULKeychainUtils.m in Sources */, + 5C048357DBF589975F0094D11A25FF22 /* GULLogger.m in Sources */, + 521E334B4F1329AEF35C863453F97A61 /* GULMutableDictionary.m in Sources */, + C455A7E8B9BC54B1EE93D4F5A0D77F38 /* GULNetwork.m in Sources */, + E41A6A8F763C5FAD662CA8BE33577E70 /* GULNetworkConstants.m in Sources */, + 5380AD627C4A430574E2DAD3F48AE8CC /* GULNetworkInfo.m in Sources */, + 9046613449009EB6FD58DB70A2EDB388 /* GULNetworkURLSession.m in Sources */, + A7592A0B36BDBDB6BE45BC03242B6D0D /* GULNSData+zlib.m in Sources */, + DBD066F5DECE546710B8F46F407C322E /* GULReachabilityChecker.m in Sources */, + 7DC81AF87DF6B545372C326DD683B2A4 /* GULSceneDelegateSwizzler.m in Sources */, + C9A3CCA63CADCE3F2527142CB886B3F8 /* GULUserDefaults.m in Sources */, + 9BAC0155AEE5E5CF0003C7E9D94485E4 /* IsAppEncrypted.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5BC03BD9DFFC25AA4E53B4B466A16173 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5CB2457BCDFFA93F73BECE4B035AF4A2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2D6CAB6076DD88C5FEF5044C38C50758 /* _ObjC_HeartbeatController.swift in Sources */, + F321B3889222BD0F720696D092E95968 /* _ObjC_HeartbeatsPayload.swift in Sources */, + 335B5194B81E15303D4B124FFFD61422 /* AtomicBox.swift in Sources */, + 7F7E8D1AEE11D58BC85ECD6A22048AB9 /* FIRAllocatedUnfairLock.swift in Sources */, + 7D307E2F6DA3935A528D0A23A6AFBC39 /* FirebaseCoreInternal-dummy.m in Sources */, + 891106CC3E66B8377A856E948607FC9C /* Heartbeat.swift in Sources */, + 957F9FD0D2CCE99FE2AD30DCAFFFFDE2 /* HeartbeatController.swift in Sources */, + E6171E5D20D270CA833B5176AD614B26 /* HeartbeatLoggingTestUtils.swift in Sources */, + 39BE841D795846D04215DAD70567FD93 /* HeartbeatsBundle.swift in Sources */, + F11EF322E540186F60A2785DC6A6FEF6 /* HeartbeatsPayload.swift in Sources */, + 7ADD9AAFE22BFF4095EE499109CB8437 /* HeartbeatStorage.swift in Sources */, + 6AFE45EDE1C2A889617FBC9734CF3029 /* RingBuffer.swift in Sources */, + 87D87718A1AF94E63DD1CA91964D77BD /* Storage.swift in Sources */, + B19DBCE20486E645459623A4196D71E6 /* StorageFactory.swift in Sources */, + C4BF4DA0B89971CDD9E7027A9C2B4467 /* WeakContainer.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6242DB25FF042E4874C8AC35BAB232F6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 688BA826FFAD96E89DFCC82DF3D24906 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F8D3DF5F1BBE22C17BEA8A3245F85592 /* FIRAnalyticsConfiguration.m in Sources */, + C8037AF1C8933CBBAF84A662DEC885FE /* FIRApp.m in Sources */, + E7E9ECA6ADB3393B08C2B762984F5FAF /* FIRBundleUtil.m in Sources */, + 0FBB7A21EB00E443EEC886E940E4ED27 /* FIRComponent.m in Sources */, + 30EEB99A07CCC1682F5007DC779DB6DA /* FIRComponentContainer.m in Sources */, + 69D68A7BB88BDB2D9CA3B81401DB3F03 /* FIRComponentType.m in Sources */, + DD344F36D2BB7A4AFEB42DDB87360542 /* FIRConfiguration.m in Sources */, + A81C3DC8BE904F38FE3B39C6EA08D975 /* FirebaseCore-dummy.m in Sources */, + C141A77C29333EF7BCE884F4B2C33304 /* FIRFirebaseUserAgent.m in Sources */, + 874AB5A539D2DB1698AEAD9C71DFB7A7 /* FIRHeartbeatLogger.m in Sources */, + 0D1BC3F8872405F5215A111915BF0FA4 /* FIRLogger.m in Sources */, + D0E43C5A3C366E325CBC48A2A3DCB827 /* FIROptions.m in Sources */, + 49B88E5079B9DE42AB4A205DE9689897 /* FIRTimestamp.m in Sources */, + B91C165E3CB57866BD2C36F4220CC467 /* FIRVersion.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6A3D605B13C8FDD80991B363F0D7AAEA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 761631FC2975B85862D0966D173A4AB9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CC2EB95352E40B738326F72DD72EC151 /* firebase_messaging-dummy.m in Sources */, + 4C8503BD05FBA66601D70F75C5082A3A /* FLTFirebaseMessagingPlugin.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7DE3BF0C370F8B10754A58A74D2CA5EA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + EE040CAA65AB77AF561A8F906609FDDD /* cct.nanopb.c in Sources */, + E9F2141C25A0A76A2F931E9E38F04F09 /* client_metrics.nanopb.c in Sources */, + 132ABC6A00573AA57C690B9577B22E9F /* compliance.nanopb.c in Sources */, + F09896DD6EA71BEFBF61A0CF86A9B0E2 /* external_prequest_context.nanopb.c in Sources */, + 861377892C783984902287CE914076F8 /* external_privacy_context.nanopb.c in Sources */, + E32449EDBFAA292BE64E912E48DA0A3D /* GDTCCTCompressionHelper.m in Sources */, + AF51A5733F3FD02A34D21274D980B91F /* GDTCCTNanopbHelpers.m in Sources */, + 5B38B7AD5DBC6762CD10D24DD1DBB933 /* GDTCCTUploader.m in Sources */, + 962FF4B0914D6FECCDDBFBB68981225C /* GDTCCTUploadOperation.m in Sources */, + 8CE5FBABF9724D94146D04CB23BB9780 /* GDTCCTURLSessionDataResponse.m in Sources */, + C900955D2D8838EC4DE9E2782BAC873B /* GDTCORAssert.m in Sources */, + 848B7ED460EB7294EB77162995F21573 /* GDTCORClock.m in Sources */, + 0BB369A5618D2911E4EEB5B16F274847 /* GDTCORConsoleLogger.m in Sources */, + 7014ED4D94FDBD4EDD1A3A5F29ACD9A7 /* GDTCORDirectorySizeTracker.m in Sources */, + 5479AE51693F1FB446F24BF9164E1419 /* GDTCOREndpoints.m in Sources */, + 349A362BFDBCE10DC57DFB6A19AF65A2 /* GDTCOREvent.m in Sources */, + FE30981B92CAAFA17348779A73DEF09D /* GDTCOREvent+GDTCCTSupport.m in Sources */, + C8226DCEB4533579AF653E4C536CD2F7 /* GDTCOREvent+GDTMetricsSupport.m in Sources */, + 4A974B87D9F1F4D0A5E6BA49601CBFD3 /* GDTCORFlatFileStorage.m in Sources */, + B41C90799FC590798C47087B4581295C /* GDTCORFlatFileStorage+Promises.m in Sources */, + 3BDA20732B8B8C91D5013016EC32B7F5 /* GDTCORLifecycle.m in Sources */, + C8B38E4BCD0E9883E40D871881C2569C /* GDTCORLogSourceMetrics.m in Sources */, + E396037E322A716F65D76406D805D13F /* GDTCORMetrics.m in Sources */, + 7BCC6BCDA6C263A4F83BE7EC5F205353 /* GDTCORMetrics+GDTCCTSupport.m in Sources */, + D0F633AE6ECFB289BD02C8870994B87F /* GDTCORMetricsController.m in Sources */, + 1AFDC4C1679F0A6AD83D1652B8CB08CC /* GDTCORMetricsMetadata.m in Sources */, + 9390D5972BB446FEC1BF3C7C7577FC3C /* GDTCORPlatform.m in Sources */, + 5F6E613D13BEEF2240EB8DC45C1E445F /* GDTCORProductData.m in Sources */, + A9CB232876B453BA32933CA6C8932022 /* GDTCORReachability.m in Sources */, + F16D33178A8A34F24C722F1B94AFA432 /* GDTCORRegistrar.m in Sources */, + 5A0BCFE4A98520629466933A5B7C2E3E /* GDTCORStorageEventSelector.m in Sources */, + D387109882D2DF15EF677B5F7C9ED35D /* GDTCORStorageMetadata.m in Sources */, + 45E57A7308BEAD7135BDBC9C8E4CFCC1 /* GDTCORTransformer.m in Sources */, + 3A8F1ED7C5FF7C67F8FA7331837AD2BC /* GDTCORTransport.m in Sources */, + 2282F718E7770C41D6BD7FB0AE6508A6 /* GDTCORUploadBatch.m in Sources */, + E75A4388F9E48E29720A7CAD7EE87ACA /* GDTCORUploadCoordinator.m in Sources */, + FBA062E88B0EB24276EC596147DC883A /* GoogleDataTransport-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 929C144419D21D1CA1DE9441530CBC7A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9DFEE358E55506508337C75CA758ED08 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A2D59A8FCD82492D4F829B09CF2FB789 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A4DD926A06AEB5F3B2521297C2FCF9FA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A9711647DDFC9AAC568DD346AEDE5EBD /* FLTImagePickerImageUtil.m in Sources */, + 99555EE2EA3C7BF7A43DFC46B9A8A53A /* FLTImagePickerMetaDataUtil.m in Sources */, + CAE8B5B491E97FAE423D537B9D3AF329 /* FLTImagePickerPhotoAssetUtil.m in Sources */, + 43C273D9572DDD1D6D6C662F919F6EF0 /* FLTImagePickerPlugin.m in Sources */, + DFF57F85C04952479C8BA9ABA0FD54DF /* FLTPHPickerSaveImageToPathOperation.m in Sources */, + 2B5B0F628F0FE3CD032B8CA1FA3A9902 /* image_picker_ios-dummy.m in Sources */, + 25CC61FBFBF14E34D42AA32298DC71DD /* messages.g.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AA845A7517D3B39DABE672F95557CE16 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 613B690A8FE3B32CB1E35E082787469C /* FirebaseMessaging-dummy.m in Sources */, + 7C84F224579B7C273F8CF870C0D39DB9 /* FIRMessaging.m in Sources */, + F2147820B509266A415E62BA877B9918 /* FIRMessaging+ExtensionHelper.m in Sources */, + 74605073686CA98767108F9F06638602 /* FIRMessagingAnalytics.m in Sources */, + 1C4BC995FAF21B8F8CF5F4CA16476B3A /* FIRMessagingAPNSInfo.m in Sources */, + 447A1B593F685BA5674A44C3529BA5F2 /* FIRMessagingAuthKeychain.m in Sources */, + 7CAA207102D0B204B3515750F1FD183B /* FIRMessagingAuthService.m in Sources */, + 7EBCEC932DA76198A8A28C15C5BA7154 /* FIRMessagingBackupExcludedPlist.m in Sources */, + 5DF7E819580A5C8044073197A5F2D21B /* FIRMessagingCheckinPreferences.m in Sources */, + 4C2A196BFB3D9BF5091632A60B885A13 /* FIRMessagingCheckinService.m in Sources */, + B7D28D2E9CEFF69C2A3516DD3734ABFA /* FIRMessagingCheckinStore.m in Sources */, + DA3B145B67A281C7D6DE12EDCA55620A /* FIRMessagingConstants.m in Sources */, + 73052EEFCB43DDEA0F82F1BF874C2F0E /* FIRMessagingContextManagerService.m in Sources */, + DC7EA112BA576E2F6389F0D41073BDB6 /* FIRMessagingExtensionHelper.m in Sources */, + A9A43073BD51BE92865A43477940A3DA /* FIRMessagingKeychain.m in Sources */, + 2FBC11779C522B4E6B0C74C8A75C9F74 /* FIRMessagingLogger.m in Sources */, + 2A285780C26D334E131321067FF165D0 /* FIRMessagingPendingTopicsList.m in Sources */, + EC1AF0772124F73D9CC857F2B4C3FA58 /* FIRMessagingPersistentSyncMessage.m in Sources */, + 5D8E977CE74A5307508857D10BAB5D3A /* FIRMessagingPubSub.m in Sources */, + 8824711A652C0411EE942C273CBB67DB /* FIRMessagingRemoteNotificationsProxy.m in Sources */, + 8E066B23F49B2C880C85C0C7D75A071A /* FIRMessagingRmqManager.m in Sources */, + 7334A11AE4BEB61513F3BD568CF06A88 /* FIRMessagingSyncMessageManager.m in Sources */, + 104FF72FD2BEFCBDFDD392930A21378D /* FIRMessagingTokenDeleteOperation.m in Sources */, + 6BADFD60DB75B4AF1D28EEA6B9A715E2 /* FIRMessagingTokenFetchOperation.m in Sources */, + B27501336005608A6DDC7115DB3EF829 /* FIRMessagingTokenInfo.m in Sources */, + 8CCDD0321249EDC12E1878FCBA0ACFFC /* FIRMessagingTokenManager.m in Sources */, + AB85D677B4693F37FB0289E4E1B43635 /* FIRMessagingTokenOperation.m in Sources */, + B2DF94E9A2C1E8636F07B902A18FBEDB /* FIRMessagingTokenStore.m in Sources */, + D3CA8D9FF4CB7EB16FDBF2BCCF89F979 /* FIRMessagingTopicOperation.m in Sources */, + 00629DB3E27C092CCBE10C553B8BC4B0 /* FIRMessagingUtilities.m in Sources */, + 258701CDB6197462997789A95414A3BB /* me.nanopb.c in Sources */, + F65AC7A62611BD5E26E1BAC990F4AD96 /* NSDictionary+FIRMessaging.m in Sources */, + E0C844B78D8CD5CA4A344FAE18FE2D47 /* NSError+FIRMessaging.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C244765427CE0A229C81D754AA6E54FA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A0D07E5309FE40DD3B60BAEC0EE9702F /* Pods-Runner-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CB8A4DBE8446DC7AC0B546C07E10BA80 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EA88393D746FF0BFF123E4DB86ACA2AF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1C3A09E95B8444D58F7D19A9A9812742 /* ActionEventSink.m in Sources */, + 570310B6BB9D1B9AF8F2FE0398A244E2 /* Converters.m in Sources */, + C6953122A45255AE149D469609596AD6 /* flutter_local_notifications-dummy.m in Sources */, + 2BCEE7F546EE3000EBB2D140C64C6EDC /* FlutterEngineManager.m in Sources */, + 0826E6A5DF896E479AE2642B4E37BF1F /* FlutterLocalNotificationsPlugin.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 02CDDA9B79E3AF65C46C03A75053ECF3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "GoogleUtilities-GoogleUtilities_Privacy"; + target = 5FF1A58DEEC5DB749FCD6C120B97CC82 /* GoogleUtilities-GoogleUtilities_Privacy */; + targetProxy = F2E64398D8064A66DBA59415CFE2A648 /* PBXContainerItemProxy */; + }; + 0E8E2C4456F612F10A156A69D326BEEE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = image_picker_ios; + target = 845DF30C6C93A1F35C6DCEBAFECA8F8A /* image_picker_ios */; + targetProxy = 97655442E1EB5F14C91CD15648367707 /* PBXContainerItemProxy */; + }; + 0EE01B0D211874C6816F991E8BE40CDE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = AAB279BAEABD7F0D2546D881A16B3189 /* PBXContainerItemProxy */; + }; + 10CB25F83A43C843C01E22489D47DEE4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = 93F636FEEDFEEF58D7F0937791C0F9BB /* PBXContainerItemProxy */; + }; + 1F89C870864A29E3B8BFCA4094B80944 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Flutter; + target = 1EFDDC32A34D56D411E640A81DCD9E73 /* Flutter */; + targetProxy = 3B641A062009906C2948E0F10A1F653B /* PBXContainerItemProxy */; + }; + 266761D37A9A8C9A937AC06A6A7D2335 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "nanopb-nanopb_Privacy"; + target = 55522A91938FF505CFEBEAD2DD85AE2D /* nanopb-nanopb_Privacy */; + targetProxy = DDCEB7C86EFCF4DF9F42E25D3A63AAB5 /* PBXContainerItemProxy */; + }; + 2869380D030F1BD3D7B625D9B5E0D28A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCoreInternal; + target = 25E9E9A17BC3F670357D7385C521E48E /* FirebaseCoreInternal */; + targetProxy = 219D323EE3BDBB104346CD612616BCF3 /* PBXContainerItemProxy */; + }; + 2CCFEE512E4639C3C0E902E42B230B2A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseMessaging; + target = 5895B432FE4D2F6826C8FF25A09DB6D2 /* FirebaseMessaging */; + targetProxy = 0762CC5A81893BA8BE745719D8AB885B /* PBXContainerItemProxy */; + }; + 3C9D6B3C27DE7FAC798F9E8ED42E6D48 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseInstallations; + target = 87803597EB3F20FC46472B85392EC4FD /* FirebaseInstallations */; + targetProxy = 8105158DB66AF0EBA32C7C70553000DF /* PBXContainerItemProxy */; + }; + 3E403294D2A189101DB7574D84F616C3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Flutter; + target = 1EFDDC32A34D56D411E640A81DCD9E73 /* Flutter */; + targetProxy = DAF6D916715838ADEABEB4D9AC715D7F /* PBXContainerItemProxy */; + }; + 43A4DFA831ABC1D8C3E6D228E330BBF9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 869347A98F9B8E8F4DFB537047767585 /* PBXContainerItemProxy */; + }; + 4C09BF1AFA89E841993276CF0342B9B3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = AE6224D1282DEF839D31B5C9F4FEEAFE /* PBXContainerItemProxy */; + }; + 50579E6A41DA8125ACDED4083FC9BAA1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = 8AA15153DC0CBB3A3DED625817ECBE3E /* PBXContainerItemProxy */; + }; + 5C92AD7A173EFF92E4092C6AF37EFDC0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = 0192270253ECFED942C0F4F590FFEC16 /* PBXContainerItemProxy */; + }; + 63F5DF323ED73744380ABA257B338150 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = flutter_local_notifications; + target = F64AA263B9D7877A7D58823DEF7F113B /* flutter_local_notifications */; + targetProxy = 94B899FA05698E30EA21B0135F230128 /* PBXContainerItemProxy */; + }; + 664C337C40D2B840B761FA06AA362A8E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = PromisesObjC; + target = 2BBF7206D7FAC92C82A042A99C4A98F8 /* PromisesObjC */; + targetProxy = FF8DB6F0FC60C5D49C51FE0D408905AE /* PBXContainerItemProxy */; + }; + 72A36FA49A29DFA754257CC533D9471E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCoreInternal; + target = 25E9E9A17BC3F670357D7385C521E48E /* FirebaseCoreInternal */; + targetProxy = B916F5018DFF5EF404096B17FF1E6670 /* PBXContainerItemProxy */; + }; + 73520F9868C9E014FC60A288F8B0D9A3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "flutter_local_notifications-flutter_local_notifications_privacy"; + target = 743B1C5626A92F8FC4AFBE2602CA840F /* flutter_local_notifications-flutter_local_notifications_privacy */; + targetProxy = 663E3630442241D6D8F1320596DBA7A1 /* PBXContainerItemProxy */; + }; + 73EFE5FFFB400190D960221C166CC0D8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "FirebaseCore-FirebaseCore_Privacy"; + target = 1001C16510D946B47CFF8B19DBC0B787 /* FirebaseCore-FirebaseCore_Privacy */; + targetProxy = 4FCD2E72D793A8DAD6C50DE106645D9B /* PBXContainerItemProxy */; + }; + 7C28218E9F953EE5E7CC0EA152EE3F7B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Flutter; + target = 1EFDDC32A34D56D411E640A81DCD9E73 /* Flutter */; + targetProxy = 6C278D1E93E8D812EE3F535EB225FC59 /* PBXContainerItemProxy */; + }; + 7D9F786F238F8E30338A94B55FBDEF94 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Firebase; + target = 072CEA044D2EF26F03496D5996BBF59F /* Firebase */; + targetProxy = 36BA05CA1EE73578C6222FF960F63B78 /* PBXContainerItemProxy */; + }; + 7DE3F59D32E758D449D9B22688C05CA9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = AAE2C625E2E4822114201AA84A528C9D /* PBXContainerItemProxy */; + }; + 80986EF8DBD794A5118CAB08EB42F6E3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Pods-Runner"; + target = 8B74B458B450D74B75744B87BD747314 /* Pods-Runner */; + targetProxy = 69008D115C5DAA717898D2837D54428C /* PBXContainerItemProxy */; + }; + 84FB2E490719510A066EE6188A4A4EF1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = AF4B247048ACDCAB34391B6BE8DBB1E7 /* PBXContainerItemProxy */; + }; + 8B1027366C2D676EE573B263C412D596 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseInstallations; + target = 87803597EB3F20FC46472B85392EC4FD /* FirebaseInstallations */; + targetProxy = 5969D7170D106F4A1AB192E1216F15AA /* PBXContainerItemProxy */; + }; + 8B95663B5F60A2335323E03400082A15 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = 044E87AB58E48E9C05DF65978B3D8571 /* PBXContainerItemProxy */; + }; + 8D5ABA0387D4D65424317F9CDC9D49D0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleUtilities; + target = 8D7F5D5DD528D21A72DC87ADA5B12E2D /* GoogleUtilities */; + targetProxy = F27493F13218D5AB3810ACCB60F7B4F6 /* PBXContainerItemProxy */; + }; + 8EE224A90E1681309C71D34E509A520B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "firebase_messaging-firebase_messaging_Privacy"; + target = DF331B019C7101D6AF15978FDCEC828E /* firebase_messaging-firebase_messaging_Privacy */; + targetProxy = B548E029B6A1C5304B6EA24842B71888 /* PBXContainerItemProxy */; + }; + 8F9268222E7F350FF069975274F2941E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Flutter; + target = 1EFDDC32A34D56D411E640A81DCD9E73 /* Flutter */; + targetProxy = 3A64087E666ACD9DFF57B700EACED484 /* PBXContainerItemProxy */; + }; + 92FF942C4FCB632500DD32D523575520 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "image_picker_ios-image_picker_ios_privacy"; + target = A450BF39E3E5256209A256E278D71BFD /* image_picker_ios-image_picker_ios_privacy */; + targetProxy = 703FBA9CB960246229152C34031EE17D /* PBXContainerItemProxy */; + }; + A8EAC6D6E4AF36FED65E29228ACE36B1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "GoogleDataTransport-GoogleDataTransport_Privacy"; + target = DD0D41A9315A48004E57F4F0E54095F1 /* GoogleDataTransport-GoogleDataTransport_Privacy */; + targetProxy = 13E7F305BB38CDE8DA75F8F9F7B578A1 /* PBXContainerItemProxy */; + }; + AC7895442E8ED9F65E03479BA0B36FD9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = firebase_messaging; + target = B92347C3E503ADBA2F0EF79DE5320B2D /* firebase_messaging */; + targetProxy = 916EECCCF2ECA3A4E92A5B7F46695892 /* PBXContainerItemProxy */; + }; + B30C651328C33AE9AF917D41339CE4DD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseMessaging; + target = 5895B432FE4D2F6826C8FF25A09DB6D2 /* FirebaseMessaging */; + targetProxy = 822FF24129B4ABB459510733D3AB564C /* PBXContainerItemProxy */; + }; + B67F50CE988161665B2AB017B92A657F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "FirebaseInstallations-FirebaseInstallations_Privacy"; + target = 3EB14444A17F9D4F1F697F7C1FF32245 /* FirebaseInstallations-FirebaseInstallations_Privacy */; + targetProxy = 7F7A8CD4EE0915D7F18EDF09B23B2F1E /* PBXContainerItemProxy */; + }; + BA47C823EA60AD852C65E2F339DCCAC7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Firebase; + target = 072CEA044D2EF26F03496D5996BBF59F /* Firebase */; + targetProxy = D77479D78C6DFAAC53455BED820DEE1C /* PBXContainerItemProxy */; + }; + BE67F450DB9D82F4A23F1D9332169775 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = firebase_core; + target = DAA3DF4B8C2F11E7A1764EF4EC560AC8 /* firebase_core */; + targetProxy = A36A467FF580B3943E553101F7099554 /* PBXContainerItemProxy */; + }; + BF273C1C9950BF7782C02342D2E52334 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = 33F5930894B3A36E1F65F7AA35711543 /* PBXContainerItemProxy */; + }; + C2E948A82861BA076D785707AB845988 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = D0456CA7DA8E033585FE84F690D6D985 /* PBXContainerItemProxy */; + }; + C4AC5F561C9A462DCEAC9DEFB1DAB202 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleDataTransport; + target = 5C0371EE948D0357B8EE0E34ABB44BF0 /* GoogleDataTransport */; + targetProxy = 7914C1F45A8D35F6B63535ED188247A4 /* PBXContainerItemProxy */; + }; + C9E65B124DC872E1B3548F41A8D0FC11 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "FirebaseCoreInternal-FirebaseCoreInternal_Privacy"; + target = 2949783F7EDB27AD4666B5427B63DC79 /* FirebaseCoreInternal-FirebaseCoreInternal_Privacy */; + targetProxy = 44444840A079E028F5B565C0B80F382C /* PBXContainerItemProxy */; + }; + CBC35C781EA13C1D19EFDF9EE9EB96C2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = GoogleDataTransport; + target = 5C0371EE948D0357B8EE0E34ABB44BF0 /* GoogleDataTransport */; + targetProxy = 1DDEC92A71C75B2B0423E0F810B08991 /* PBXContainerItemProxy */; + }; + CCC08443CD338CE1211FCE38A0FE8A95 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Firebase; + target = 072CEA044D2EF26F03496D5996BBF59F /* Firebase */; + targetProxy = 7051DFF3BD836497C1B9299F679A1D5F /* PBXContainerItemProxy */; + }; + D14D86C928DA86CF300718D1228D2887 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "FirebaseMessaging-FirebaseMessaging_Privacy"; + target = 21FB29F43C8A2A81ABFE8C478370070E /* FirebaseMessaging-FirebaseMessaging_Privacy */; + targetProxy = 3EC43A0AA2CFD9AFF53ECAEF03306581 /* PBXContainerItemProxy */; + }; + D82107409C69EEE8FC243BCF5B94F6BD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "PromisesObjC-FBLPromises_Privacy"; + target = 1BFBEDBF7E03729D43C96530EE190825 /* PromisesObjC-FBLPromises_Privacy */; + targetProxy = 0DBF59B522E2B64B7F8788C45573BAED /* PBXContainerItemProxy */; + }; + D87D7501B4DB30CE959EE8EB0D788B17 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FirebaseCore; + target = 4402AFF83DBDC4DD07E198685FDC2DF2 /* FirebaseCore */; + targetProxy = 7C952A87E3C258490947FA285883D816 /* PBXContainerItemProxy */; + }; + ED7FC5BAE4BADD9FBE87E8C470DF7280 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = nanopb; + target = D2B5E7DCCBBFB32341D857D01211A1A3 /* nanopb */; + targetProxy = DF63A07312E00CAD6561968DEBFBC90A /* PBXContainerItemProxy */; + }; + F1D853F524E23D8D4413930C90692190 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = firebase_core; + target = DAA3DF4B8C2F11E7A1764EF4EC560AC8 /* firebase_core */; + targetProxy = 5E4A5B3DD62A4C720EC874F4302A4EBF /* PBXContainerItemProxy */; + }; + FCEF46B0022F39DDD0C6F3BDB924C78F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = Flutter; + target = 1EFDDC32A34D56D411E640A81DCD9E73 /* Flutter */; + targetProxy = F43AF25452369BC5A3F4C31900856C45 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 04AA69C36E4EC5ED74C9E811C31E019A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0C6A42B0370A0BB6545A0CCA144AF3F4 /* nanopb.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/nanopb"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = nanopb; + INFOPLIST_FILE = "Target Support Files/nanopb/ResourceBundle-nanopb_Privacy-nanopb-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = nanopb_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 077C7C76734FD6F7B076FA38B24A9923 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DD8C8ACC853AF1B657D17AEC50E540A9 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap"; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 09C301D131507FC84CBCBBDE0F071483 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E2411C6C639146FA21E9291E20EB02BF /* GoogleUtilities.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities.modulemap"; + PRODUCT_MODULE_NAME = GoogleUtilities; + PRODUCT_NAME = GoogleUtilities; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 0A63100F2D79FF6565A96B5B3ECD12E8 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E2411C6C639146FA21E9291E20EB02BF /* GoogleUtilities.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities.modulemap"; + PRODUCT_MODULE_NAME = GoogleUtilities; + PRODUCT_NAME = GoogleUtilities; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 1063555FC107B4D7A5D9C5D0253F95A7 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 00817846E0BC0BA43768612211393B49 /* FirebaseMessaging.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseMessaging"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseMessaging; + INFOPLIST_FILE = "Target Support Files/FirebaseMessaging/ResourceBundle-FirebaseMessaging_Privacy-FirebaseMessaging-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + PRODUCT_NAME = FirebaseMessaging_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + 1C99355F2074A98756DD5D3332462725 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2B3AF9D90D4B088422687FFF4641CBC3 /* Pods-Runner.profile.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-Runner/Pods-Runner-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Runner/Pods-Runner.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 1DDC7A3842663897A09165E4EF42AE98 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ADD75767BCDDF56305838AA3576C0D6A /* firebase_messaging.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/firebase_messaging/firebase_messaging-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/firebase_messaging/firebase_messaging-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/firebase_messaging/firebase_messaging.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = firebase_messaging; + PRODUCT_NAME = firebase_messaging; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 1EBE1F477B516E2C7C7B8DD27EAD54E6 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 618D7CDD1897742A6C54A37FFB4D0219 /* FirebaseInstallations.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseInstallations"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseInstallations; + INFOPLIST_FILE = "Target Support Files/FirebaseInstallations/ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = FirebaseInstallations_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + 21F7E3A1AC7683AE910B4FDCCABC4319 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8D8A24088A30A466B083BC03A5AE1101 /* FirebaseInstallations.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseInstallations"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseInstallations; + INFOPLIST_FILE = "Target Support Files/FirebaseInstallations/ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = FirebaseInstallations_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 2635F6DE66B31906BE9D745EE9284997 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7D0ECCE4F5783E4482638C77ECFF4F5B /* GoogleUtilities.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleUtilities/GoogleUtilities.modulemap"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_MODULE_NAME = GoogleUtilities; + PRODUCT_NAME = GoogleUtilities; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 27541DDD4A591561DBF1134E3A6316F2 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2F0908B8A5026151E2800777E4B17F20 /* Pods-Runner.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-Runner/Pods-Runner-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Runner/Pods-Runner.modulemap"; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 2B463BFC9FBD8B4BB57844360F8360C0 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9D929313305FB6B3C350F1CCF65FFEA9 /* firebase_core.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/firebase_core/firebase_core-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/firebase_core/firebase_core-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/firebase_core/firebase_core.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = firebase_core; + PRODUCT_NAME = firebase_core; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 2B5DCD8E8333ED83E26BE9C10A05B225 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7D0ECCE4F5783E4482638C77ECFF4F5B /* GoogleUtilities.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/GoogleUtilities"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = GoogleUtilities; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = GoogleUtilities_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 2EBEA1D76DD986F57E8289ACDA91C7BD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 279906FE251A2F87816561487A4BBB08 /* FirebaseCoreInternal.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseCoreInternal"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseCoreInternal; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreInternal/ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = FirebaseCoreInternal_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 3499A754927859DDA28311A94C7FF0AD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0C6A42B0370A0BB6545A0CCA144AF3F4 /* nanopb.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_PREFIX_HEADER = "Target Support Files/nanopb/nanopb-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/nanopb/nanopb-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/nanopb/nanopb.modulemap"; + PRODUCT_MODULE_NAME = nanopb; + PRODUCT_NAME = nanopb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 37551EE8A7A4179130B614C1EEF5E6CF /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7658FDF5AEDDE8CAA80B12334DDD9D37 /* GoogleDataTransport.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/GoogleDataTransport"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = GoogleDataTransport; + INFOPLIST_FILE = "Target Support Files/GoogleDataTransport/ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = GoogleDataTransport_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + 396E8955BF2D439DA7122A2BE0706B0C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3F9429AEFF528448C4A75318298FA20A /* firebase_core.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/firebase_core/firebase_core-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/firebase_core/firebase_core-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/firebase_core/firebase_core.modulemap"; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = firebase_core; + PRODUCT_NAME = firebase_core; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 3FA2DB8C8B8C7DFB2B3DC4C218BEB775 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 490691048F9A43D41B5F491C8D800AA6 /* FirebaseCore.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/FirebaseCore-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCore/FirebaseCore.modulemap"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_MODULE_NAME = FirebaseCore; + PRODUCT_NAME = FirebaseCore; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 403B285D6A23E1957F2D84ED6C96369C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EDE3C6D61BC0AFA10BEE62B82A8CB6BC /* FirebaseMessaging.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseMessaging/FirebaseMessaging-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseMessaging/FirebaseMessaging.modulemap"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_MODULE_NAME = FirebaseMessaging; + PRODUCT_NAME = FirebaseMessaging; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 45B19E6A729A44EB45DE0A3CBD8FCF7A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2E3135844263DBDB97D0179BDAB2CB68 /* flutter_local_notifications.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/flutter_local_notifications"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = flutter_local_notifications; + INFOPLIST_FILE = "Target Support Files/flutter_local_notifications/ResourceBundle-flutter_local_notifications_privacy-flutter_local_notifications-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = flutter_local_notifications_privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 4CA6634EB21589D5B270D26BAA869FAC /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 490691048F9A43D41B5F491C8D800AA6 /* FirebaseCore.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseCore"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseCore; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = FirebaseCore_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 4ECBE3F533EE4B0EB2988DBEDE3B39B5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 75D435FE4E37C337A7F1C57E230D8EBD /* flutter_local_notifications.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/flutter_local_notifications"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = flutter_local_notifications; + INFOPLIST_FILE = "Target Support Files/flutter_local_notifications/ResourceBundle-flutter_local_notifications_privacy-flutter_local_notifications-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + PRODUCT_NAME = flutter_local_notifications_privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + 503C1EFFF98ABB8F379FAECB16E0AEE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_PROFILE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Profile; + }; + 50414FC1E141D80F69FB1F2C2A459F5B /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B6937D9D9C997E2BA32C1EA4575FD8BA /* PromisesObjC.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/PromisesObjC-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PromisesObjC/PromisesObjC.modulemap"; + PRODUCT_MODULE_NAME = FBLPromises; + PRODUCT_NAME = FBLPromises; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 51F68F8D568210EBF8C9046AA827A488 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7658FDF5AEDDE8CAA80B12334DDD9D37 /* GoogleDataTransport.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap"; + PRODUCT_MODULE_NAME = GoogleDataTransport; + PRODUCT_NAME = GoogleDataTransport; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 54D0CD2434ACE221EAD238EC3030852C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 618D7CDD1897742A6C54A37FFB4D0219 /* FirebaseInstallations.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseInstallations"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseInstallations; + INFOPLIST_FILE = "Target Support Files/FirebaseInstallations/ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = FirebaseInstallations_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 54FF12E6C8A3DF0D3E0003325A4866F8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 78CF3937473E3F59F7E47C945F33DB50 /* FirebaseCoreInternal.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_PREFIX_HEADER = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_MODULE_NAME = FirebaseCoreInternal; + PRODUCT_NAME = FirebaseCoreInternal; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 55A9012DDF56727920FDF4BF7F450EE7 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 279906FE251A2F87816561487A4BBB08 /* FirebaseCoreInternal.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_PREFIX_HEADER = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCoreInternal; + PRODUCT_NAME = FirebaseCoreInternal; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 5CDAD1637A42957C4FE587A561AB4200 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 279906FE251A2F87816561487A4BBB08 /* FirebaseCoreInternal.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseCoreInternal"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseCoreInternal; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreInternal/ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = FirebaseCoreInternal_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + 5E5C470B05B913A0A49D50D4BBF4761F /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9D925A34FCE9DF5AF00DD4BB47713016 /* FirebaseCore.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseCore"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseCore; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = FirebaseCore_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 6031CA618212A7E0FABFB70FD3103E20 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 618D7CDD1897742A6C54A37FFB4D0219 /* FirebaseInstallations.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap"; + PRODUCT_MODULE_NAME = FirebaseInstallations; + PRODUCT_NAME = FirebaseInstallations; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 64AB9ABD43361E4FCED9A975B0B36E60 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B903D4DE875B151937BA3E87E4A04205 /* image_picker_ios.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/image_picker_ios"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = image_picker_ios; + INFOPLIST_FILE = "Target Support Files/image_picker_ios/ResourceBundle-image_picker_ios_privacy-image_picker_ios-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + PRODUCT_NAME = image_picker_ios_privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 664DCF4122D4CD53FB287C2A28A38A87 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ADD75767BCDDF56305838AA3576C0D6A /* firebase_messaging.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/firebase_messaging/firebase_messaging-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/firebase_messaging/firebase_messaging-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/firebase_messaging/firebase_messaging.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = firebase_messaging; + PRODUCT_NAME = firebase_messaging; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 66AB2934750D40AD8076557987F1C242 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FFE7D2BB92263A9180243E4881212E9B /* Flutter.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + ONLY_ACTIVE_ARCH = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 6B8612A46C65E8E346F142115414E01C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FB0D5A901EA4BB55EB4272787CA2B4B8 /* Firebase.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 73BB390A37F36B7E1B6109415E2D8B87 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7658FDF5AEDDE8CAA80B12334DDD9D37 /* GoogleDataTransport.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/GoogleDataTransport"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = GoogleDataTransport; + INFOPLIST_FILE = "Target Support Files/GoogleDataTransport/ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = GoogleDataTransport_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 746F4DB1D1DFC4F86CA44D2C4565CF9C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8117DDCAB0947EC036DA8BE1D942F629 /* PromisesObjC.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/PromisesObjC"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FBLPromises; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = FBLPromises_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 74A7B5838C5F4443C1F71F4B3F1851B2 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9D925A34FCE9DF5AF00DD4BB47713016 /* FirebaseCore.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/FirebaseCore-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCore/FirebaseCore.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCore; + PRODUCT_NAME = FirebaseCore; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 7595D10F89260DA87587255190DAF749 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0C6A42B0370A0BB6545A0CCA144AF3F4 /* nanopb.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_PREFIX_HEADER = "Target Support Files/nanopb/nanopb-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/nanopb/nanopb-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/nanopb/nanopb.modulemap"; + PRODUCT_MODULE_NAME = nanopb; + PRODUCT_NAME = nanopb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 7FFA91376AF8D75F232E56810901DFA6 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8D8A24088A30A466B083BC03A5AE1101 /* FirebaseInstallations.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_MODULE_NAME = FirebaseInstallations; + PRODUCT_NAME = FirebaseInstallations; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 87F517E8E959E9505A13F72742193D01 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 75D435FE4E37C337A7F1C57E230D8EBD /* flutter_local_notifications.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/flutter_local_notifications/flutter_local_notifications-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/flutter_local_notifications/flutter_local_notifications-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/flutter_local_notifications/flutter_local_notifications.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = flutter_local_notifications; + PRODUCT_NAME = flutter_local_notifications; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 88A9E6691A093E7A240C80283949E743 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 75D435FE4E37C337A7F1C57E230D8EBD /* flutter_local_notifications.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/flutter_local_notifications/flutter_local_notifications-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/flutter_local_notifications/flutter_local_notifications-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/flutter_local_notifications/flutter_local_notifications.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = flutter_local_notifications; + PRODUCT_NAME = flutter_local_notifications; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 88D6CBAF1C2523D9539A18FB783B118D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 618D7CDD1897742A6C54A37FFB4D0219 /* FirebaseInstallations.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap"; + PRODUCT_MODULE_NAME = FirebaseInstallations; + PRODUCT_NAME = FirebaseInstallations; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 897319BB2669AE8ADA194B05DDC4BE7E /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 00817846E0BC0BA43768612211393B49 /* FirebaseMessaging.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseMessaging/FirebaseMessaging-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseMessaging/FirebaseMessaging.modulemap"; + PRODUCT_MODULE_NAME = FirebaseMessaging; + PRODUCT_NAME = FirebaseMessaging; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 8B6D882CCE6FE085466C7258850770E9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B903D4DE875B151937BA3E87E4A04205 /* image_picker_ios.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/image_picker_ios"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = image_picker_ios; + INFOPLIST_FILE = "Target Support Files/image_picker_ios/ResourceBundle-image_picker_ios_privacy-image_picker_ios-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + PRODUCT_NAME = image_picker_ios_privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + 8C4E3B5F06D46AD0745906D171387ED1 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B6937D9D9C997E2BA32C1EA4575FD8BA /* PromisesObjC.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/PromisesObjC"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FBLPromises; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + PRODUCT_NAME = FBLPromises_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + 8DE5143C03248BB6CD542DE3963D6F3A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 90D7899BAB8C9FC56495251F169E87A5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F8547457089967DAC30C3130D4EDF7D1 /* Pods-Runner.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-Runner/Pods-Runner-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Runner/Pods-Runner.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 9136A0462E7B1A43CC80803149773894 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ADD75767BCDDF56305838AA3576C0D6A /* firebase_messaging.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/firebase_messaging"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = firebase_messaging; + INFOPLIST_FILE = "Target Support Files/firebase_messaging/ResourceBundle-firebase_messaging_Privacy-firebase_messaging-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + PRODUCT_NAME = firebase_messaging_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 955B32BF38B39B5ED743029D3687C01B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1792230F1C96C80BBCBE1F3E25A86437 /* nanopb.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_PREFIX_HEADER = "Target Support Files/nanopb/nanopb-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/nanopb/nanopb-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/nanopb/nanopb.modulemap"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_MODULE_NAME = nanopb; + PRODUCT_NAME = nanopb; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 97162EF46E16C09F313C69A0BBFDCAC7 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6C16E4E43B9D4F77B6DB7BB1766F356E /* image_picker_ios.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/image_picker_ios"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = image_picker_ios; + INFOPLIST_FILE = "Target Support Files/image_picker_ios/ResourceBundle-image_picker_ios_privacy-image_picker_ios-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = image_picker_ios_privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 98C166D001ADB177D51F8E827795C598 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9D925A34FCE9DF5AF00DD4BB47713016 /* FirebaseCore.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/FirebaseCore-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCore/FirebaseCore.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCore; + PRODUCT_NAME = FirebaseCore; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 9B5869DD19B02FED38C6A04096ED3070 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B903D4DE875B151937BA3E87E4A04205 /* image_picker_ios.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/image_picker_ios/image_picker_ios-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/image_picker_ios/image_picker_ios-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/image_picker_ios/image_picker_ios.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = image_picker_ios; + PRODUCT_NAME = image_picker_ios; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 9D1940C4805BBD3778B61566DAEBD38C /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9D929313305FB6B3C350F1CCF65FFEA9 /* firebase_core.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/firebase_core/firebase_core-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/firebase_core/firebase_core-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/firebase_core/firebase_core.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = firebase_core; + PRODUCT_NAME = firebase_core; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 9E406C6AAF85E580207CD97B0044DEAB /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; + A7322DBA55F7B770D7980C10F5F19C82 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6D057386278D6ACF2F30795937A5D7B6 /* firebase_messaging.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/firebase_messaging"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = firebase_messaging; + INFOPLIST_FILE = "Target Support Files/firebase_messaging/ResourceBundle-firebase_messaging_Privacy-firebase_messaging-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = firebase_messaging_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + B037CE77FDFCF8512BC2FCE5E90E788A /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1FC96341216BBB5BBE3744FB1F35DEEE /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + B499AB9AD5EE1C55282E8BC32CFBDDD6 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5D9309B998555FFB2544D65E50F4A2F9 /* GoogleDataTransport.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/GoogleDataTransport"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = GoogleDataTransport; + INFOPLIST_FILE = "Target Support Files/GoogleDataTransport/ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = GoogleDataTransport_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + B86F7DBE7C3708E6790AF0A7ADFA30B8 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1ADB61306F50F60E65BED44878011822 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + B891CB62AA79F6D20909113C5C6EF3A1 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9D925A34FCE9DF5AF00DD4BB47713016 /* FirebaseCore.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseCore"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseCore; + INFOPLIST_FILE = "Target Support Files/FirebaseCore/ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = FirebaseCore_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + B90F9ECA1CF6F4B009B3F630F29E5FEC /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5F2A42EA92F0EA92CF755046DDC08290 /* Flutter.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + BE0F51E6F34579C69DC8B50A17D9DE3E /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EDE3C6D61BC0AFA10BEE62B82A8CB6BC /* FirebaseMessaging.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseMessaging"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseMessaging; + INFOPLIST_FILE = "Target Support Files/FirebaseMessaging/ResourceBundle-FirebaseMessaging_Privacy-FirebaseMessaging-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = FirebaseMessaging_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + BF0E851448A7C1822432EBCFC3EAA01A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B6937D9D9C997E2BA32C1EA4575FD8BA /* PromisesObjC.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/PromisesObjC-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PromisesObjC/PromisesObjC.modulemap"; + PRODUCT_MODULE_NAME = FBLPromises; + PRODUCT_NAME = FBLPromises; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + BF7D2820E3D076148CD1DE61C911DA11 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 00817846E0BC0BA43768612211393B49 /* FirebaseMessaging.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseMessaging"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseMessaging; + INFOPLIST_FILE = "Target Support Files/FirebaseMessaging/ResourceBundle-FirebaseMessaging_Privacy-FirebaseMessaging-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + PRODUCT_NAME = FirebaseMessaging_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + C5C07FEBC3487282500002BA4B774FE4 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FB0D5A901EA4BB55EB4272787CA2B4B8 /* Firebase.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + C80D54694C8103A7785D43A016C63A48 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 78CF3937473E3F59F7E47C945F33DB50 /* FirebaseCoreInternal.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/FirebaseCoreInternal"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FirebaseCoreInternal; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreInternal/ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = FirebaseCoreInternal_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + D090AD1CFACF48F665C5C8CAEBD7F3F0 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B903D4DE875B151937BA3E87E4A04205 /* image_picker_ios.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/image_picker_ios/image_picker_ios-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/image_picker_ios/image_picker_ios-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/image_picker_ios/image_picker_ios.modulemap"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = image_picker_ios; + PRODUCT_NAME = image_picker_ios; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + D1B3BE482449F1BF40AB62CF4CEE8FDC /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ADD75767BCDDF56305838AA3576C0D6A /* firebase_messaging.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/firebase_messaging"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = firebase_messaging; + INFOPLIST_FILE = "Target Support Files/firebase_messaging/ResourceBundle-firebase_messaging_Privacy-firebase_messaging-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + PRODUCT_NAME = firebase_messaging_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + D84263EFDC805B043279372E788DD421 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E2411C6C639146FA21E9291E20EB02BF /* GoogleUtilities.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/GoogleUtilities"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = GoogleUtilities; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = GoogleUtilities_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + DF33887CE310A988C1E927894F81E383 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5D9309B998555FFB2544D65E50F4A2F9 /* GoogleDataTransport.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_MODULE_NAME = GoogleDataTransport; + PRODUCT_NAME = GoogleDataTransport; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + E08F9969AADAFA314865DD510537D27F /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 279906FE251A2F87816561487A4BBB08 /* FirebaseCoreInternal.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_PREFIX_HEADER = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap"; + PRODUCT_MODULE_NAME = FirebaseCoreInternal; + PRODUCT_NAME = FirebaseCoreInternal; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + EA09AABE16DE849EFBFC683043B1EB17 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 00817846E0BC0BA43768612211393B49 /* FirebaseMessaging.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/FirebaseMessaging/FirebaseMessaging-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/FirebaseMessaging/FirebaseMessaging.modulemap"; + PRODUCT_MODULE_NAME = FirebaseMessaging; + PRODUCT_NAME = FirebaseMessaging; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.9; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + EA4B15E6D9C116EC1B4A2E7B81674A8C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1792230F1C96C80BBCBE1F3E25A86437 /* nanopb.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/nanopb"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = nanopb; + INFOPLIST_FILE = "Target Support Files/nanopb/ResourceBundle-nanopb_Privacy-nanopb-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = nanopb_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + EB01ED5337906C7B510810DED7A2B774 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6C16E4E43B9D4F77B6DB7BB1766F356E /* image_picker_ios.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/image_picker_ios/image_picker_ios-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/image_picker_ios/image_picker_ios-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/image_picker_ios/image_picker_ios.modulemap"; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = image_picker_ios; + PRODUCT_NAME = image_picker_ios; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + EB68FF0711E7BA8C6C3032AAE7B957EC /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6D057386278D6ACF2F30795937A5D7B6 /* firebase_messaging.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/firebase_messaging/firebase_messaging-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/firebase_messaging/firebase_messaging-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/firebase_messaging/firebase_messaging.modulemap"; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = firebase_messaging; + PRODUCT_NAME = firebase_messaging; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + ECADC3DA3CA35C50136F729EA9ECE827 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5F2A42EA92F0EA92CF755046DDC08290 /* Flutter.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + F01AC0E8354228481B9C3E05BCC9DA24 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 75D435FE4E37C337A7F1C57E230D8EBD /* flutter_local_notifications.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/flutter_local_notifications"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = flutter_local_notifications; + INFOPLIST_FILE = "Target Support Files/flutter_local_notifications/ResourceBundle-flutter_local_notifications_privacy-flutter_local_notifications-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + PRODUCT_NAME = flutter_local_notifications_privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + F356B75D6B8E2C5ED4A7C409054CD802 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0C6A42B0370A0BB6545A0CCA144AF3F4 /* nanopb.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/nanopb"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = nanopb; + INFOPLIST_FILE = "Target Support Files/nanopb/ResourceBundle-nanopb_Privacy-nanopb-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = nanopb_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + F5BB03A1328EE54B9DB26FFC69518306 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B6937D9D9C997E2BA32C1EA4575FD8BA /* PromisesObjC.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/PromisesObjC"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = FBLPromises; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + PRODUCT_NAME = FBLPromises_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + F62F88E217B41B232B787B0706822594 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 97EF58920BA75188BEFB815F403ECFD7 /* Firebase.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + ONLY_ACTIVE_ARCH = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + F80FB38FBC68C92B61351A29D372E0AA /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7658FDF5AEDDE8CAA80B12334DDD9D37 /* GoogleDataTransport.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap"; + PRODUCT_MODULE_NAME = GoogleDataTransport; + PRODUCT_NAME = GoogleDataTransport; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + F82ABE84BF051B3A21E605798013BC13 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8117DDCAB0947EC036DA8BE1D942F629 /* PromisesObjC.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/PromisesObjC/PromisesObjC-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/PromisesObjC/PromisesObjC.modulemap"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_MODULE_NAME = FBLPromises; + PRODUCT_NAME = FBLPromises; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + FB341C0100BFCF6B97990EAF78F7ABFF /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2E3135844263DBDB97D0179BDAB2CB68 /* flutter_local_notifications.debug.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = NO; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "$(inherited) armv7"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "$(inherited) i386"; + "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64\"", + "$(inherited)", + ); + "FRAMEWORK_SEARCH_PATHS[sdk=iphonesimulator*]" = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/ios/Flutter.xcframework/ios-arm64_x86_64-simulator\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/flutter_local_notifications/flutter_local_notifications-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/flutter_local_notifications/flutter_local_notifications-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/flutter_local_notifications/flutter_local_notifications.modulemap"; + ONLY_ACTIVE_ARCH = NO; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + Flutter, + ); + PRODUCT_MODULE_NAME = flutter_local_notifications; + PRODUCT_NAME = flutter_local_notifications; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + "VALID_ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + FDAFD113A9405BC0A95CE47F00577C34 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E2411C6C639146FA21E9291E20EB02BF /* GoogleUtilities.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_IDENTITY = "-"; + CODE_SIGNING_REQUIRED = NO; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/GoogleUtilities"; + EXPANDED_CODE_SIGN_IDENTITY = "-"; + IBSC_MODULE = GoogleUtilities; + INFOPLIST_FILE = "Target Support Files/GoogleUtilities/ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + PRODUCT_NAME = GoogleUtilities_Privacy; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 044818E6F13FF69D67D99BB49C808856 /* Build configuration list for PBXAggregateTarget "Firebase" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F62F88E217B41B232B787B0706822594 /* Debug */, + C5C07FEBC3487282500002BA4B774FE4 /* Profile */, + 6B8612A46C65E8E346F142115414E01C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0D939566A978AA1625D9977E74EC39C1 /* Build configuration list for PBXNativeTarget "flutter_local_notifications" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FB341C0100BFCF6B97990EAF78F7ABFF /* Debug */, + 88A9E6691A093E7A240C80283949E743 /* Profile */, + 87F517E8E959E9505A13F72742193D01 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 16DD5A8F60AB91B2757F7AAB20D27667 /* Build configuration list for PBXNativeTarget "FirebaseCore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3FA2DB8C8B8C7DFB2B3DC4C218BEB775 /* Debug */, + 98C166D001ADB177D51F8E827795C598 /* Profile */, + 74A7B5838C5F4443C1F71F4B3F1851B2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 25571F03D4736F86E7D5D1363783468B /* Build configuration list for PBXNativeTarget "nanopb-nanopb_Privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EA4B15E6D9C116EC1B4A2E7B81674A8C /* Debug */, + F356B75D6B8E2C5ED4A7C409054CD802 /* Profile */, + 04AA69C36E4EC5ED74C9E811C31E019A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 338130EB3FC87F51A0A88EE26D25D074 /* Build configuration list for PBXNativeTarget "FirebaseCoreInternal-FirebaseCoreInternal_Privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C80D54694C8103A7785D43A016C63A48 /* Debug */, + 5CDAD1637A42957C4FE587A561AB4200 /* Profile */, + 2EBEA1D76DD986F57E8289ACDA91C7BD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8DE5143C03248BB6CD542DE3963D6F3A /* Debug */, + 503C1EFFF98ABB8F379FAECB16E0AEE5 /* Profile */, + 9E406C6AAF85E580207CD97B0044DEAB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4B1508164EFB91BCA6B7DFAAAE1EDDF9 /* Build configuration list for PBXNativeTarget "image_picker_ios" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB01ED5337906C7B510810DED7A2B774 /* Debug */, + D090AD1CFACF48F665C5C8CAEBD7F3F0 /* Profile */, + 9B5869DD19B02FED38C6A04096ED3070 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 52D03D1C0585986A645E6E4DA0F5A0BD /* Build configuration list for PBXNativeTarget "image_picker_ios-image_picker_ios_privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97162EF46E16C09F313C69A0BBFDCAC7 /* Debug */, + 8B6D882CCE6FE085466C7258850770E9 /* Profile */, + 64AB9ABD43361E4FCED9A975B0B36E60 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5678139697F427A1F6A8CE2EFE1109D4 /* Build configuration list for PBXNativeTarget "firebase_core" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 396E8955BF2D439DA7122A2BE0706B0C /* Debug */, + 9D1940C4805BBD3778B61566DAEBD38C /* Profile */, + 2B463BFC9FBD8B4BB57844360F8360C0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 594BD1BA1D4D0F671BC521421AC4390C /* Build configuration list for PBXNativeTarget "nanopb" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 955B32BF38B39B5ED743029D3687C01B /* Debug */, + 7595D10F89260DA87587255190DAF749 /* Profile */, + 3499A754927859DDA28311A94C7FF0AD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5F381D5E26CE1B96CEC0BA50A1F94D0F /* Build configuration list for PBXNativeTarget "GoogleDataTransport-GoogleDataTransport_Privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B499AB9AD5EE1C55282E8BC32CFBDDD6 /* Debug */, + 37551EE8A7A4179130B614C1EEF5E6CF /* Profile */, + 73BB390A37F36B7E1B6109415E2D8B87 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5FA5B327F6D79B0503F3F3AC10FABE44 /* Build configuration list for PBXNativeTarget "FirebaseInstallations" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7FFA91376AF8D75F232E56810901DFA6 /* Debug */, + 6031CA618212A7E0FABFB70FD3103E20 /* Profile */, + 88D6CBAF1C2523D9539A18FB783B118D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6596288413C6F6B681EBF266486DE2A1 /* Build configuration list for PBXNativeTarget "FirebaseInstallations-FirebaseInstallations_Privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 21F7E3A1AC7683AE910B4FDCCABC4319 /* Debug */, + 1EBE1F477B516E2C7C7B8DD27EAD54E6 /* Profile */, + 54D0CD2434ACE221EAD238EC3030852C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 94078A06C17E946ADC1F2C06726219E5 /* Build configuration list for PBXAggregateTarget "Flutter" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 66AB2934750D40AD8076557987F1C242 /* Debug */, + ECADC3DA3CA35C50136F729EA9ECE827 /* Profile */, + B90F9ECA1CF6F4B009B3F630F29E5FEC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9891BD206978E995A3D1B39280730E93 /* Build configuration list for PBXNativeTarget "GoogleUtilities-GoogleUtilities_Privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2B5DCD8E8333ED83E26BE9C10A05B225 /* Debug */, + D84263EFDC805B043279372E788DD421 /* Profile */, + FDAFD113A9405BC0A95CE47F00577C34 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9A05DFC822D8BC454D903BCEAD22B415 /* Build configuration list for PBXNativeTarget "firebase_messaging-firebase_messaging_Privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A7322DBA55F7B770D7980C10F5F19C82 /* Debug */, + D1B3BE482449F1BF40AB62CF4CEE8FDC /* Profile */, + 9136A0462E7B1A43CC80803149773894 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A5B701584A7226F4EA1D22F8A8C3212C /* Build configuration list for PBXNativeTarget "FirebaseCore-FirebaseCore_Privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4CA6634EB21589D5B270D26BAA869FAC /* Debug */, + B891CB62AA79F6D20909113C5C6EF3A1 /* Profile */, + 5E5C470B05B913A0A49D50D4BBF4761F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A742CB9DC752699A7ADA6C62CF5707F9 /* Build configuration list for PBXNativeTarget "firebase_messaging" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + EB68FF0711E7BA8C6C3032AAE7B957EC /* Debug */, + 664DCF4122D4CD53FB287C2A28A38A87 /* Profile */, + 1DDC7A3842663897A09165E4EF42AE98 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B36E02CAB92E20E1B6C0F3F7684B23EE /* Build configuration list for PBXNativeTarget "FirebaseMessaging" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 403B285D6A23E1957F2D84ED6C96369C /* Debug */, + 897319BB2669AE8ADA194B05DDC4BE7E /* Profile */, + EA09AABE16DE849EFBFC683043B1EB17 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B5736ABBC2B983C7339FD9E4C90C933E /* Build configuration list for PBXNativeTarget "GoogleUtilities" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2635F6DE66B31906BE9D745EE9284997 /* Debug */, + 0A63100F2D79FF6565A96B5B3ECD12E8 /* Profile */, + 09C301D131507FC84CBCBBDE0F071483 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D29D81EAA2B56AA0D77047034F77C3F2 /* Build configuration list for PBXNativeTarget "flutter_local_notifications-flutter_local_notifications_privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 45B19E6A729A44EB45DE0A3CBD8FCF7A /* Debug */, + 4ECBE3F533EE4B0EB2988DBEDE3B39B5 /* Profile */, + F01AC0E8354228481B9C3E05BCC9DA24 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D52099AA1537D0F3745166E1889F6CA3 /* Build configuration list for PBXNativeTarget "Pods-RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 077C7C76734FD6F7B076FA38B24A9923 /* Debug */, + B037CE77FDFCF8512BC2FCE5E90E788A /* Profile */, + B86F7DBE7C3708E6790AF0A7ADFA30B8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D833327BDF1E3BCD88C1AB96DD27BB16 /* Build configuration list for PBXNativeTarget "FirebaseMessaging-FirebaseMessaging_Privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE0F51E6F34579C69DC8B50A17D9DE3E /* Debug */, + 1063555FC107B4D7A5D9C5D0253F95A7 /* Profile */, + BF7D2820E3D076148CD1DE61C911DA11 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D9B3D27CA537F94301490675549265C6 /* Build configuration list for PBXNativeTarget "Pods-Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 27541DDD4A591561DBF1134E3A6316F2 /* Debug */, + 1C99355F2074A98756DD5D3332462725 /* Profile */, + 90D7899BAB8C9FC56495251F169E87A5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DD3CE85025D7A56421ADB3E62D3F3DA7 /* Build configuration list for PBXNativeTarget "PromisesObjC" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F82ABE84BF051B3A21E605798013BC13 /* Debug */, + 50414FC1E141D80F69FB1F2C2A459F5B /* Profile */, + BF0E851448A7C1822432EBCFC3EAA01A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E62B9E5503856CC7A80E2ECC1748C89C /* Build configuration list for PBXNativeTarget "GoogleDataTransport" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DF33887CE310A988C1E927894F81E383 /* Debug */, + 51F68F8D568210EBF8C9046AA827A488 /* Profile */, + F80FB38FBC68C92B61351A29D372E0AA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F415E1450AA4CE65860E7ADC0DD4E41B /* Build configuration list for PBXNativeTarget "PromisesObjC-FBLPromises_Privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 746F4DB1D1DFC4F86CA44D2C4565CF9C /* Debug */, + 8C4E3B5F06D46AD0745906D171387ED1 /* Profile */, + F5BB03A1328EE54B9DB26FFC69518306 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FA208D28700E3A65EA795BE0320525EA /* Build configuration list for PBXNativeTarget "FirebaseCoreInternal" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 54FF12E6C8A3DF0D3E0003325A4866F8 /* Debug */, + E08F9969AADAFA314865DD510537D27F /* Profile */, + 55A9012DDF56727920FDF4BF7F450EE7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Firebase.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Firebase.xcscheme new file mode 100644 index 0000000..c9537b5 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Firebase.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCore-FirebaseCore_Privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCore-FirebaseCore_Privacy.xcscheme new file mode 100644 index 0000000..db5ab1a --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCore-FirebaseCore_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCore.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCore.xcscheme new file mode 100644 index 0000000..d940df9 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCore.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCoreInternal-FirebaseCoreInternal_Privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCoreInternal-FirebaseCoreInternal_Privacy.xcscheme new file mode 100644 index 0000000..381966a --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCoreInternal-FirebaseCoreInternal_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCoreInternal.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCoreInternal.xcscheme new file mode 100644 index 0000000..3bd33ab --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseCoreInternal.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseInstallations-FirebaseInstallations_Privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseInstallations-FirebaseInstallations_Privacy.xcscheme new file mode 100644 index 0000000..938f09f --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseInstallations-FirebaseInstallations_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseInstallations.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseInstallations.xcscheme new file mode 100644 index 0000000..f4c66d3 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseInstallations.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseMessaging-FirebaseMessaging_Privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseMessaging-FirebaseMessaging_Privacy.xcscheme new file mode 100644 index 0000000..06a4324 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseMessaging-FirebaseMessaging_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseMessaging.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseMessaging.xcscheme new file mode 100644 index 0000000..1572e4a --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FirebaseMessaging.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Flutter.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Flutter.xcscheme new file mode 100644 index 0000000..efb76cc --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Flutter.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleDataTransport-GoogleDataTransport_Privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleDataTransport-GoogleDataTransport_Privacy.xcscheme new file mode 100644 index 0000000..1f6831e --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleDataTransport-GoogleDataTransport_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleDataTransport.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleDataTransport.xcscheme new file mode 100644 index 0000000..5143a18 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleDataTransport.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleUtilities-GoogleUtilities_Privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleUtilities-GoogleUtilities_Privacy.xcscheme new file mode 100644 index 0000000..cd8f14b --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleUtilities-GoogleUtilities_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleUtilities.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleUtilities.xcscheme new file mode 100644 index 0000000..370e321 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/GoogleUtilities.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-Runner.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-Runner.xcscheme new file mode 100644 index 0000000..2eb6216 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-Runner.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-RunnerTests.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-RunnerTests.xcscheme new file mode 100644 index 0000000..ce8b385 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-RunnerTests.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/PromisesObjC-FBLPromises_Privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/PromisesObjC-FBLPromises_Privacy.xcscheme new file mode 100644 index 0000000..aa272c6 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/PromisesObjC-FBLPromises_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/PromisesObjC.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/PromisesObjC.xcscheme new file mode 100644 index 0000000..a44c01c --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/PromisesObjC.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/firebase_core.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/firebase_core.xcscheme new file mode 100644 index 0000000..c6132bd --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/firebase_core.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/firebase_messaging-firebase_messaging_Privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/firebase_messaging-firebase_messaging_Privacy.xcscheme new file mode 100644 index 0000000..f0956cc --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/firebase_messaging-firebase_messaging_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/firebase_messaging.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/firebase_messaging.xcscheme new file mode 100644 index 0000000..93caefc --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/firebase_messaging.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/flutter_local_notifications-flutter_local_notifications_privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/flutter_local_notifications-flutter_local_notifications_privacy.xcscheme new file mode 100644 index 0000000..e369c2f --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/flutter_local_notifications-flutter_local_notifications_privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/flutter_local_notifications.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/flutter_local_notifications.xcscheme new file mode 100644 index 0000000..070f16c --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/flutter_local_notifications.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/image_picker_ios-image_picker_ios_privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/image_picker_ios-image_picker_ios_privacy.xcscheme new file mode 100644 index 0000000..95a7ce1 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/image_picker_ios-image_picker_ios_privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/image_picker_ios.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/image_picker_ios.xcscheme new file mode 100644 index 0000000..b4e72e2 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/image_picker_ios.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/nanopb-nanopb_Privacy.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/nanopb-nanopb_Privacy.xcscheme new file mode 100644 index 0000000..ecb3559 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/nanopb-nanopb_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/nanopb.xcscheme b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/nanopb.xcscheme new file mode 100644 index 0000000..b79a7c3 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/nanopb.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/xcschememanagement.plist b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..1fbbb45 --- /dev/null +++ b/frontend/ios/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,146 @@ + + + + + SchemeUserState + + Firebase.xcscheme + + isShown + + + FirebaseCore-FirebaseCore_Privacy.xcscheme + + isShown + + + FirebaseCore.xcscheme + + isShown + + + FirebaseCoreInternal-FirebaseCoreInternal_Privacy.xcscheme + + isShown + + + FirebaseCoreInternal.xcscheme + + isShown + + + FirebaseInstallations-FirebaseInstallations_Privacy.xcscheme + + isShown + + + FirebaseInstallations.xcscheme + + isShown + + + FirebaseMessaging-FirebaseMessaging_Privacy.xcscheme + + isShown + + + FirebaseMessaging.xcscheme + + isShown + + + Flutter.xcscheme + + isShown + + + GoogleDataTransport-GoogleDataTransport_Privacy.xcscheme + + isShown + + + GoogleDataTransport.xcscheme + + isShown + + + GoogleUtilities-GoogleUtilities_Privacy.xcscheme + + isShown + + + GoogleUtilities.xcscheme + + isShown + + + Pods-Runner.xcscheme + + isShown + + + Pods-RunnerTests.xcscheme + + isShown + + + PromisesObjC-FBLPromises_Privacy.xcscheme + + isShown + + + PromisesObjC.xcscheme + + isShown + + + firebase_core.xcscheme + + isShown + + + firebase_messaging-firebase_messaging_Privacy.xcscheme + + isShown + + + firebase_messaging.xcscheme + + isShown + + + flutter_local_notifications-flutter_local_notifications_privacy.xcscheme + + isShown + + + flutter_local_notifications.xcscheme + + isShown + + + image_picker_ios-image_picker_ios_privacy.xcscheme + + isShown + + + image_picker_ios.xcscheme + + isShown + + + nanopb-nanopb_Privacy.xcscheme + + isShown + + + nanopb.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + + diff --git a/frontend/ios/Pods/PromisesObjC/LICENSE b/frontend/ios/Pods/PromisesObjC/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/ios/Pods/PromisesObjC/README.md b/frontend/ios/Pods/PromisesObjC/README.md new file mode 100644 index 0000000..e0e65b7 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/README.md @@ -0,0 +1,60 @@ +[![Apache +License](https://img.shields.io/github/license/google/promises.svg)](LICENSE) +[![Travis](https://api.travis-ci.org/google/promises.svg?branch=master)](https://travis-ci.org/google/promises) +[![Gitter Chat](https://badges.gitter.im/google/promises.svg)](https://gitter.im/google/promises) + +![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS-blue.svg?longCache=true&style=flat) +![Languages](https://img.shields.io/badge/languages-Swift%20%7C%20ObjC-orange.svg?longCache=true&style=flat) +![Package Managers](https://img.shields.io/badge/supports-Bazel%20%7C%20SwiftPM%20%7C%20CocoaPods%20%7C%20Carthage-yellow.svg?longCache=true&style=flat) + +# Promises + +Promises is a modern framework that provides a synchronization construct for +Objective-C and Swift to facilitate writing asynchronous code. + +* [Introduction](g3doc/index.md) + * [The problem with async + code](g3doc/index.md#the-problem-with-async-code) + * [Promises to the rescue](g3doc/index.md#promises-to-the-rescue) + * [What is a promise?](g3doc/index.md#what-is-a-promise) +* [Framework](g3doc/index.md#framework) + * [Features](g3doc/index.md#features) + * [Benchmark](g3doc/index.md#benchmark) +* [Getting started](g3doc/index.md#getting-started) + * [Add dependency](g3doc/index.md#add-dependency) + * [Import](g3doc/index.md#import) + * [Adopt](g3doc/index.md#adopt) +* [Basics](g3doc/index.md#basics) + * [Creating promises](g3doc/index.md#creating-promises) + * [Async](g3doc/index.md#async) + * [Do](g3doc/index.md#do) + * [Pending](g3doc/index.md#pending) + * [Resolved](g3doc/index.md#create-a-resolved-promise) + * [Observing fulfillment](g3doc/index.md#observing-fulfillment) + * [Then](g3doc/index.md#then) + * [Observing rejection](g3doc/index.md#observing-rejection) + * [Catch](g3doc/index.md#catch) +* [Extensions](g3doc/index.md#extensions) + * [All](g3doc/index.md#all) + * [Always](g3doc/index.md#always) + * [Any](g3doc/index.md#any) + * [AwaitPromise](g3doc/index.md#awaitpromise) + * [Delay](g3doc/index.md#delay) + * [Race](g3doc/index.md#race) + * [Recover](g3doc/index.md#recover) + * [Reduce](g3doc/index.md#reduce) + * [Retry](g3doc/index.md#retry) + * [Timeout](g3doc/index.md#timeout) + * [Validate](g3doc/index.md#validate) + * [Wrap](g3doc/index.md#wrap) +* [Advanced topics](g3doc/index.md#advanced-topics) + * [Default dispatch queue](g3doc/index.md#default-dispatch-queue) + * [Ownership and retain + cycles](g3doc/index.md#ownership-and-retain-cycles) + * [Testing](g3doc/index.md#testing) + * [Objective-C <-> Swift + interoperability](g3doc/index.md#objective-c---swift-interoperability) + * [Dot-syntax in Objective-C](g3doc/index.md#dot-syntax-in-objective-c) +* [Anti-patterns](g3doc/index.md#anti-patterns) + * [Broken chain](g3doc/index.md#broken-chain) + * [Nested promises](g3doc/index.md#nested-promises) diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m new file mode 100644 index 0000000..a9c7feb --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m @@ -0,0 +1,89 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+All.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AllAdditions) + ++ (FBLPromise *)all:(NSArray *)promises { + return [self onQueue:self.defaultDispatchQueue all:promises]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue all:(NSArray *)allPromises { + NSParameterAssert(queue); + NSParameterAssert(allPromises); + + if (allPromises.count == 0) { + return [[self alloc] initWithResolution:@[]]; + } + NSMutableArray *promises = [allPromises mutableCopy]; + return [self + onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (NSUInteger i = 0; i < promises.count; ++i) { + id promise = promises[i]; + if ([promise isKindOfClass:self]) { + continue; + } else if ([promise isKindOfClass:[NSError class]]) { + reject(promise); + return; + } else { + [promises replaceObjectAtIndex:i + withObject:[[self alloc] initWithResolution:promise]]; + } + } + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue + fulfill:^(id __unused _) { + // Wait until all are fulfilled. + for (FBLPromise *promise in promises) { + if (!promise.isFulfilled) { + return; + } + } + // If called multiple times, only the first one affects the result. + fulfill([promises valueForKey:NSStringFromSelector(@selector(value))]); + } + reject:^(NSError *error) { + reject(error); + }]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AllAdditions) + ++ (FBLPromise * (^)(NSArray *))all { + return ^(NSArray *promises) { + return [self all:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))allOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue all:promises]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAllCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m new file mode 100644 index 0000000..c4e9776 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m @@ -0,0 +1,61 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Always.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AlwaysAdditions) + +- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue always:work]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue always:(FBLPromiseAlwaysWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self chainOnQueue:queue + chainedFulfill:^id(id value) { + work(); + return value; + } + chainedReject:^id(NSError *error) { + work(); + return error; + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AlwaysAdditions) + +- (FBLPromise * (^)(FBLPromiseAlwaysWorkBlock))always { + return ^(FBLPromiseAlwaysWorkBlock work) { + return [self always:work]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseAlwaysWorkBlock))alwaysOn { + return ^(dispatch_queue_t queue, FBLPromiseAlwaysWorkBlock work) { + return [self onQueue:queue always:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAlwaysCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m new file mode 100644 index 0000000..8454c34 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m @@ -0,0 +1,115 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Any.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +static NSArray *FBLPromiseCombineValuesAndErrors(NSArray *promises) { + NSMutableArray *combinedValuesAndErrors = [[NSMutableArray alloc] init]; + for (FBLPromise *promise in promises) { + if (promise.isFulfilled) { + [combinedValuesAndErrors addObject:promise.value ?: [NSNull null]]; + continue; + } + if (promise.isRejected) { + [combinedValuesAndErrors addObject:promise.error]; + continue; + } + assert(!promise.isPending); + }; + return combinedValuesAndErrors; +} + +@implementation FBLPromise (AnyAdditions) + ++ (FBLPromise *)any:(NSArray *)promises { + return [self onQueue:FBLPromise.defaultDispatchQueue any:promises]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue any:(NSArray *)anyPromises { + NSParameterAssert(queue); + NSParameterAssert(anyPromises); + + if (anyPromises.count == 0) { + return [[self alloc] initWithResolution:@[]]; + } + NSMutableArray *promises = [anyPromises mutableCopy]; + return [self + onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (NSUInteger i = 0; i < promises.count; ++i) { + id promise = promises[i]; + if ([promise isKindOfClass:self]) { + continue; + } else { + [promises replaceObjectAtIndex:i + withObject:[[self alloc] initWithResolution:promise]]; + } + } + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue + fulfill:^(id __unused _) { + // Wait until all are resolved. + for (FBLPromise *promise in promises) { + if (promise.isPending) { + return; + } + } + // If called multiple times, only the first one affects the result. + fulfill(FBLPromiseCombineValuesAndErrors(promises)); + } + reject:^(NSError *error) { + BOOL atLeastOneIsFulfilled = NO; + for (FBLPromise *promise in promises) { + if (promise.isPending) { + return; + } + if (promise.isFulfilled) { + atLeastOneIsFulfilled = YES; + } + } + if (atLeastOneIsFulfilled) { + fulfill(FBLPromiseCombineValuesAndErrors(promises)); + } else { + reject(error); + } + }]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AnyAdditions) + ++ (FBLPromise * (^)(NSArray *))any { + return ^(NSArray *promises) { + return [self any:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue any:promises]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAnyCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m new file mode 100644 index 0000000..c0a89d3 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m @@ -0,0 +1,73 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Async.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AsyncAdditions) + ++ (instancetype)async:(FBLPromiseAsyncWorkBlock)work { + return [self onQueue:self.defaultDispatchQueue async:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue async:(FBLPromiseAsyncWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[self alloc] initPending]; + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + work( + ^(id __nullable value) { + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }, + ^(NSError *error) { + [promise reject:error]; + }); + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_AsyncAdditions) + ++ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async { + return ^(FBLPromiseAsyncWorkBlock work) { + return [self async:work]; + }; +} + ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn { + return ^(dispatch_queue_t queue, FBLPromiseAsyncWorkBlock work) { + return [self onQueue:queue async:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAsyncCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m new file mode 100644 index 0000000..0f86b2f --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m @@ -0,0 +1,51 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Await.h" + +#import "FBLPromisePrivate.h" + +id __nullable FBLPromiseAwait(FBLPromise *promise, NSError **outError) { + assert(promise); + + static dispatch_once_t onceToken; + static dispatch_queue_t queue; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.google.FBLPromises.Await", DISPATCH_QUEUE_CONCURRENT); + }); + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + id __block resolution; + NSError __block *blockError; + [promise chainOnQueue:queue + chainedFulfill:^id(id value) { + resolution = value; + dispatch_semaphore_signal(semaphore); + return value; + } + chainedReject:^id(NSError *error) { + blockError = error; + dispatch_semaphore_signal(semaphore); + return error; + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (outError) { + *outError = blockError; + } + return resolution; +} + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAwaitCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m new file mode 100644 index 0000000..fff7690 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m @@ -0,0 +1,58 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Catch.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (CatchAdditions) + +- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject { + return [self onQueue:FBLPromise.defaultDispatchQueue catch:reject]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue catch:(FBLPromiseCatchWorkBlock)reject { + NSParameterAssert(queue); + NSParameterAssert(reject); + + return [self chainOnQueue:queue + chainedFulfill:nil + chainedReject:^id(NSError *error) { + reject(error); + return error; + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_CatchAdditions) + +- (FBLPromise* (^)(FBLPromiseCatchWorkBlock))catch { + return ^(FBLPromiseCatchWorkBlock catch) { + return [self catch:catch]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchWorkBlock))catchOn { + return ^(dispatch_queue_t queue, FBLPromiseCatchWorkBlock catch) { + return [self onQueue:queue catch:catch]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeCatchCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m new file mode 100644 index 0000000..5aeeb1f --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m @@ -0,0 +1,62 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Delay.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (DelayAdditions) + +- (FBLPromise *)delay:(NSTimeInterval)interval { + return [self onQueue:FBLPromise.defaultDispatchQueue delay:interval]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue delay:(NSTimeInterval)interval { + NSParameterAssert(queue); + + FBLPromise *promise = [[[self class] alloc] initPending]; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + [promise fulfill:value]; + }); + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_DelayAdditions) + +- (FBLPromise * (^)(NSTimeInterval))delay { + return ^(NSTimeInterval interval) { + return [self delay:interval]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, NSTimeInterval))delayOn { + return ^(dispatch_queue_t queue, NSTimeInterval interval) { + return [self onQueue:queue delay:interval]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeDelayCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m new file mode 100644 index 0000000..9ae6033 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m @@ -0,0 +1,62 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Do.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (DoAdditions) + ++ (instancetype)do:(FBLPromiseDoWorkBlock)work { + return [self onQueue:self.defaultDispatchQueue do:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[self alloc] initPending]; + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + id value = work(); + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_DoAdditions) + ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn { + return ^(dispatch_queue_t queue, FBLPromiseDoWorkBlock work) { + return [self onQueue:queue do:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeDoCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m new file mode 100644 index 0000000..1672ac4 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m @@ -0,0 +1,68 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Race.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (RaceAdditions) + ++ (instancetype)race:(NSArray *)promises { + return [self onQueue:self.defaultDispatchQueue race:promises]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)racePromises { + NSParameterAssert(queue); + NSAssert(racePromises.count > 0, @"No promises to observe"); + + NSArray *promises = [racePromises copy]; + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (id promise in promises) { + if (![promise isKindOfClass:self]) { + fulfill(promise); + return; + } + } + // Subscribe all, but only the first one to resolve will change + // the resulting promise's state. + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue fulfill:fulfill reject:reject]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_RaceAdditions) + ++ (FBLPromise * (^)(NSArray *))race { + return ^(NSArray *promises) { + return [self race:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))raceOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue race:promises]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeRaceCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m new file mode 100644 index 0000000..50e337a --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Recover.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (RecoverAdditions) + +- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery { + return [self onQueue:FBLPromise.defaultDispatchQueue recover:recovery]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue recover:(FBLPromiseRecoverWorkBlock)recovery { + NSParameterAssert(queue); + NSParameterAssert(recovery); + + return [self chainOnQueue:queue + chainedFulfill:nil + chainedReject:^id(NSError *error) { + return recovery(error); + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_RecoverAdditions) + +- (FBLPromise * (^)(FBLPromiseRecoverWorkBlock))recover { + return ^(FBLPromiseRecoverWorkBlock recovery) { + return [self recover:recovery]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRecoverWorkBlock))recoverOn { + return ^(dispatch_queue_t queue, FBLPromiseRecoverWorkBlock recovery) { + return [self onQueue:queue recover:recovery]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeRecoverCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m new file mode 100644 index 0000000..f98cf69 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m @@ -0,0 +1,64 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Reduce.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ReduceAdditions) + +- (FBLPromise *)reduce:(NSArray *)items combine:(FBLPromiseReducerBlock)reducer { + return [self onQueue:FBLPromise.defaultDispatchQueue reduce:items combine:reducer]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer { + NSParameterAssert(queue); + NSParameterAssert(items); + NSParameterAssert(reducer); + + FBLPromise *promise = self; + for (id item in items) { + promise = [promise chainOnQueue:queue + chainedFulfill:^id(id value) { + return reducer(value, item); + } + chainedReject:nil]; + } + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_ReduceAdditions) + +- (FBLPromise * (^)(NSArray *, FBLPromiseReducerBlock))reduce { + return ^(NSArray *items, FBLPromiseReducerBlock reducer) { + return [self reduce:items combine:reducer]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, NSArray *, FBLPromiseReducerBlock))reduceOn { + return ^(dispatch_queue_t queue, NSArray *items, FBLPromiseReducerBlock reducer) { + return [self onQueue:queue reduce:items combine:reducer]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeReduceCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m new file mode 100644 index 0000000..841be68 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m @@ -0,0 +1,131 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Retry.h" + +#import "FBLPromisePrivate.h" + +NSInteger const FBLPromiseRetryDefaultAttemptsCount = 1; +NSTimeInterval const FBLPromiseRetryDefaultDelayInterval = 1.0; + +static void FBLPromiseRetryAttempt(FBLPromise *promise, dispatch_queue_t queue, NSInteger count, + NSTimeInterval interval, FBLPromiseRetryPredicateBlock predicate, + FBLPromiseRetryWorkBlock work) { + __auto_type retrier = ^(id __nullable value) { + if ([value isKindOfClass:[NSError class]]) { + if (count <= 0 || (predicate && !predicate(count, value))) { + [promise reject:value]; + } else { + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + FBLPromiseRetryAttempt(promise, queue, count - 1, interval, predicate, work); + }); + } + } else { + [promise fulfill:value]; + } + }; + id value = work(); + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue fulfill:retrier reject:retrier]; + } else { + retrier(value); + } +} + +@implementation FBLPromise (RetryAdditions) + ++ (instancetype)retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue retry:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:queue attempts:FBLPromiseRetryDefaultAttemptsCount retry:work]; +} + ++ (instancetype)attempts:(NSInteger)count retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue attempts:count retry:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:queue + attempts:count + delay:FBLPromiseRetryDefaultDelayInterval + condition:nil + retry:work]; +} + ++ (instancetype)attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue + attempts:count + delay:interval + condition:predicate + retry:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[self alloc] initPending]; + FBLPromiseRetryAttempt(promise, queue, count, interval, predicate, work); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_RetryAdditions) + ++ (FBLPromise * (^)(FBLPromiseRetryWorkBlock))retry { + return ^id(FBLPromiseRetryWorkBlock work) { + return [self retry:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRetryWorkBlock))retryOn { + return ^id(dispatch_queue_t queue, FBLPromiseRetryWorkBlock work) { + return [self onQueue:queue retry:work]; + }; +} + ++ (FBLPromise * (^)(NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock, + FBLPromiseRetryWorkBlock))retryAgain { + return ^id(NSInteger count, NSTimeInterval interval, FBLPromiseRetryPredicateBlock predicate, + FBLPromiseRetryWorkBlock work) { + return [self attempts:count delay:interval condition:predicate retry:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock, + FBLPromiseRetryWorkBlock))retryAgainOn { + return ^id(dispatch_queue_t queue, NSInteger count, NSTimeInterval interval, + FBLPromiseRetryPredicateBlock predicate, FBLPromiseRetryWorkBlock work) { + return [self onQueue:queue attempts:count delay:interval condition:predicate retry:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeRetryCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m new file mode 100644 index 0000000..7d6b461 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m @@ -0,0 +1,58 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Testing.h" + +BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) { + BOOL isTimedOut = NO; + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout]; + static NSTimeInterval const minimalTimeout = 0.01; + static int64_t const minimalTimeToWait = (int64_t)(minimalTimeout * NSEC_PER_SEC); + dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, minimalTimeToWait); + dispatch_group_t dispatchGroup = FBLPromise.dispatchGroup; + NSRunLoop *runLoop = NSRunLoop.currentRunLoop; + while (dispatch_group_wait(dispatchGroup, waitTime)) { + isTimedOut = timeoutDate.timeIntervalSinceNow < 0.0; + if (isTimedOut) { + break; + } + [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:minimalTimeout]]; + } + return !isTimedOut; +} + +@implementation FBLPromise (TestingAdditions) + +// These properties are implemented in the FBLPromise class itself. +@dynamic isPending; +@dynamic isFulfilled; +@dynamic isRejected; +@dynamic value; +@dynamic error; + ++ (dispatch_group_t)dispatchGroup { + static dispatch_group_t gDispatchGroup; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gDispatchGroup = dispatch_group_create(); + }); + return gDispatchGroup; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeTestingCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m new file mode 100644 index 0000000..32df102 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m @@ -0,0 +1,53 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Then.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ThenAdditions) + +- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue then:work]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue then:(FBLPromiseThenWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self chainOnQueue:queue chainedFulfill:work chainedReject:nil]; +} + +@end + +@implementation FBLPromise (DotSyntax_ThenAdditions) + +- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then { + return ^(FBLPromiseThenWorkBlock work) { + return [self then:work]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn { + return ^(dispatch_queue_t queue, FBLPromiseThenWorkBlock work) { + return [self onQueue:queue then:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeThenCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m new file mode 100644 index 0000000..91da9ff --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m @@ -0,0 +1,67 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Timeout.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (TimeoutAdditions) + +- (FBLPromise *)timeout:(NSTimeInterval)interval { + return [self onQueue:FBLPromise.defaultDispatchQueue timeout:interval]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue timeout:(NSTimeInterval)interval { + NSParameterAssert(queue); + + FBLPromise *promise = [[[self class] alloc] initPending]; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + FBLPromise* __weak weakPromise = promise; + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + NSError *timedOutError = [[NSError alloc] initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeTimedOut + userInfo:nil]; + [weakPromise reject:timedOutError]; + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_TimeoutAdditions) + +- (FBLPromise* (^)(NSTimeInterval))timeout { + return ^(NSTimeInterval interval) { + return [self timeout:interval]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn { + return ^(dispatch_queue_t queue, NSTimeInterval interval) { + return [self onQueue:queue timeout:interval]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeTimeoutCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m new file mode 100644 index 0000000..3520e24 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Validate.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ValidateAdditions) + +- (FBLPromise*)validate:(FBLPromiseValidateWorkBlock)predicate { + return [self onQueue:FBLPromise.defaultDispatchQueue validate:predicate]; +} + +- (FBLPromise*)onQueue:(dispatch_queue_t)queue validate:(FBLPromiseValidateWorkBlock)predicate { + NSParameterAssert(queue); + NSParameterAssert(predicate); + + FBLPromiseChainedFulfillBlock chainedFulfill = ^id(id value) { + return predicate(value) ? value : + [[NSError alloc] initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeValidationFailure + userInfo:nil]; + }; + return [self chainOnQueue:queue chainedFulfill:chainedFulfill chainedReject:nil]; +} + +@end + +@implementation FBLPromise (DotSyntax_ValidateAdditions) + +- (FBLPromise* (^)(FBLPromiseValidateWorkBlock))validate { + return ^(FBLPromiseValidateWorkBlock predicate) { + return [self validate:predicate]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseValidateWorkBlock))validateOn { + return ^(dispatch_queue_t queue, FBLPromiseValidateWorkBlock predicate) { + return [self onQueue:queue validate:predicate]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeValidateCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m new file mode 100644 index 0000000..840bc16 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m @@ -0,0 +1,423 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Wrap.h" + +#import "FBLPromise+Async.h" + +@implementation FBLPromise (WrapAdditions) + ++ (instancetype)wrapCompletion:(void (^)(FBLPromiseCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapCompletion:(void (^)(FBLPromiseCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^{ + fulfill(nil); + }); + }]; +} + ++ (instancetype)wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapObjectCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(id __nullable value) { + fulfill(value); + }); + }]; +} + ++ (instancetype)wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapErrorCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(nil); + } + }); + }]; +} + ++ (instancetype)wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapObjectOrErrorCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(id __nullable value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(value); + } + }); + }]; +} + ++ (instancetype)wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapErrorOrObjectCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSError *__nullable error, id __nullable value) { + if (error) { + reject(error); + } else { + fulfill(value); + } + }); + }]; +} + ++ (FBLPromise *)wrap2ObjectsOrErrorCompletion: + (void (^)(FBLPromise2ObjectsOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrap2ObjectsOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrap2ObjectsOrErrorCompletion:(void (^)(FBLPromise2ObjectsOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(id __nullable value1, id __nullable value2, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@[ value1 ?: [NSNull null], value2 ?: [NSNull null] ]); + } + }); + }]; +} + ++ (FBLPromise *)wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapBoolCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(BOOL value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapBoolOrErrorCompletion: + (void (^)(FBLPromiseBoolOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapBoolOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapBoolOrErrorCompletion:(void (^)(FBLPromiseBoolOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(BOOL value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + ++ (FBLPromise *)wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapIntegerCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(NSInteger value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapIntegerOrErrorCompletion: + (void (^)(FBLPromiseIntegerOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapIntegerOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapIntegerOrErrorCompletion:(void (^)(FBLPromiseIntegerOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSInteger value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + ++ (FBLPromise *)wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapDoubleCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:(dispatch_queue_t)queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(double value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapDoubleOrErrorCompletion: + (void (^)(FBLPromiseDoubleOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapDoubleOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapDoubleOrErrorCompletion:(void (^)(FBLPromiseDoubleOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(double value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_WrapAdditions) + ++ (FBLPromise * (^)(void (^)(FBLPromiseCompletion)))wrapCompletion { + return ^(void (^work)(FBLPromiseCompletion)) { + return [self wrapCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseCompletion)))wrapCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseCompletion)) { + return [self onQueue:queue wrapCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletion { + return ^(void (^work)(FBLPromiseObjectCompletion)) { + return [self wrapObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseObjectCompletion)) { + return [self onQueue:queue wrapObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletion { + return ^(void (^work)(FBLPromiseErrorCompletion)) { + return [self wrapErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseErrorCompletion)) { + return [self onQueue:queue wrapErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletion { + return ^(void (^work)(FBLPromiseObjectOrErrorCompletion)) { + return [self wrapObjectOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseObjectOrErrorCompletion)) { + return [self onQueue:queue wrapObjectOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletion { + return ^(void (^work)(FBLPromiseErrorOrObjectCompletion)) { + return [self wrapErrorOrObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseErrorOrObjectCompletion)) { + return [self onQueue:queue wrapErrorOrObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletion { + return ^(void (^work)(FBLPromise2ObjectsOrErrorCompletion)) { + return [self wrap2ObjectsOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromise2ObjectsOrErrorCompletion)) { + return [self onQueue:queue wrap2ObjectsOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletion { + return ^(void (^work)(FBLPromiseBoolCompletion)) { + return [self wrapBoolCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseBoolCompletion)) { + return [self onQueue:queue wrapBoolCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseBoolOrErrorCompletion))) + wrapBoolOrErrorCompletion { + return ^(void (^work)(FBLPromiseBoolOrErrorCompletion)) { + return [self wrapBoolOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseBoolOrErrorCompletion))) + wrapBoolOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseBoolOrErrorCompletion)) { + return [self onQueue:queue wrapBoolOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletion { + return ^(void (^work)(FBLPromiseIntegerCompletion)) { + return [self wrapIntegerCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseIntegerCompletion)) { + return [self onQueue:queue wrapIntegerCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletion { + return ^(void (^work)(FBLPromiseIntegerOrErrorCompletion)) { + return [self wrapIntegerOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseIntegerOrErrorCompletion)) { + return [self onQueue:queue wrapIntegerOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletion { + return ^(void (^work)(FBLPromiseDoubleCompletion)) { + return [self wrapDoubleCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseDoubleCompletion)) { + return [self onQueue:queue wrapDoubleCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletion { + return ^(void (^work)(FBLPromiseDoubleOrErrorCompletion)) { + return [self wrapDoubleOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseDoubleOrErrorCompletion)) { + return [self onQueue:queue wrapDoubleOrErrorCompletion:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeWrapCategory(void) {} diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m new file mode 100644 index 0000000..9a61ed2 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m @@ -0,0 +1,346 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromisePrivate.h" + +/** All states a promise can be in. */ +typedef NS_ENUM(NSInteger, FBLPromiseState) { + FBLPromiseStatePending = 0, + FBLPromiseStateFulfilled, + FBLPromiseStateRejected, +}; + +typedef void (^FBLPromiseObserver)(FBLPromiseState state, id __nullable resolution); + +static dispatch_queue_t gFBLPromiseDefaultDispatchQueue; + +@implementation FBLPromise { + /** Current state of the promise. */ + FBLPromiseState _state; + /** + Set of arbitrary objects to keep strongly while the promise is pending. + Becomes nil after the promise has been resolved. + */ + NSMutableSet *__nullable _pendingObjects; + /** + Value to fulfill the promise with. + Can be nil if the promise is still pending, was resolved with nil or after it has been rejected. + */ + id __nullable _value; + /** + Error to reject the promise with. + Can be nil if the promise is still pending or after it has been fulfilled. + */ + NSError *__nullable _error; + /** List of observers to notify when the promise gets resolved. */ + NSMutableArray *_observers; +} + ++ (void)initialize { + if (self == [FBLPromise class]) { + gFBLPromiseDefaultDispatchQueue = dispatch_get_main_queue(); + } +} + ++ (dispatch_queue_t)defaultDispatchQueue { + @synchronized(self) { + return gFBLPromiseDefaultDispatchQueue; + } +} + ++ (void)setDefaultDispatchQueue:(dispatch_queue_t)queue { + NSParameterAssert(queue); + + @synchronized(self) { + gFBLPromiseDefaultDispatchQueue = queue; + } +} + ++ (instancetype)pendingPromise { + return [[self alloc] initPending]; +} + ++ (instancetype)resolvedWith:(nullable id)resolution { + return [[self alloc] initWithResolution:resolution]; +} + +- (void)fulfill:(nullable id)value { + if ([value isKindOfClass:[NSError class]]) { + [self reject:(NSError *)value]; + } else { + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + _state = FBLPromiseStateFulfilled; + _value = value; + _pendingObjects = nil; + for (FBLPromiseObserver observer in _observers) { + observer(_state, _value); + } + _observers = nil; + dispatch_group_leave(FBLPromise.dispatchGroup); + } + } + } +} + +- (void)reject:(NSError *)error { + NSAssert([error isKindOfClass:[NSError class]], @"Invalid error type."); + + if (![error isKindOfClass:[NSError class]]) { + // Give up on invalid error type in Release mode. + @throw error; // NOLINT + } + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + _state = FBLPromiseStateRejected; + _error = error; + _pendingObjects = nil; + for (FBLPromiseObserver observer in _observers) { + observer(_state, _error); + } + _observers = nil; + dispatch_group_leave(FBLPromise.dispatchGroup); + } + } +} + +#pragma mark - NSObject + +- (NSString *)description { + if (self.isFulfilled) { + return [NSString stringWithFormat:@"<%@ %p> Fulfilled: %@", NSStringFromClass([self class]), + self, self.value]; + } + if (self.isRejected) { + return [NSString stringWithFormat:@"<%@ %p> Rejected: %@", NSStringFromClass([self class]), + self, self.error]; + } + return [NSString stringWithFormat:@"<%@ %p> Pending", NSStringFromClass([self class]), self]; +} + +#pragma mark - Private + +- (instancetype)initPending { + self = [super init]; + if (self) { + dispatch_group_enter(FBLPromise.dispatchGroup); + } + return self; +} + +- (instancetype)initWithResolution:(nullable id)resolution { + self = [super init]; + if (self) { + if ([resolution isKindOfClass:[NSError class]]) { + _state = FBLPromiseStateRejected; + _error = (NSError *)resolution; + } else { + _state = FBLPromiseStateFulfilled; + _value = resolution; + } + } + return self; +} + +- (void)dealloc { + if (_state == FBLPromiseStatePending) { + dispatch_group_leave(FBLPromise.dispatchGroup); + } +} + +- (BOOL)isPending { + @synchronized(self) { + return _state == FBLPromiseStatePending; + } +} + +- (BOOL)isFulfilled { + @synchronized(self) { + return _state == FBLPromiseStateFulfilled; + } +} + +- (BOOL)isRejected { + @synchronized(self) { + return _state == FBLPromiseStateRejected; + } +} + +- (nullable id)value { + @synchronized(self) { + return _value; + } +} + +- (NSError *__nullable)error { + @synchronized(self) { + return _error; + } +} + +- (void)addPendingObject:(id)object { + NSParameterAssert(object); + + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + if (!_pendingObjects) { + _pendingObjects = [[NSMutableSet alloc] init]; + } + [_pendingObjects addObject:object]; + } + } +} + +- (void)observeOnQueue:(dispatch_queue_t)queue + fulfill:(FBLPromiseOnFulfillBlock)onFulfill + reject:(FBLPromiseOnRejectBlock)onReject { + NSParameterAssert(queue); + NSParameterAssert(onFulfill); + NSParameterAssert(onReject); + + @synchronized(self) { + switch (_state) { + case FBLPromiseStatePending: { + if (!_observers) { + _observers = [[NSMutableArray alloc] init]; + } + [_observers addObject:^(FBLPromiseState state, id __nullable resolution) { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + switch (state) { + case FBLPromiseStatePending: + break; + case FBLPromiseStateFulfilled: + onFulfill(resolution); + break; + case FBLPromiseStateRejected: + onReject(resolution); + break; + } + }); + }]; + break; + } + case FBLPromiseStateFulfilled: { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + onFulfill(self->_value); + }); + break; + } + case FBLPromiseStateRejected: { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + onReject(self->_error); + }); + break; + } + } + } +} + +- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue + chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill + chainedReject:(FBLPromiseChainedRejectBlock)chainedReject { + NSParameterAssert(queue); + + FBLPromise *promise = [[[self class] alloc] initPending]; + __auto_type resolver = ^(id __nullable value) { + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + value = chainedFulfill ? chainedFulfill(value) : value; + resolver(value); + } + reject:^(NSError *error) { + id value = chainedReject ? chainedReject(error) : error; + resolver(value); + }]; + return promise; +} + +#pragma mark - Category linking workaround + +extern void FBLIncludeAllCategory(void); +extern void FBLIncludeAlwaysCategory(void); +extern void FBLIncludeAnyCategory(void); +extern void FBLIncludeAsyncCategory(void); +extern void FBLIncludeAwaitCategory(void); +extern void FBLIncludeCatchCategory(void); +extern void FBLIncludeDelayCategory(void); +extern void FBLIncludeDoCategory(void); +extern void FBLIncludeRaceCategory(void); +extern void FBLIncludeRecoverCategory(void); +extern void FBLIncludeReduceCategory(void); +extern void FBLIncludeRetryCategory(void); +extern void FBLIncludeTestingCategory(void); +extern void FBLIncludeThenCategory(void); +extern void FBLIncludeTimeoutCategory(void); +extern void FBLIncludeValidateCategory(void); +extern void FBLIncludeWrapCategory(void); + +/** + Does nothing when called, and not meant to be called. + + This method forces the linker to include all FBLPromise categories even if + users do not include the '-ObjC' linker flag in their projects. + */ ++ (void)noop { + FBLIncludeAllCategory(); + FBLIncludeAllCategory(); + FBLIncludeAlwaysCategory(); + FBLIncludeAnyCategory(); + FBLIncludeAsyncCategory(); + FBLIncludeAwaitCategory(); + FBLIncludeCatchCategory(); + FBLIncludeDelayCategory(); + FBLIncludeDoCategory(); + FBLIncludeRaceCategory(); + FBLIncludeRecoverCategory(); + FBLIncludeReduceCategory(); + FBLIncludeRetryCategory(); + FBLIncludeTestingCategory(); + FBLIncludeThenCategory(); + FBLIncludeTimeoutCategory(); + FBLIncludeValidateCategory(); + FBLIncludeWrapCategory(); +} + +@end + +@implementation FBLPromise (DotSyntaxAdditions) + ++ (FBLPromise * (^)(void))pending { + return ^(void) { + return [self pendingPromise]; + }; +} + ++ (FBLPromise * (^)(id __nullable))resolved { + return ^(id resolution) { + return [self resolvedWith:resolution]; + }; +} + +@end diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m new file mode 100644 index 0000000..1cc181a --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m @@ -0,0 +1,19 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromiseError.h" + +NSErrorDomain const FBLPromiseErrorDomain = @"com.google.FBLPromises.Error"; diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/Resources/PrivacyInfo.xcprivacy b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..5397adc --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h new file mode 100644 index 0000000..9c0090e --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h @@ -0,0 +1,63 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AllAdditions) + +/** + Wait until all of the given promises are fulfilled. + If one of the given promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param promises Promises to wait for. + @return Promise of an array containing the values of input promises in the same order. + */ ++ (FBLPromise *)all:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Wait until all of the given promises are fulfilled. + If one of the given promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected FBLPromise correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return Promise of an array containing the values of input promises in the same order. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + all:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `all` operators. + Usage: FBLPromise.all(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_AllAdditions) + ++ (FBLPromise * (^)(NSArray *))all FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))allOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h new file mode 100644 index 0000000..13000f5 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h @@ -0,0 +1,54 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AlwaysAdditions) + +typedef void (^FBLPromiseAlwaysWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block that always executes, no matter if the receiver is rejected or fulfilled. + @return A new pending promise to be resolved with same resolution as the receiver. + */ +- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to dispatch on. + @param work A block that always executes, no matter if the receiver is rejected or fulfilled. + @return A new pending promise to be resolved with same resolution as the receiver. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + always:(FBLPromiseAlwaysWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `always` operators. + Usage: promise.always(^{...}) + */ +@interface FBLPromise(DotSyntax_AlwaysAdditions) + +- (FBLPromise* (^)(FBLPromiseAlwaysWorkBlock))always FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAlwaysWorkBlock))alwaysOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h new file mode 100644 index 0000000..82875bf --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h @@ -0,0 +1,69 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AnyAdditions) + +/** + Waits until all of the given promises are either fulfilled or rejected. + If all promises are rejected, then the returned promise is rejected with same error + as the last one rejected. + If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of + values or `NSErrors`, matching the original order of fulfilled or rejected promises respectively. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param promises Promises to wait for. + @return Promise of array containing the values or `NSError`s of input promises in the same order. + */ ++ (FBLPromise *)any:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Waits until all of the given promises are either fulfilled or rejected. + If all promises are rejected, then the returned promise is rejected with same error + as the last one rejected. + If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of + values or `NSError`s, matching the original order of fulfilled or rejected promises respectively. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return Promise of array containing the values or `NSError`s of input promises in the same order. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + any:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `any` operators. + Usage: FBLPromise.any(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_AnyAdditions) + ++ (FBLPromise * (^)(NSArray *))any FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h new file mode 100644 index 0000000..0588a9e --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AsyncAdditions) + +typedef void (^FBLPromiseFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseAsyncWorkBlock)(FBLPromiseFulfillBlock fulfill, + FBLPromiseRejectBlock reject) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously. + + @param work A block to perform any operations needed to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)async:(FBLPromiseAsyncWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously on the given queue. + + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + async:(FBLPromiseAsyncWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `async` operators. + Usage: FBLPromise.async(^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { ... }) + */ +@interface FBLPromise(DotSyntax_AsyncAdditions) + ++ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h new file mode 100644 index 0000000..c97a1ba --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h @@ -0,0 +1,32 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Waits for promise resolution. The current thread blocks until the promise is resolved. + + @param promise Promise to wait for. + @param error Error the promise was rejected with, or `nil` if the promise was fulfilled. + @return Value the promise was fulfilled with. If the promise was rejected, the return value + is always `nil`, but the error out arg is not. + */ +FOUNDATION_EXTERN id __nullable FBLPromiseAwait(FBLPromise *promise, + NSError **error) NS_REFINED_FOR_SWIFT; + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h new file mode 100644 index 0000000..a9ff170 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(CatchAdditions) + +typedef void (^FBLPromiseCatchWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with same resolution as the receiver. + If receiver is rejected, then `reject` block is executed asynchronously. + + @param reject A block to handle the error that receiver was rejected with. + @return A new pending promise. + */ +- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with same resolution as the receiver. + If receiver is rejected, then `reject` block is executed asynchronously on the given queue. + + @param queue A queue to invoke the `reject` block on. + @param reject A block to handle the error that receiver was rejected with. + @return A new pending promise. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + catch:(FBLPromiseCatchWorkBlock)reject NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `catch` operators. + Usage: promise.catch(^(NSError *error) { ... }) + */ +@interface FBLPromise(DotSyntax_CatchAdditions) + +- (FBLPromise* (^)(FBLPromiseCatchWorkBlock))catch FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchWorkBlock))catchOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h new file mode 100644 index 0000000..557df48 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(DelayAdditions) + +/** + Creates a new pending promise that fulfills with the same value as `self` after the `delay`, or + rejects with the same error immediately. + + @param interval Time to wait in seconds. + @return A new pending promise that fulfills at least `delay` seconds later than `self`, or rejects + with the same error immediately. + */ +- (FBLPromise *)delay:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a new pending promise that fulfills with the same value as `self` after the `delay`, or + rejects with the same error immediately. + + @param queue A queue to dispatch on. + @param interval Time to wait in seconds. + @return A new pending promise that fulfills at least `delay` seconds later than `self`, or rejects + with the same error immediately. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + delay:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `delay` operators. + Usage: promise.delay(...) + */ +@interface FBLPromise(DotSyntax_DelayAdditions) + +- (FBLPromise * (^)(NSTimeInterval))delay FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, NSTimeInterval))delayOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h new file mode 100644 index 0000000..6838e0a --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h @@ -0,0 +1,55 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(DoAdditions) + +typedef id __nullable (^FBLPromiseDoWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously. + + @param work A block that returns a value or an error used to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)do:(FBLPromiseDoWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously on the given queue. + + @param queue A queue to invoke the `work` block on. + @param work A block that returns a value or an error used to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `do` operators. + Usage: FBLPromise.doOn(queue, ^(NSError *error) { ... }) + */ +@interface FBLPromise(DotSyntax_DoAdditions) + ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h new file mode 100644 index 0000000..2f67258 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h @@ -0,0 +1,62 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(RaceAdditions) + +/** + Wait until any of the given promises are fulfilled. + If one of the promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + + @param promises Promises to wait for. + @return A new pending promise to be resolved with the same resolution as the first promise, among + the given ones, which was resolved. + */ ++ (instancetype)race:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Wait until any of the given promises are fulfilled. + If one of the promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return A new pending promise to be resolved with the same resolution as the first promise, among + the given ones, which was resolved. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `race` operators. + Usage: FBLPromise.race(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_RaceAdditions) + ++ (FBLPromise * (^)(NSArray *))race FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))raceOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h new file mode 100644 index 0000000..bb7df7e --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(RecoverAdditions) + +typedef id __nullable (^FBLPromiseRecoverWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); + +/** + Provides a new promise to recover in case the receiver gets rejected. + + @param recovery A block to handle the error that the receiver was rejected with. + @return A new pending promise to use instead of the rejected one that gets resolved with resolution + returned from `recovery` block. + */ +- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery NS_SWIFT_UNAVAILABLE(""); + +/** + Provides a new promise to recover in case the receiver gets rejected. + + @param queue A queue to dispatch on. + @param recovery A block to handle the error that the receiver was rejected with. + @return A new pending promise to use instead of the rejected one that gets resolved with resolution + returned from `recovery` block. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + recover:(FBLPromiseRecoverWorkBlock)recovery NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `recover` operators. + Usage: promise.recover(^id(NSError *error) {...}) + */ +@interface FBLPromise(DotSyntax_RecoverAdditions) + +- (FBLPromise * (^)(FBLPromiseRecoverWorkBlock))recover FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRecoverWorkBlock))recoverOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h new file mode 100644 index 0000000..5bb1eee --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h @@ -0,0 +1,71 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ReduceAdditions) + +typedef id __nullable (^FBLPromiseReducerBlock)(Value __nullable partial, id next) + NS_SWIFT_UNAVAILABLE(""); + +/** + Sequentially reduces a collection of values to a single promise using a given combining block + and the value `self` resolves with as initial value. + + @param items An array of values to process in order. + @param reducer A block to combine an accumulating value and an element of the sequence into + the new accumulating value or a promise resolved with it, to be used in the next + call of the `reducer` or returned to the caller. + @return A new pending promise returned from the last `reducer` invocation. + Or `self` if `items` is empty. + */ +- (FBLPromise *)reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE(""); + +/** + Sequentially reduces a collection of values to a single promise using a given combining block + and the value `self` resolves with as initial value. + + @param queue A queue to dispatch on. + @param items An array of values to process in order. + @param reducer A block to combine an accumulating value and an element of the sequence into + the new accumulating value or a promise resolved with it, to be used in the next + call of the `reducer` or returned to the caller. + @return A new pending promise returned from the last `reducer` invocation. + Or `self` if `items` is empty. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE(""); + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `reduce` operators. + Usage: promise.reduce(values, ^id(id partial, id next) { ... }) + */ +@interface FBLPromise(DotSyntax_ReduceAdditions) + +- (FBLPromise * (^)(NSArray *, FBLPromiseReducerBlock))reduce FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, NSArray *, FBLPromiseReducerBlock))reduceOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h new file mode 100644 index 0000000..414a17a --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h @@ -0,0 +1,165 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The default number of retry attempts is 1. */ +FOUNDATION_EXTERN NSInteger const FBLPromiseRetryDefaultAttemptsCount NS_REFINED_FOR_SWIFT; + +/** The default delay interval before making a retry attempt is 1.0 second. */ +FOUNDATION_EXTERN NSTimeInterval const FBLPromiseRetryDefaultDelayInterval NS_REFINED_FOR_SWIFT; + +@interface FBLPromise(RetryAdditions) + +typedef id __nullable (^FBLPromiseRetryWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); +typedef BOOL (^FBLPromiseRetryPredicateBlock)(NSInteger, NSError *) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. Defaults to `FBLPromiseRetryDefaultAttemptsCount` attempt(s) on rejection where the + `work` block is retried after a delay of `FBLPromiseRetryDefaultDelayInterval` second(s). + + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. Defaults to `FBLPromiseRetryDefaultAttemptsCount` attempt(s) on + rejection where the `work` block is retried on the given `queue` after a delay of + `FBLPromiseRetryDefaultDelayInterval` second(s). + + @param queue A queue to invoke the `work` block on. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. + + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. + + @param queue A queue to invoke the `work` block on. + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. On rejection, the `work` block is retried after the given delay `interval` and will + continue to retry until the number of specified attempts have been exhausted or will bail early if + the given condition is not met. + + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param interval Time to wait before the next retry attempt. + @param predicate Condition to check before the next retry attempt. The predicate block provides the + the number of remaining retry attempts and the error that the promise was rejected + with. + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted or if + the given condition is not met. + */ ++ (instancetype)attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. On rejection, the `work` block is retried after the given + delay `interval` and will continue to retry until the number of specified attempts have been + exhausted or will bail early if the given condition is not met. + + @param queue A queue to invoke the `work` block on. + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param interval Time to wait before the next retry attempt. + @param predicate Condition to check before the next retry attempt. The predicate block provides the + the number of remaining retry attempts and the error that the promise was rejected + with. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted or if + the given condition is not met. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise+Retry` operators. + Usage: FBLPromise.retry(^id { ... }) + */ +@interface FBLPromise(DotSyntax_RetryAdditions) + ++ (FBLPromise * (^)(FBLPromiseRetryWorkBlock))retry FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRetryWorkBlock))retryOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock __nullable, + FBLPromiseRetryWorkBlock))retryAgain FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSInteger, NSTimeInterval, + FBLPromiseRetryPredicateBlock __nullable, + FBLPromiseRetryWorkBlock))retryAgainOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h new file mode 100644 index 0000000..8478ae2 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Waits for all scheduled promises blocks. + + @param timeout Maximum time to wait. + @return YES if all promises blocks have completed before the timeout and NO otherwise. + */ +FOUNDATION_EXTERN BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) NS_REFINED_FOR_SWIFT; + +@interface FBLPromise(TestingAdditions) + +/** + Dispatch group for promises that is typically used to wait for all scheduled blocks. + */ +@property(class, nonatomic, readonly) dispatch_group_t dispatchGroup NS_REFINED_FOR_SWIFT; + +/** + Properties to get the current state of the promise. + */ +@property(nonatomic, readonly) BOOL isPending NS_REFINED_FOR_SWIFT; +@property(nonatomic, readonly) BOOL isFulfilled NS_REFINED_FOR_SWIFT; +@property(nonatomic, readonly) BOOL isRejected NS_REFINED_FOR_SWIFT; + +/** + Value the promise was fulfilled with. + Can be nil if the promise is still pending, was resolved with nil or after it has been rejected. + */ +@property(nonatomic, readonly, nullable) Value value NS_REFINED_FOR_SWIFT; + +/** + Error the promise was rejected with. + Can be nil if the promise is still pending or after it has been fulfilled. + */ +@property(nonatomic, readonly, nullable) NSError *error NS_REFINED_FOR_SWIFT; + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h new file mode 100644 index 0000000..32027e6 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h @@ -0,0 +1,63 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ThenAdditions) + +typedef id __nullable (^FBLPromiseThenWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with resolution returned from `work` + block: either value, error or another promise. The `work` block is executed asynchronously only + when the receiver is fulfilled. If receiver is rejected, the returned promise is also rejected with + the same error. + + @param work A block to handle the value that receiver was fulfilled with. + @return A new pending promise to be resolved with resolution returned from the `work` block. + */ +- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with resolution returned from `work` + block: either value, error or another promise. The `work` block is executed asynchronously when the + receiver is fulfilled. If receiver is rejected, the returned promise is also rejected with the same + error. + + @param queue A queue to invoke the `work` block on. + @param work A block to handle the value that receiver was fulfilled with. + @return A new pending promise to be resolved with resolution returned from the `work` block. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + then:(FBLPromiseThenWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `then` operators. + Usage: promise.then(^id(id value) { ... }) + */ +@interface FBLPromise(DotSyntax_ThenAdditions) + +- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h new file mode 100644 index 0000000..184ba16 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(TimeoutAdditions) + +/** + Waits for a promise with the specified `timeout`. + + @param interval Time to wait in seconds. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)timeout:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE(""); + +/** + Waits for a promise with the specified `timeout`. + + @param queue A queue to dispatch on. + @param interval Time to wait in seconds. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + timeout:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `timeout` operators. + Usage: promise.timeout(...) + */ +@interface FBLPromise(DotSyntax_TimeoutAdditions) + +- (FBLPromise* (^)(NSTimeInterval))timeout FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h new file mode 100644 index 0000000..9dfa2f1 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ValidateAdditions) + +typedef BOOL (^FBLPromiseValidateWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); + +/** + Validates a fulfilled value or rejects the value if it can not be validated. + + @param predicate An expression to validate. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)validate:(FBLPromiseValidateWorkBlock)predicate NS_SWIFT_UNAVAILABLE(""); + +/** + Validates a fulfilled value or rejects the value if it can not be validated. + + @param queue A queue to dispatch on. + @param predicate An expression to validate. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + validate:(FBLPromiseValidateWorkBlock)predicate NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `validate` operators. + Usage: promise.validate(^BOOL(id value) { ... }) + */ +@interface FBLPromise(DotSyntax_ValidateAdditions) + +- (FBLPromise * (^)(FBLPromiseValidateWorkBlock))validate FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseValidateWorkBlock))validateOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h new file mode 100644 index 0000000..664e1bb --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h @@ -0,0 +1,316 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Different types of completion handlers available to be wrapped with promise. + */ +typedef void (^FBLPromiseCompletion)(void) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseObjectCompletion)(id __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseErrorCompletion)(NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseObjectOrErrorCompletion)(id __nullable, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseErrorOrObjectCompletion)(NSError* __nullable, id __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromise2ObjectsOrErrorCompletion)(id __nullable, id __nullable, + NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseBoolCompletion)(BOOL) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseBoolOrErrorCompletion)(BOOL, NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseIntegerCompletion)(NSInteger) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseIntegerOrErrorCompletion)(NSInteger, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseDoubleCompletion)(double) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseDoubleOrErrorCompletion)(double, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); + +/** + Provides an easy way to convert methods that use common callback patterns into promises. + */ +@interface FBLPromise(WrapAdditions) + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with `nil` when completion handler is invoked. + */ ++ (instancetype)wrapCompletion:(void (^)(FBLPromiseCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with `nil` when completion handler is invoked. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapCompletion:(void (^)(FBLPromiseCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler. + */ ++ (instancetype)wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error provided by completion handler. + If error is `nil`, fulfills with `nil`, otherwise rejects with the error. + */ ++ (instancetype)wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error provided by completion handler. + If error is `nil`, fulfills with `nil`, otherwise rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler if error is `nil`. + Otherwise, rejects with the error. + */ ++ (instancetype)wrapObjectOrErrorCompletion: + (void (^)(FBLPromiseObjectOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler if error is `nil`. + Otherwise, rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error or object provided by completion handler. If error + is not `nil`, rejects with the error. + */ ++ (instancetype)wrapErrorOrObjectCompletion: + (void (^)(FBLPromiseErrorOrObjectCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error or object provided by completion handler. If error + is not `nil`, rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an array of objects provided by completion handler in order + if error is `nil`. Otherwise, rejects with the error. + */ ++ (FBLPromise*)wrap2ObjectsOrErrorCompletion: + (void (^)(FBLPromise2ObjectsOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an array of objects provided by completion handler in order + if error is `nil`. Otherwise, rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrap2ObjectsOrErrorCompletion:(void (^)(FBLPromise2ObjectsOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO. + */ ++ (FBLPromise*)wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapBoolOrErrorCompletion: + (void (^)(FBLPromiseBoolOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapBoolOrErrorCompletion:(void (^)(FBLPromiseBoolOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer. + */ ++ (FBLPromise*)wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapIntegerOrErrorCompletion: + (void (^)(FBLPromiseIntegerOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapIntegerOrErrorCompletion:(void (^)(FBLPromiseIntegerOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double. + */ ++ (FBLPromise*)wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapDoubleOrErrorCompletion: + (void (^)(FBLPromiseDoubleOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapDoubleOrErrorCompletion:(void (^)(FBLPromiseDoubleOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `wrap` operators. + Usage: FBLPromise.wrapCompletion(^(FBLPromiseCompletion handler) {...}) + */ +@interface FBLPromise(DotSyntax_WrapAdditions) + ++ (FBLPromise* (^)(void (^)(FBLPromiseCompletion)))wrapCompletion FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseCompletion)))wrapCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletion FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseBoolOrErrorCompletion)))wrapBoolOrErrorCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolOrErrorCompletion)))wrapBoolOrErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h new file mode 100644 index 0000000..98c813b --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h @@ -0,0 +1,93 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromiseError.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Promises synchronization construct in Objective-C. + */ +@interface FBLPromise<__covariant Value> : NSObject + +/** + Default dispatch queue used for `FBLPromise`, which is `main` if a queue is not specified. + */ +@property(class) dispatch_queue_t defaultDispatchQueue NS_REFINED_FOR_SWIFT; + +/** + Creates a pending promise. + */ ++ (instancetype)pendingPromise NS_REFINED_FOR_SWIFT; + +/** + Creates a resolved promise. + + @param resolution An object to resolve the promise with: either a value or an error. + @return A new resolved promise. + */ ++ (instancetype)resolvedWith:(nullable id)resolution NS_REFINED_FOR_SWIFT; + +/** + Synchronously fulfills the promise with a value. + + @param value An arbitrary value to fulfill the promise with, including `nil`. + */ +- (void)fulfill:(nullable Value)value NS_REFINED_FOR_SWIFT; + +/** + Synchronously rejects the promise with an error. + + @param error An error to reject the promise with. + */ +- (void)reject:(NSError *)error NS_REFINED_FOR_SWIFT; + ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; +@end + +@interface FBLPromise() + +/** + Adds an object to the set of pending objects to keep strongly while the promise is pending. + Used by the Swift wrappers to keep them alive until the underlying ObjC promise is resolved. + + @param object An object to add. + */ +- (void)addPendingObject:(id)object NS_REFINED_FOR_SWIFT; + +@end + +#ifdef FBL_PROMISES_DOT_SYNTAX_IS_DEPRECATED +#define FBL_PROMISES_DOT_SYNTAX __attribute__((deprecated)) +#else +#define FBL_PROMISES_DOT_SYNTAX +#endif + +@interface FBLPromise(DotSyntaxAdditions) + +/** + Convenience dot-syntax wrappers for FBLPromise. + Usage: FBLPromise.pending() + FBLPromise.resolved(value) + + */ ++ (FBLPromise * (^)(void))pending FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(id __nullable))resolved FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h new file mode 100644 index 0000000..d37af53 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h @@ -0,0 +1,43 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXTERN NSErrorDomain const FBLPromiseErrorDomain NS_REFINED_FOR_SWIFT; + +/** + Possible error codes in `FBLPromiseErrorDomain`. + */ +typedef NS_ENUM(NSInteger, FBLPromiseErrorCode) { + /** Promise failed to resolve in time. */ + FBLPromiseErrorCodeTimedOut = 1, + /** Validation predicate returned false. */ + FBLPromiseErrorCodeValidationFailure = 2, +} NS_REFINED_FOR_SWIFT; + +NS_INLINE BOOL FBLPromiseErrorIsTimedOut(NSError *error) NS_SWIFT_UNAVAILABLE("") { + return error.domain == FBLPromiseErrorDomain && + error.code == FBLPromiseErrorCodeTimedOut; +} + +NS_INLINE BOOL FBLPromiseErrorIsValidationFailure(NSError *error) NS_SWIFT_UNAVAILABLE("") { + return error.domain == FBLPromiseErrorDomain && + error.code == FBLPromiseErrorCodeValidationFailure; +} + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h new file mode 100644 index 0000000..7a132f2 --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h @@ -0,0 +1,66 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Testing.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Miscellaneous low-level private interfaces available to extend standard FBLPromise functionality. + */ +@interface FBLPromise() + +typedef void (^FBLPromiseOnFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseOnRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); +typedef id __nullable (^__nullable FBLPromiseChainedFulfillBlock)(Value __nullable value) + NS_SWIFT_UNAVAILABLE(""); +typedef id __nullable (^__nullable FBLPromiseChainedRejectBlock)(NSError *error) + NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise. + */ +- (instancetype)initPending NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a resolved promise. + + @param resolution An object to resolve the promise with: either a value or an error. + @return A new resolved promise. + */ +- (instancetype)initWithResolution:(nullable id)resolution NS_SWIFT_UNAVAILABLE(""); + +/** + Invokes `fulfill` and `reject` blocks on `queue` when the receiver gets either fulfilled or + rejected respectively. + */ +- (void)observeOnQueue:(dispatch_queue_t)queue + fulfill:(FBLPromiseOnFulfillBlock)onFulfill + reject:(FBLPromiseOnRejectBlock)onReject NS_SWIFT_UNAVAILABLE(""); + +/** + Returns a new promise which gets resolved with the return value of `chainedFulfill` or + `chainedReject` blocks respectively. The blocks are invoked when the receiver gets either + fulfilled or rejected. If `nil` is passed to either block arg, the returned promise is resolved + with the same resolution as the receiver. + */ +- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue + chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill + chainedReject:(FBLPromiseChainedRejectBlock)chainedReject NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h new file mode 100644 index 0000000..2d90bad --- /dev/null +++ b/frontend/ios/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h @@ -0,0 +1,32 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+All.h" +#import "FBLPromise+Always.h" +#import "FBLPromise+Any.h" +#import "FBLPromise+Async.h" +#import "FBLPromise+Await.h" +#import "FBLPromise+Catch.h" +#import "FBLPromise+Delay.h" +#import "FBLPromise+Do.h" +#import "FBLPromise+Race.h" +#import "FBLPromise+Recover.h" +#import "FBLPromise+Reduce.h" +#import "FBLPromise+Retry.h" +#import "FBLPromise+Then.h" +#import "FBLPromise+Timeout.h" +#import "FBLPromise+Validate.h" +#import "FBLPromise+Wrap.h" diff --git a/frontend/ios/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig b/frontend/ios/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig new file mode 100644 index 0000000..acc4071 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig @@ -0,0 +1,17 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Firebase +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Firebase" "${PODS_ROOT}/Headers/Public" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -weak_framework "UserNotifications" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Firebase +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/Firebase/Firebase.release.xcconfig b/frontend/ios/Pods/Target Support Files/Firebase/Firebase.release.xcconfig new file mode 100644 index 0000000..acc4071 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Firebase/Firebase.release.xcconfig @@ -0,0 +1,17 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Firebase +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Firebase" "${PODS_ROOT}/Headers/Public" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -weak_framework "UserNotifications" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Firebase +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist new file mode 100644 index 0000000..faeba49 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.15.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m new file mode 100644 index 0000000..4f1eb27 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseCore : NSObject +@end +@implementation PodsDummy_FirebaseCore +@end diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h new file mode 100644 index 0000000..509268c --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h @@ -0,0 +1,23 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRApp.h" +#import "FIRConfiguration.h" +#import "FirebaseCore.h" +#import "FIRLoggerLevel.h" +#import "FIROptions.h" +#import "FIRTimestamp.h" +#import "FIRVersion.h" + +FOUNDATION_EXPORT double FirebaseCoreVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseCoreVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig new file mode 100644 index 0000000..e9d39ef --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 Firebase_VERSION=11.15.0 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_CFLAGS = $(inherited) -fno-autolink +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCoreInternal" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCore +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap new file mode 100644 index 0000000..4c38b87 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseCore { + umbrella header "FirebaseCore-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig new file mode 100644 index 0000000..e9d39ef --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 Firebase_VERSION=11.15.0 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_CFLAGS = $(inherited) -fno-autolink +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCoreInternal" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCore +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCore/ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist b/frontend/ios/Pods/Target Support Files/FirebaseCore/ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist new file mode 100644 index 0000000..0e378c1 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCore/ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.15.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist new file mode 100644 index 0000000..faeba49 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.15.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-dummy.m b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-dummy.m new file mode 100644 index 0000000..1eb5767 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseCoreInternal : NSObject +@end +@implementation PodsDummy_FirebaseCoreInternal +@end diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-umbrella.h b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-umbrella.h new file mode 100644 index 0000000..559d38b --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double FirebaseCoreInternalVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseCoreInternalVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.debug.xcconfig b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.debug.xcconfig new file mode 100644 index 0000000..7137f77 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCoreInternal +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap new file mode 100644 index 0000000..c5a589e --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseCoreInternal { + umbrella header "FirebaseCoreInternal-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.release.xcconfig b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.release.xcconfig new file mode 100644 index 0000000..7137f77 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCoreInternal +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist new file mode 100644 index 0000000..0e378c1 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseCoreInternal/ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.15.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist new file mode 100644 index 0000000..faeba49 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.15.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-dummy.m b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-dummy.m new file mode 100644 index 0000000..ae19551 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseInstallations : NSObject +@end +@implementation PodsDummy_FirebaseInstallations +@end diff --git a/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-umbrella.h b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-umbrella.h new file mode 100644 index 0000000..431ef45 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-umbrella.h @@ -0,0 +1,20 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FirebaseInstallations.h" +#import "FIRInstallations.h" +#import "FIRInstallationsAuthTokenResult.h" +#import "FIRInstallationsErrors.h" + +FOUNDATION_EXPORT double FirebaseInstallationsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseInstallationsVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.debug.xcconfig b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.debug.xcconfig new file mode 100644 index 0000000..e9420bb --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FBLPromises" -framework "FirebaseCore" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseInstallations +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap new file mode 100644 index 0000000..f6e2a29 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseInstallations { + umbrella header "FirebaseInstallations-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.release.xcconfig b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.release.xcconfig new file mode 100644 index 0000000..e9420bb --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FBLPromises" -framework "FirebaseCore" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseInstallations +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/FirebaseInstallations/ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist new file mode 100644 index 0000000..0e378c1 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseInstallations/ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.15.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging-Info.plist b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging-Info.plist new file mode 100644 index 0000000..faeba49 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.15.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging-dummy.m b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging-dummy.m new file mode 100644 index 0000000..ec94549 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseMessaging : NSObject +@end +@implementation PodsDummy_FirebaseMessaging +@end diff --git a/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging-umbrella.h b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging-umbrella.h new file mode 100644 index 0000000..b9cc86f --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging-umbrella.h @@ -0,0 +1,20 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FirebaseMessaging.h" +#import "FIRMessaging+ExtensionHelper.h" +#import "FIRMessaging.h" +#import "FIRMessagingExtensionHelper.h" + +FOUNDATION_EXPORT double FirebaseMessagingVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseMessagingVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging.debug.xcconfig b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging.debug.xcconfig new file mode 100644 index 0000000..db8ca33 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"sqlite3" -framework "CoreTelephony" -framework "FirebaseCore" -framework "FirebaseInstallations" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "nanopb" -weak_framework "UserNotifications" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseMessaging +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging.modulemap b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging.modulemap new file mode 100644 index 0000000..4ab5827 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseMessaging { + umbrella header "FirebaseMessaging-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging.release.xcconfig b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging.release.xcconfig new file mode 100644 index 0000000..db8ca33 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/FirebaseMessaging.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"sqlite3" -framework "CoreTelephony" -framework "FirebaseCore" -framework "FirebaseInstallations" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "nanopb" -weak_framework "UserNotifications" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseMessaging +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/FirebaseMessaging/ResourceBundle-FirebaseMessaging_Privacy-FirebaseMessaging-Info.plist b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/ResourceBundle-FirebaseMessaging_Privacy-FirebaseMessaging-Info.plist new file mode 100644 index 0000000..0e378c1 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/FirebaseMessaging/ResourceBundle-FirebaseMessaging_Privacy-FirebaseMessaging-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.15.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/Flutter/Flutter.debug.xcconfig b/frontend/ios/Pods/Target Support Files/Flutter/Flutter.debug.xcconfig new file mode 100644 index 0000000..1d192c5 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Flutter/Flutter.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Flutter +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../Flutter +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/Flutter/Flutter.release.xcconfig b/frontend/ios/Pods/Target Support Files/Flutter/Flutter.release.xcconfig new file mode 100644 index 0000000..1d192c5 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Flutter/Flutter.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Flutter +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../Flutter +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist new file mode 100644 index 0000000..3ce28c0 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 10.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m new file mode 100644 index 0000000..9a08ec3 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GoogleDataTransport : NSObject +@end +@implementation PodsDummy_GoogleDataTransport +@end diff --git a/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h new file mode 100644 index 0000000..368a3aa --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h @@ -0,0 +1,26 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GDTCORClock.h" +#import "GDTCORConsoleLogger.h" +#import "GDTCOREndpoints.h" +#import "GDTCOREvent.h" +#import "GDTCOREventDataObject.h" +#import "GDTCOREventTransformer.h" +#import "GDTCORProductData.h" +#import "GDTCORTargets.h" +#import "GDTCORTransport.h" +#import "GoogleDataTransport.h" + +FOUNDATION_EXPORT double GoogleDataTransportVersionNumber; +FOUNDATION_EXPORT const unsigned char GoogleDataTransportVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig new file mode 100644 index 0000000..4557a14 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig @@ -0,0 +1,17 @@ +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1GDTCOR_VERSION=10.1.0 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}/" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "SystemConfiguration" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleDataTransport +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap new file mode 100644 index 0000000..8a67414 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap @@ -0,0 +1,6 @@ +framework module GoogleDataTransport { + umbrella header "GoogleDataTransport-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig new file mode 100644 index 0000000..4557a14 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig @@ -0,0 +1,17 @@ +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1GDTCOR_VERSION=10.1.0 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}/" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "SystemConfiguration" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleDataTransport +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/GoogleDataTransport/ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist new file mode 100644 index 0000000..728a55b --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleDataTransport/ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist new file mode 100644 index 0000000..b9c6265 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 8.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m new file mode 100644 index 0000000..98ac4e9 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GoogleUtilities : NSObject +@end +@implementation PodsDummy_GoogleUtilities +@end diff --git a/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h new file mode 100644 index 0000000..daedce1 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h @@ -0,0 +1,34 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GULAppDelegateSwizzler.h" +#import "GULApplication.h" +#import "GULSceneDelegateSwizzler.h" +#import "GULAppEnvironmentUtil.h" +#import "GULKeychainStorage.h" +#import "GULKeychainUtils.h" +#import "GULNetworkInfo.h" +#import "GULLogger.h" +#import "GULLoggerLevel.h" +#import "GULNSData+zlib.h" +#import "GULMutableDictionary.h" +#import "GULNetwork.h" +#import "GULNetworkConstants.h" +#import "GULNetworkLoggerProtocol.h" +#import "GULNetworkMessageCode.h" +#import "GULNetworkURLSession.h" +#import "GULReachabilityChecker.h" +#import "GULUserDefaults.h" + +FOUNDATION_EXPORT double GoogleUtilitiesVersionNumber; +FOUNDATION_EXPORT const unsigned char GoogleUtilitiesVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig new file mode 100644 index 0000000..cacc27c --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "Security" -framework "SystemConfiguration" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleUtilities +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap new file mode 100644 index 0000000..491dd0a --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap @@ -0,0 +1,6 @@ +framework module GoogleUtilities { + umbrella header "GoogleUtilities-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig new file mode 100644 index 0000000..cacc27c --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "Security" -framework "SystemConfiguration" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleUtilities +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/GoogleUtilities/ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist b/frontend/ios/Pods/Target Support Files/GoogleUtilities/ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist new file mode 100644 index 0000000..2393462 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/GoogleUtilities/ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 8.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-Info.plist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-Info.plist new file mode 100644 index 0000000..19cf209 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.markdown b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.markdown new file mode 100644 index 0000000..d925232 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.markdown @@ -0,0 +1,2022 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## Firebase + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## FirebaseCore + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## FirebaseCoreInternal + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## FirebaseInstallations + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## FirebaseMessaging + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## GoogleDataTransport + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## GoogleUtilities + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +================================================================================ + +Copyright (c) 2017 Landon J. Fuller +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +## PromisesObjC + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## firebase_core + +// Copyright 2017 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## firebase_messaging + +// Copyright 2017 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## flutter_local_notifications + +Copyright 2018 Michael Bui. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +## image_picker_ios + +image_picker + +Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +aFileChooser + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2011 - 2013 Paul Burke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## nanopb + +Copyright (c) 2011 Petteri Aimonen + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held liable +for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + +Generated by CocoaPods - https://cocoapods.org diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.plist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.plist new file mode 100644 index 0000000..4068f09 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.plist @@ -0,0 +1,2122 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache-2.0 + Title + Firebase + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache-2.0 + Title + FirebaseCore + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache-2.0 + Title + FirebaseCoreInternal + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache-2.0 + Title + FirebaseInstallations + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache-2.0 + Title + FirebaseMessaging + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache-2.0 + Title + GoogleDataTransport + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +================================================================================ + +Copyright (c) 2017 Landon J. Fuller <landon@landonf.org> +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + License + Apache-2.0 + Title + GoogleUtilities + Type + PSGroupSpecifier + + + FooterText + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + Apache-2.0 + Title + PromisesObjC + Type + PSGroupSpecifier + + + FooterText + // Copyright 2017 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Title + firebase_core + Type + PSGroupSpecifier + + + FooterText + // Copyright 2017 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + Title + firebase_messaging + Type + PSGroupSpecifier + + + FooterText + Copyright 2018 Michael Bui. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + License + BSD + Title + flutter_local_notifications + Type + PSGroupSpecifier + + + FooterText + image_picker + +Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +aFileChooser + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2011 - 2013 Paul Burke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + License + BSD + Title + image_picker_ios + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2011 Petteri Aimonen <jpa at nanopb.mail.kapsi.fi> + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held liable +for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + + License + zlib + Title + nanopb + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-dummy.m b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-dummy.m new file mode 100644 index 0000000..0b73bc1 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_Runner : NSObject +@end +@implementation PodsDummy_Pods_Runner +@end diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-input-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-input-files.xcfilelist new file mode 100644 index 0000000..b5c4214 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-input-files.xcfilelist @@ -0,0 +1,11 @@ +${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh +${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework +${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework +${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework +${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework +${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework +${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework +${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework +${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework +${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework +${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-output-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-output-files.xcfilelist new file mode 100644 index 0000000..cfb9c02 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-output-files.xcfilelist @@ -0,0 +1,10 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-input-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-input-files.xcfilelist new file mode 100644 index 0000000..b5c4214 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-input-files.xcfilelist @@ -0,0 +1,11 @@ +${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh +${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework +${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework +${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework +${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework +${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework +${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework +${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework +${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework +${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework +${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-output-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-output-files.xcfilelist new file mode 100644 index 0000000..cfb9c02 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-output-files.xcfilelist @@ -0,0 +1,10 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-input-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-input-files.xcfilelist new file mode 100644 index 0000000..b5c4214 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-input-files.xcfilelist @@ -0,0 +1,11 @@ +${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh +${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework +${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework +${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework +${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework +${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework +${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework +${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework +${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework +${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework +${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-output-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-output-files.xcfilelist new file mode 100644 index 0000000..cfb9c02 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-output-files.xcfilelist @@ -0,0 +1,10 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCore.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseCoreInternal.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseInstallations.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FirebaseMessaging.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleDataTransport.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh new file mode 100755 index 0000000..64d040e --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh @@ -0,0 +1,216 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then + # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy + # frameworks to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" +SWIFT_STDLIB_PATH="${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +BCSYMBOLMAP_DIR="BCSymbolMaps" + + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +# Copies and strips a vendored framework +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink -f "${source}")" + fi + + if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then + # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied + find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do + echo "Installing $f" + install_bcsymbolmap "$f" "$destination" + rm "$f" + done + rmdir "${source}/${BCSYMBOLMAP_DIR}" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + elif [ -L "${binary}" ]; then + echo "Destination binary is symlinked..." + dirname="$(dirname "${binary}")" + binary="${dirname}/$(readlink "${binary}")" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} +# Copies and strips a vendored dSYM +install_dsym() { + local source="$1" + warn_missing_arch=${2:-true} + if [ -r "$source" ]; then + # Copy the dSYM into the targets temp dir. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" + + local basename + basename="$(basename -s .dSYM "$source")" + binary_name="$(ls "$source/Contents/Resources/DWARF")" + binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" + + # Strip invalid architectures from the dSYM. + if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then + strip_invalid_archs "$binary" "$warn_missing_arch" + fi + if [[ $STRIP_BINARY_RETVAL == 0 ]]; then + # Move the stripped file into its final destination. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + else + # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. + mkdir -p "${DWARF_DSYM_FOLDER_PATH}" + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" + fi + fi +} + +# Used as a return value for each invocation of `strip_invalid_archs` function. +STRIP_BINARY_RETVAL=0 + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + warn_missing_arch=${2:-true} + # Get architectures for current target binary + binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" + # Intersect them with the architectures we are building for + intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" + # If there are no archs supported by this binary then warn the user + if [[ -z "$intersected_archs" ]]; then + if [[ "$warn_missing_arch" == "true" ]]; then + echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." + fi + STRIP_BINARY_RETVAL=1 + return + fi + stripped="" + for arch in $binary_archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi + STRIP_BINARY_RETVAL=0 +} + +# Copies the bcsymbolmap files of a vendored framework +install_bcsymbolmap() { + local bcsymbolmap_path="$1" + local destination="${BUILT_PRODUCTS_DIR}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identity + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework" + install_framework "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework" + install_framework "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework" + install_framework "${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework" + install_framework "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework" +fi +if [[ "$CONFIGURATION" == "Profile" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework" + install_framework "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework" + install_framework "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework" + install_framework "${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework" + install_framework "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCore/FirebaseCore.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseInstallations/FirebaseInstallations.framework" + install_framework "${BUILT_PRODUCTS_DIR}/FirebaseMessaging/FirebaseMessaging.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework" + install_framework "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework" + install_framework "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework" + install_framework "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework" + install_framework "${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework" + install_framework "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Debug-input-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Debug-input-files.xcfilelist new file mode 100644 index 0000000..7496c0f --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Debug-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh +${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Debug-output-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Debug-output-files.xcfilelist new file mode 100644 index 0000000..939be67 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Debug-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/firebase_messaging_Privacy.bundle \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Profile-input-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Profile-input-files.xcfilelist new file mode 100644 index 0000000..7496c0f --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Profile-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh +${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Profile-output-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Profile-output-files.xcfilelist new file mode 100644 index 0000000..939be67 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Profile-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/firebase_messaging_Privacy.bundle \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Release-input-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Release-input-files.xcfilelist new file mode 100644 index 0000000..7496c0f --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Release-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh +${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Release-output-files.xcfilelist b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Release-output-files.xcfilelist new file mode 100644 index 0000000..939be67 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources-Release-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/firebase_messaging_Privacy.bundle \ No newline at end of file diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh new file mode 100755 index 0000000..84253a0 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh @@ -0,0 +1,132 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then + # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy + # resources to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +case "${TARGETED_DEVICE_FAMILY:-}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + 3) + TARGET_DEVICE_ARGS="--target-device tv" + ;; + 4) + TARGET_DEVICE_ARGS="--target-device watch" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; +esac + +install_resource() +{ + if [[ "$1" = /* ]] ; then + RESOURCE_PATH="$1" + else + RESOURCE_PATH="${PODS_ROOT}/$1" + fi + if [[ ! -e "$RESOURCE_PATH" ]] ; then + cat << EOM +error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. +EOM + exit 1 + fi + case $RESOURCE_PATH in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true + ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} + ;; + *.framework) + echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true + mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true + xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true + xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + *) + echo "$RESOURCE_PATH" || true + echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" + ;; + esac +} +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_resource "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_resource "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle" +fi +if [[ "$CONFIGURATION" == "Profile" ]]; then + install_resource "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle" +fi + +mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] +then + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find -L "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "${PODS_ROOT}*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + else + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" + fi +fi diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-umbrella.h b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-umbrella.h new file mode 100644 index 0000000..5bf0aab --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_RunnerVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_RunnerVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig new file mode 100644 index 0000000..8a891a8 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig @@ -0,0 +1,16 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations/FirebaseInstallations.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging/FirebaseMessaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities/GoogleUtilities.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core/firebase_core.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications/flutter_local_notifications.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios/image_picker_ios.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -ObjC -l"sqlite3" -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseCore" -framework "FirebaseCoreInternal" -framework "FirebaseInstallations" -framework "FirebaseMessaging" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "firebase_core" -framework "firebase_messaging" -framework "flutter_local_notifications" -framework "image_picker_ios" -framework "nanopb" -weak_framework "UserNotifications" +OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/Firebase" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "-F${PODS_CONFIGURATION_BUILD_DIR}/Flutter" "-F${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "-F${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "-F${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "-F${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "-F${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging" "-F${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications" "-F${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios" "-F${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.modulemap b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.modulemap new file mode 100644 index 0000000..d2cf6f6 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.modulemap @@ -0,0 +1,6 @@ +framework module Pods_Runner { + umbrella header "Pods-Runner-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig new file mode 100644 index 0000000..8a891a8 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig @@ -0,0 +1,16 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations/FirebaseInstallations.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging/FirebaseMessaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities/GoogleUtilities.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core/firebase_core.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications/flutter_local_notifications.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios/image_picker_ios.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -ObjC -l"sqlite3" -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseCore" -framework "FirebaseCoreInternal" -framework "FirebaseInstallations" -framework "FirebaseMessaging" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "firebase_core" -framework "firebase_messaging" -framework "flutter_local_notifications" -framework "image_picker_ios" -framework "nanopb" -weak_framework "UserNotifications" +OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/Firebase" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "-F${PODS_CONFIGURATION_BUILD_DIR}/Flutter" "-F${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "-F${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "-F${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "-F${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "-F${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging" "-F${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications" "-F${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios" "-F${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig new file mode 100644 index 0000000..8a891a8 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig @@ -0,0 +1,16 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations/FirebaseInstallations.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging/FirebaseMessaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities/GoogleUtilities.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core/firebase_core.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications/flutter_local_notifications.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios/image_picker_ios.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -ObjC -l"sqlite3" -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseCore" -framework "FirebaseCoreInternal" -framework "FirebaseInstallations" -framework "FirebaseMessaging" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "firebase_core" -framework "firebase_messaging" -framework "flutter_local_notifications" -framework "image_picker_ios" -framework "nanopb" -weak_framework "UserNotifications" +OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/Firebase" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "-F${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "-F${PODS_CONFIGURATION_BUILD_DIR}/Flutter" "-F${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "-F${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "-F${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "-F${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "-F${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging" "-F${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications" "-F${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios" "-F${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist new file mode 100644 index 0000000..19cf209 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.markdown b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.markdown new file mode 100644 index 0000000..102af75 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.markdown @@ -0,0 +1,3 @@ +# Acknowledgements +This application makes use of the following third party libraries: +Generated by CocoaPods - https://cocoapods.org diff --git a/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.plist b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.plist new file mode 100644 index 0000000..7acbad1 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.plist @@ -0,0 +1,29 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-dummy.m b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-dummy.m new file mode 100644 index 0000000..a664d4a --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_RunnerTests : NSObject +@end +@implementation PodsDummy_Pods_RunnerTests +@end diff --git a/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-umbrella.h b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-umbrella.h new file mode 100644 index 0000000..643118b --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_RunnerTestsVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_RunnerTestsVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig new file mode 100644 index 0000000..c0d7f87 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations/FirebaseInstallations.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging/FirebaseMessaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities/GoogleUtilities.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core/firebase_core.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications/flutter_local_notifications.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios/image_picker_ios.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources +OTHER_LDFLAGS = $(inherited) -l"sqlite3" -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseCore" -framework "FirebaseCoreInternal" -framework "FirebaseInstallations" -framework "FirebaseMessaging" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "flutter_local_notifications" -framework "image_picker_ios" -framework "nanopb" -weak_framework "UserNotifications" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap new file mode 100644 index 0000000..c3d99a7 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap @@ -0,0 +1,6 @@ +framework module Pods_RunnerTests { + umbrella header "Pods-RunnerTests-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig new file mode 100644 index 0000000..c0d7f87 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations/FirebaseInstallations.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging/FirebaseMessaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities/GoogleUtilities.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core/firebase_core.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications/flutter_local_notifications.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios/image_picker_ios.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources +OTHER_LDFLAGS = $(inherited) -l"sqlite3" -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseCore" -framework "FirebaseCoreInternal" -framework "FirebaseInstallations" -framework "FirebaseMessaging" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "flutter_local_notifications" -framework "image_picker_ios" -framework "nanopb" -weak_framework "UserNotifications" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig new file mode 100644 index 0000000..c0d7f87 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore/FirebaseCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal/FirebaseCoreInternal.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations/FirebaseInstallations.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging/FirebaseMessaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport/GoogleDataTransport.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities/GoogleUtilities.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC/FBLPromises.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core/firebase_core.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications/flutter_local_notifications.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios/image_picker_ios.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb/nanopb.framework/Headers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Firebase" $(inherited) ${PODS_ROOT}/Firebase/CoreOnly/Sources +OTHER_LDFLAGS = $(inherited) -l"sqlite3" -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseCore" -framework "FirebaseCoreInternal" -framework "FirebaseInstallations" -framework "FirebaseMessaging" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "flutter_local_notifications" -framework "image_picker_ios" -framework "nanopb" -weak_framework "UserNotifications" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist new file mode 100644 index 0000000..2780533 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.4.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m new file mode 100644 index 0000000..ab1f210 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_PromisesObjC : NSObject +@end +@implementation PodsDummy_PromisesObjC +@end diff --git a/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h new file mode 100644 index 0000000..5b014a8 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h @@ -0,0 +1,36 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FBLPromise+All.h" +#import "FBLPromise+Always.h" +#import "FBLPromise+Any.h" +#import "FBLPromise+Async.h" +#import "FBLPromise+Await.h" +#import "FBLPromise+Catch.h" +#import "FBLPromise+Delay.h" +#import "FBLPromise+Do.h" +#import "FBLPromise+Race.h" +#import "FBLPromise+Recover.h" +#import "FBLPromise+Reduce.h" +#import "FBLPromise+Retry.h" +#import "FBLPromise+Testing.h" +#import "FBLPromise+Then.h" +#import "FBLPromise+Timeout.h" +#import "FBLPromise+Validate.h" +#import "FBLPromise+Wrap.h" +#import "FBLPromise.h" +#import "FBLPromiseError.h" +#import "FBLPromises.h" + +FOUNDATION_EXPORT double FBLPromisesVersionNumber; +FOUNDATION_EXPORT const unsigned char FBLPromisesVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig new file mode 100644 index 0000000..132f10c --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC +DEFINES_MODULE = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PromisesObjC +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap new file mode 100644 index 0000000..7d485cd --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap @@ -0,0 +1,6 @@ +framework module FBLPromises { + umbrella header "PromisesObjC-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig new file mode 100644 index 0000000..132f10c --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC +DEFINES_MODULE = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PromisesObjC +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/PromisesObjC/ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist b/frontend/ios/Pods/Target Support Files/PromisesObjC/ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist new file mode 100644 index 0000000..1f1f0af --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/PromisesObjC/ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 2.4.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-Info.plist b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-Info.plist new file mode 100644 index 0000000..c7c3564 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.15.2 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-dummy.m b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-dummy.m new file mode 100644 index 0000000..f39d571 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_firebase_core : NSObject +@end +@implementation PodsDummy_firebase_core +@end diff --git a/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-prefix.pch b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-umbrella.h b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-umbrella.h new file mode 100644 index 0000000..a2abcaf --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core-umbrella.h @@ -0,0 +1,21 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "dummy.h" +#import "FLTFirebaseCorePlugin.h" +#import "FLTFirebasePlugin.h" +#import "FLTFirebasePluginRegistry.h" +#import "messages.g.h" + +FOUNDATION_EXPORT double firebase_coreVersionNumber; +FOUNDATION_EXPORT const unsigned char firebase_coreVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core.debug.xcconfig b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core.debug.xcconfig new file mode 100644 index 0000000..ca655d7 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/firebase_core +DEFINES_MODULE = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 LIBRARY_VERSION=\"3.15.2\" LIBRARY_NAME=\"flutter-fire-core\" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.symlinks/plugins/firebase_core/ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core.modulemap b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core.modulemap new file mode 100644 index 0000000..15a8440 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core.modulemap @@ -0,0 +1,6 @@ +framework module firebase_core { + umbrella header "firebase_core-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core.release.xcconfig b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core.release.xcconfig new file mode 100644 index 0000000..ca655d7 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_core/firebase_core.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/firebase_core +DEFINES_MODULE = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 LIBRARY_VERSION=\"3.15.2\" LIBRARY_NAME=\"flutter-fire-core\" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.symlinks/plugins/firebase_core/ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/firebase_messaging/ResourceBundle-firebase_messaging_Privacy-firebase_messaging-Info.plist b/frontend/ios/Pods/Target Support Files/firebase_messaging/ResourceBundle-firebase_messaging_Privacy-firebase_messaging-Info.plist new file mode 100644 index 0000000..981def3 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_messaging/ResourceBundle-firebase_messaging_Privacy-firebase_messaging-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 15.2.10 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-Info.plist b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-Info.plist new file mode 100644 index 0000000..a80c080 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 15.2.10 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-dummy.m b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-dummy.m new file mode 100644 index 0000000..125568d --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_firebase_messaging : NSObject +@end +@implementation PodsDummy_firebase_messaging +@end diff --git a/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-prefix.pch b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-umbrella.h b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-umbrella.h new file mode 100644 index 0000000..fe9678a --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging-umbrella.h @@ -0,0 +1,17 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FLTFirebaseMessagingPlugin.h" + +FOUNDATION_EXPORT double firebase_messagingVersionNumber; +FOUNDATION_EXPORT const unsigned char firebase_messagingVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging.debug.xcconfig b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging.debug.xcconfig new file mode 100644 index 0000000..434c022 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging +DEFINES_MODULE = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 LIBRARY_VERSION=\"15.2.10\" LIBRARY_NAME=\"flutter-fire-fcm\" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.symlinks/plugins/firebase_messaging/ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging.modulemap b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging.modulemap new file mode 100644 index 0000000..f751b4e --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging.modulemap @@ -0,0 +1,6 @@ +framework module firebase_messaging { + umbrella header "firebase_messaging-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging.release.xcconfig b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging.release.xcconfig new file mode 100644 index 0000000..434c022 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/firebase_messaging/firebase_messaging.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging +DEFINES_MODULE = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/firebase_core" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 LIBRARY_VERSION=\"15.2.10\" LIBRARY_NAME=\"flutter-fire-fcm\" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.symlinks/plugins/firebase_messaging/ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/flutter_local_notifications/ResourceBundle-flutter_local_notifications_privacy-flutter_local_notifications-Info.plist b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/ResourceBundle-flutter_local_notifications_privacy-flutter_local_notifications-Info.plist new file mode 100644 index 0000000..e22a9aa --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/ResourceBundle-flutter_local_notifications_privacy-flutter_local_notifications-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 0.0.1 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-Info.plist b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-Info.plist new file mode 100644 index 0000000..8928a8d --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.0.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-dummy.m b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-dummy.m new file mode 100644 index 0000000..2a6ce0c --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_flutter_local_notifications : NSObject +@end +@implementation PodsDummy_flutter_local_notifications +@end diff --git a/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-prefix.pch b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-umbrella.h b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-umbrella.h new file mode 100644 index 0000000..6f225ff --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications-umbrella.h @@ -0,0 +1,20 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "ActionEventSink.h" +#import "Converters.h" +#import "FlutterEngineManager.h" +#import "FlutterLocalNotificationsPlugin.h" + +FOUNDATION_EXPORT double flutter_local_notificationsVersionNumber; +FOUNDATION_EXPORT const unsigned char flutter_local_notificationsVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications.debug.xcconfig b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications.debug.xcconfig new file mode 100644 index 0000000..fba992c --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.symlinks/plugins/flutter_local_notifications/ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications.modulemap b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications.modulemap new file mode 100644 index 0000000..2872c54 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications.modulemap @@ -0,0 +1,6 @@ +framework module flutter_local_notifications { + umbrella header "flutter_local_notifications-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications.release.xcconfig b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications.release.xcconfig new file mode 100644 index 0000000..fba992c --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/flutter_local_notifications/flutter_local_notifications.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/flutter_local_notifications +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.symlinks/plugins/flutter_local_notifications/ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/image_picker_ios/ResourceBundle-image_picker_ios_privacy-image_picker_ios-Info.plist b/frontend/ios/Pods/Target Support Files/image_picker_ios/ResourceBundle-image_picker_ios_privacy-image_picker_ios-Info.plist new file mode 100644 index 0000000..e22a9aa --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/image_picker_ios/ResourceBundle-image_picker_ios_privacy-image_picker_ios-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 0.0.1 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios-Info.plist b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios-Info.plist new file mode 100644 index 0000000..8928a8d --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.0.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios-dummy.m b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios-dummy.m new file mode 100644 index 0000000..bdfb4b7 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_image_picker_ios : NSObject +@end +@implementation PodsDummy_image_picker_ios +@end diff --git a/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios-prefix.pch b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios.debug.xcconfig b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios.debug.xcconfig new file mode 100644 index 0000000..8bdaccb --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios +DEFINES_MODULE = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.symlinks/plugins/image_picker_ios/ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios.modulemap b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios.modulemap new file mode 100644 index 0000000..0d60b68 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios.modulemap @@ -0,0 +1,14 @@ +framework module image_picker_ios { + umbrella header "image_picker_ios-umbrella.h" + + export * + module * { export * } + + explicit module Test { + header "FLTImagePickerPlugin_Test.h" + header "FLTImagePickerImageUtil.h" + header "FLTImagePickerMetaDataUtil.h" + header "FLTImagePickerPhotoAssetUtil.h" + header "FLTPHPickerSaveImageToPathOperation.h" + } +} diff --git a/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios.release.xcconfig b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios.release.xcconfig new file mode 100644 index 0000000..8bdaccb --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/image_picker_ios/image_picker_ios.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/image_picker_ios +DEFINES_MODULE = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.symlinks/plugins/image_picker_ios/ios +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/nanopb/ResourceBundle-nanopb_Privacy-nanopb-Info.plist b/frontend/ios/Pods/Target Support Files/nanopb/ResourceBundle-nanopb_Privacy-nanopb-Info.plist new file mode 100644 index 0000000..b5d917c --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/nanopb/ResourceBundle-nanopb_Privacy-nanopb-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 3.30910.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/nanopb/nanopb-Info.plist b/frontend/ios/Pods/Target Support Files/nanopb/nanopb-Info.plist new file mode 100644 index 0000000..e39b8ca --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/nanopb/nanopb-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.30910.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/ios/Pods/Target Support Files/nanopb/nanopb-dummy.m b/frontend/ios/Pods/Target Support Files/nanopb/nanopb-dummy.m new file mode 100644 index 0000000..b3fa595 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/nanopb/nanopb-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_nanopb : NSObject +@end +@implementation PodsDummy_nanopb +@end diff --git a/frontend/ios/Pods/Target Support Files/nanopb/nanopb-prefix.pch b/frontend/ios/Pods/Target Support Files/nanopb/nanopb-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/nanopb/nanopb-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/frontend/ios/Pods/Target Support Files/nanopb/nanopb-umbrella.h b/frontend/ios/Pods/Target Support Files/nanopb/nanopb-umbrella.h new file mode 100644 index 0000000..07e77b3 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/nanopb/nanopb-umbrella.h @@ -0,0 +1,26 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "pb.h" +#import "pb_common.h" +#import "pb_decode.h" +#import "pb_encode.h" +#import "pb.h" +#import "pb_decode.h" +#import "pb_common.h" +#import "pb.h" +#import "pb_encode.h" +#import "pb_common.h" + +FOUNDATION_EXPORT double nanopbVersionNumber; +FOUNDATION_EXPORT const unsigned char nanopbVersionString[]; + diff --git a/frontend/ios/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig b/frontend/ios/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig new file mode 100644 index 0000000..b682973 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/nanopb +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/nanopb +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/Target Support Files/nanopb/nanopb.modulemap b/frontend/ios/Pods/Target Support Files/nanopb/nanopb.modulemap new file mode 100644 index 0000000..e8d4b53 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/nanopb/nanopb.modulemap @@ -0,0 +1,6 @@ +framework module nanopb { + umbrella header "nanopb-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/ios/Pods/Target Support Files/nanopb/nanopb.release.xcconfig b/frontend/ios/Pods/Target Support Files/nanopb/nanopb.release.xcconfig new file mode 100644 index 0000000..b682973 --- /dev/null +++ b/frontend/ios/Pods/Target Support Files/nanopb/nanopb.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/nanopb +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/nanopb +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/ios/Pods/nanopb/LICENSE.txt b/frontend/ios/Pods/nanopb/LICENSE.txt new file mode 100644 index 0000000..d11c9af --- /dev/null +++ b/frontend/ios/Pods/nanopb/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2011 Petteri Aimonen + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held liable +for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. diff --git a/frontend/ios/Pods/nanopb/README.md b/frontend/ios/Pods/nanopb/README.md new file mode 100644 index 0000000..1a73cdd --- /dev/null +++ b/frontend/ios/Pods/nanopb/README.md @@ -0,0 +1,71 @@ +Nanopb - Protocol Buffers for Embedded Systems +============================================== + +[![Build Status](https://travis-ci.org/nanopb/nanopb.svg?branch=master)](https://travis-ci.org/nanopb/nanopb) + +Nanopb is a small code-size Protocol Buffers implementation in ansi C. It is +especially suitable for use in microcontrollers, but fits any memory +restricted system. + +* **Homepage:** https://jpa.kapsi.fi/nanopb/ +* **Documentation:** https://jpa.kapsi.fi/nanopb/docs/ +* **Downloads:** https://jpa.kapsi.fi/nanopb/download/ +* **Forum:** https://groups.google.com/forum/#!forum/nanopb + + + +Using the nanopb library +------------------------ +To use the nanopb library, you need to do two things: + +1. Compile your .proto files for nanopb, using `protoc`. +2. Include *pb_encode.c*, *pb_decode.c* and *pb_common.c* in your project. + +The easiest way to get started is to study the project in "examples/simple". +It contains a Makefile, which should work directly under most Linux systems. +However, for any other kind of build system, see the manual steps in +README.txt in that folder. + + + +Using the Protocol Buffers compiler (protoc) +-------------------------------------------- +The nanopb generator is implemented as a plugin for the Google's own `protoc` +compiler. This has the advantage that there is no need to reimplement the +basic parsing of .proto files. However, it does mean that you need the +Google's protobuf library in order to run the generator. + +If you have downloaded a binary package for nanopb (either Windows, Linux or +Mac OS X version), the `protoc` binary is included in the 'generator-bin' +folder. In this case, you are ready to go. Simply run this command: + + generator-bin/protoc --nanopb_out=. myprotocol.proto + +However, if you are using a git checkout or a plain source distribution, you +need to provide your own version of `protoc` and the Google's protobuf library. +On Linux, the necessary packages are `protobuf-compiler` and `python-protobuf`. +On Windows, you can either build Google's protobuf library from source or use +one of the binary distributions of it. In either case, if you use a separate +`protoc`, you need to manually give the path to nanopb generator: + + protoc --plugin=protoc-gen-nanopb=nanopb/generator/protoc-gen-nanopb ... + + + +Running the tests +----------------- +If you want to perform further development of the nanopb core, or to verify +its functionality using your compiler and platform, you'll want to run the +test suite. The build rules for the test suite are implemented using Scons, +so you need to have that installed (ex: `sudo apt install scons` on Ubuntu). To run the tests: + + cd tests + scons + +This will show the progress of various test cases. If the output does not +end in an error, the test cases were successful. + +Note: Mac OS X by default aliases 'clang' as 'gcc', while not actually +supporting the same command line options as gcc does. To run tests on +Mac OS X, use: "scons CC=clang CXX=clang". Same way can be used to run +tests with different compilers on any platform. diff --git a/frontend/ios/Pods/nanopb/pb.h b/frontend/ios/Pods/nanopb/pb.h new file mode 100644 index 0000000..2bd4568 --- /dev/null +++ b/frontend/ios/Pods/nanopb/pb.h @@ -0,0 +1,599 @@ +/* Common parts of the nanopb library. Most of these are quite low-level + * stuff. For the high-level interface, see pb_encode.h and pb_decode.h. + */ + +#ifndef PB_H_INCLUDED +#define PB_H_INCLUDED + +/***************************************************************** + * Nanopb compilation time options. You can change these here by * + * uncommenting the lines, or on the compiler command line. * + *****************************************************************/ + +/* Enable support for dynamically allocated fields */ +/* #define PB_ENABLE_MALLOC 1 */ + +/* Define this if your CPU / compiler combination does not support + * unaligned memory access to packed structures. */ +/* #define PB_NO_PACKED_STRUCTS 1 */ + +/* Increase the number of required fields that are tracked. + * A compiler warning will tell if you need this. */ +/* #define PB_MAX_REQUIRED_FIELDS 256 */ + +/* Add support for tag numbers > 255 and fields larger than 255 bytes. */ +/* #define PB_FIELD_16BIT 1 */ + +/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */ +/* #define PB_FIELD_32BIT 1 */ + +/* Disable support for error messages in order to save some code space. */ +/* #define PB_NO_ERRMSG 1 */ + +/* Disable support for custom streams (support only memory buffers). */ +/* #define PB_BUFFER_ONLY 1 */ + +/* Switch back to the old-style callback function signature. + * This was the default until nanopb-0.2.1. */ +/* #define PB_OLD_CALLBACK_STYLE */ + + +/* Don't encode scalar arrays as packed. This is only to be used when + * the decoder on the receiving side cannot process packed scalar arrays. + * Such example is older protobuf.js. */ +/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */ + +/****************************************************************** + * You usually don't need to change anything below this line. * + * Feel free to look around and use the defined macros, though. * + ******************************************************************/ + + +/* Version of the nanopb library. Just in case you want to check it in + * your own program. */ +#define NANOPB_VERSION nanopb-0.3.9.10 + +/* Include all the system headers needed by nanopb. You will need the + * definitions of the following: + * - strlen, memcpy, memset functions + * - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t + * - size_t + * - bool + * + * If you don't have the standard header files, you can instead provide + * a custom header that defines or includes all this. In that case, + * define PB_SYSTEM_HEADER to the path of this file. + */ +#ifdef PB_SYSTEM_HEADER +#include PB_SYSTEM_HEADER +#else +#include +#include +#include +#include + +#ifdef PB_ENABLE_MALLOC +#include +#endif +#endif + +/* Macro for defining packed structures (compiler dependent). + * This just reduces memory requirements, but is not required. + */ +#if defined(PB_NO_PACKED_STRUCTS) + /* Disable struct packing */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed +#elif defined(__GNUC__) || defined(__clang__) + /* For GCC and clang */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed __attribute__((packed)) +#elif defined(__ICCARM__) || defined(__CC_ARM) + /* For IAR ARM and Keil MDK-ARM compilers */ +# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") +# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") +# define pb_packed +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) + /* For Microsoft Visual C++ */ +# define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) +# define PB_PACKED_STRUCT_END __pragma(pack(pop)) +# define pb_packed +#else + /* Unknown compiler */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed +#endif + +/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ +#ifndef PB_UNUSED +#define PB_UNUSED(x) (void)(x) +#endif + +/* Compile-time assertion, used for checking compatible compilation options. + * If this does not work properly on your compiler, use + * #define PB_NO_STATIC_ASSERT to disable it. + * + * But before doing that, check carefully the error message / place where it + * comes from to see if the error has a real cause. Unfortunately the error + * message is not always very clear to read, but you can see the reason better + * in the place where the PB_STATIC_ASSERT macro was called. + */ +#ifndef PB_NO_STATIC_ASSERT +#ifndef PB_STATIC_ASSERT +#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; +#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) +#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER +#endif +#else +#define PB_STATIC_ASSERT(COND,MSG) +#endif + +/* Number of required fields to keep track of. */ +#ifndef PB_MAX_REQUIRED_FIELDS +#define PB_MAX_REQUIRED_FIELDS 64 +#endif + +#if PB_MAX_REQUIRED_FIELDS < 64 +#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64). +#endif + +/* List of possible field types. These are used in the autogenerated code. + * Least-significant 4 bits tell the scalar type + * Most-significant 4 bits specify repeated/required/packed etc. + */ + +typedef uint_least8_t pb_type_t; + +/**** Field data types ****/ + +/* Numeric types */ +#define PB_LTYPE_BOOL 0x00 /* bool */ +#define PB_LTYPE_VARINT 0x01 /* int32, int64, enum, bool */ +#define PB_LTYPE_UVARINT 0x02 /* uint32, uint64 */ +#define PB_LTYPE_SVARINT 0x03 /* sint32, sint64 */ +#define PB_LTYPE_FIXED32 0x04 /* fixed32, sfixed32, float */ +#define PB_LTYPE_FIXED64 0x05 /* fixed64, sfixed64, double */ + +/* Marker for last packable field type. */ +#define PB_LTYPE_LAST_PACKABLE 0x05 + +/* Byte array with pre-allocated buffer. + * data_size is the length of the allocated PB_BYTES_ARRAY structure. */ +#define PB_LTYPE_BYTES 0x06 + +/* String with pre-allocated buffer. + * data_size is the maximum length. */ +#define PB_LTYPE_STRING 0x07 + +/* Submessage + * submsg_fields is pointer to field descriptions */ +#define PB_LTYPE_SUBMESSAGE 0x08 + +/* Extension pseudo-field + * The field contains a pointer to pb_extension_t */ +#define PB_LTYPE_EXTENSION 0x09 + +/* Byte array with inline, pre-allocated byffer. + * data_size is the length of the inline, allocated buffer. + * This differs from PB_LTYPE_BYTES by defining the element as + * pb_byte_t[data_size] rather than pb_bytes_array_t. */ +#define PB_LTYPE_FIXED_LENGTH_BYTES 0x0A + +/* Number of declared LTYPES */ +#define PB_LTYPES_COUNT 0x0B +#define PB_LTYPE_MASK 0x0F + +/**** Field repetition rules ****/ + +#define PB_HTYPE_REQUIRED 0x00 +#define PB_HTYPE_OPTIONAL 0x10 +#define PB_HTYPE_REPEATED 0x20 +#define PB_HTYPE_ONEOF 0x30 +#define PB_HTYPE_MASK 0x30 + +/**** Field allocation types ****/ + +#define PB_ATYPE_STATIC 0x00 +#define PB_ATYPE_POINTER 0x80 +#define PB_ATYPE_CALLBACK 0x40 +#define PB_ATYPE_MASK 0xC0 + +#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) +#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) +#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) + +/* Data type used for storing sizes of struct fields + * and array counts. + */ +#if defined(PB_FIELD_32BIT) + typedef uint32_t pb_size_t; + typedef int32_t pb_ssize_t; +#elif defined(PB_FIELD_16BIT) + typedef uint_least16_t pb_size_t; + typedef int_least16_t pb_ssize_t; +#else + typedef uint_least8_t pb_size_t; + typedef int_least8_t pb_ssize_t; +#endif +#define PB_SIZE_MAX ((pb_size_t)-1) + +/* Data type for storing encoded data and other byte streams. + * This typedef exists to support platforms where uint8_t does not exist. + * You can regard it as equivalent on uint8_t on other platforms. + */ +typedef uint_least8_t pb_byte_t; + +/* This structure is used in auto-generated constants + * to specify struct fields. + * You can change field sizes if you need structures + * larger than 256 bytes or field tags larger than 256. + * The compiler should complain if your .proto has such + * structures. Fix that by defining PB_FIELD_16BIT or + * PB_FIELD_32BIT. + */ +PB_PACKED_STRUCT_START +typedef struct pb_field_s pb_field_t; +struct pb_field_s { + pb_size_t tag; + pb_type_t type; + pb_size_t data_offset; /* Offset of field data, relative to previous field. */ + pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */ + pb_size_t data_size; /* Data size in bytes for a single item */ + pb_size_t array_size; /* Maximum number of entries in array */ + + /* Field definitions for submessage + * OR default value for all other non-array, non-callback types + * If null, then field will zeroed. */ + const void *ptr; +} pb_packed; +PB_PACKED_STRUCT_END + +/* Make sure that the standard integer types are of the expected sizes. + * Otherwise fixed32/fixed64 fields can break. + * + * If you get errors here, it probably means that your stdint.h is not + * correct for your platform. + */ +#ifndef PB_WITHOUT_64BIT +PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE) +#endif + +/* This structure is used for 'bytes' arrays. + * It has the number of bytes in the beginning, and after that an array. + * Note that actual structs used will have a different length of bytes array. + */ +#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; } +#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) + +struct pb_bytes_array_s { + pb_size_t size; + pb_byte_t bytes[1]; +}; +typedef struct pb_bytes_array_s pb_bytes_array_t; + +/* This structure is used for giving the callback function. + * It is stored in the message structure and filled in by the method that + * calls pb_decode. + * + * The decoding callback will be given a limited-length stream + * If the wire type was string, the length is the length of the string. + * If the wire type was a varint/fixed32/fixed64, the length is the length + * of the actual value. + * The function may be called multiple times (especially for repeated types, + * but also otherwise if the message happens to contain the field multiple + * times.) + * + * The encoding callback will receive the actual output stream. + * It should write all the data in one call, including the field tag and + * wire type. It can write multiple fields. + * + * The callback can be null if you want to skip a field. + */ +typedef struct pb_istream_s pb_istream_t; +typedef struct pb_ostream_s pb_ostream_t; +typedef struct pb_callback_s pb_callback_t; +struct pb_callback_s { +#ifdef PB_OLD_CALLBACK_STYLE + /* Deprecated since nanopb-0.2.1 */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg); + } funcs; +#else + /* New function signature, which allows modifying arg contents in callback. */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); + } funcs; +#endif + + /* Free arg for use by callback */ + void *arg; +}; + +/* Wire types. Library user needs these only in encoder callbacks. */ +typedef enum { + PB_WT_VARINT = 0, + PB_WT_64BIT = 1, + PB_WT_STRING = 2, + PB_WT_32BIT = 5 +} pb_wire_type_t; + +/* Structure for defining the handling of unknown/extension fields. + * Usually the pb_extension_type_t structure is automatically generated, + * while the pb_extension_t structure is created by the user. However, + * if you want to catch all unknown fields, you can also create a custom + * pb_extension_type_t with your own callback. + */ +typedef struct pb_extension_type_s pb_extension_type_t; +typedef struct pb_extension_s pb_extension_t; +struct pb_extension_type_s { + /* Called for each unknown field in the message. + * If you handle the field, read off all of its data and return true. + * If you do not handle the field, do not read anything and return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, + uint32_t tag, pb_wire_type_t wire_type); + + /* Called once after all regular fields have been encoded. + * If you have something to write, do so and return true. + * If you do not have anything to write, just return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); + + /* Free field for use by the callback. */ + const void *arg; +}; + +struct pb_extension_s { + /* Type describing the extension field. Usually you'll initialize + * this to a pointer to the automatically generated structure. */ + const pb_extension_type_t *type; + + /* Destination for the decoded data. This must match the datatype + * of the extension field. */ + void *dest; + + /* Pointer to the next extension handler, or NULL. + * If this extension does not match a field, the next handler is + * automatically called. */ + pb_extension_t *next; + + /* The decoder sets this to true if the extension was found. + * Ignored for encoding. */ + bool found; +}; + +/* Memory allocation functions to use. You can define pb_realloc and + * pb_free to custom functions if you want. */ +#ifdef PB_ENABLE_MALLOC +# ifndef pb_realloc +# define pb_realloc(ptr, size) realloc(ptr, size) +# endif +# ifndef pb_free +# define pb_free(ptr) free(ptr) +# endif +#endif + +/* This is used to inform about need to regenerate .pb.h/.pb.c files. */ +#define PB_PROTO_HEADER_VERSION 30 + +/* These macros are used to declare pb_field_t's in the constant array. */ +/* Size of a structure member, in bytes. */ +#define pb_membersize(st, m) (sizeof ((st*)0)->m) +/* Number of entries in an array. */ +#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) +/* Delta from start of one member to the start of another member. */ +#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) +/* Marks the end of the field list */ +#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0} + +/* Macros for filling in the data_offset field */ +/* data_offset for first field in a message */ +#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1)) +/* data_offset for subsequent fields */ +#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2)) +/* data offset for subsequent fields inside an union (oneof) */ +#define PB_DATAOFFSET_UNION(st, m1, m2) (PB_SIZE_MAX) +/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */ +#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \ + ? PB_DATAOFFSET_FIRST(st, m1, m2) \ + : PB_DATAOFFSET_OTHER(st, m1, m2)) + +/* Required fields are the simplest. They just have delta (padding) from + * previous field end, and the size of the field. Pointer is used for + * submessages and default values. + */ +#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional fields add the delta to the has_ variable. */ +#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + fd, \ + pb_delta(st, has_ ## m, m), \ + pb_membersize(st, m), 0, ptr} + +#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Repeated fields have a _count field and also the maximum number of entries. */ +#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \ + fd, \ + pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), \ + pb_arraysize(st, m), ptr} + +/* Allocated fields carry the size of the actual data, not the pointer */ +#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Optional fields don't need a has_ variable, as information would be redundant */ +#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Same as optional fields*/ +#define PB_SINGULAR_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Repeated fields have a _count field and a pointer to array of pointers */ +#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \ + fd, pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), 0, ptr} + +/* Callbacks are much like required fields except with special datatype. */ +#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_SINGULAR_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional extensions don't have the has_ field, as that would be redundant. + * Furthermore, the combination of OPTIONAL without has_ field is used + * for indicating proto3 style fields. Extensions exist in proto2 mode only, + * so they should be encoded according to proto2 rules. To avoid the conflict, + * extensions are marked as REQUIRED instead. + */ +#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ + 0, \ + 0, \ + pb_membersize(st, m), 0, ptr} + +#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \ + PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) + +#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ + PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) + +/* The mapping from protobuf types to LTYPEs is done using these macros. */ +#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL +#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES +#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT +#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE +#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING +#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION +#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES + +/* This is the actual macro used in field descriptions. + * It takes these arguments: + * - Field tag number + * - Field type: BOOL, BYTES, DOUBLE, ENUM, UENUM, FIXED32, FIXED64, + * FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64 + * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION + * - Field rules: REQUIRED, OPTIONAL or REPEATED + * - Allocation: STATIC, CALLBACK or POINTER + * - Placement: FIRST or OTHER, depending on if this is the first field in structure. + * - Message name + * - Field name + * - Previous field name (or field name again for first field) + * - Pointer to default value or submsg fields. + */ + +#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ ## rules ## _ ## allocation(tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* Field description for repeated static fixed count fields.*/ +#define PB_REPEATED_FIXED_COUNT(tag, type, placement, message, field, prevfield, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | PB_LTYPE_MAP_ ## type, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + 0, \ + pb_membersize(message, field[0]), \ + pb_arraysize(message, field), ptr} + +/* Field description for oneof fields. This requires taking into account the + * union name also, that's why a separate set of macros is needed. + */ +#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, u.m), \ + pb_membersize(st, u.m), 0, ptr} + +#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, u.m), \ + pb_membersize(st, u.m[0]), 0, ptr} + +#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +#define PB_ANONYMOUS_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, m), \ + pb_membersize(st, m), 0, ptr} + +#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, m), \ + pb_membersize(st, m[0]), 0, ptr} + +#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* These macros are used for giving out error messages. + * They are mostly a debugging aid; the main error information + * is the true/false return value from functions. + * Some code space can be saved by disabling the error + * messages if not used. + * + * PB_SET_ERROR() sets the error message if none has been set yet. + * msg must be a constant string literal. + * PB_GET_ERROR() always returns a pointer to a string. + * PB_RETURN_ERROR() sets the error and returns false from current + * function. + */ +#ifdef PB_NO_ERRMSG +#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream) +#define PB_GET_ERROR(stream) "(errmsg disabled)" +#else +#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg)) +#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") +#endif + +#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false + +#endif diff --git a/frontend/ios/Pods/nanopb/pb_common.c b/frontend/ios/Pods/nanopb/pb_common.c new file mode 100644 index 0000000..5799db2 --- /dev/null +++ b/frontend/ios/Pods/nanopb/pb_common.c @@ -0,0 +1,106 @@ +/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c. + * + * 2014 Petteri Aimonen + */ + +#include "pb_common.h" + +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct) +{ + iter->start = fields; + iter->pos = fields; + iter->required_field_index = 0; + iter->dest_struct = dest_struct; + + if (!dest_struct) + { + iter->pData = NULL; + iter->pSize = NULL; + } + else + { + iter->pData = (char*)dest_struct + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + } + + return (iter->pos->tag != 0); +} + +bool pb_field_iter_next(pb_field_iter_t *iter) +{ + const pb_field_t *prev_field = iter->pos; + + if (prev_field->tag == 0) + { + /* Handle empty message types, where the first field is already the terminator. + * In other cases, the iter->pos never points to the terminator. */ + return false; + } + + iter->pos++; + + if (iter->pos->tag == 0) + { + /* Wrapped back to beginning, reinitialize */ + (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct); + return false; + } + else + { + /* Increment the pointers based on previous field size */ + size_t prev_size = prev_field->data_size; + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF && + PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF && + iter->pos->data_offset == PB_SIZE_MAX) + { + /* Don't advance pointers inside unions */ + return true; + } + else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC && + PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED) + { + /* In static arrays, the data_size tells the size of a single entry and + * array_size is the number of entries */ + prev_size *= prev_field->array_size; + } + else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER) + { + /* Pointer fields always have a constant size in the main structure. + * The data_size only applies to the dynamically allocated area. */ + prev_size = sizeof(void*); + } + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED) + { + /* Count the required fields, in order to check their presence in the + * decoder. */ + iter->required_field_index++; + } + + iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + return true; + } +} + +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) +{ + const pb_field_t *start = iter->pos; + + do { + if (iter->pos->tag == tag && + PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) + { + /* Found the wanted field */ + return true; + } + + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + /* Searched all the way back to start, and found nothing. */ + return false; +} + + diff --git a/frontend/ios/Pods/nanopb/pb_common.h b/frontend/ios/Pods/nanopb/pb_common.h new file mode 100644 index 0000000..60b3d37 --- /dev/null +++ b/frontend/ios/Pods/nanopb/pb_common.h @@ -0,0 +1,42 @@ +/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c. + * These functions are rarely needed by applications directly. + */ + +#ifndef PB_COMMON_H_INCLUDED +#define PB_COMMON_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Iterator for pb_field_t list */ +struct pb_field_iter_s { + const pb_field_t *start; /* Start of the pb_field_t array */ + const pb_field_t *pos; /* Current position of the iterator */ + unsigned required_field_index; /* Zero-based index that counts only the required fields */ + void *dest_struct; /* Pointer to start of the structure */ + void *pData; /* Pointer to current field value */ + void *pSize; /* Pointer to count/has field */ +}; +typedef struct pb_field_iter_s pb_field_iter_t; + +/* Initialize the field iterator structure to beginning. + * Returns false if the message type is empty. */ +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct); + +/* Advance the iterator to the next field. + * Returns false when the iterator wraps back to the first field. */ +bool pb_field_iter_next(pb_field_iter_t *iter); + +/* Advance the iterator until it points at a field with the given tag. + * Returns false if no such field exists. */ +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif + diff --git a/frontend/ios/Pods/nanopb/pb_decode.c b/frontend/ios/Pods/nanopb/pb_decode.c new file mode 100644 index 0000000..ebf7e85 --- /dev/null +++ b/frontend/ios/Pods/nanopb/pb_decode.c @@ -0,0 +1,1570 @@ +/* pb_decode.c -- decode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +#include "pb.h" +#include "pb_decode.h" +#include "pb_common.h" + +/************************************** + * Declarations internal to this file * + **************************************/ + +typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; + +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension); +static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn find_extension_field(pb_field_iter_t *iter); +static void pb_field_set_to_default(pb_field_iter_t *iter); +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); +static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof); +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_skip_varint(pb_istream_t *stream); +static bool checkreturn pb_skip_string(pb_istream_t *stream); + +#ifdef PB_ENABLE_MALLOC +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); +static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); +static void pb_release_single_field(const pb_field_iter_t *iter); +#endif + +#ifdef PB_WITHOUT_64BIT +#define pb_int64_t int32_t +#define pb_uint64_t uint32_t +#else +#define pb_int64_t int64_t +#define pb_uint64_t uint64_t +#endif + +/* --- Function pointers to field decoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { + &pb_dec_bool, + &pb_dec_varint, + &pb_dec_uvarint, + &pb_dec_svarint, + &pb_dec_fixed32, + &pb_dec_fixed64, + + &pb_dec_bytes, + &pb_dec_string, + &pb_dec_submessage, + NULL, /* extensions */ + &pb_dec_fixed_length_bytes +}; + +/******************************* + * pb_istream_t implementation * + *******************************/ + +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) +{ + size_t i; + const pb_byte_t *source = (const pb_byte_t*)stream->state; + stream->state = (pb_byte_t*)stream->state + count; + + if (buf != NULL) + { + for (i = 0; i < count; i++) + buf[i] = source[i]; + } + + return true; +} + +bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) +{ + if (count == 0) + return true; + +#ifndef PB_BUFFER_ONLY + if (buf == NULL && stream->callback != buf_read) + { + /* Skip input bytes */ + pb_byte_t tmp[16]; + while (count > 16) + { + if (!pb_read(stream, tmp, 16)) + return false; + + count -= 16; + } + + return pb_read(stream, tmp, count); + } +#endif + + if (stream->bytes_left < count) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!buf_read(stream, buf, count)) + return false; +#endif + + stream->bytes_left -= count; + return true; +} + +/* Read a single byte from input stream. buf may not be NULL. + * This is an optimization for the varint decoding. */ +static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) +{ + if (stream->bytes_left == 0) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, 1)) + PB_RETURN_ERROR(stream, "io error"); +#else + *buf = *(const pb_byte_t*)stream->state; + stream->state = (pb_byte_t*)stream->state + 1; +#endif + + stream->bytes_left--; + + return true; +} + +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) +{ + pb_istream_t stream; + /* Cast away the const from buf without a compiler error. We are + * careful to use it only in a const manner in the callbacks. + */ + union { + void *state; + const void *c_state; + } state; +#ifdef PB_BUFFER_ONLY + stream.callback = NULL; +#else + stream.callback = &buf_read; +#endif + state.c_state = buf; + stream.state = state.state; + stream.bytes_left = bufsize; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +/******************** + * Helper functions * + ********************/ + +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof) +{ + pb_byte_t byte; + uint32_t result; + + if (!pb_readbyte(stream, &byte)) + { + if (stream->bytes_left == 0) + { + if (eof) + { + *eof = true; + } + } + + return false; + } + + if ((byte & 0x80) == 0) + { + /* Quick case, 1 byte value */ + result = byte; + } + else + { + /* Multibyte case */ + uint_fast8_t bitpos = 7; + result = byte & 0x7F; + + do + { + if (!pb_readbyte(stream, &byte)) + return false; + + if (bitpos >= 32) + { + /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */ + uint8_t sign_extension = (bitpos < 63) ? 0xFF : 0x01; + + if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension)) + { + PB_RETURN_ERROR(stream, "varint overflow"); + } + } + else + { + result |= (uint32_t)(byte & 0x7F) << bitpos; + } + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + + if (bitpos == 35 && (byte & 0x70) != 0) + { + /* The last byte was at bitpos=28, so only bottom 4 bits fit. */ + PB_RETURN_ERROR(stream, "varint overflow"); + } + } + + *dest = result; + return true; +} + +bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) +{ + return pb_decode_varint32_eof(stream, dest, NULL); +} + +#ifndef PB_WITHOUT_64BIT +bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) +{ + pb_byte_t byte; + uint_fast8_t bitpos = 0; + uint64_t result = 0; + + do + { + if (bitpos >= 64) + PB_RETURN_ERROR(stream, "varint overflow"); + + if (!pb_readbyte(stream, &byte)) + return false; + + result |= (uint64_t)(byte & 0x7F) << bitpos; + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + + *dest = result; + return true; +} +#endif + +bool checkreturn pb_skip_varint(pb_istream_t *stream) +{ + pb_byte_t byte; + do + { + if (!pb_read(stream, &byte, 1)) + return false; + } while (byte & 0x80); + return true; +} + +bool checkreturn pb_skip_string(pb_istream_t *stream) +{ + uint32_t length; + if (!pb_decode_varint32(stream, &length)) + return false; + + return pb_read(stream, NULL, length); +} + +bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) +{ + uint32_t temp; + *eof = false; + *wire_type = (pb_wire_type_t) 0; + *tag = 0; + + if (!pb_decode_varint32_eof(stream, &temp, eof)) + { + return false; + } + + if (temp == 0) + { + *eof = true; /* Special feature: allow 0-terminated messages. */ + return false; + } + + *tag = temp >> 3; + *wire_type = (pb_wire_type_t)(temp & 7); + return true; +} + +bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) +{ + switch (wire_type) + { + case PB_WT_VARINT: return pb_skip_varint(stream); + case PB_WT_64BIT: return pb_read(stream, NULL, 8); + case PB_WT_STRING: return pb_skip_string(stream); + case PB_WT_32BIT: return pb_read(stream, NULL, 4); + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Read a raw value to buffer, for the purpose of passing it to callback as + * a substream. Size is maximum size on call, and actual size on return. + */ +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size) +{ + size_t max_size = *size; + switch (wire_type) + { + case PB_WT_VARINT: + *size = 0; + do + { + (*size)++; + if (*size > max_size) return false; + if (!pb_read(stream, buf, 1)) return false; + } while (*buf++ & 0x80); + return true; + + case PB_WT_64BIT: + *size = 8; + return pb_read(stream, buf, 8); + + case PB_WT_32BIT: + *size = 4; + return pb_read(stream, buf, 4); + + case PB_WT_STRING: + /* Calling read_raw_value with a PB_WT_STRING is an error. + * Explicitly handle this case and fallthrough to default to avoid + * compiler warnings. + */ + + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Decode string length from stream and return a substream with limited length. + * Remember to close the substream using pb_close_string_substream(). + */ +bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + uint32_t size; + if (!pb_decode_varint32(stream, &size)) + return false; + + *substream = *stream; + if (substream->bytes_left < size) + PB_RETURN_ERROR(stream, "parent stream too short"); + + substream->bytes_left = size; + stream->bytes_left -= size; + return true; +} + +bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + if (substream->bytes_left) { + if (!pb_read(substream, NULL, substream->bytes_left)) + return false; + } + + stream->state = substream->state; + +#ifndef PB_NO_ERRMSG + stream->errmsg = substream->errmsg; +#endif + return true; +} + +/************************* + * Decode a single field * + *************************/ + +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_OPTIONAL: + if (iter->pSize != iter->pData) + *(bool*)iter->pSize = true; + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array */ + bool status = true; + pb_size_t *size = (pb_size_t*)iter->pSize; + + pb_istream_t substream; + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left > 0 && *size < iter->pos->array_size) + { + void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + (*size)++; + } + + if (substream.bytes_left != 0) + PB_RETURN_ERROR(stream, "array overflow"); + if (!pb_close_string_substream(stream, &substream)) + return false; + + return status; + } + else + { + /* Repeated field */ + pb_size_t *size = (pb_size_t*)iter->pSize; + char *pItem = (char*)iter->pData + iter->pos->data_size * (*size); + + if ((*size)++ >= iter->pos->array_size) + PB_RETURN_ERROR(stream, "array overflow"); + + return func(stream, iter->pos, pItem); + } + + case PB_HTYPE_ONEOF: + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + *(pb_size_t*)iter->pSize != iter->pos->tag) + { + /* We memset to zero so that any callbacks are set to NULL. + * This is because the callbacks might otherwise have values + * from some other union field. */ + memset(iter->pData, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData); + } + *(pb_size_t*)iter->pSize = iter->pos->tag; + + return func(stream, iter->pos, iter->pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +#ifdef PB_ENABLE_MALLOC +/* Allocate storage for the field and store the pointer at iter->pData. + * array_size is the number of entries to reserve in an array. + * Zero size is not allowed, use pb_free() for releasing. + */ +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) +{ + void *ptr = *(void**)pData; + + if (data_size == 0 || array_size == 0) + PB_RETURN_ERROR(stream, "invalid size"); + +#ifdef __AVR__ + /* Workaround for AVR libc bug 53284: http://savannah.nongnu.org/bugs/?53284 + * Realloc to size of 1 byte can cause corruption of the malloc structures. + */ + if (data_size == 1 && array_size == 1) + { + data_size = 2; + } +#endif + + /* Check for multiplication overflows. + * This code avoids the costly division if the sizes are small enough. + * Multiplication is safe as long as only half of bits are set + * in either multiplicand. + */ + { + const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); + if (data_size >= check_limit || array_size >= check_limit) + { + const size_t size_max = (size_t)-1; + if (size_max / array_size < data_size) + { + PB_RETURN_ERROR(stream, "size too large"); + } + } + } + + /* Allocate new or expand previous allocation */ + /* Note: on failure the old pointer will remain in the structure, + * the message must be freed by caller also on error return. */ + ptr = pb_realloc(ptr, array_size * data_size); + if (ptr == NULL) + PB_RETURN_ERROR(stream, "realloc failed"); + + *(void**)pData = ptr; + return true; +} + +/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ +static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) +{ + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || + PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) + { + *(void**)pItem = NULL; + } + else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + /* We memset to zero so that any callbacks are set to NULL. + * Then set any default values. */ + memset(pItem, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); + } +} +#endif + +static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ +#ifndef PB_ENABLE_MALLOC + PB_UNUSED(wire_type); + PB_UNUSED(iter); + PB_RETURN_ERROR(stream, "no malloc support"); +#else + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + case PB_HTYPE_OPTIONAL: + case PB_HTYPE_ONEOF: + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + *(void**)iter->pData != NULL) + { + /* Duplicate field, have to release the old allocation first. */ + pb_release_single_field(iter); + } + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + *(pb_size_t*)iter->pSize = iter->pos->tag; + } + + if (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES) + { + return func(stream, iter->pos, iter->pData); + } + else + { + if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) + return false; + + initialize_pointer_field(*(void**)iter->pData, iter); + return func(stream, iter->pos, *(void**)iter->pData); + } + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array, multiple items come in at once. */ + bool status = true; + pb_size_t *size = (pb_size_t*)iter->pSize; + size_t allocated_size = *size; + void *pItem; + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left) + { + if (*size == PB_SIZE_MAX) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = "too many array entries"; +#endif + status = false; + break; + } + + if ((size_t)*size + 1 > allocated_size) + { + /* Allocate more storage. This tries to guess the + * number of remaining entries. Round the division + * upwards. */ + size_t remain = (substream.bytes_left - 1) / iter->pos->data_size + 1; + if (remain < PB_SIZE_MAX - allocated_size) + allocated_size += remain; + else + allocated_size += 1; + + if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) + { + status = false; + break; + } + } + + /* Decode the array entry */ + pItem = *(char**)iter->pData + iter->pos->data_size * (*size); + if (pItem == NULL) + { + /* Shouldn't happen, but satisfies static analyzers */ + status = false; + break; + } + initialize_pointer_field(pItem, iter); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + + (*size)++; + } + if (!pb_close_string_substream(stream, &substream)) + return false; + + return status; + } + else + { + /* Normal repeated field, i.e. only one item at a time. */ + pb_size_t *size = (pb_size_t*)iter->pSize; + void *pItem; + + if (*size == PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "too many array entries"); + + if (!allocate_field(stream, iter->pData, iter->pos->data_size, (size_t)(*size + 1))) + return false; + + pItem = *(char**)iter->pData + iter->pos->data_size * (*size); + (*size)++; + initialize_pointer_field(pItem, iter); + return func(stream, iter->pos, pItem); + } + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +#endif +} + +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_callback_t *pCallback = (pb_callback_t*)iter->pData; +#ifdef PB_OLD_CALLBACK_STYLE + void *arg; +#else + void **arg; +#endif + + if (pCallback == NULL || pCallback->funcs.decode == NULL) + return pb_skip_field(stream, wire_type); + +#ifdef PB_OLD_CALLBACK_STYLE + arg = pCallback->arg; +#else + arg = &(pCallback->arg); +#endif + + if (wire_type == PB_WT_STRING) + { + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + do + { + if (!pCallback->funcs.decode(&substream, iter->pos, arg)) + PB_RETURN_ERROR(stream, "callback failed"); + } while (substream.bytes_left); + + if (!pb_close_string_substream(stream, &substream)) + return false; + + return true; + } + else + { + /* Copy the single scalar value to stack. + * This is required so that we can limit the stream length, + * which in turn allows to use same callback for packed and + * not-packed fields. */ + pb_istream_t substream; + pb_byte_t buffer[10]; + size_t size = sizeof(buffer); + + if (!read_raw_value(stream, wire_type, buffer, &size)) + return false; + substream = pb_istream_from_buffer(buffer, size); + + return pCallback->funcs.decode(&substream, iter->pos, arg); + } +} + +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ +#ifdef PB_ENABLE_MALLOC + /* When decoding an oneof field, check if there is old data that must be + * released first. */ + if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) + { + if (!pb_release_union_field(stream, iter)) + return false; + } +#endif + + switch (PB_ATYPE(iter->pos->type)) + { + case PB_ATYPE_STATIC: + return decode_static_field(stream, wire_type, iter); + + case PB_ATYPE_POINTER: + return decode_pointer_field(stream, wire_type, iter); + + case PB_ATYPE_CALLBACK: + return decode_callback_field(stream, wire_type, iter); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension) +{ + /* Fake a field iterator for the extension field. + * It is not actually safe to advance this iterator, but decode_field + * will not even try to. */ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + (void)pb_field_iter_begin(iter, field, extension->dest); + iter->pData = extension->dest; + iter->pSize = &extension->found; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + iter->pData = &extension->dest; + } +} + +/* Default handler for extension fields. Expects a pb_field_t structure + * in extension->type->arg. */ +static bool checkreturn default_extension_decoder(pb_istream_t *stream, + pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + pb_field_iter_t iter; + + if (field->tag != tag) + return true; + + iter_from_extension(&iter, extension); + extension->found = true; + return decode_field(stream, wire_type, &iter); +} + +/* Try to decode an unknown field as an extension field. Tries each extension + * decoder in turn, until one of them handles the field or loop ends. */ +static bool checkreturn decode_extension(pb_istream_t *stream, + uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; + size_t pos = stream->bytes_left; + + while (extension != NULL && pos == stream->bytes_left) + { + bool status; + if (extension->type->decode) + status = extension->type->decode(stream, extension, tag, wire_type); + else + status = default_extension_decoder(stream, extension, tag, wire_type); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/* Step through the iterator until an extension field is found or until all + * entries have been checked. There can be only one extension field per + * message. Returns false if no extension field is found. */ +static bool checkreturn find_extension_field(pb_field_iter_t *iter) +{ + const pb_field_t *start = iter->pos; + + do { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) + return true; + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + return false; +} + +/* Initialize message fields to default values, recursively */ +static void pb_field_set_to_default(pb_field_iter_t *iter) +{ + pb_type_t type; + type = iter->pos->type; + + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + pb_extension_t *ext = *(pb_extension_t* const *)iter->pData; + while (ext != NULL) + { + pb_field_iter_t ext_iter; + ext->found = false; + iter_from_extension(&ext_iter, ext); + pb_field_set_to_default(&ext_iter); + ext = ext->next; + } + } + else if (PB_ATYPE(type) == PB_ATYPE_STATIC) + { + bool init_data = true; + if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData) + { + /* Set has_field to false. Still initialize the optional field + * itself also. */ + *(bool*)iter->pSize = false; + } + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + /* REPEATED: Set array count to 0, no need to initialize contents. + ONEOF: Set which_field to 0. */ + *(pb_size_t*)iter->pSize = 0; + init_data = false; + } + + if (init_data) + { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + /* Initialize submessage to defaults */ + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData); + } + else if (iter->pos->ptr != NULL) + { + /* Initialize to default value */ + memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size); + } + else + { + /* Initialize to zeros */ + memset(iter->pData, 0, iter->pos->data_size); + } + } + } + else if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + /* Initialize the pointer to NULL. */ + *(void**)iter->pData = NULL; + + /* Initialize array count to 0. */ + if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + *(pb_size_t*)iter->pSize = 0; + } + } + else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) + { + /* Don't overwrite callback */ + } +} + +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iter_t iter; + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do + { + pb_field_set_to_default(&iter); + } while (pb_field_iter_next(&iter)); +} + +/********************* + * Decode all fields * + *********************/ + +bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0}; + const uint32_t allbits = ~(uint32_t)0; + uint32_t extension_range_start = 0; + pb_field_iter_t iter; + + /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed + * count field. This can only handle _one_ repeated fixed count field that + * is unpacked and unordered among other (non repeated fixed count) fields. + */ + const pb_field_t *fixed_count_field = NULL; + pb_size_t fixed_count_size = 0; + + /* Return value ignored, as empty message types will be correctly handled by + * pb_field_iter_find() anyway. */ + (void)pb_field_iter_begin(&iter, fields, dest_struct); + + while (stream->bytes_left) + { + uint32_t tag; + pb_wire_type_t wire_type; + bool eof; + + if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) + { + if (eof) + break; + else + return false; + } + + if (!pb_field_iter_find(&iter, tag)) + { + /* No match found, check if it matches an extension. */ + if (tag >= extension_range_start) + { + if (!find_extension_field(&iter)) + extension_range_start = (uint32_t)-1; + else + extension_range_start = iter.pos->tag; + + if (tag >= extension_range_start) + { + size_t pos = stream->bytes_left; + + if (!decode_extension(stream, tag, wire_type, &iter)) + return false; + + if (pos != stream->bytes_left) + { + /* The field was handled */ + continue; + } + } + } + + /* No match found, skip data */ + if (!pb_skip_field(stream, wire_type)) + return false; + continue; + } + + /* If a repeated fixed count field was found, get size from + * 'fixed_count_field' as there is no counter contained in the struct. + */ + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REPEATED + && iter.pSize == iter.pData) + { + if (fixed_count_field != iter.pos) { + /* If the new fixed count field does not match the previous one, + * check that the previous one is NULL or that it finished + * receiving all the expected data. + */ + if (fixed_count_field != NULL && + fixed_count_size != fixed_count_field->array_size) + { + PB_RETURN_ERROR(stream, "wrong size for fixed count field"); + } + + fixed_count_field = iter.pos; + fixed_count_size = 0; + } + + iter.pSize = &fixed_count_size; + } + + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED + && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) + { + uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31)); + fields_seen[iter.required_field_index >> 5] |= tmp; + } + + if (!decode_field(stream, wire_type, &iter)) + return false; + } + + /* Check that all elements of the last decoded fixed count field were present. */ + if (fixed_count_field != NULL && + fixed_count_size != fixed_count_field->array_size) + { + PB_RETURN_ERROR(stream, "wrong size for fixed count field"); + } + + /* Check that all required fields were present. */ + { + /* First figure out the number of required fields by + * seeking to the end of the field array. Usually we + * are already close to end after decoding. + */ + unsigned req_field_count; + pb_type_t last_type; + unsigned i; + do { + req_field_count = iter.required_field_index; + last_type = iter.pos->type; + } while (pb_field_iter_next(&iter)); + + /* Fixup if last field was also required. */ + if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) + req_field_count++; + + if (req_field_count > PB_MAX_REQUIRED_FIELDS) + req_field_count = PB_MAX_REQUIRED_FIELDS; + + if (req_field_count > 0) + { + /* Check the whole words */ + for (i = 0; i < (req_field_count >> 5); i++) + { + if (fields_seen[i] != allbits) + PB_RETURN_ERROR(stream, "missing required field"); + } + + /* Check the remaining bits (if any) */ + if ((req_field_count & 31) != 0) + { + if (fields_seen[req_field_count >> 5] != + (allbits >> (32 - (req_field_count & 31)))) + { + PB_RETURN_ERROR(stream, "missing required field"); + } + } + } + } + + return true; +} + +bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + bool status; + pb_message_set_to_defaults(fields, dest_struct); + status = pb_decode_noinit(stream, fields, dest_struct); + +#ifdef PB_ENABLE_MALLOC + if (!status) + pb_release(fields, dest_struct); +#endif + + return status; +} + +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + pb_istream_t substream; + bool status; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + status = pb_decode_noinit(&substream, fields, dest_struct); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + pb_istream_t substream; + bool status; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + status = pb_decode(&substream, fields, dest_struct); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */ + return pb_decode(stream, fields, dest_struct); +} + +#ifdef PB_ENABLE_MALLOC +/* Given an oneof field, if there has already been a field inside this oneof, + * release it before overwriting with a different one. */ +static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter) +{ + pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */ + pb_size_t new_tag = iter->pos->tag; /* New which_ value */ + + if (old_tag == 0) + return true; /* Ok, no old data in union */ + + if (old_tag == new_tag) + return true; /* Ok, old data is of same type => merge */ + + /* Release old data. The find can fail if the message struct contains + * invalid data. */ + if (!pb_field_iter_find(iter, old_tag)) + PB_RETURN_ERROR(stream, "invalid union tag"); + + pb_release_single_field(iter); + + /* Restore iterator to where it should be. + * This shouldn't fail unless the pb_field_t structure is corrupted. */ + if (!pb_field_iter_find(iter, new_tag)) + PB_RETURN_ERROR(stream, "iterator error"); + + if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) + { + /* Initialize the pointer to NULL to make sure it is valid + * even in case of error return. */ + *(void**)iter->pData = NULL; + } + + return true; +} + +static void pb_release_single_field(const pb_field_iter_t *iter) +{ + pb_type_t type; + type = iter->pos->type; + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + if (*(pb_size_t*)iter->pSize != iter->pos->tag) + return; /* This is not the current field in the union */ + } + + /* Release anything contained inside an extension or submsg. + * This has to be done even if the submsg itself is statically + * allocated. */ + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + /* Release fields from all extensions in the linked list */ + pb_extension_t *ext = *(pb_extension_t**)iter->pData; + while (ext != NULL) + { + pb_field_iter_t ext_iter; + iter_from_extension(&ext_iter, ext); + pb_release_single_field(&ext_iter); + ext = ext->next; + } + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && PB_ATYPE(type) != PB_ATYPE_CALLBACK) + { + /* Release fields in submessage or submsg array */ + void *pItem = iter->pData; + pb_size_t count = 1; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + pItem = *(void**)iter->pData; + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + if (PB_ATYPE(type) == PB_ATYPE_STATIC && iter->pSize == iter->pData) { + /* No _count field so use size of the array */ + count = iter->pos->array_size; + } else { + count = *(pb_size_t*)iter->pSize; + } + + if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) + { + /* Protect against corrupted _count fields */ + count = iter->pos->array_size; + } + } + + if (pItem) + { + for (; count > 0; count--) + { + pb_release((const pb_field_t*)iter->pos->ptr, pItem); + pItem = (char*)pItem + iter->pos->data_size; + } + } + } + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + if (PB_HTYPE(type) == PB_HTYPE_REPEATED && + (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES)) + { + /* Release entries in repeated string or bytes array */ + void **pItem = *(void***)iter->pData; + pb_size_t count = *(pb_size_t*)iter->pSize; + for (; count > 0; count--) + { + pb_free(*pItem); + *pItem++ = NULL; + } + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + /* We are going to release the array, so set the size to 0 */ + *(pb_size_t*)iter->pSize = 0; + } + + /* Release main item */ + pb_free(*(void**)iter->pData); + *(void**)iter->pData = NULL; + } +} + +void pb_release(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iter_t iter; + + if (!dest_struct) + return; /* Ignore NULL pointers, similar to free() */ + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do + { + pb_release_single_field(&iter); + } while (pb_field_iter_next(&iter)); +} +#endif + +/* Field decoders */ + +bool pb_decode_bool(pb_istream_t *stream, bool *dest) +{ + return pb_dec_bool(stream, NULL, (void*)dest); +} + +bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest) +{ + pb_uint64_t value; + if (!pb_decode_varint(stream, &value)) + return false; + + if (value & 1) + *dest = (pb_int64_t)(~(value >> 1)); + else + *dest = (pb_int64_t)(value >> 1); + + return true; +} + +bool pb_decode_fixed32(pb_istream_t *stream, void *dest) +{ + pb_byte_t bytes[4]; + + if (!pb_read(stream, bytes, 4)) + return false; + + *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) | + ((uint32_t)bytes[1] << 8) | + ((uint32_t)bytes[2] << 16) | + ((uint32_t)bytes[3] << 24); + return true; +} + +#ifndef PB_WITHOUT_64BIT +bool pb_decode_fixed64(pb_istream_t *stream, void *dest) +{ + pb_byte_t bytes[8]; + + if (!pb_read(stream, bytes, 8)) + return false; + + *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) | + ((uint64_t)bytes[1] << 8) | + ((uint64_t)bytes[2] << 16) | + ((uint64_t)bytes[3] << 24) | + ((uint64_t)bytes[4] << 32) | + ((uint64_t)bytes[5] << 40) | + ((uint64_t)bytes[6] << 48) | + ((uint64_t)bytes[7] << 56); + + return true; +} +#endif + +static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t value; + PB_UNUSED(field); + if (!pb_decode_varint32(stream, &value)) + return false; + + *(bool*)dest = (value != 0); + return true; +} + +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + pb_uint64_t value; + pb_int64_t svalue; + pb_int64_t clamped; + if (!pb_decode_varint(stream, &value)) + return false; + + /* See issue 97: Google's C++ protobuf allows negative varint values to + * be cast as int32_t, instead of the int64_t that should be used when + * encoding. Previous nanopb versions had a bug in encoding. In order to + * not break decoding of such messages, we cast <=32 bit fields to + * int32_t first to get the sign correct. + */ + if (field->data_size == sizeof(pb_int64_t)) + svalue = (pb_int64_t)value; + else + svalue = (int32_t)value; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t*)dest = svalue; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t*)dest = (int32_t)svalue; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t*)dest = (int_least16_t)svalue; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t*)dest = (int_least8_t)svalue; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != svalue) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + pb_uint64_t value, clamped; + if (!pb_decode_varint(stream, &value)) + return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_uint64_t)) + clamped = *(pb_uint64_t*)dest = value; + else if (field->data_size == sizeof(uint32_t)) + clamped = *(uint32_t*)dest = (uint32_t)value; + else if (field->data_size == sizeof(uint_least16_t)) + clamped = *(uint_least16_t*)dest = (uint_least16_t)value; + else if (field->data_size == sizeof(uint_least8_t)) + clamped = *(uint_least8_t*)dest = (uint_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + pb_int64_t value, clamped; + if (!pb_decode_svarint(stream, &value)) + return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t*)dest = value; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t*)dest = (int32_t)value; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t*)dest = (int_least16_t)value; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t*)dest = (int_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + PB_UNUSED(field); + return pb_decode_fixed32(stream, dest); +} + +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + PB_UNUSED(field); +#ifndef PB_WITHOUT_64BIT + return pb_decode_fixed64(stream, dest); +#else + PB_UNUSED(dest); + PB_RETURN_ERROR(stream, "no 64bit support"); +#endif +} + +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + size_t alloc_size; + pb_bytes_array_t *bdest; + + if (!pb_decode_varint32(stream, &size)) + return false; + + if (size > PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "bytes overflow"); + + alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); + if (size > alloc_size) + PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (stream->bytes_left < size) + PB_RETURN_ERROR(stream, "end-of-stream"); + + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + bdest = *(pb_bytes_array_t**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "bytes overflow"); + bdest = (pb_bytes_array_t*)dest; + } + + bdest->size = (pb_size_t)size; + return pb_read(stream, bdest->bytes, size); +} + +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + size_t alloc_size; + bool status; + if (!pb_decode_varint32(stream, &size)) + return false; + + /* Space for null terminator */ + alloc_size = size + 1; + + if (alloc_size < size) + PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (stream->bytes_left < size) + PB_RETURN_ERROR(stream, "end-of-stream"); + + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + dest = *(void**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "string overflow"); + } + + status = pb_read(stream, (pb_byte_t*)dest, size); + *((pb_byte_t*)dest + size) = 0; + return status; +} + +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + bool status; + pb_istream_t substream; + const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + /* New array entries need to be initialized, while required and optional + * submessages have already been initialized in the top-level pb_decode. */ + if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) + status = pb_decode(&substream, submsg_fields, dest); + else + status = pb_decode_noinit(&substream, submsg_fields, dest); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + + if (!pb_decode_varint32(stream, &size)) + return false; + + if (size > PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "bytes overflow"); + + if (size == 0) + { + /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */ + memset(dest, 0, field->data_size); + return true; + } + + if (size != field->data_size) + PB_RETURN_ERROR(stream, "incorrect fixed length bytes size"); + + return pb_read(stream, (pb_byte_t*)dest, field->data_size); +} diff --git a/frontend/ios/Pods/nanopb/pb_decode.h b/frontend/ios/Pods/nanopb/pb_decode.h new file mode 100644 index 0000000..3577c20 --- /dev/null +++ b/frontend/ios/Pods/nanopb/pb_decode.h @@ -0,0 +1,178 @@ +/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c. + * The main function is pb_decode. You also need an input stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef PB_DECODE_H_INCLUDED +#define PB_DECODE_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom input streams. You will need to provide + * a callback function to read the bytes from your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause decoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer), + * and rely on pb_read to verify that no-body reads past bytes_left. + * 3) Your callback may be used with substreams, in which case bytes_left + * is different than from the main stream. Don't use bytes_left to compute + * any pointers. + */ +struct pb_istream_s +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + */ + int *callback; +#else + bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count); +#endif + + void *state; /* Free field for use by callback implementation */ + size_t bytes_left; + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main decoding functions * + ***************************/ + +/* Decode a single protocol buffers message from input stream into a C structure. + * Returns true on success, false on any failure. + * The actual struct pointed to by dest must match the description in fields. + * Callback fields of the destination structure must be initialized by caller. + * All other fields will be initialized by this function. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_istream_t stream; + * + * // ... read some data into buffer ... + * + * stream = pb_istream_from_buffer(buffer, count); + * pb_decode(&stream, MyMessage_fields, &msg); + */ +bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except does not initialize the destination structure + * to default values. This is slightly faster if you need no default values + * and just do memset(struct, 0, sizeof(struct)) yourself. + * + * This can also be used for 'merging' two messages, i.e. update only the + * fields that exist in the new message. + * + * Note: If this function returns with an error, it will not release any + * dynamically allocated fields. You will need to call pb_release() yourself. + */ +bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except expects the stream to start with the message size + * encoded as varint. Corresponds to parseDelimitedFrom() in Google's + * protobuf API. + */ +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode_delimited, except that it does not initialize the destination structure. + * See pb_decode_noinit + */ +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except allows the message to be terminated with a null byte. + * NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. This behaviour + * is not supported in most other protobuf implementations, so pb_decode_delimited() + * is a better option for compatibility. + */ +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +#ifdef PB_ENABLE_MALLOC +/* Release any allocated pointer fields. If you use dynamic allocation, you should + * call this for any successfully decoded message when you are done with it. If + * pb_decode() returns with an error, the message is already released. + */ +void pb_release(const pb_field_t fields[], void *dest_struct); +#endif + + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an input stream for reading from a memory buffer. + * + * Alternatively, you can use a custom stream that reads directly from e.g. + * a file or a network socket. + */ +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize); + +/* Function to read from a pb_istream_t. You can use this if you need to + * read some custom header data, or to read data in field callbacks. + */ +bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Decode the tag for the next field in the stream. Gives the wire type and + * field tag. At end of the message, returns false and sets eof to true. */ +bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof); + +/* Skip the field payload data, given the wire type. */ +bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); + +/* Decode an integer in the varint format. This works for enum, int32, + * int64, uint32 and uint64 field types. */ +#ifndef PB_WITHOUT_64BIT +bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); +#else +#define pb_decode_varint pb_decode_varint32 +#endif + +/* Decode an integer in the varint format. This works for enum, int32, + * and uint32 field types. */ +bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); + +/* Decode a bool value in varint format. */ +bool pb_decode_bool(pb_istream_t *stream, bool *dest); + +/* Decode an integer in the zig-zagged svarint format. This works for sint32 + * and sint64. */ +#ifndef PB_WITHOUT_64BIT +bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest); +#else +bool pb_decode_svarint(pb_istream_t *stream, int32_t *dest); +#endif + +/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to + * a 4-byte wide C variable. */ +bool pb_decode_fixed32(pb_istream_t *stream, void *dest); + +#ifndef PB_WITHOUT_64BIT +/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to + * a 8-byte wide C variable. */ +bool pb_decode_fixed64(pb_istream_t *stream, void *dest); +#endif + +/* Make a limited-length substream for reading a PB_WT_STRING field. */ +bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream); +bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/frontend/ios/Pods/nanopb/pb_encode.c b/frontend/ios/Pods/nanopb/pb_encode.c new file mode 100644 index 0000000..f6e60c4 --- /dev/null +++ b/frontend/ios/Pods/nanopb/pb_encode.c @@ -0,0 +1,911 @@ +/* pb_encode.c -- encode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +#include "pb.h" +#include "pb_encode.h" +#include "pb_common.h" + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +/************************************** + * Declarations internal to this file * + **************************************/ +typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn; + +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func); +static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); +static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static void *pb_const_cast(const void *p); +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); + +#ifdef PB_WITHOUT_64BIT +#define pb_int64_t int32_t +#define pb_uint64_t uint32_t + +static bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value); +#else +#define pb_int64_t int64_t +#define pb_uint64_t uint64_t +#endif + +/* --- Function pointers to field encoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { + &pb_enc_bool, + &pb_enc_varint, + &pb_enc_uvarint, + &pb_enc_svarint, + &pb_enc_fixed32, + &pb_enc_fixed64, + + &pb_enc_bytes, + &pb_enc_string, + &pb_enc_submessage, + NULL, /* extensions */ + &pb_enc_fixed_length_bytes +}; + +/******************************* + * pb_ostream_t implementation * + *******************************/ + +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) +{ + size_t i; + pb_byte_t *dest = (pb_byte_t*)stream->state; + stream->state = dest + count; + + for (i = 0; i < count; i++) + dest[i] = buf[i]; + + return true; +} + +pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize) +{ + pb_ostream_t stream; +#ifdef PB_BUFFER_ONLY + stream.callback = (void*)1; /* Just a marker value */ +#else + stream.callback = &buf_write; +#endif + stream.state = buf; + stream.max_size = bufsize; + stream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) +{ + if (count > 0 && stream->callback != NULL) + { + if (stream->bytes_written + count < stream->bytes_written || + stream->bytes_written + count > stream->max_size) + { + PB_RETURN_ERROR(stream, "stream full"); + } + +#ifdef PB_BUFFER_ONLY + if (!buf_write(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#endif + } + + stream->bytes_written += count; + return true; +} + +/************************* + * Encode a single field * + *************************/ + +/* Read a bool value without causing undefined behavior even if the value + * is invalid. See issue #434 and + * https://stackoverflow.com/questions/27661768/weird-results-for-conditional + */ +static bool safe_read_bool(const void *pSize) +{ + const char *p = (const char *)pSize; + size_t i; + for (i = 0; i < sizeof(bool); i++) + { + if (p[i] != 0) + return true; + } + return false; +} + +/* Encode a static array. Handles the size calculations and possible packing. */ +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, + const void *pData, size_t count, pb_encoder_t func) +{ + size_t i; + const void *p; +#ifndef PB_ENCODE_ARRAYS_UNPACKED + size_t size; +#endif + + if (count == 0) + return true; + + if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) + PB_RETURN_ERROR(stream, "array max size exceeded"); + +#ifndef PB_ENCODE_ARRAYS_UNPACKED + /* We always pack arrays if the datatype allows it. */ + if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) + { + if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) + return false; + + /* Determine the total size of packed array. */ + if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) + { + size = 4 * count; + } + else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) + { + size = 8 * count; + } + else + { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + p = pData; + for (i = 0; i < count; i++) + { + if (!func(&sizestream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + size = sizestream.bytes_written; + } + + if (!pb_encode_varint(stream, (pb_uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing.. */ + + /* Write the data */ + p = pData; + for (i = 0; i < count; i++) + { + if (!func(stream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + } + else +#endif + { + p = pData; + for (i = 0; i < count; i++) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + /* Normally the data is stored directly in the array entries, but + * for pointer-type string and bytes fields, the array entries are + * actually pointers themselves also. So we have to dereference once + * more to get to the actual data. */ + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && + (PB_LTYPE(field->type) == PB_LTYPE_STRING || + PB_LTYPE(field->type) == PB_LTYPE_BYTES)) + { + if (!func(stream, field, *(const void* const*)p)) + return false; + } + else + { + if (!func(stream, field, p)) + return false; + } + p = (const char*)p + field->data_size; + } + } + + return true; +} + +/* In proto3, all fields are optional and are only encoded if their value is "non-zero". + * This function implements the check for the zero value. */ +static bool pb_check_proto3_default_value(const pb_field_t *field, const void *pData) +{ + pb_type_t type = field->type; + const void *pSize = (const char*)pData + field->size_offset; + + if (PB_HTYPE(type) == PB_HTYPE_REQUIRED) + { + /* Required proto2 fields inside proto3 submessage, pretty rare case */ + return false; + } + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + /* Repeated fields inside proto3 submessage: present if count != 0 */ + if (field->size_offset != 0) + return *(const pb_size_t*)pSize == 0; + else if (PB_ATYPE(type) == PB_ATYPE_STATIC) + return false; /* Fixed length array */ + } + else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + /* Oneof fields */ + return *(const pb_size_t*)pSize == 0; + } + else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset != 0) + { + /* Proto2 optional fields inside proto3 submessage */ + return safe_read_bool(pSize) == false; + } + + /* Rest is proto3 singular fields */ + + if (PB_ATYPE(type) == PB_ATYPE_STATIC) + { + if (PB_LTYPE(type) == PB_LTYPE_BYTES) + { + const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData; + return bytes->size == 0; + } + else if (PB_LTYPE(type) == PB_LTYPE_STRING) + { + return *(const char*)pData == '\0'; + } + else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES) + { + /* Fixed length bytes is only empty if its length is fixed + * as 0. Which would be pretty strange, but we can check + * it anyway. */ + return field->data_size == 0; + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Check all fields in the submessage to find if any of them + * are non-zero. The comparison cannot be done byte-per-byte + * because the C struct may contain padding bytes that must + * be skipped. + */ + pb_field_iter_t iter; + if (pb_field_iter_begin(&iter, (const pb_field_t*)field->ptr, pb_const_cast(pData))) + { + do + { + if (!pb_check_proto3_default_value(iter.pos, iter.pData)) + { + return false; + } + } while (pb_field_iter_next(&iter)); + } + return true; + } + } + + /* Compares pointers to NULL in case of FT_POINTER */ + if (PB_ATYPE(type) == PB_ATYPE_POINTER && PB_LTYPE(type) > PB_LTYPE_LAST_PACKABLE) + { + return !*(const void**)((uintptr_t)pData); + } + + { + /* Catch-all branch that does byte-per-byte comparison for zero value. + * + * This is for all pointer fields, and for static PB_LTYPE_VARINT, + * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also + * callback fields. These all have integer or pointer value which + * can be compared with 0. + */ + pb_size_t i; + const char *p = (const char*)pData; + for (i = 0; i < field->data_size; i++) + { + if (p[i] != 0) + { + return false; + } + } + + return true; + } +} + +/* Encode a field with static or pointer allocation, i.e. one whose data + * is available to the encoder directly. */ +static bool checkreturn encode_basic_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + pb_encoder_t func; + bool implicit_has; + const void *pSize = &implicit_has; + + func = PB_ENCODERS[PB_LTYPE(field->type)]; + + if (field->size_offset) + { + /* Static optional, repeated or oneof field */ + pSize = (const char*)pData + field->size_offset; + } + else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL) + { + /* Proto3 style field, optional but without explicit has_ field. */ + implicit_has = !pb_check_proto3_default_value(field, pData); + } + else + { + /* Required field, always present */ + implicit_has = true; + } + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* pData is a pointer to the field, which contains pointer to + * the data. If the 2nd pointer is NULL, it is interpreted as if + * the has_field was false. + */ + pData = *(const void* const*)pData; + implicit_has = (pData != NULL); + } + + switch (PB_HTYPE(field->type)) + { + case PB_HTYPE_REQUIRED: + if (!pData) + PB_RETURN_ERROR(stream, "missing required field"); + if (!pb_encode_tag_for_field(stream, field)) + return false; + if (!func(stream, field, pData)) + return false; + break; + + case PB_HTYPE_OPTIONAL: + if (safe_read_bool(pSize)) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + if (!func(stream, field, pData)) + return false; + } + break; + + case PB_HTYPE_REPEATED: { + pb_size_t count; + if (field->size_offset != 0) { + count = *(const pb_size_t*)pSize; + } else { + count = field->array_size; + } + if (!encode_array(stream, field, pData, count, func)) + return false; + break; + } + + case PB_HTYPE_ONEOF: + if (*(const pb_size_t*)pSize == field->tag) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + if (!func(stream, field, pData)) + return false; + } + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return true; +} + +/* Encode a field with callback semantics. This means that a user function is + * called to provide and encode the actual data. */ +static bool checkreturn encode_callback_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_callback_t *callback = (const pb_callback_t*)pData; + +#ifdef PB_OLD_CALLBACK_STYLE + const void *arg = callback->arg; +#else + void * const *arg = &(callback->arg); +#endif + + if (callback->funcs.encode != NULL) + { + if (!callback->funcs.encode(stream, field, arg)) + PB_RETURN_ERROR(stream, "callback error"); + } + return true; +} + +/* Encode a single field of any callback or static type. */ +static bool checkreturn encode_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + switch (PB_ATYPE(field->type)) + { + case PB_ATYPE_STATIC: + case PB_ATYPE_POINTER: + return encode_basic_field(stream, field, pData); + + case PB_ATYPE_CALLBACK: + return encode_callback_field(stream, field, pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +/* Default handler for extension fields. Expects to have a pb_field_t + * pointer in the extension->type->arg field. */ +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, + const pb_extension_t *extension) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + return encode_field(stream, field, &extension->dest); + } + else + { + return encode_field(stream, field, extension->dest); + } +} + +/* Walk through all the registered extensions and give them a chance + * to encode themselves. */ +static bool checkreturn encode_extension_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_extension_t *extension = *(const pb_extension_t* const *)pData; + PB_UNUSED(field); + + while (extension) + { + bool status; + if (extension->type->encode) + status = extension->type->encode(stream, extension); + else + status = default_extension_encoder(stream, extension); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/********************* + * Encode all fields * + *********************/ + +static void *pb_const_cast(const void *p) +{ + /* Note: this casts away const, in order to use the common field iterator + * logic for both encoding and decoding. */ + union { + void *p1; + const void *p2; + } t; + t.p2 = p; + return t.p1; +} + +bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + pb_field_iter_t iter; + if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct))) + return true; /* Empty message type */ + + do { + if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) + { + /* Special case for the extension field placeholder */ + if (!encode_extension_field(stream, iter.pos, iter.pData)) + return false; + } + else + { + /* Regular field */ + if (!encode_field(stream, iter.pos, iter.pData)) + return false; + } + } while (pb_field_iter_next(&iter)); + + return true; +} + +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + return pb_encode_submessage(stream, fields, src_struct); +} + +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + const pb_byte_t zero = 0; + + if (!pb_encode(stream, fields, src_struct)) + return false; + + return pb_write(stream, &zero, 1); +} + +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) +{ + pb_ostream_t stream = PB_OSTREAM_SIZING; + + if (!pb_encode(&stream, fields, src_struct)) + return false; + + *size = stream.bytes_written; + return true; +} + +/******************** + * Helper functions * + ********************/ + +#ifdef PB_WITHOUT_64BIT +bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value) +{ + pb_byte_t buffer[10]; + size_t i = 0; + size_t compensation = 32;/* we need to compensate 32 bits all set to 1 */ + + while (value) + { + buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); + value >>= 7; + if (compensation) + { + /* re-set all the compensation bits we can or need */ + size_t bits = compensation > 7 ? 7 : compensation; + value ^= (pb_uint64_t)((0xFFu >> (8 - bits)) << 25); /* set the number of bits needed on the lowest of the most significant 7 bits */ + compensation -= bits; + } + i++; + } + buffer[i - 1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); +} +#endif + +bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value) +{ + pb_byte_t buffer[10]; + size_t i = 0; + + if (value <= 0x7F) + { + pb_byte_t v = (pb_byte_t)value; + return pb_write(stream, &v, 1); + } + + while (value) + { + buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); + value >>= 7; + i++; + } + buffer[i-1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); +} + +bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value) +{ + pb_uint64_t zigzagged; + if (value < 0) + zigzagged = ~((pb_uint64_t)value << 1); + else + zigzagged = (pb_uint64_t)value << 1; + + return pb_encode_varint(stream, zigzagged); +} + +bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) +{ + uint32_t val = *(const uint32_t*)value; + pb_byte_t bytes[4]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + return pb_write(stream, bytes, 4); +} + +#ifndef PB_WITHOUT_64BIT +bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) +{ + uint64_t val = *(const uint64_t*)value; + pb_byte_t bytes[8]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + bytes[4] = (pb_byte_t)((val >> 32) & 0xFF); + bytes[5] = (pb_byte_t)((val >> 40) & 0xFF); + bytes[6] = (pb_byte_t)((val >> 48) & 0xFF); + bytes[7] = (pb_byte_t)((val >> 56) & 0xFF); + return pb_write(stream, bytes, 8); +} +#endif + +bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) +{ + pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype; + return pb_encode_varint(stream, tag); +} + +bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field) +{ + pb_wire_type_t wiretype; + switch (PB_LTYPE(field->type)) + { + case PB_LTYPE_BOOL: + case PB_LTYPE_VARINT: + case PB_LTYPE_UVARINT: + case PB_LTYPE_SVARINT: + wiretype = PB_WT_VARINT; + break; + + case PB_LTYPE_FIXED32: + wiretype = PB_WT_32BIT; + break; + + case PB_LTYPE_FIXED64: + wiretype = PB_WT_64BIT; + break; + + case PB_LTYPE_BYTES: + case PB_LTYPE_STRING: + case PB_LTYPE_SUBMESSAGE: + case PB_LTYPE_FIXED_LENGTH_BYTES: + wiretype = PB_WT_STRING; + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return pb_encode_tag(stream, wiretype, field->tag); +} + +bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size) +{ + if (!pb_encode_varint(stream, (pb_uint64_t)size)) + return false; + + return pb_write(stream, buffer, size); +} + +bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + /* First calculate the message size using a non-writing substream. */ + pb_ostream_t substream = PB_OSTREAM_SIZING; + size_t size; + bool status; + + if (!pb_encode(&substream, fields, src_struct)) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + return false; + } + + size = substream.bytes_written; + + if (!pb_encode_varint(stream, (pb_uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing */ + + if (stream->bytes_written + size > stream->max_size) + PB_RETURN_ERROR(stream, "stream full"); + + /* Use a substream to verify that a callback doesn't write more than + * what it did the first time. */ + substream.callback = stream->callback; + substream.state = stream->state; + substream.max_size = size; + substream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + substream.errmsg = NULL; +#endif + + status = pb_encode(&substream, fields, src_struct); + + stream->bytes_written += substream.bytes_written; + stream->state = substream.state; +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + + if (substream.bytes_written != size) + PB_RETURN_ERROR(stream, "submsg size changed"); + + return status; +} + +/* Field encoders */ + +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + uint32_t value = safe_read_bool(src) ? 1 : 0; + PB_UNUSED(field); + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + pb_int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t*)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t*)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t*)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + +#ifdef PB_WITHOUT_64BIT + if (value < 0) + return pb_encode_negative_varint(stream, (pb_uint64_t)value); + else +#endif + return pb_encode_varint(stream, (pb_uint64_t)value); +} + +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + pb_uint64_t value = 0; + + if (field->data_size == sizeof(uint_least8_t)) + value = *(const uint_least8_t*)src; + else if (field->data_size == sizeof(uint_least16_t)) + value = *(const uint_least16_t*)src; + else if (field->data_size == sizeof(uint32_t)) + value = *(const uint32_t*)src; + else if (field->data_size == sizeof(pb_uint64_t)) + value = *(const pb_uint64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + pb_int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t*)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t*)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t*)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_svarint(stream, value); +} + +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + PB_UNUSED(field); +#ifndef PB_WITHOUT_64BIT + return pb_encode_fixed64(stream, src); +#else + PB_UNUSED(src); + PB_RETURN_ERROR(stream, "no 64bit support"); +#endif +} + +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + PB_UNUSED(field); + return pb_encode_fixed32(stream, src); +} + +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + const pb_bytes_array_t *bytes = NULL; + + bytes = (const pb_bytes_array_t*)src; + + if (src == NULL) + { + /* Treat null pointer as an empty bytes field */ + return pb_encode_string(stream, NULL, 0); + } + + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && + bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) + { + PB_RETURN_ERROR(stream, "bytes size exceeded"); + } + + return pb_encode_string(stream, bytes->bytes, bytes->size); +} + +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + size_t size = 0; + size_t max_size = field->data_size; + const char *p = (const char*)src; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + max_size = (size_t)-1; + + if (src == NULL) + { + size = 0; /* Treat null pointer as an empty string */ + } + else + { + /* strnlen() is not always available, so just use a loop */ + while (size < max_size && *p != '\0') + { + size++; + p++; + } + } + + return pb_encode_string(stream, (const pb_byte_t*)src, size); +} + +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src); +} + +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size); +} + diff --git a/frontend/ios/Pods/nanopb/pb_encode.h b/frontend/ios/Pods/nanopb/pb_encode.h new file mode 100644 index 0000000..b1d822f --- /dev/null +++ b/frontend/ios/Pods/nanopb/pb_encode.h @@ -0,0 +1,170 @@ +/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c. + * The main function is pb_encode. You also need an output stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef PB_ENCODE_H_INCLUDED +#define PB_ENCODE_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom output streams. You will need to provide + * a callback function to write the bytes to your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause encoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer). + * 3) pb_write will update bytes_written after your callback runs. + * 4) Substreams will modify max_size and bytes_written. Don't use them + * to calculate any pointers. + */ +struct pb_ostream_s +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + * Also, NULL pointer marks a 'sizing stream' that does not + * write anything. + */ + int *callback; +#else + bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); +#endif + void *state; /* Free field for use by callback implementation. */ + size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ + size_t bytes_written; /* Number of bytes written so far. */ + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main encoding functions * + ***************************/ + +/* Encode a single protocol buffers message from C structure into a stream. + * Returns true on success, false on any failure. + * The actual struct pointed to by src_struct must match the description in fields. + * All required fields in the struct are assumed to have been filled in. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_ostream_t stream; + * + * msg.field1 = 42; + * stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + * pb_encode(&stream, MyMessage_fields, &msg); + */ +bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Same as pb_encode, but prepends the length of the message as a varint. + * Corresponds to writeDelimitedTo() in Google's protobuf API. + */ +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Same as pb_encode, but appends a null byte to the message for termination. + * NOTE: This behaviour is not supported in most other protobuf implementations, so pb_encode_delimited() + * is a better option for compatibility. + */ +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Encode the message to get the size of the encoded data, but do not store + * the data. */ +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an output stream for writing into a memory buffer. + * The number of bytes written can be found in stream.bytes_written after + * encoding the message. + * + * Alternatively, you can use a custom stream that writes directly to e.g. + * a file or a network socket. + */ +pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize); + +/* Pseudo-stream for measuring the size of a message without actually storing + * the encoded data. + * + * Example usage: + * MyMessage msg = {}; + * pb_ostream_t stream = PB_OSTREAM_SIZING; + * pb_encode(&stream, MyMessage_fields, &msg); + * printf("Message size is %d\n", stream.bytes_written); + */ +#ifndef PB_NO_ERRMSG +#define PB_OSTREAM_SIZING {0,0,0,0,0} +#else +#define PB_OSTREAM_SIZING {0,0,0,0} +#endif + +/* Function to write into a pb_ostream_t stream. You can use this if you need + * to append or prepend some custom headers to the message. + */ +bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Encode field header based on type and field number defined in the field + * structure. Call this from the callback before writing out field contents. */ +bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field); + +/* Encode field header by manually specifying wire type. You need to use this + * if you want to write out packed arrays from a callback field. */ +bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); + +/* Encode an integer in the varint format. + * This works for bool, enum, int32, int64, uint32 and uint64 field types. */ +#ifndef PB_WITHOUT_64BIT +bool pb_encode_varint(pb_ostream_t *stream, uint64_t value); +#else +bool pb_encode_varint(pb_ostream_t *stream, uint32_t value); +#endif + +/* Encode an integer in the zig-zagged svarint format. + * This works for sint32 and sint64. */ +#ifndef PB_WITHOUT_64BIT +bool pb_encode_svarint(pb_ostream_t *stream, int64_t value); +#else +bool pb_encode_svarint(pb_ostream_t *stream, int32_t value); +#endif + +/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ +bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size); + +/* Encode a fixed32, sfixed32 or float value. + * You need to pass a pointer to a 4-byte wide C variable. */ +bool pb_encode_fixed32(pb_ostream_t *stream, const void *value); + +#ifndef PB_WITHOUT_64BIT +/* Encode a fixed64, sfixed64 or double value. + * You need to pass a pointer to a 8-byte wide C variable. */ +bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); +#endif + +/* Encode a submessage field. + * You need to pass the pb_field_t array and pointer to struct, just like + * with pb_encode(). This internally encodes the submessage twice, first to + * calculate message size and then to actually write it out. + */ +bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/frontend/ios/Pods/nanopb/spm_resources/PrivacyInfo.xcprivacy b/frontend/ios/Pods/nanopb/spm_resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..72e00ac --- /dev/null +++ b/frontend/ios/Pods/nanopb/spm_resources/PrivacyInfo.xcprivacy @@ -0,0 +1,15 @@ + + + + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + + diff --git a/frontend/ios/Runner.xcodeproj/project.pbxproj b/frontend/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1e53225 --- /dev/null +++ b/frontend/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,746 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 67F1F235865D41A8AC041331 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62E7CF9BBFC5EE1542832891 /* Pods_RunnerTests.framework */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + C8E68B25785E14B7EC8281D7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAB97F8AE2516CEA9D2CBE82 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 62BE2AF662A3DA048C5A2743 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 62E7CF9BBFC5EE1542832891 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 8355CFCCC8D3B7D7D44F9496 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 83E289D0077BBD097DD0C1A9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + ABBD770F1CE3DBD688BC9D28 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + D072D449FF26B78F521EB1DD /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + EAB97F8AE2516CEA9D2CBE82 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + FE38EA114836D3510C2E29D6 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 37CB58D838F221DF2F7793F4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 67F1F235865D41A8AC041331 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C8E68B25785E14B7EC8281D7 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1D556364884FA141A357534F /* Frameworks */ = { + isa = PBXGroup; + children = ( + EAB97F8AE2516CEA9D2CBE82 /* Pods_Runner.framework */, + 62E7CF9BBFC5EE1542832891 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 7BB045AB70CB4278220F2375 /* Pods */ = { + isa = PBXGroup; + children = ( + ABBD770F1CE3DBD688BC9D28 /* Pods-Runner.debug.xcconfig */, + 83E289D0077BBD097DD0C1A9 /* Pods-Runner.release.xcconfig */, + FE38EA114836D3510C2E29D6 /* Pods-Runner.profile.xcconfig */, + 62BE2AF662A3DA048C5A2743 /* Pods-RunnerTests.debug.xcconfig */, + D072D449FF26B78F521EB1DD /* Pods-RunnerTests.release.xcconfig */, + 8355CFCCC8D3B7D7D44F9496 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + 7BB045AB70CB4278220F2375 /* Pods */, + 1D556364884FA141A357534F /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + DDB6D5790E411E8FE8FF65B5 /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + 37CB58D838F221DF2F7793F4 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 2C15F4A9DE85EC80718098C0 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 74C368189A1BE97070672D34 /* [CP] Embed Pods Frameworks */, + B4F28619E97ED39F39498BCC /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2C15F4A9DE85EC80718098C0 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 74C368189A1BE97070672D34 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + B4F28619E97ED39F39498BCC /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + DDB6D5790E411E8FE8FF65B5 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 62BE2AF662A3DA048C5A2743 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D072D449FF26B78F521EB1DD /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8355CFCCC8D3B7D7D44F9496 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/frontend/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/frontend/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/frontend/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/frontend/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/frontend/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..e3773d4 --- /dev/null +++ b/frontend/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Runner.xcworkspace/contents.xcworkspacedata b/frontend/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/frontend/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/frontend/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/frontend/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/frontend/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/frontend/ios/Runner/AppDelegate.swift b/frontend/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..6266644 --- /dev/null +++ b/frontend/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..7353c41 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..6ed2d93 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cd7b00 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..fe73094 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..321773c Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..502f463 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..e9f5fea Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..84ac32a Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..8953cba Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..0467bf1 Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/frontend/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/frontend/ios/Runner/Base.lproj/LaunchScreen.storyboard b/frontend/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/frontend/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Runner/Base.lproj/Main.storyboard b/frontend/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/frontend/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/ios/Runner/GeneratedPluginRegistrant.h b/frontend/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 0000000..7a89092 --- /dev/null +++ b/frontend/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/frontend/ios/Runner/GeneratedPluginRegistrant.m b/frontend/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 0000000..efe65ec --- /dev/null +++ b/frontend/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#import "GeneratedPluginRegistrant.h" + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { +} + +@end diff --git a/frontend/ios/Runner/GoogleService-Info.plist b/frontend/ios/Runner/GoogleService-Info.plist new file mode 100644 index 0000000..ed15c41 --- /dev/null +++ b/frontend/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,30 @@ + + + + + API_KEY + AIzaSyAYs3bpt4mcglJvZaQXFc6eha2FCVZf72Y + GCM_SENDER_ID + 120799260544 + PLIST_VERSION + 1 + BUNDLE_ID + com.gradi.gradiFrontend + PROJECT_ID + gradi-bd52c + STORAGE_BUCKET + gradi-bd52c.firebasestorage.app + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:120799260544:ios:6dba36b595142ec0b19b65 + + \ No newline at end of file diff --git a/frontend/ios/Runner/Info.plist b/frontend/ios/Runner/Info.plist new file mode 100644 index 0000000..93950eb --- /dev/null +++ b/frontend/ios/Runner/Info.plist @@ -0,0 +1,59 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Gradi Frontend + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + gradi_frontend + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + NSPhotoLibraryUsageDescription + ํ•™์Šต ๋ฌธ์ œ๋ฅผ ์—…๋กœ๋“œํ•˜๊ธฐ ์œ„ํ•ด ๊ฐค๋Ÿฌ๋ฆฌ ์ ‘๊ทผ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. + NSCameraUsageDescription + ํ•™์Šต ๋ฌธ์ œ๋ฅผ ์ดฌ์˜ํ•˜๊ธฐ ์œ„ํ•ด ์นด๋ฉ”๋ผ ์ ‘๊ทผ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. + NSLocationWhenInUseUsageDescription + ๊ทผ์ฒ˜ ํ•™์›์„ ์ฐพ๊ธฐ ์œ„ํ•ด ์œ„์น˜ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. + NSLocationAlwaysUsageDescription + ๊ทผ์ฒ˜ ํ•™์›์„ ์ฐพ๊ธฐ ์œ„ํ•ด ์œ„์น˜ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. + FirebaseAppDelegateProxyEnabled + + + diff --git a/frontend/ios/Runner/Runner-Bridging-Header.h b/frontend/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/frontend/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/frontend/ios/RunnerTests/RunnerTests.swift b/frontend/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/frontend/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/frontend/lib/application/explanation/explanation_service.dart b/frontend/lib/application/explanation/explanation_service.dart new file mode 100644 index 0000000..43405c8 --- /dev/null +++ b/frontend/lib/application/explanation/explanation_service.dart @@ -0,0 +1,147 @@ +import '../../domain/explanation/explanation_entity.dart'; +import '../../domain/explanation/explanation_repository.dart'; +import '../../domain/explanation/explanation_source.dart'; +import '../../domain/explanation/get_explanation_use_case.dart'; +import '../../domain/explanation/request_explanation_use_case.dart'; +import '../../services/auth_service.dart'; +import '../../services/academy_service.dart'; +import '../../utils/app_logger.dart'; + +/// ํ•ด์„ค ์กฐํšŒ/์ƒ์„ฑ ๊ฒฐ๊ณผ +class ExplanationLoadResult { + final ExplanationEntity? explanation; + final bool requestPerformed; + + const ExplanationLoadResult({ + required this.explanation, + required this.requestPerformed, + }); +} + +/// ํ•ด์„ค ์กฐํšŒ/์ƒ์„ฑ ํ๋ฆ„์„ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ํ•˜๋Š” Application Service +class ExplanationService { + final ExplanationRepository _repository; + final GetExplanationUseCase _getExplanationUseCase; + final RequestExplanationUseCase _requestExplanationUseCase; + final AuthService _authService; + final AcademyService _academyService; + + ExplanationService({ + required ExplanationRepository repository, + required GetExplanationUseCase getExplanationUseCase, + required RequestExplanationUseCase requestExplanationUseCase, + required AuthService authService, + required AcademyService academyService, + }) : _repository = repository, + _getExplanationUseCase = getExplanationUseCase, + _requestExplanationUseCase = requestExplanationUseCase, + _authService = authService, + _academyService = academyService; + + /// ์ด๋ฏธ ์ƒ์„ฑ๋œ ํ•ด์„ค๋งŒ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. + /// + /// ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด null์„ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, POST ์š”์ฒญ์€ ์ ˆ๋Œ€ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + Future loadExistingExplanation( + ExplanationSource source, + ) async { + return _getExplanationUseCase(source); + } + + /// ํ•ด์„ค์„ ๋ถˆ๋Ÿฌ์˜ค๊ฑฐ๋‚˜, ์—†์œผ๋ฉด ์ƒ์„ฑ ์š”์ฒญ ํ›„ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. + /// + /// [ExplanationLoadResult.requestPerformed]๊ฐ€ true์ด๋ฉด + /// ์ด๋ฒˆ ํ˜ธ์ถœ์—์„œ ์‹ค์ œ๋กœ POST ์š”์ฒญ์ด ์ˆ˜ํ–‰๋˜์—ˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. + /// + /// ํ๋ฆ„: + /// 1. GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) - 404/400์ด์–ด๋„ ๊ณ„์† ์ง„ํ–‰ + /// 2. GET (์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ) + /// 3. POST (ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ) + /// 4. GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) + Future loadOrRequestExplanation( + ExplanationSource source, + ) async { + appLog('[explanation] ========== ํ•ด์„ค ์š”์ฒญ ํ๋ฆ„ ์‹œ์ž‘ =========='); + appLog( + '[explanation] source: studentResponseId=${source.studentResponseId}, academyUserId=${source.academyUserId}, question=${source.question.questionNumber}, subQuestion=${source.question.subQuestionNumber}', + ); + + // 1) ์บ์‹œ/๊ธฐ์กด ํ•ด์„ค ์กฐํšŒ (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) + // 404/400์ด์–ด๋„ null์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๊ณ„์† ์ง„ํ–‰ + appLog('[explanation] [1/4] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) ์‹œ์ž‘'); + final existing = await _getExplanationUseCase(source); + + if (existing != null) { + appLog( + '[explanation] [1/4] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) ์™„๋ฃŒ: ํ•ด์„ค ์กด์žฌ, POST ์ƒ๋žต', + ); + appLog('[explanation] ========== ํ•ด์„ค ์š”์ฒญ ํ๋ฆ„ ์ข…๋ฃŒ (๊ธฐ์กด ํ•ด์„ค ๋ฐ˜ํ™˜) =========='); + return ExplanationLoadResult( + explanation: existing, + requestPerformed: false, + ); + } + + appLog( + '[explanation] [1/4] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) ์™„๋ฃŒ: ํ•ด์„ค ์—†์Œ (404/400), ๋‹ค์Œ ๋‹จ๊ณ„ ์ง„ํ–‰', + ); + + // 2) ํ•™์ƒ ๋‹ต์•ˆ ์ •๋ณด ์กฐํšŒ (์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ) + // ์ฒซ ๋ฒˆ์งธ GET์—์„œ 404/400์ด ๋‚˜์™”์–ด๋„ ์ •์ƒ์ ์œผ๋กœ ์ง„ํ–‰ + appLog('[explanation] [2/4] GET (์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ) ์‹œ์ž‘'); + final studentAnswerInfo = await _repository.findStudentAnswer(source); + appLog( + '[explanation] [2/4] GET (์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ) ์™„๋ฃŒ: answer=${studentAnswerInfo.answer}', + ); + + // 3) ์š”์ฒญ์ž ID ํ™•๋ณด + final userIdStr = await _authService.getUserId(); + if (userIdStr == null) { + throw Exception('์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด ์ฃผ์„ธ์š”.'); + } + final userId = int.tryParse(userIdStr) ?? 0; + if (userId == 0) { + throw Exception('์œ ํšจํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž ID์ž…๋‹ˆ๋‹ค.'); + } + + // 4) academyId ๊ฐ€์ ธ์˜ค๊ธฐ (ํ•™์› ๋ชฉ๋ก์—์„œ academyUserId๋กœ ์ฐพ๊ธฐ) + final academies = await _academyService.loadAcademiesFromCache(); + if (academies == null || academies.isEmpty) { + throw Exception('ํ•™์› ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + final academy = academies.firstWhere( + (a) => a.academy_user_id == source.academyUserId, + orElse: () => academies.first, + ); + + final academyId = academy.academy_id; + if (academyId == null) { + throw Exception('ํ•™์› ID๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + appLog( + '[explanation] POST ์ค€๋น„: userId=$userId, academyId=$academyId, answer=${studentAnswerInfo.answer}', + ); + + // 5) ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ (POST) + appLog('[explanation] [3/4] POST (ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ) ์‹œ์ž‘'); + await _requestExplanationUseCase( + source, + requestedByUserId: userId, + academyId: academyId, + answer: studentAnswerInfo.answer, + ); + appLog('[explanation] [3/4] POST (ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ) ์™„๋ฃŒ'); + + // 6) ๋‹ค์‹œ ์กฐํšŒ (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) + // ์ƒ์„ฑ ํ›„ ์บ์‹œ์— ๋ฐ˜์˜๋˜์—ˆ๋‹ค๋Š” ๊ฐ€์ • + appLog('[explanation] [4/4] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) ์‹œ์ž‘'); + final after = await _getExplanationUseCase(source); + appLog( + '[explanation] [4/4] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) ์™„๋ฃŒ: ${after != null ? "ํ•ด์„ค ์กด์žฌ" : "ํ•ด์„ค ์—†์Œ"}', + ); + appLog('[explanation] ========== ํ•ด์„ค ์š”์ฒญ ํ๋ฆ„ ์ข…๋ฃŒ =========='); + + return ExplanationLoadResult(explanation: after, requestPerformed: true); + } +} diff --git a/frontend/lib/application/explanation/question_explanation_controller.dart b/frontend/lib/application/explanation/question_explanation_controller.dart new file mode 100644 index 0000000..30b48f8 --- /dev/null +++ b/frontend/lib/application/explanation/question_explanation_controller.dart @@ -0,0 +1,128 @@ +import 'package:flutter/foundation.dart'; + +import '../../domain/explanation/explanation_entity.dart'; +import '../../domain/explanation/explanation_source.dart'; +import 'explanation_service.dart'; + +/// ํ•ด์„ค ํ™”๋ฉด ์ƒํƒœ +class QuestionExplanationState { + final bool isLoading; + final String? errorMessage; + final ExplanationEntity? explanation; + + /// ๋งˆ์ง€๋ง‰ load ํ˜ธ์ถœ์—์„œ ์‹ค์ œ๋กœ ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ(POST)์ด ์ˆ˜ํ–‰๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€ + final bool lastRequestPerformed; + + const QuestionExplanationState({ + required this.isLoading, + this.errorMessage, + this.explanation, + required this.lastRequestPerformed, + }); + + const QuestionExplanationState.initial() + : isLoading = false, + errorMessage = null, + explanation = null, + lastRequestPerformed = false; + + QuestionExplanationState copyWith({ + bool? isLoading, + String? errorMessage, + ExplanationEntity? explanation, + bool? lastRequestPerformed, + }) { + return QuestionExplanationState( + isLoading: isLoading ?? this.isLoading, + errorMessage: errorMessage, + explanation: explanation ?? this.explanation, + lastRequestPerformed: lastRequestPerformed ?? this.lastRequestPerformed, + ); + } +} + +/// ํ•ด์„ค ์กฐํšŒ/์ƒ์„ฑ์„ ๋‹ด๋‹นํ•˜๋Š” Controller (ViewModel) +class QuestionExplanationController extends ChangeNotifier { + final ExplanationService _service; + + QuestionExplanationState _state = + const QuestionExplanationState.initial(); + QuestionExplanationState get state => _state; + + QuestionExplanationController({required ExplanationService service}) + : _service = service; + + /// ์ด๋ฏธ ์ƒ์„ฑ๋œ ํ•ด์„ค๋งŒ ์กฐํšŒํ•˜๋Š” ์ง„์ž… ์‹œ ๋กœ๋”ฉ์šฉ ๋ฉ”์„œ๋“œ + /// + /// ํ•ด์„ค์ด ์—†์œผ๋ฉด POST๋ฅผ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ , [lastRequestPerformed]๋„ false๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. + Future loadExisting(ExplanationSource source) async { + _setState( + _state.copyWith( + isLoading: true, + errorMessage: null, + lastRequestPerformed: false, + ), + ); + try { + final existing = await _service.loadExistingExplanation(source); + _setState( + _state.copyWith( + isLoading: false, + errorMessage: null, + explanation: existing, + lastRequestPerformed: false, + ), + ); + } catch (_) { + _setState( + _state.copyWith( + isLoading: false, + errorMessage: 'ํ•ด์„ค์„ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.', + lastRequestPerformed: false, + ), + ); + } + } + + /// ํ•ด์„ค ์š”์ฒญ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ + /// + /// ํ•„์š” ์‹œ ํ•ด์„ค ์ƒ์„ฑ POST๊นŒ์ง€ ์ˆ˜ํ–‰ํ•˜๋ฉฐ, ์ด๋•Œ [lastRequestPerformed]๊ฐ€ true๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. + Future load(ExplanationSource source) async { + _setState( + _state.copyWith( + isLoading: true, + errorMessage: null, + lastRequestPerformed: false, + ), + ); + try { + final result = await _service.loadOrRequestExplanation(source); + _setState( + _state.copyWith( + isLoading: false, + errorMessage: null, + explanation: result.explanation, + lastRequestPerformed: result.requestPerformed, + ), + ); + } catch (_) { + _setState( + _state.copyWith( + isLoading: false, + errorMessage: 'ํ•ด์„ค์„ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.', + lastRequestPerformed: false, + ), + ); + } + } + + Future requestAgain(ExplanationSource source) async { + await load(source); + } + + void _setState(QuestionExplanationState newState) { + _state = newState; + notifyListeners(); + } +} + diff --git a/frontend/lib/application/notification/notification_notifier.dart b/frontend/lib/application/notification/notification_notifier.dart new file mode 100644 index 0000000..591e503 --- /dev/null +++ b/frontend/lib/application/notification/notification_notifier.dart @@ -0,0 +1,103 @@ +import 'dart:developer' as developer; +import 'package:flutter/foundation.dart'; +import '../../domain/notification/notification_entity.dart'; +import '../../domain/notification/notification_repository.dart'; + +/// ์•Œ๋ฆผ ์ƒํƒœ ๊ด€๋ฆฌ์ž (ValueNotifier ๊ธฐ๋ฐ˜) +class NotificationNotifier { + final NotificationRepository repository; + + NotificationNotifier(this.repository); + + /// ์•Œ๋ฆผ ๋ชฉ๋ก ์ƒํƒœ + final ValueNotifier> notifications = + ValueNotifier>([]); + + /// ๋กœ๋”ฉ ์ƒํƒœ + final ValueNotifier isLoading = ValueNotifier(false); + + /// ์ฝ์ง€ ์•Š์€ ์•Œ๋ฆผ ๊ฐœ์ˆ˜ + int get unreadCount => + notifications.value.where((n) => !n.isRead).length; + + /// ์•Œ๋ฆผ ๋ชฉ๋ก ๋กœ๋“œ + Future load() async { + isLoading.value = true; + try { + final list = await repository.fetchNotifications(); + notifications.value = list; + developer.log('โœ… ์•Œ๋ฆผ ๋ชฉ๋ก ๋กœ๋“œ ์™„๋ฃŒ: ${list.length}๊ฐœ'); + } catch (e) { + developer.log('โŒ ์•Œ๋ฆผ ๋ชฉ๋ก ๋กœ๋“œ ์‹คํŒจ: $e'); + notifications.value = []; + } finally { + isLoading.value = false; + } + } + + /// ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ + Future markAsRead(String id) async { + try { + await repository.markAsRead(id); + // ๋กœ์ปฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ + notifications.value = notifications.value + .map((n) => n.id == id ? n.copyWith(isRead: true) : n) + .toList(); + developer.log('โœ… ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์™„๋ฃŒ: $id'); + } catch (e) { + developer.log('โŒ ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์‹คํŒจ: $e'); + rethrow; + } + } + + /// ์ „์ฒด ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ + Future markAllAsRead() async { + try { + await repository.markAllAsRead(); + // ๋กœ์ปฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ + notifications.value = + notifications.value.map((n) => n.copyWith(isRead: true)).toList(); + developer.log('โœ… ์ „์ฒด ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์™„๋ฃŒ'); + } catch (e) { + developer.log('โŒ ์ „์ฒด ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์‹คํŒจ: $e'); + rethrow; + } + } + + /// ์•Œ๋ฆผ ์‚ญ์ œ + Future delete(String id) async { + try { + await repository.delete(id); + // ๋กœ์ปฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ + notifications.value = + notifications.value.where((n) => n.id != id).toList(); + developer.log('โœ… ์•Œ๋ฆผ ์‚ญ์ œ ์™„๋ฃŒ: $id'); + } catch (e) { + developer.log('โŒ ์•Œ๋ฆผ ์‚ญ์ œ ์‹คํŒจ: $e'); + rethrow; + } + } + + /// FCM ์•Œ๋ฆผ ์ถ”๊ฐ€ (Repository ์ €์žฅ + ๋กœ์ปฌ ์ƒํƒœ ์ฆ‰์‹œ ๋ฐ˜์˜) + Future addFromFCM(NotificationEntity notification) async { + try { + await repository.saveNotification(notification); + // ๋กœ์ปฌ ์ƒํƒœ์— ์ฆ‰์‹œ ์ถ”๊ฐ€ (์ตœ์‹ ์ˆœ ์œ ์ง€) + final currentList = notifications.value; + final filtered = currentList.where((n) => n.id != notification.id).toList(); + filtered.insert(0, notification); + notifications.value = filtered; + developer.log('โœ… FCM ์•Œ๋ฆผ ์ถ”๊ฐ€ ์™„๋ฃŒ: ${notification.id}'); + } catch (e) { + developer.log('โŒ FCM ์•Œ๋ฆผ ์ถ”๊ฐ€ ์‹คํŒจ: $e'); + rethrow; + } + } + + /// ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ + void dispose() { + notifications.dispose(); + isLoading.dispose(); + } +} + diff --git a/frontend/lib/config/api_config.dart b/frontend/lib/config/api_config.dart new file mode 100644 index 0000000..c258972 --- /dev/null +++ b/frontend/lib/config/api_config.dart @@ -0,0 +1,115 @@ +/// API ์„ค์ • ๊ด€๋ฆฌ +/// +/// ํ™˜๊ฒฝ๋ณ„ ์„œ๋ฒ„ URL ๋ฐ ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. +/// TODO: ํ™˜๊ฒฝ๋ณ„๋กœ ๋ถ„๋ฆฌ (๊ฐœ๋ฐœ/ํ”„๋กœ๋•์…˜) +class ApiConfig { + // ๊ธฐ๋ณธ ์„œ๋ฒ„ URL + static const String baseUrl = 'https://3.34.214.133'; + + // ========== ์—”๋“œํฌ์ธํŠธ ์ •์˜ ========== + + // ์‚ฌ์šฉ์ž ์ •๋ณด + static const String meEndpoint = '/me'; + + // ์ธ์ฆ ๊ด€๋ จ + static const String signInEndpoint = '/sign-in'; + static const String signUpEndpoint = '/sign-up'; + static const String refreshTokenEndpoint = '/refresh-token'; + + // ๊ณ„์ • ๊ด€๋ฆฌ + static const String checkAccountIdEndpoint = '/users/check-accountId'; + static const String resetPasswordEndpoint = '/users/reset-password'; + static const String changeResetPasswordEndpoint = '/change/reset_password'; + static const String signOutEndpoint = '/sign-out'; + static const String uploadStreamEndpoint = '/storage/upload-stream'; + static const String uploadUrlBatchEndpoint = '/storage/upload-url/batch'; + + // ์ธ์ฆ ์ฝ”๋“œ ๋ฐœ์†ก + static const String sendCodeSignUpEndpoint = '/send-code/sign_up'; + static const String sendCodeResetPasswordEndpoint = + '/send-code/reset_password'; + static const String sendCodeFindAccountEndpoint = '/send-code/find_account'; + + // ์ธ์ฆ ์ฝ”๋“œ ํ™•์ธ + static const String verifySignUpEndpoint = '/verify/sign_up'; + static const String verifyResetPasswordEndpoint = '/verify/reset_password'; + static const String verifyFindAccountEndpoint = '/verify/find_account'; + + // Assessment ๊ด€๋ จ + static const String assessmentsAssigneeEndpoint = + '/grading/assessments/assignee'; + + // Academy ๊ด€๋ จ + static const String academyClassesEndpoint = '/academy/academy-users/classes'; + + // ========== URI ์ƒ์„ฑ ํ—ฌํผ ๋ฉ”์„œ๋“œ ========== + + // ์‚ฌ์šฉ์ž ์ •๋ณด + static Uri getMeUri() => Uri.parse('$baseUrl$meEndpoint'); + + // ์ธ์ฆ ๊ด€๋ จ + static Uri getSignInUri() => Uri.parse('$baseUrl$signInEndpoint'); + static Uri getSignUpUri() => Uri.parse('$baseUrl$signUpEndpoint'); + static Uri getRefreshTokenUri() => Uri.parse('$baseUrl$refreshTokenEndpoint'); + + // ๊ณ„์ • ๊ด€๋ฆฌ + static Uri getCheckAccountIdUri(String accountId) => + Uri.parse('$baseUrl$checkAccountIdEndpoint?accountId=$accountId'); + static Uri getResetPasswordUri() => + Uri.parse('$baseUrl$resetPasswordEndpoint'); + static Uri getChangeResetPasswordUri() => + Uri.parse('$baseUrl$changeResetPasswordEndpoint'); + static Uri getSignOutUri() => Uri.parse('$baseUrl$signOutEndpoint'); + static Uri getUploadStreamUri() => Uri.parse('$baseUrl$uploadStreamEndpoint'); + static Uri getUploadUrlBatchUri() => + Uri.parse('$baseUrl$uploadUrlBatchEndpoint'); + + // ์ธ์ฆ ์ฝ”๋“œ ๋ฐœ์†ก + static Uri getSendCodeSignUpUri() => + Uri.parse('$baseUrl$sendCodeSignUpEndpoint'); + static Uri getSendCodeResetPasswordUri() => + Uri.parse('$baseUrl$sendCodeResetPasswordEndpoint'); + static Uri getSendCodeFindAccountUri() => + Uri.parse('$baseUrl$sendCodeFindAccountEndpoint'); + + // ์ธ์ฆ ์ฝ”๋“œ ํ™•์ธ + static Uri getVerifySignUpUri() => Uri.parse('$baseUrl$verifySignUpEndpoint'); + static Uri getVerifyResetPasswordUri() => + Uri.parse('$baseUrl$verifyResetPasswordEndpoint'); + static Uri getVerifyFindAccountUri() => + Uri.parse('$baseUrl$verifyFindAccountEndpoint'); + + // Assessment ๊ด€๋ จ + static Uri getAssessmentsAssigneeUri( + String userAcademyId, { + DateTime? dateTime, // ISO 8601 ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•  DateTime + String? iso8601String, // ์ง์ ‘ ISO 8601 ๋ฌธ์ž์—ด ์ „๋‹ฌ (์„ ํƒ์‚ฌํ•ญ) + }) { + // ์ƒˆ๋กœ์šด ๋ฐฉ์‹: DateTime์„ ISO 8601 ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ + if (dateTime != null) { + final monthStart = DateTime.utc(dateTime.year, dateTime.month, 1); + final iso8601Str = monthStart.toIso8601String().split('.').first; + final encodedIso8601 = Uri.encodeComponent(iso8601Str); + return Uri.parse( + '$baseUrl$assessmentsAssigneeEndpoint/$userAcademyId/$encodedIso8601', + ); + } + + // ์ง์ ‘ ISO 8601 ๋ฌธ์ž์—ด ์ „๋‹ฌ + if (iso8601String != null) { + final encodedIso8601 = Uri.encodeComponent(iso8601String); + return Uri.parse( + '$baseUrl$assessmentsAssigneeEndpoint/$userAcademyId/$encodedIso8601', + ); + } + + // dateTime๊ณผ iso8601String์ด ๋ชจ๋‘ null์ด๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ + throw ArgumentError('dateTime ๋˜๋Š” iso8601String ์ค‘ ํ•˜๋‚˜๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.'); + } + + // Academy ๊ด€๋ จ + static Uri getAcademyClassesUri(List assigneeIds) { + final idsParam = assigneeIds.join(','); + return Uri.parse('$baseUrl$academyClassesEndpoint?ids=$idsParam'); + } +} diff --git a/frontend/lib/config/app_dependencies.dart b/frontend/lib/config/app_dependencies.dart new file mode 100644 index 0000000..46089bc --- /dev/null +++ b/frontend/lib/config/app_dependencies.dart @@ -0,0 +1,46 @@ +import 'package:get_it/get_it.dart'; + +import '../domain/chapter/get_chapters_for_book_use_case.dart'; +import '../services/get_chapter_question_statuses_use_case.dart'; +import '../domain/student_answer/student_answer_repository.dart'; +import '../domain/student_answer/get_student_answers_for_response_use_case.dart'; +import '../domain/student_answer/update_student_answers_use_case.dart'; +import '../domain/student_answer/update_single_student_answer_use_case.dart'; +import '../domain/section_image/get_section_image_use_case.dart'; + +final GetIt _getIt = GetIt.instance; + +/// AppDependencies๋Š” ๊ณผ๊ฑฐ static ์‹ฑ๊ธ€ํ†ค์„ ์‚ฌ์šฉํ•˜๋˜ ์ฝ”๋“œ๋ฅผ ์œ„ํ•œ +/// **์ž„์‹œ ๋ž˜ํผ**์ž…๋‹ˆ๋‹ค. +/// +/// ์ƒˆ ์ฝ”๋“œ๋Š” `getIt<>()`์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•˜๋ฉฐ, +/// ์ด ํด๋ž˜์Šค๋Š” ์ ์ง„์ ์œผ๋กœ ์ œ๊ฑฐ๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. +@Deprecated('Use getIt<>() from di_container.dart directly instead.') +class AppDependencies { + // Chapter + static GetChaptersForBookUseCase get getChaptersForBookUseCase => + _getIt(); + + static GetChapterQuestionStatusesUseCase + get getChapterQuestionStatusesUseCase => + _getIt(); + + // Student Answer + static StudentAnswerRepository get studentAnswerRepository => + _getIt(); + + static GetStudentAnswersForResponseUseCase + get getStudentAnswersForResponseUseCase => + _getIt(); + + static UpdateStudentAnswersUseCase get updateStudentAnswersUseCase => + _getIt(); + + static UpdateSingleStudentAnswerUseCase + get updateSingleStudentAnswerUseCase => + _getIt(); + + // Section Image + static GetSectionImageUseCase get getSectionImageUseCase => + _getIt(); +} diff --git a/frontend/lib/config/di_container.dart b/frontend/lib/config/di_container.dart new file mode 100644 index 0000000..d8d3eb4 --- /dev/null +++ b/frontend/lib/config/di_container.dart @@ -0,0 +1,359 @@ +import 'package:get_it/get_it.dart'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../services/auth_service.dart'; +import '../services/location_service.dart'; +import '../services/user_service.dart'; +import '../services/academy_service.dart'; +import '../data/notification/notification_local_data_source.dart'; +import '../services/assessment_local_store.dart'; +import '../domain/notification/notification_repository.dart'; +import '../data/notification/notification_repository_impl.dart'; +import '../services/fcm_service.dart'; +import '../services/upload_sse_service.dart'; +import '../services/grading_history_api.dart'; +import '../services/workbook_api.dart'; +import '../services/assessment_api.dart'; +import '../services/continuous_learning_api.dart'; +import '../services/student_answer_api.dart'; +import '../services/section_image_api.dart'; +import '../data/chapter/chapter_api.dart'; +import '../data/mappers/grading_history_mapper.dart'; +import '../data/mappers/workbook_mapper.dart'; +import '../services/student_answer_mapper.dart'; +import '../services/section_image_mapper.dart'; +import '../domain/grading_history/grading_history_repository.dart'; +import '../domain/workbook/workbook_repository.dart'; +import '../domain/student_answer/student_answer_repository.dart'; +import '../domain/section_image/section_image_repository.dart'; +import '../domain/chapter/chapter_repository.dart'; +import '../services/assessment_repository.dart'; +import '../services/grading_history_repository_impl.dart'; +import '../services/workbook_repository_impl.dart'; +import '../services/student_answer_repository_impl.dart'; +import '../services/section_image_repository_impl.dart'; +import '../services/explanation_repository_impl.dart'; +import '../data/chapter/chapter_repository_impl.dart'; +import '../domain/chapter/get_chapters_for_book_use_case.dart'; +import '../services/get_chapter_question_statuses_use_case.dart'; +import '../domain/student_answer/get_student_answers_for_response_use_case.dart'; +import '../domain/student_answer/update_student_answers_use_case.dart'; +import '../domain/student_answer/update_single_student_answer_use_case.dart'; +import '../domain/section_image/get_section_image_use_case.dart'; +import '../services/get_monthly_learning_status_use_case_impl.dart'; +import '../domain/learning/get_monthly_learning_status_use_case.dart'; +import '../services/learning_completion_service_impl.dart'; +import '../services/policies/answer_selection_policy.dart'; +import '../services/explanation_api.dart'; +import '../data/explanation/explanation_mapper.dart'; +import '../domain/explanation/explanation_repository.dart'; +import '../domain/explanation/get_explanation_use_case.dart'; +import '../domain/explanation/request_explanation_use_case.dart'; +import '../application/explanation/explanation_service.dart'; +import '../application/explanation/question_explanation_controller.dart'; +import '../services/daily_learning_service.dart'; + +/// ์ „์—ญ DI Container ์ธ์Šคํ„ด์Šค +final getIt = GetIt.instance; + +/// Core ์˜์กด์„ฑ ๋“ฑ๋ก (์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ) +void registerCore() { + getIt.registerLazySingleton(() => http.Client()); +} + +/// Infrastructure Services ๋“ฑ๋ก +void registerInfrastructureServices() { + // Auth & User & Academy & Location + getIt.registerLazySingleton(() => AuthService()); + getIt.registerLazySingleton(() => LocationService()); + getIt.registerLazySingleton( + () => UserService(authService: getIt()), + ); + getIt.registerLazySingleton( + () => AcademyService(authService: getIt()), + ); + + // Notification Repository + getIt.registerLazySingleton( + () => NotificationRepositoryImpl( + getIt(), + ), + ); + + // FCM Service (์ƒํƒœ ์—†๋Š” singleton) + getIt.registerLazySingleton( + () => FCMService( + notificationRepository: getIt(), + ), + ); + + // Upload SSE Service (์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๋ฏ€๋กœ factory) + getIt.registerFactory( + () => UploadSseService( + authService: getIt(), + ), + ); + + // Daily Learning Service + getIt.registerLazySingleton( + () => DailyLearningService( + workbookApi: getIt(), + academyService: getIt(), + authService: getIt(), + ), + ); +} + +/// Data Sources ๋“ฑ๋ก +void registerDataSources({required SharedPreferences sharedPrefs}) { + // SharedPreferences๋ฅผ singleton์œผ๋กœ ๋“ฑ๋ก + getIt.registerSingleton(sharedPrefs); + + // Local stores / data sources + getIt.registerLazySingleton(() => AssessmentLocalStore()); + + getIt.registerLazySingleton( + () => NotificationLocalDataSource(getIt()), + ); +} + +/// Mapper ๋“ฑ๋ก +void registerMappers() { + getIt.registerLazySingleton(() => GradingHistoryMapper()); + getIt.registerLazySingleton(() => WorkbookMapper()); + getIt.registerLazySingleton(() => StudentAnswerMapper()); + getIt.registerLazySingleton(() => SectionImageMapper()); + getIt.registerLazySingleton(() => ExplanationMapper()); +} + +/// API ๋“ฑ๋ก +void registerApis() { + getIt.registerLazySingleton( + () => GradingHistoryApi( + authService: getIt(), + httpClient: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => WorkbookApi( + authService: getIt(), + httpClient: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => AssessmentApi( + authService: getIt(), + httpClient: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => ContinuousLearningApi( + authService: getIt(), + httpClient: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => StudentAnswerApi( + authService: getIt(), + httpClient: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => SectionImageApi( + authService: getIt(), + httpClient: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => ChapterApi( + authService: getIt(), + httpClient: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => ExplanationApi( + tokenProvider: () => getIt().ensureValidAccessToken(), + httpClient: getIt(), + ), + ); +} + +/// Repository ๋“ฑ๋ก +void registerRepositories() { + // Impl ๋“ฑ๋ก + getIt.registerLazySingleton( + () => AssessmentRepository( + api: getIt(), + localStore: getIt(), + academyService: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => GradingHistoryRepositoryImpl( + api: getIt(), + mapper: getIt(), + academyService: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => WorkbookRepositoryImpl( + api: getIt(), + mapper: getIt(), + academyService: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => StudentAnswerRepositoryImpl( + api: getIt(), + mapper: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => SectionImageRepositoryImpl( + api: getIt(), + mapper: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => ChapterRepositoryImpl( + api: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => ExplanationRepositoryImpl( + api: getIt(), + mapper: getIt(), + ), + ); + + // Interface ํƒ€์ž…์œผ๋กœ๋„ ๋“ฑ๋ก + getIt.registerLazySingleton( + () => getIt(), + ); + getIt.registerLazySingleton( + () => getIt(), + ); + getIt.registerLazySingleton( + () => getIt(), + ); + getIt.registerLazySingleton( + () => getIt(), + ); + getIt.registerLazySingleton( + () => getIt(), + ); + getIt.registerLazySingleton( + () => getIt(), + ); +} + +/// UseCase ๋“ฑ๋ก +void registerUseCases() { + // Chapter + getIt.registerLazySingleton( + () => GetChaptersForBookUseCase( + repository: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => GetChapterQuestionStatusesUseCase( + chapterRepository: getIt(), + studentAnswerRepository: getIt(), + selectionPolicy: AnswerSelectionPolicy(), + ), + ); + + // Student Answer + getIt.registerLazySingleton( + () => GetStudentAnswersForResponseUseCase( + repository: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => UpdateStudentAnswersUseCase( + repository: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => UpdateSingleStudentAnswerUseCase( + api: getIt(), + ), + ); + + // Section Image + getIt.registerLazySingleton( + () => GetSectionImageUseCase( + repository: getIt(), + ), + ); + + // Monthly Learning Status + getIt.registerLazySingleton( + () => GetMonthlyLearningStatusUseCaseImpl( + assessmentRepository: getIt(), + gradingHistoryRepository: getIt(), + completionService: const LearningCompletionServiceImpl(), + ), + ); + + // Explanation + getIt.registerLazySingleton( + () => GetExplanationUseCase( + repository: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => RequestExplanationUseCase( + repository: getIt(), + ), + ); + + getIt.registerLazySingleton( + () => ExplanationService( + repository: getIt(), + getExplanationUseCase: getIt(), + requestExplanationUseCase: getIt(), + authService: getIt(), + academyService: getIt(), + ), + ); + + getIt.registerFactory( + () => QuestionExplanationController( + service: getIt(), + ), + ); +} + +/// DI Container ์ดˆ๊ธฐํ™” +/// +/// SharedPreferences๋Š” main.dart์—์„œ ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑํ•ด ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. +Future setupDependencies({required SharedPreferences sharedPrefs}) async { + registerCore(); + registerInfrastructureServices(); + registerDataSources(sharedPrefs: sharedPrefs); + registerMappers(); + registerApis(); + registerRepositories(); + registerUseCases(); +} + + diff --git a/frontend/lib/constants/learning_widget_spacing.dart b/frontend/lib/constants/learning_widget_spacing.dart new file mode 100644 index 0000000..b202a30 --- /dev/null +++ b/frontend/lib/constants/learning_widget_spacing.dart @@ -0,0 +1,70 @@ +import 'package:flutter/material.dart'; + +/// ์—ฐ์† ํ•™์Šต ์œ„์ ฏ์˜ spacing ์ƒ์ˆ˜ ์ •์˜ +/// +/// ๋””๋ฐ”์ด์Šค tier๋ณ„๋กœ ๊ณ ์ • px ๊ฐ’์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. +/// - Phone: ๊ธฐ๋ณธ๊ฐ’ +/// - Tablet: ์ค‘๊ฐ„ ํฌ๊ธฐ +/// - Large Tablet: ํฐ ํƒœ๋ธ”๋ฆฟ +class LearningWidgetSpacing { + LearningWidgetSpacing._(); + + /// ๋””๋ฐ”์ด์Šค๊ฐ€ ํƒœ๋ธ”๋ฆฟ์ธ์ง€ ํ™•์ธ + static bool isTablet(BuildContext context) { + final width = MediaQuery.of(context).size.width; + return width >= 600 && width < 1200; + } + + /// ๋””๋ฐ”์ด์Šค๊ฐ€ ๋Œ€ํ˜• ํƒœ๋ธ”๋ฆฟ์ธ์ง€ ํ™•์ธ + static bool isLargeTablet(BuildContext context) { + final width = MediaQuery.of(context).size.width; + return width >= 1200; + } + + /// ListView ์™ธ๋ถ€ padding (์ขŒ์šฐ) + /// Phone: 20px, Tablet: 32px, Large Tablet: 40px + static double getOuterPadding(BuildContext context) { + if (isLargeTablet(context)) return 40.0; + if (isTablet(context)) return 32.0; + return 20.0; + } + + /// DateItem ๋‚ด๋ถ€ padding (์ขŒ์šฐ) + /// Phone: 4px, Tablet: 8px, Large Tablet: 12px + static double getInnerPadding(BuildContext context) { + if (isLargeTablet(context)) return 12.0; + if (isTablet(context)) return 8.0; + return 4.0; + } + + /// Connector ๋„ˆ๋น„ (์—ฐ๊ฒฐ์„ ) + /// Phone: 6px, Tablet: 10px, Large Tablet: 14px + static double getConnectorWidth(BuildContext context) { + if (isLargeTablet(context)) return 14.0; + if (isTablet(context)) return 10.0; + return 6.0; + } + + /// ํžŒํŠธ ๋‚ด๋ถ€ ์ขŒ์šฐ padding + /// Phone: 12px, Tablet: 16px, Large Tablet: 20px + static double getHintInnerHorizontalPadding(BuildContext context) { + if (isLargeTablet(context)) return 20.0; + if (isTablet(context)) return 16.0; + return 12.0; + } + + /// ํžŒํŠธ ๋‚ด๋ถ€ ์ƒํ•˜ padding + /// Phone: 8px, Tablet: 10px, Large Tablet: 12px + static double getHintInnerVerticalPadding(BuildContext context) { + if (isLargeTablet(context)) return 12.0; + if (isTablet(context)) return 10.0; + return 8.0; + } + + /// ํžŒํŠธ ์™ธ๋ถ€ ์ขŒ์šฐ padding (๊ณ ์ •๊ฐ’) + static const double hintOuterHorizontalPadding = 8.0; + + /// ํžŒํŠธ ์™ธ๋ถ€ ์ƒํ•˜ padding (๊ณ ์ •๊ฐ’) + static const double hintOuterVerticalPadding = 8.0; +} + diff --git a/frontend/lib/data/chapter/chapter_api.dart b/frontend/lib/data/chapter/chapter_api.dart new file mode 100644 index 0000000..057c559 --- /dev/null +++ b/frontend/lib/data/chapter/chapter_api.dart @@ -0,0 +1,244 @@ +import 'dart:convert'; +import 'dart:developer' as developer; +import 'package:http/http.dart' as http; +import '../../config/api_config.dart'; +import '../../services/auth_service.dart'; +import '../../utils/app_logger.dart'; + +/// ์ฑ•ํ„ฐ API ์‘๋‹ต DTO +/// +/// ์„œ๋ฒ„ ์‘๋‹ต ๊ตฌ์กฐ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค. +class ChapterApiResponse { + final int chapterId; + final int bookId; + final int mainChapterNumber; + final int subChapterNumber; + final String? chapterName; + final int chapterStartPage; + final int chapterEndPage; + final int chapterStartQuestion; + final int chapterEndQuestion; + final int totalChapterQuestion; + final int studentAnswerCount; + + ChapterApiResponse({ + required this.chapterId, + required this.bookId, + required this.mainChapterNumber, + required this.subChapterNumber, + this.chapterName, + required this.chapterStartPage, + required this.chapterEndPage, + required this.chapterStartQuestion, + required this.chapterEndQuestion, + required this.totalChapterQuestion, + required this.studentAnswerCount, + }); + + factory ChapterApiResponse.fromJson(Map json) { + // ์•ˆ์ „ํ•œ int ๋ณ€ํ™˜ ํ—ฌํผ ํ•จ์ˆ˜ + int _toInt(dynamic value, {int defaultValue = 0}) { + if (value == null) return defaultValue; + if (value is int) return value; + if (value is double) return value.toInt(); + if (value is String) { + final parsed = int.tryParse(value); + if (parsed != null) return parsed; + } + return defaultValue; + } + + // ํ•„์ˆ˜ ํ•„๋“œ: null์ด๋ฉด ์˜ˆ์™ธ ๋ฐœ์ƒ (๋ฒ„๊ทธ ์กฐ๊ธฐ ๋ฐœ๊ฒฌ) + final chapterId = json['chapter_id']; + final bookId = json['book_id']; + + if (chapterId == null || bookId == null) { + throw FormatException( + 'ChapterApiResponse: chapter_id or book_id is null', + jsonEncode(json), + ); + } + + // count/๋ฒˆํ˜ธ ํ•„๋“œ๋Š” 0 ๊ธฐ๋ณธ๊ฐ’ ํ—ˆ์šฉ + return ChapterApiResponse( + chapterId: _toInt(chapterId), + bookId: _toInt(bookId), + mainChapterNumber: _toInt(json['main_chapter_number']), + subChapterNumber: _toInt(json['sub_chapter_number']), + chapterName: json['chapter_name'] as String?, + chapterStartPage: _toInt(json['chapter_start_page']), + chapterEndPage: _toInt(json['chapter_end_page']), + chapterStartQuestion: _toInt(json['chapter_start_question']), + chapterEndQuestion: _toInt(json['chapter_end_question']), + // ํ•˜์œ„ ํ˜ธํ™˜์„ฑ: total_chapter_question์ด ์—†์œผ๋ฉด total_chapter_problem ์‚ฌ์šฉ + totalChapterQuestion: _toInt( + json['total_chapter_question'] ?? json['total_chapter_problem'], + ), + studentAnswerCount: _toInt(json['student_answer_count']), + ); + } +} + +/// ์ฑ•ํ„ฐ API ํ˜ธ์ถœ ์ „์šฉ ๋ ˆ์ด์–ด +class ChapterApi { + ChapterApi({ + required AuthService authService, + required http.Client httpClient, + }) : _authService = authService, + _httpClient = httpClient; + + final AuthService _authService; + final http.Client _httpClient; + + /// ์ฑ•ํ„ฐ ๋ชฉ๋ก ์กฐํšŒ + /// + /// **API ์ŠคํŽ™**: + /// - Method: GET + /// - Endpoint: `/grading/chapter/book/{book_id}/user/{academy_user_id}` + /// - Headers: `Authorization: Bearer {token}` + /// + /// [bookId]: ๋ฌธ์ œ์ง‘ ID + /// [academyUserId]: ํ•™์› ์‚ฌ์šฉ์ž ID + /// + /// ๋ฐ˜ํ™˜: ์ฑ•ํ„ฐ API ์‘๋‹ต ๋ฆฌ์ŠคํŠธ + Future> fetchChapters( + int bookId, + int academyUserId, + ) async { + appLog( + '๐Ÿ“– [ChapterApi] ์ฑ•ํ„ฐ ๋ชฉ๋ก ์กฐํšŒ ์‹œ์ž‘ - bookId: $bookId, academyUserId: $academyUserId', + ); + + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + appLog('โŒ [ChapterApi] ์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค.'); + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/chapter/book/$bookId/user/$academyUserId', + ); + + appLog('๐Ÿ“– [ChapterApi] GET $uri'); + developer.log('๐Ÿ“– [ChapterApi] GET $uri'); + + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + appLog('๐Ÿ“– [ChapterApi] Response status: ${response.statusCode}'); + developer.log('๐Ÿ“– [ChapterApi] Response status: ${response.statusCode}'); + + if (response.statusCode == 401) { + appLog('โŒ [ChapterApi] ์ธ์ฆ ์‹คํŒจ (401)'); + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + appLog('โŒ [ChapterApi] API ํ˜ธ์ถœ ์‹คํŒจ (status: ${response.statusCode})'); + throw Exception('Chapter API ํ˜ธ์ถœ ์‹คํŒจ (status: ${response.statusCode})'); + } + + try { + final List data = json.decode(response.body); + appLog('๐Ÿ“– [ChapterApi] ์‘๋‹ต ํŒŒ์‹ฑ ์„ฑ๊ณต - ์ฑ•ํ„ฐ ๊ฐœ์ˆ˜: ${data.length}'); + + final result = data + .map( + (item) => ChapterApiResponse.fromJson(item as Map), + ) + .toList(); + + // ์‘๋‹ต ๊ตฌ์กฐ ์ „์ฒด ๋กœ๊ทธ ์ถœ๋ ฅ + appLog('๐Ÿ“– [ChapterApi] ์‘๋‹ต ๊ตฌ์กฐ:'); + for (var i = 0; i < result.length; i++) { + final chapter = result[i]; + appLog(' [์ฑ•ํ„ฐ ${i + 1}]'); + appLog(' - chapterId: ${chapter.chapterId}'); + appLog(' - bookId: ${chapter.bookId}'); + appLog(' - mainChapterNumber: ${chapter.mainChapterNumber}'); + appLog(' - subChapterNumber: ${chapter.subChapterNumber}'); + appLog(' - chapterName: ${chapter.chapterName ?? "null"}'); + appLog(' - chapterStartPage: ${chapter.chapterStartPage}'); + appLog(' - chapterEndPage: ${chapter.chapterEndPage}'); + appLog(' - chapterStartQuestion: ${chapter.chapterStartQuestion}'); + appLog(' - chapterEndQuestion: ${chapter.chapterEndQuestion}'); + appLog(' - totalChapterQuestion: ${chapter.totalChapterQuestion}'); + appLog(' - studentAnswerCount: ${chapter.studentAnswerCount}'); + } + + return result; + } catch (e) { + appLog('โŒ [ChapterApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + appLog('โŒ [ChapterApi] Response body: ${response.body}'); + developer.log('โŒ [ChapterApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + developer.log('โŒ [ChapterApi] Response body: ${response.body}'); + rethrow; + } + } + + /// chapterId๋กœ ๋‹จ์ผ ์ฑ•ํ„ฐ ์ •๋ณด ์กฐํšŒ + /// + /// **API ์ŠคํŽ™**: + /// - Method: GET + /// - Endpoint: `/grading/chapter/{chapter_id}` + /// - Headers: `Authorization: Bearer {token}` + /// + /// [chapterId]: ์ฑ•ํ„ฐ ID + /// + /// ๋ฐ˜ํ™˜: ์ฑ•ํ„ฐ API ์‘๋‹ต + Future fetchChapterById(int chapterId) async { + appLog('๐Ÿ“– [ChapterApi] ์ฑ•ํ„ฐ ์กฐํšŒ ์‹œ์ž‘ - chapterId: $chapterId'); + + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + appLog('โŒ [ChapterApi] ์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค.'); + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = Uri.parse('${ApiConfig.baseUrl}/grading/chapter/$chapterId'); + + appLog('๐Ÿ“– [ChapterApi] GET $uri'); + developer.log('๐Ÿ“– [ChapterApi] GET $uri'); + + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + appLog('๐Ÿ“– [ChapterApi] Response status: ${response.statusCode}'); + developer.log('๐Ÿ“– [ChapterApi] Response status: ${response.statusCode}'); + + if (response.statusCode == 401) { + appLog('โŒ [ChapterApi] ์ธ์ฆ ์‹คํŒจ (401)'); + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + appLog('โŒ [ChapterApi] API ํ˜ธ์ถœ ์‹คํŒจ (status: ${response.statusCode})'); + throw Exception('Chapter API ํ˜ธ์ถœ ์‹คํŒจ (status: ${response.statusCode})'); + } + + try { + final Map data = json.decode(response.body); + appLog('๐Ÿ“– [ChapterApi] ์‘๋‹ต ํŒŒ์‹ฑ ์„ฑ๊ณต'); + + return ChapterApiResponse.fromJson(data); + } catch (e) { + appLog('โŒ [ChapterApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + appLog('โŒ [ChapterApi] Response body: ${response.body}'); + developer.log('โŒ [ChapterApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + developer.log('โŒ [ChapterApi] Response body: ${response.body}'); + rethrow; + } + } +} diff --git a/frontend/lib/data/chapter/chapter_repository_impl.dart b/frontend/lib/data/chapter/chapter_repository_impl.dart new file mode 100644 index 0000000..9616256 --- /dev/null +++ b/frontend/lib/data/chapter/chapter_repository_impl.dart @@ -0,0 +1,70 @@ +import 'dart:developer' as developer; +import '../../domain/chapter/chapter_entity.dart'; +import '../../domain/chapter/chapter_repository.dart'; +import 'chapter_api.dart'; + +/// ์ฑ•ํ„ฐ Repository ๊ตฌํ˜„์ฒด +/// +/// API ํ˜ธ์ถœ ๋ฐ DTO โ†’ Entity ๋ณ€ํ™˜์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. +class ChapterRepositoryImpl implements ChapterRepository { + ChapterRepositoryImpl({required ChapterApi api}) : _api = api; + + final ChapterApi _api; + + @override + Future> getChaptersByBookIdAndAcademyUserId( + int bookId, + int academyUserId, + ) async { + try { + final apiResponses = await _api.fetchChapters(bookId, academyUserId); + + // API ์‘๋‹ต โ†’ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜ + return apiResponses + .map( + (response) => ChapterEntity( + chapterId: response.chapterId, + bookId: response.bookId, + mainChapterNumber: response.mainChapterNumber, + subChapterNumber: response.subChapterNumber, + chapterName: response.chapterName, + chapterStartPage: response.chapterStartPage, + chapterEndPage: response.chapterEndPage, + chapterStartQuestion: response.chapterStartQuestion, + chapterEndQuestion: response.chapterEndQuestion, + totalChapterQuestion: response.totalChapterQuestion, + studentAnswerCount: response.studentAnswerCount, + ), + ) + .toList(); + } catch (e) { + developer.log('โŒ [ChapterRepository] API ํ˜ธ์ถœ ์‹คํŒจ: $e'); + rethrow; + } + } + + @override + Future getChapterById(int chapterId) async { + try { + final apiResponse = await _api.fetchChapterById(chapterId); + + // API ์‘๋‹ต โ†’ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜ + return ChapterEntity( + chapterId: apiResponse.chapterId, + bookId: apiResponse.bookId, + mainChapterNumber: apiResponse.mainChapterNumber, + subChapterNumber: apiResponse.subChapterNumber, + chapterName: apiResponse.chapterName, + chapterStartPage: apiResponse.chapterStartPage, + chapterEndPage: apiResponse.chapterEndPage, + chapterStartQuestion: apiResponse.chapterStartQuestion, + chapterEndQuestion: apiResponse.chapterEndQuestion, + totalChapterQuestion: apiResponse.totalChapterQuestion, + studentAnswerCount: apiResponse.studentAnswerCount, + ); + } catch (e) { + developer.log('โŒ [ChapterRepository] ์ฑ•ํ„ฐ ์กฐํšŒ ์‹คํŒจ: $e'); + rethrow; + } + } +} diff --git a/frontend/lib/data/explanation/explanation_mapper.dart b/frontend/lib/data/explanation/explanation_mapper.dart new file mode 100644 index 0000000..0579aa3 --- /dev/null +++ b/frontend/lib/data/explanation/explanation_mapper.dart @@ -0,0 +1,46 @@ +import '../../domain/question/question_identifier.dart'; +import '../../domain/explanation/explanation_entity.dart'; + +/// Explanation API ์‘๋‹ต์„ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” Mapper +class ExplanationMapper { + /// POST /grading/student-answers/explanation ์‘๋‹ต ํŒŒ์‹ฑ + ExplanationEntity fromPostResponse(Map json) { + final explanation = + json['explanation'] as Map? ?? const {}; + + final question = QuestionIdentifier( + bookId: explanation['book_id'] as int? ?? 0, + chapterId: explanation['chapter_id'] as int? ?? 0, + page: explanation['page'] as int? ?? 0, + questionNumber: explanation['question_number'] as int? ?? 0, + subQuestionNumber: explanation['sub_question_number'] as int? ?? 0, + ); + + final text = explanation['explanation'] as String? ?? ''; + + return ExplanationEntity( + question: question, + text: text, + ); + } + + /// GET /grading/student-answers/get-explanation ์‘๋‹ต ํŒŒ์‹ฑ + ExplanationEntity fromGetResponse(Map json) { + final question = QuestionIdentifier( + bookId: json['book_id'] as int? ?? 0, + chapterId: json['chapter_id'] as int? ?? 0, + page: json['page'] as int? ?? 0, + questionNumber: json['question_number'] as int? ?? 0, + subQuestionNumber: json['sub_question_number'] as int? ?? 0, + ); + + final text = json['explanation'] as String? ?? ''; + + return ExplanationEntity( + question: question, + text: text, + ); + } +} + + diff --git a/frontend/lib/data/mappers/grading_history_mapper.dart b/frontend/lib/data/mappers/grading_history_mapper.dart new file mode 100644 index 0000000..eaaeaf5 --- /dev/null +++ b/frontend/lib/data/mappers/grading_history_mapper.dart @@ -0,0 +1,68 @@ +import '../../domain/grading_history/grading_history_entity.dart'; +import '../../services/grading_history_api.dart'; + +/// Grading History Mapper +/// +/// API ์‘๋‹ต์„ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ฑ…์ž„๋งŒ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. +class GradingHistoryMapper { + /// API ์‘๋‹ต ๋ฆฌ์ŠคํŠธ๋ฅผ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜ + /// + /// [responses]: API ์‘๋‹ต ๋ฆฌ์ŠคํŠธ (flat array) + /// [classNameMap]: academyUserId โ†’ className ๋งคํ•‘ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋ฆฌ์ŠคํŠธ (์ •๋ ฌ ์—†์Œ, ์ˆœ์ˆ˜ ๋ณ€ํ™˜๋งŒ) + /// ์ •๋ ฌ์€ UI ๋ ˆ์ด์–ด์—์„œ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. + List convertApiResponsesToEntities( + List responses, + Map classNameMap, + ) { + return responses.map((response) { + // 1. createdAt ํŒŒ์‹ฑ (UTC โ†’ ๋กœ์ปฌ ๋ณ€ํ™˜, ๋ฐฉ์–ด ๋กœ์ง ํฌํ•จ) + final createdAt = _parseCreatedAt(response.createdAt); + + // 2. className ์ฃผ์ž… + final className = classNameMap[response.academyUserId]; + + // 3. ์—”ํ‹ฐํ‹ฐ ์ƒ์„ฑ + return GradingHistoryEntity( + studentResponseId: response.studentResponseId, + academyUserId: response.academyUserId, + bookId: response.bookId, + bookName: response.bookName, + bookCoverImageUrl: response.bookImageUrl, + startPage: response.responseStartPage, + endPage: response.responseEndPage, + className: className, + gradingDate: createdAt, + assessId: response.assessId, + unrecognizedResponseCount: response.unrecognizedResponseCount, + ); + }).toList(); + } + + /// createdAt ๋ฌธ์ž์—ด์„ DateTime์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ํŒŒ์‹ฑ + /// + /// ๋นˆ ๋ฌธ์ž์—ด์ด๊ฑฐ๋‚˜ ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๊ณผ๊ฑฐ ๊ณ ์ •๊ฐ’ ๋ฐ˜ํ™˜ (์ •๋ ฌ ์‹œ ๋’ค๋กœ ๊ฐ€๋„๋ก) + /// + /// ๊ทœ์น™: + /// - created_at์€ ์„œ๋ฒ„์—์„œ UTC ๊ธฐ์ค€ ISO ๋ฌธ์ž์—ด๋กœ ๋‚ด๋ ค์˜จ๋‹ค๋Š” ์ „์ œ ํ•˜์— toLocal() ์ ์šฉ + /// - ๋งŒ์•ฝ ์„œ๋ฒ„๊ฐ€ ์ด๋ฏธ KST๋กœ ๋‚ด๋ ค์ฃผ๋ฉด toLocal() ์ œ๊ฑฐ ํ•„์š” + /// - ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ DateTime(1970, 1, 1) ๋ฐ˜ํ™˜ (์ •๋ ฌ ์‹œ ๊ฐ€์žฅ ๋’ค๋กœ) + DateTime _parseCreatedAt(String value) { + if (value.isEmpty) { + // ๋นˆ ๋ฌธ์ž์—ด์ด๋ฉด ๊ณผ๊ฑฐ ๊ณ ์ •๊ฐ’ ๋ฐ˜ํ™˜ (์ •๋ ฌ ์‹œ ๋’ค๋กœ ๊ฐ€๋„๋ก) + return DateTime(1970, 1, 1); + } + + try { + // created_at์€ ์„œ๋ฒ„์—์„œ UTC ๊ธฐ์ค€ ISO ๋ฌธ์ž์—ด๋กœ ๋‚ด๋ ค์˜จ๋‹ค๋Š” ์ „์ œ ํ•˜์— toLocal() ์ ์šฉ + // ๋งŒ์•ฝ ์„œ๋ฒ„๊ฐ€ ์ด๋ฏธ KST๋กœ ๋‚ด๋ ค์ฃผ๋ฉด toLocal() ์ œ๊ฑฐ ํ•„์š” + return DateTime.parse(value).toLocal(); + } catch (_) { + // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๊ณผ๊ฑฐ ๊ณ ์ •๊ฐ’ ๋ฐ˜ํ™˜ (์ •๋ ฌ ์‹œ ๊ฐ€์žฅ ๋’ค๋กœ) + return DateTime(1970, 1, 1); + } + } +} + + diff --git a/frontend/lib/data/mappers/workbook_mapper.dart b/frontend/lib/data/mappers/workbook_mapper.dart new file mode 100644 index 0000000..24b6714 --- /dev/null +++ b/frontend/lib/data/mappers/workbook_mapper.dart @@ -0,0 +1,178 @@ +import '../../domain/workbook/workbook_summary_entity.dart'; +import '../../services/workbook_api.dart'; +import '../../screens/workbook/models/class_data.dart'; +import '../../screens/workbook/models/workbook_info.dart'; +import '../../screens/workbook/models/workbook_data.dart'; + +/// Workbook ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ Mapper +/// +/// API ์‘๋‹ต์„ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋ฐ UI ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ฑ…์ž„๋งŒ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. +class WorkbookMapper { + /// API ์‘๋‹ต์„ WorkbookSummaryEntity๋กœ ๋ณ€ํ™˜ + /// + /// [apiResponses]: API ์‘๋‹ต ๋ฆฌ์ŠคํŠธ (์—ฌ๋Ÿฌ academyUserId) + /// [classNameMap]: academyUserId โ†’ className ๋งคํ•‘ (Repository์—์„œ ์กฐํšŒ๋จ) + Future>> convertApiResponsesToSummaries( + List apiResponses, + Map classNameMap, + ) async { + final summariesMap = >{}; + + for (final apiResponse in apiResponses) { + final summaries = []; + final className = classNameMap[apiResponse.academyUserId]; + + for (final bookData in apiResponse.books) { + // latest_updated_at ํŒŒ์‹ฑ + DateTime? lastStudyDate; + if (bookData.latestUpdatedAt != null && + bookData.latestUpdatedAt!.isNotEmpty) { + try { + lastStudyDate = DateTime.parse(bookData.latestUpdatedAt!).toLocal(); + } catch (e) { + // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ null ์œ ์ง€ + } + } + + // WorkbookSummaryEntity ์ƒ์„ฑ + final summary = WorkbookSummaryEntity( + bookId: bookData.bookId, + bookName: bookData.bookName ?? '์•Œ ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ์ง‘', + coverImageUrl: bookData.bookImageUrl, + totalPages: bookData.bookPage, // book_page ์‚ฌ์šฉ + totalSolvedPages: bookData.totalSolvedPages, + lastStudyDate: lastStudyDate, + academyUserId: apiResponse.academyUserId, + className: className, + bookSemester: bookData.bookSemester, + ); + + summaries.add(summary); + } + + summariesMap[apiResponse.academyUserId] = summaries; + } + + return summariesMap; + } + + /// WorkbookSummaryEntity ๋ฆฌ์ŠคํŠธ๋ฅผ ClassData๋กœ ๋ณ€ํ™˜ + /// + /// DateTime ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ ํ›„ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + List convertToClassData( + Map> summariesByAcademyUserId, + ) { + final classDataList = []; + + summariesByAcademyUserId.forEach((academyUserId, summaries) { + if (summaries.isEmpty) return; + + final className = summaries.first.className ?? '์•Œ ์ˆ˜ ์—†๋Š” ํด๋ž˜์Šค'; + + // DateTime ๊ธฐ์ค€์œผ๋กœ ์ตœ์‹  ๋‚ ์งœ ์ฐพ๊ธฐ + final lastStudyDate = _getLatestDateTime(summaries); + + // WorkbookInfo ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ + final workbooks = summaries.map((summary) { + return WorkbookInfo( + name: summary.bookName, + lastStudyDate: summary.formattedLastStudyDate, + progress: summary.progress, + thumbnailPath: summary.thumbnailPath, + bookId: summary.bookId, + academyUserId: summary.academyUserId, + ); + }).toList(); + + classDataList.add( + ClassData( + className: className, + lastStudyDate: _formatDateTime(lastStudyDate), + workbooks: workbooks, + ), + ); + }); + + // DateTime ๊ธฐ์ค€ ์ •๋ ฌ ํ›„ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ + classDataList.sort((a, b) { + final dateA = _parseFormattedDate(a.lastStudyDate); + final dateB = _parseFormattedDate(b.lastStudyDate); + return dateB.compareTo(dateA); // ์ตœ์‹ ์ˆœ + }); + + return classDataList; + } + + /// WorkbookSummaryEntity ๋ฆฌ์ŠคํŠธ๋ฅผ WorkbookData๋กœ ๋ณ€ํ™˜ + /// + /// DateTime ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ ํ›„ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + List convertToWorkbookData( + Map> summariesByAcademyUserId, + ) { + final workbookDataList = []; + + summariesByAcademyUserId.forEach((academyUserId, summaries) { + for (final summary in summaries) { + workbookDataList.add( + WorkbookData( + workbookName: summary.bookName, + lastStudyDate: summary.formattedLastStudyDate, + progress: summary.progress, + thumbnailPath: summary.thumbnailPath, + className: summary.className ?? '์•Œ ์ˆ˜ ์—†๋Š” ํด๋ž˜์Šค', + bookId: summary.bookId, + academyUserId: summary.academyUserId, + ), + ); + } + }); + + // DateTime ๊ธฐ์ค€ ์ •๋ ฌ ํ›„ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ + workbookDataList.sort((a, b) { + final dateA = _parseFormattedDate(a.lastStudyDate); + final dateB = _parseFormattedDate(b.lastStudyDate); + return dateB.compareTo(dateA); // ์ตœ์‹ ์ˆœ + }); + + return workbookDataList; + } + + /// summaries์—์„œ ๊ฐ€์žฅ ์ตœ๊ทผ DateTime ์ฐพ๊ธฐ + DateTime? _getLatestDateTime(List summaries) { + DateTime? latest; + for (final summary in summaries) { + if (summary.lastStudyDate != null) { + if (latest == null || summary.lastStudyDate!.isAfter(latest)) { + latest = summary.lastStudyDate; + } + } + } + return latest; + } + + /// DateTime์„ YYYY.MM.DD ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ + String _formatDateTime(DateTime? dateTime) { + if (dateTime == null) return ''; + return '${dateTime.year}.${dateTime.month.toString().padLeft(2, '0')}.${dateTime.day.toString().padLeft(2, '0')}'; + } + + /// YYYY.MM.DD ํ˜•์‹ ๋ฌธ์ž์—ด์„ DateTime์œผ๋กœ ํŒŒ์‹ฑ + DateTime _parseFormattedDate(String dateStr) { + if (dateStr.isEmpty) return DateTime(1970, 1, 1); // ๊ธฐ๋ณธ๊ฐ’ + try { + final parts = dateStr.split('.'); + if (parts.length == 3) { + return DateTime( + int.parse(parts[0]), + int.parse(parts[1]), + int.parse(parts[2]), + ); + } + } catch (e) { + // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๊ธฐ๋ณธ๊ฐ’ + } + return DateTime(1970, 1, 1); + } +} + + diff --git a/frontend/lib/data/notification/notification_local_data_source.dart b/frontend/lib/data/notification/notification_local_data_source.dart new file mode 100644 index 0000000..0ee690f --- /dev/null +++ b/frontend/lib/data/notification/notification_local_data_source.dart @@ -0,0 +1,34 @@ +import 'dart:convert'; +import 'package:shared_preferences/shared_preferences.dart'; + +/// ์•Œ๋ฆผ ๋กœ์ปฌ ๋ฐ์ดํ„ฐ ์†Œ์Šค (SharedPreferences ์ง์ ‘ ์ ‘๊ทผ) +class NotificationLocalDataSource { + static const String _key = 'notifications_list'; + + final SharedPreferences prefs; + + NotificationLocalDataSource(this.prefs); + + /// ์•Œ๋ฆผ ๋ชฉ๋ก ๋กœ๋“œ (JSON ๋ฌธ์ž์—ด์„ List์œผ๋กœ ๋ณ€ํ™˜) + Future>> loadRawList() async { + final jsonString = prefs.getString(_key); + if (jsonString == null || jsonString.isEmpty) { + return []; + } + + try { + final List decoded = jsonDecode(jsonString); + return decoded.cast>(); + } catch (e) { + // JSON ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ ๋ฐ˜ํ™˜ + return []; + } + } + + /// ์•Œ๋ฆผ ๋ชฉ๋ก ์ €์žฅ (List์„ JSON ๋ฌธ์ž์—ด๋กœ ์ €์žฅ) + Future saveRawList(List> items) async { + final jsonString = jsonEncode(items); + await prefs.setString(_key, jsonString); + } +} + diff --git a/frontend/lib/data/notification/notification_repository_impl.dart b/frontend/lib/data/notification/notification_repository_impl.dart new file mode 100644 index 0000000..34d8aca --- /dev/null +++ b/frontend/lib/data/notification/notification_repository_impl.dart @@ -0,0 +1,123 @@ +import 'dart:developer' as developer; +import '../../domain/notification/notification_entity.dart'; +import '../../domain/notification/notification_repository.dart'; +import 'notification_local_data_source.dart'; + +/// ์•Œ๋ฆผ ์ €์žฅ์†Œ ๊ตฌํ˜„์ฒด (SharedPreferences ๊ธฐ๋ฐ˜) +class NotificationRepositoryImpl implements NotificationRepository { + final NotificationLocalDataSource local; + + NotificationRepositoryImpl(this.local); + + static const int _maxCount = 100; // ์ตœ๋Œ€ ์•Œ๋ฆผ ๊ฐœ์ˆ˜ + + @override + Future> fetchNotifications() async { + try { + final rawList = await local.loadRawList(); + final list = rawList + .map((json) => NotificationEntity.fromJson(json)) + .toList() + ..sort((a, b) => b.time.compareTo(a.time)); // ์ตœ์‹ ์ˆœ ์ •๋ ฌ + + return list; + } catch (e) { + developer.log('โŒ ์•Œ๋ฆผ ๋ชฉ๋ก ๋กœ๋“œ ์‹คํŒจ: $e'); + return []; + } + } + + @override + Future saveNotification(NotificationEntity notification) async { + try { + final list = await fetchNotifications(); + + // ์ค‘๋ณต ์ œ๊ฑฐ (๋™์ผ id ์ œ๊ฑฐ) + final filtered = list.where((n) => n.id != notification.id).toList(); + + // ์ƒˆ ์•Œ๋ฆผ์„ ๋งจ ์•ž์— ์ถ”๊ฐ€ + filtered.insert(0, notification); + + // ์ตœ๋Œ€ ๊ฐœ์ˆ˜ ์ œํ•œ + final truncated = filtered.take(_maxCount).toList(); + + // ์ €์žฅ + await local.saveRawList( + truncated.map((e) => e.toJson()).toList(), + ); + + developer.log('โœ… ์•Œ๋ฆผ ์ €์žฅ ์™„๋ฃŒ: ${notification.id}'); + } catch (e) { + developer.log('โŒ ์•Œ๋ฆผ ์ €์žฅ ์‹คํŒจ: $e'); + rethrow; + } + } + + @override + Future markAsRead(String id) async { + try { + final list = await fetchNotifications(); + final updated = list.map((n) { + if (n.id == id) { + return n.copyWith(isRead: true); + } + return n; + }).toList(); + + await local.saveRawList( + updated.map((e) => e.toJson()).toList(), + ); + + developer.log('โœ… ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์™„๋ฃŒ: $id'); + } catch (e) { + developer.log('โŒ ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์‹คํŒจ: $e'); + rethrow; + } + } + + @override + Future markAllAsRead() async { + try { + final list = await fetchNotifications(); + final updated = list.map((n) => n.copyWith(isRead: true)).toList(); + + await local.saveRawList( + updated.map((e) => e.toJson()).toList(), + ); + + developer.log('โœ… ์ „์ฒด ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์™„๋ฃŒ'); + } catch (e) { + developer.log('โŒ ์ „์ฒด ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์‹คํŒจ: $e'); + rethrow; + } + } + + @override + Future delete(String id) async { + try { + final list = await fetchNotifications(); + final filtered = list.where((n) => n.id != id).toList(); + + await local.saveRawList( + filtered.map((e) => e.toJson()).toList(), + ); + + developer.log('โœ… ์•Œ๋ฆผ ์‚ญ์ œ ์™„๋ฃŒ: $id'); + } catch (e) { + developer.log('โŒ ์•Œ๋ฆผ ์‚ญ์ œ ์‹คํŒจ: $e'); + rethrow; + } + } + + @override + Future clearAll() async { + try { + await local.saveRawList([]); + developer.log('โœ… ์ „์ฒด ์•Œ๋ฆผ ์‚ญ์ œ ์™„๋ฃŒ'); + } catch (e) { + developer.log('โŒ ์ „์ฒด ์•Œ๋ฆผ ์‚ญ์ œ ์‹คํŒจ: $e'); + rethrow; + } + } +} + diff --git a/frontend/lib/domain/chapter/chapter_entity.dart b/frontend/lib/domain/chapter/chapter_entity.dart new file mode 100644 index 0000000..8c1a275 --- /dev/null +++ b/frontend/lib/domain/chapter/chapter_entity.dart @@ -0,0 +1,64 @@ +/// ์ฑ•ํ„ฐ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ +/// +/// API ์‘๋‹ต์„ ๋„๋ฉ”์ธ ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. +class ChapterEntity { + final int chapterId; + final int bookId; + final int mainChapterNumber; + final int subChapterNumber; + final String? chapterName; + final int chapterStartPage; + final int chapterEndPage; + final int chapterStartQuestion; + final int chapterEndQuestion; + final int totalChapterQuestion; + final int studentAnswerCount; + + ChapterEntity({ + required this.chapterId, + required this.bookId, + required this.mainChapterNumber, + required this.subChapterNumber, + this.chapterName, + required this.chapterStartPage, + required this.chapterEndPage, + required this.chapterStartQuestion, + required this.chapterEndQuestion, + required this.totalChapterQuestion, + required this.studentAnswerCount, + }); + + /// ์ง„ํ–‰๋ฅ  ๊ณ„์‚ฐ (0.0 ~ 1.0) + /// + /// **์ฃผ์˜**: progress๋Š” "ํ•™์ƒ์ด ํ‘ผ ๋ฌธ์ œ ์ˆ˜ / ์ „์ฒด ๋ฌธ์ œ ์ˆ˜"๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. + /// studentAnswerCount๋Š” ์„œ๋ฒ„์—์„œ ์ œ๊ณตํ•˜๋Š” "ํ•™์ƒ์ด ๋‹ต์•ˆ์„ ์ œ์ถœํ•œ ๋ฌธ์ œ ์ˆ˜"์ž…๋‹ˆ๋‹ค. + /// ์•„์ง ์ฑ„์ ๋˜์ง€ ์•Š์€ ๋ฌธ์ œ๋„ ํฌํ•จ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์‹ค์ œ ์™„๋ฃŒ์œจ๊ณผ๋Š” ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + /// + /// totalChapterQuestion์ด 0์ด๋ฉด 0.0์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + /// + /// **๊ฒฝ๊ณ„ ์กฐ๊ฑด**: + /// - totalChapterQuestion == 0 && studentAnswerCount > 0์ธ ๊ฒฝ์šฐ: + /// ๋ฐฑ์—”๋“œ ์ŠคํŽ™์ƒ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํ™ฉ์ด์ง€๋งŒ, ์•ˆ์ „ํ•˜๊ฒŒ 0.0์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + double get progress { + if (totalChapterQuestion <= 0) return 0.0; + return (studentAnswerCount / totalChapterQuestion).clamp(0.0, 1.0); + } + + /// ์ฑ•ํ„ฐ๋ช… ํฌ๋งทํŒ… "{chapterId}. {chapterName}" + /// + /// chapterId๋ฅผ ์ธ๋ฑ์Šค๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ์ฑ•ํ„ฐ๋ฅผ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„ํ•ฉ๋‹ˆ๋‹ค. + /// chapterName์ด null์ด๊ฑฐ๋‚˜ ๋นˆ ๋ฌธ์ž์—ด์ด๋ฉด "{chapterId}." ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + /// ์˜ˆ: "1. ์†Œ์ธ์ˆ˜๋ถ„ํ•ด" ๋˜๋Š” "1." + String get formattedName { + final base = '$chapterId.'; + if (chapterName == null || chapterName!.trim().isEmpty) { + return base; + } + return '$base $chapterName'; + } + + /// ๋ฌธ์ œ ์ˆ˜ ํ‘œ์‹œ ๋ฌธ์ž์—ด "{studentAnswerCount} / {totalChapterQuestion}" + String get problemCountDisplay { + return '$studentAnswerCount / $totalChapterQuestion'; + } +} diff --git a/frontend/lib/domain/chapter/chapter_repository.dart b/frontend/lib/domain/chapter/chapter_repository.dart new file mode 100644 index 0000000..2b2259e --- /dev/null +++ b/frontend/lib/domain/chapter/chapter_repository.dart @@ -0,0 +1,24 @@ +import 'chapter_entity.dart'; + +/// ์ฑ•ํ„ฐ Repository ์ธํ„ฐํŽ˜์ด์Šค +/// +/// ๋„๋ฉ”์ธ ๋ ˆ์ด์–ด์—์„œ ๋ฐ์ดํ„ฐ ๋ ˆ์ด์–ด์— ์˜์กดํ•˜์ง€ ์•Š๋„๋ก ์ถ”์ƒํ™”ํ•ฉ๋‹ˆ๋‹ค. +abstract class ChapterRepository { + /// bookId์™€ academyUserId๋กœ ์ฑ•ํ„ฐ ๋ชฉ๋ก ์กฐํšŒ + /// + /// [bookId]: ๋ฌธ์ œ์ง‘ ID + /// [academyUserId]: ํ•™์› ์‚ฌ์šฉ์ž ID + /// + /// ๋ฐ˜ํ™˜: ์ฑ•ํ„ฐ ์—”ํ‹ฐํ‹ฐ ๋ฆฌ์ŠคํŠธ (์ •๋ ฌ๋˜์ง€ ์•Š์€ ์ƒํƒœ) + Future> getChaptersByBookIdAndAcademyUserId( + int bookId, + int academyUserId, + ); + + /// chapterId๋กœ ๋‹จ์ผ ์ฑ•ํ„ฐ ์ •๋ณด ์กฐํšŒ + /// + /// [chapterId]: ์ฑ•ํ„ฐ ID + /// + /// ๋ฐ˜ํ™˜: ์ฑ•ํ„ฐ ์—”ํ‹ฐํ‹ฐ + Future getChapterById(int chapterId); +} diff --git a/frontend/lib/domain/chapter/get_chapters_for_book_use_case.dart b/frontend/lib/domain/chapter/get_chapters_for_book_use_case.dart new file mode 100644 index 0000000..3e4438d --- /dev/null +++ b/frontend/lib/domain/chapter/get_chapters_for_book_use_case.dart @@ -0,0 +1,41 @@ +import 'chapter_entity.dart'; +import 'chapter_repository.dart'; + +/// ๋ฌธ์ œ์ง‘์˜ ์ฑ•ํ„ฐ ๋ชฉ๋ก ์กฐํšŒ UseCase +/// +/// ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™: +/// 1. ์ฑ•ํ„ฐ๋ฅผ mainChapterNumber, subChapterNumber ์ˆœ์œผ๋กœ ์ •๋ ฌ +/// 2. ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜ +class GetChaptersForBookUseCase { + final ChapterRepository _repository; + + GetChaptersForBookUseCase({required ChapterRepository repository}) + : _repository = repository; + + /// ์ฑ•ํ„ฐ ๋ชฉ๋ก ์กฐํšŒ ๋ฐ ์ •๋ ฌ + /// + /// [bookId]: ๋ฌธ์ œ์ง‘ ID + /// [academyUserId]: ํ•™์› ์‚ฌ์šฉ์ž ID + /// + /// ๋ฐ˜ํ™˜: ์ •๋ ฌ๋œ ์ฑ•ํ„ฐ ์—”ํ‹ฐํ‹ฐ ๋ฆฌ์ŠคํŠธ + Future> call({ + required int bookId, + required int academyUserId, + }) async { + final chapters = await _repository.getChaptersByBookIdAndAcademyUserId( + bookId, + academyUserId, + ); + + // ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™: mainChapterNumber ์šฐ์„ , ๊ทธ ๋‹ค์Œ subChapterNumber๋กœ ์ •๋ ฌ + // โš ๏ธ Repository๊ฐ€ ์บ์‹ฑ๋œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๋ณต์‚ฌ ํ›„ ์ •๋ ฌ + final sorted = List.from(chapters); + sorted.sort((a, b) { + final mainCompare = a.mainChapterNumber.compareTo(b.mainChapterNumber); + if (mainCompare != 0) return mainCompare; + return a.subChapterNumber.compareTo(b.subChapterNumber); + }); + + return sorted; + } +} diff --git a/frontend/lib/domain/explanation/explanation_entity.dart b/frontend/lib/domain/explanation/explanation_entity.dart new file mode 100644 index 0000000..b9bb7b5 --- /dev/null +++ b/frontend/lib/domain/explanation/explanation_entity.dart @@ -0,0 +1,17 @@ +import '../question/question_identifier.dart'; + +/// ๋ฌธ์ œ ํ•ด์„ค ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ +class ExplanationEntity { + /// ์–ด๋–ค ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด์„ค์ธ์ง€ + final QuestionIdentifier question; + + /// ํ•ด์„ค ํ…์ŠคํŠธ + final String text; + + const ExplanationEntity({ + required this.question, + required this.text, + }); +} + + diff --git a/frontend/lib/domain/explanation/explanation_repository.dart b/frontend/lib/domain/explanation/explanation_repository.dart new file mode 100644 index 0000000..62f896a --- /dev/null +++ b/frontend/lib/domain/explanation/explanation_repository.dart @@ -0,0 +1,52 @@ +import 'explanation_entity.dart'; +import 'explanation_source.dart'; + +/// ํ•™์ƒ ๋‹ต์•ˆ ์ •๋ณด (findStudentAnswer ์‘๋‹ต) +class StudentAnswerInfo { + final int studentAnswerId; + final int studentResponseId; + final int chapterId; + final int page; + final int questionNumber; + final int subQuestionNumber; + final String answer; + final String? sectionUrl; + final double score; + final bool correct; + + const StudentAnswerInfo({ + required this.studentAnswerId, + required this.studentResponseId, + required this.chapterId, + required this.page, + required this.questionNumber, + required this.subQuestionNumber, + required this.answer, + this.sectionUrl, + required this.score, + required this.correct, + }); +} + +/// ๋ฌธ์ œ ํ•ด์„ค ์กฐํšŒ/์ƒ์„ฑ์„ ์œ„ํ•œ ๋„๋ฉ”์ธ Repository ์ธํ„ฐํŽ˜์ด์Šค +abstract class ExplanationRepository { + /// ํ•™์ƒ ๋‹ต์•ˆ ์ •๋ณด๋ฅผ ์กฐํšŒํ•œ๋‹ค. + Future findStudentAnswer(ExplanationSource source); + + /// ์ด๋ฏธ ์ƒ์„ฑ/์ €์žฅ๋œ ํ•ด์„ค์„ ์กฐํšŒํ•œ๋‹ค. ์—†์œผ๋ฉด null. + Future getExplanation(ExplanationSource source); + + /// ํ•ด์„ค ์ƒ์„ฑ์„ ์š”์ฒญํ•˜๊ณ , ๊ฒฐ๊ณผ ์Šค๋ƒ…์ƒท์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. + /// + /// [requestedByUserId]๋Š” ๋ˆ„๊ฐ€ ํ•ด์„ค ์ƒ์„ฑ์„ ์š”์ฒญํ–ˆ๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋กœ, + /// Domain์—์„œ๋Š” ์˜๋ฏธ๋ฅผ ํ•ด์„ํ•˜์ง€ ์•Š๊ณ  ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ๋งŒ ํ•œ๋‹ค. + /// [academyId]์™€ [answer]๋Š” findStudentAnswer์—์„œ ๊ฐ€์ ธ์˜จ ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. + Future requestExplanation( + ExplanationSource source, { + required int requestedByUserId, + required int academyId, + required String answer, + }); +} + + diff --git a/frontend/lib/domain/explanation/explanation_source.dart b/frontend/lib/domain/explanation/explanation_source.dart new file mode 100644 index 0000000..4cff59a --- /dev/null +++ b/frontend/lib/domain/explanation/explanation_source.dart @@ -0,0 +1,21 @@ +import '../question/question_identifier.dart'; + +/// ํ•ด์„ค ์กฐํšŒ/์ƒ์„ฑ์— ํ•„์š”ํ•œ ์™ธ๋ถ€ ์‹๋ณ„์ž + ๋ฌธ์ œ ์‹๋ณ„์ž ๋ฌถ์Œ +class ExplanationSource { + /// ํ•™์ƒ ๋‹ต์•ˆ ์‘๋‹ต ID + final int studentResponseId; + + /// ํ•™์› ์‚ฌ์šฉ์ž ID + final int academyUserId; + + /// ์–ด๋–ค ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด์„ค์ธ์ง€ + final QuestionIdentifier question; + + const ExplanationSource({ + required this.studentResponseId, + required this.academyUserId, + required this.question, + }); +} + + diff --git a/frontend/lib/domain/explanation/get_explanation_use_case.dart b/frontend/lib/domain/explanation/get_explanation_use_case.dart new file mode 100644 index 0000000..549e3e2 --- /dev/null +++ b/frontend/lib/domain/explanation/get_explanation_use_case.dart @@ -0,0 +1,17 @@ +import 'explanation_entity.dart'; +import 'explanation_repository.dart'; +import 'explanation_source.dart'; + +/// ์ด๋ฏธ ์ƒ์„ฑ๋œ ํ•ด์„ค์„ ์กฐํšŒํ•˜๋Š” UseCase +class GetExplanationUseCase { + final ExplanationRepository _repository; + + GetExplanationUseCase({required ExplanationRepository repository}) + : _repository = repository; + + Future call(ExplanationSource source) { + return _repository.getExplanation(source); + } +} + + diff --git a/frontend/lib/domain/explanation/request_explanation_use_case.dart b/frontend/lib/domain/explanation/request_explanation_use_case.dart new file mode 100644 index 0000000..0ca8862 --- /dev/null +++ b/frontend/lib/domain/explanation/request_explanation_use_case.dart @@ -0,0 +1,27 @@ +import 'explanation_entity.dart'; +import 'explanation_repository.dart'; +import 'explanation_source.dart'; + +/// ํ•ด์„ค ์ƒ์„ฑ์„ ์š”์ฒญํ•˜๋Š” UseCase +class RequestExplanationUseCase { + final ExplanationRepository _repository; + + RequestExplanationUseCase({required ExplanationRepository repository}) + : _repository = repository; + + Future call( + ExplanationSource source, { + required int requestedByUserId, + required int academyId, + required String answer, + }) { + return _repository.requestExplanation( + source, + requestedByUserId: requestedByUserId, + academyId: academyId, + answer: answer, + ); + } +} + + diff --git a/frontend/lib/domain/grading_history/grading_history_entity.dart b/frontend/lib/domain/grading_history/grading_history_entity.dart new file mode 100644 index 0000000..8e70362 --- /dev/null +++ b/frontend/lib/domain/grading_history/grading_history_entity.dart @@ -0,0 +1,99 @@ +/// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ +/// +/// API ์‘๋‹ต์˜ student response ์ •๋ณด๋ฅผ ๋„๋ฉ”์ธ ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. +class GradingHistoryEntity { + final int studentResponseId; + final int academyUserId; + final int? bookId; + final String? bookName; + final String? bookCoverImageUrl; // book_image_url + final int startPage; // response_start_page + final int endPage; // response_end_page + final String? className; // Repository์—์„œ ์ฃผ์ž… + final DateTime gradingDate; // created_at ํŒŒ์‹ฑ ํ›„ toLocal() + + // ์„ ํƒ์  ํ•„๋“œ (ํ˜„์žฌ UI์—์„œ ์‚ฌ์šฉ ์•ˆ ํ•˜์ง€๋งŒ ํ–ฅํ›„ ํ™•์žฅ ๊ฐ€๋Šฅ์„ฑ) + final int? assessId; + final int unrecognizedResponseCount; + + const GradingHistoryEntity({ + required this.studentResponseId, + required this.academyUserId, + this.bookId, + this.bookName, + this.bookCoverImageUrl, + required this.startPage, + required this.endPage, + this.className, + required this.gradingDate, + this.assessId, + this.unrecognizedResponseCount = 0, + }); + + /// โš ๏ธ ์„œ๋ฒ„ API ์‘๋‹ต์ด ์•„๋‹ˆ๋ผ, SharedPreferences ์บ์‹œ ์ „์šฉ JSON ์Šคํ‚ค๋งˆ์ž…๋‹ˆ๋‹ค. + /// + /// API ์‘๋‹ต์€ GradingHistoryApiResponse โ†’ UseCase โ†’ GradingHistoryEntity๋กœ ๋ณ€ํ™˜๋˜๋ฉฐ, + /// ์ด ๋ฉ”์„œ๋“œ๋Š” ์บ์‹œ์—์„œ ๋ณต์›ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. + /// + /// ์บ์‹œ ์Šคํ‚ค๋งˆ: + /// - book_cover_image_url (API: book_image_url) + /// - start_page (API: response_start_page) + /// - end_page (API: response_end_page) + /// - grading_date (API: created_at) + factory GradingHistoryEntity.fromCacheJson(Map json) { + return GradingHistoryEntity( + studentResponseId: json['student_response_id'] as int? ?? 0, + academyUserId: json['academy_user_id'] as int? ?? 0, + bookId: json['book_id'] as int?, + bookName: json['book_name'] as String?, + bookCoverImageUrl: json['book_cover_image_url'] as String?, + startPage: json['start_page'] as int? ?? 0, + endPage: json['end_page'] as int? ?? 0, + className: json['class_name'] as String?, + gradingDate: _parseGradingDate(json['grading_date']), + assessId: json['assess_id'] as int?, + unrecognizedResponseCount: + json['unrecognized_response_count'] as int? ?? 0, + ); + } + + /// โš ๏ธ ์„œ๋ฒ„ API ์‘๋‹ต์ด ์•„๋‹ˆ๋ผ, SharedPreferences ์บ์‹œ ์ „์šฉ JSON ์Šคํ‚ค๋งˆ์ž…๋‹ˆ๋‹ค. + /// + /// ์บ์‹œ ์ €์žฅ ์‹œ ์‚ฌ์šฉ๋˜๋ฉฐ, API ์Šคํ‚ค๋งˆ์™€๋Š” ๋‹ค๋ฅธ ํ‚ค ์ด๋ฆ„์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. + Map toCacheJson() { + return { + 'student_response_id': studentResponseId, + 'academy_user_id': academyUserId, + 'book_id': bookId, + 'book_name': bookName, + 'book_cover_image_url': bookCoverImageUrl, + 'start_page': startPage, + 'end_page': endPage, + 'class_name': className, + 'grading_date': gradingDate.toIso8601String(), + 'assess_id': assessId, + 'unrecognized_response_count': unrecognizedResponseCount, + }; + } + + /// ์บ์‹œ์—์„œ grading_date๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ํŒŒ์‹ฑ + /// + /// ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ์ด๋‚˜ ์†์ƒ๋œ ์บ์‹œ ๋ฐ์ดํ„ฐ์— ๋Œ€๋น„ํ•œ ๋ฐฉ์–ด ๋กœ์ง + static DateTime _parseGradingDate(dynamic value) { + if (value == null) { + // ๊ฐ’์ด ์—†์œผ๋ฉด ๊ณผ๊ฑฐ ๊ณ ์ •๊ฐ’ ๋ฐ˜ํ™˜ (์ •๋ ฌ ์‹œ ๋’ค๋กœ ๊ฐ€๋„๋ก) + return DateTime(1970, 1, 1); + } + + if (value is! String) { + return DateTime(1970, 1, 1); + } + + try { + return DateTime.parse(value).toLocal(); + } catch (_) { + // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๊ณผ๊ฑฐ ๊ณ ์ •๊ฐ’ ๋ฐ˜ํ™˜ + return DateTime(1970, 1, 1); + } + } +} diff --git a/frontend/lib/domain/grading_history/grading_history_repository.dart b/frontend/lib/domain/grading_history/grading_history_repository.dart new file mode 100644 index 0000000..016da9d --- /dev/null +++ b/frontend/lib/domain/grading_history/grading_history_repository.dart @@ -0,0 +1,11 @@ +import 'grading_history_entity.dart'; + +/// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ Repository ์ธํ„ฐํŽ˜์ด์Šค +abstract class GradingHistoryRepository { + /// ์—ฌ๋Ÿฌ academyUserId์— ๋Œ€ํ•œ ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ์กฐํšŒ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: academyUserId๋ฅผ ํ‚ค๋กœ ํ•˜๋Š” Map + /// UI์—์„œ ํ•„์š”์‹œ flatํ•˜๊ฒŒ ํ•ฉ์ณ์„œ ์‚ฌ์šฉ + Future>> + getGradingHistoriesByAcademyUserIds(List academyUserIds); +} diff --git a/frontend/lib/domain/learning/daily_learning_status.dart b/frontend/lib/domain/learning/daily_learning_status.dart new file mode 100644 index 0000000..4385c30 --- /dev/null +++ b/frontend/lib/domain/learning/daily_learning_status.dart @@ -0,0 +1,71 @@ +/// ์ผ๋ณ„ ํ•™์Šต ์ƒํƒœ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ +/// +/// UI ๋ ˆ์ด์–ด์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํ†ตํ•ฉ ๋ชจ๋ธ๋กœ, +/// Assessment์™€ GradingHistory๋ฅผ ๋ชจ๋‘ ์ถ”์ƒํ™”ํ•ฉ๋‹ˆ๋‹ค. +/// +/// ์ฃผ์˜์‚ฌํ•ญ: +/// - date๋Š” ํ•ญ์ƒ DateTime(year, month, day) (์‹œ๊ฐ„ 00:00)๋กœ ์ •๊ทœํ™”ํ•ด์„œ ์ €์žฅ/๋น„๊ตํ•ฉ๋‹ˆ๋‹ค. +class DailyLearningStatus { + final DateTime date; + final bool isCompleted; + + // ํ–ฅํ›„ ํ™•์žฅ ํ•„๋“œ + final List? bookProgresses; // ํ•ด๋‹น ๋‚ ์งœ์— ํ‘ผ ๋ฌธ์ œ์ง‘๋ณ„ ์ง„ํ–‰๋ฅ  + + const DailyLearningStatus({ + required this.date, + required this.isCompleted, + this.bookProgresses, + }); + + /// ๋‚ ์งœ ๋ฌธ์ž์—ด (YYYY-MM-DD) + String get dateString { + return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; + } + + /// DateTime์„ ์ •๊ทœํ™” (์‹œ๊ฐ„์„ 00:00์œผ๋กœ ์„ค์ •) + /// + /// Map์˜ key๋กœ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋น„๊ตํ•  ๋•Œ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. + static DateTime normalizeDate(DateTime date) { + return DateTime(date.year, date.month, date.day); + } +} + +/// ๋ฌธ์ œ์ง‘๋ณ„ ์ง„ํ–‰๋ฅ  Value Object +/// +/// ํŠน์ • ๋‚ ์งœ์— ๋Œ€ํ•œ ๋ฌธ์ œ์ง‘๋ณ„ ํ•™์Šต ์ง„ํ–‰๋ฅ ์„ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค. +class BookProgress { + final int? bookId; + final String bookName; + final String? bookCoverImageUrl; + final int todayPages; // ํ•ด๋‹น ๋‚ ์งœ์— ํ‘ผ ํŽ˜์ด์ง€ ์ˆ˜ + final int accumulatedPages; // ํ•ด๋‹น ๋‚ ์งœ ์ด์ „๊นŒ์ง€ ๋ˆ„์  ํŽ˜์ด์ง€ ์ˆ˜ + final int totalPages; // ์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜ + + const BookProgress({ + this.bookId, + required this.bookName, + this.bookCoverImageUrl, + required this.todayPages, + required this.accumulatedPages, + required this.totalPages, + }); + + /// ๋ˆ„์  ์ง„ํ–‰๋ฅ  (0.0 ~ 1.0) + double get accumulatedRatio { + if (totalPages <= 0) return 0.0; + return (accumulatedPages / totalPages).clamp(0.0, 1.0); + } + + /// ๋‹น์ผ ์ง„ํ–‰๋ฅ  (0.0 ~ 1.0) + double get todayRatio { + if (totalPages <= 0) return 0.0; + return (todayPages / totalPages).clamp(0.0, 1.0); + } + + /// ์ „์ฒด ์ง„ํ–‰๋ฅ  (๋ˆ„์  + ๋‹น์ผ) + double get totalRatio { + if (totalPages <= 0) return 0.0; + return ((accumulatedPages + todayPages) / totalPages).clamp(0.0, 1.0); + } +} diff --git a/frontend/lib/domain/learning/get_monthly_learning_status_use_case.dart b/frontend/lib/domain/learning/get_monthly_learning_status_use_case.dart new file mode 100644 index 0000000..bdbf694 --- /dev/null +++ b/frontend/lib/domain/learning/get_monthly_learning_status_use_case.dart @@ -0,0 +1,25 @@ +import 'daily_learning_status.dart'; + +/// ์›”๋ณ„ ํ•™์Šต ์ƒํƒœ ์กฐํšŒ UseCase ์ธํ„ฐํŽ˜์ด์Šค +/// +/// Domain Layer์˜ ์ถ”์ƒ ์ธํ„ฐํŽ˜์ด์Šค๋กœ, +/// Data Layer์—์„œ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. +abstract class GetMonthlyLearningStatusUseCase { + /// ํŠน์ • ์›”์˜ ์ผ๋ณ„ ํ•™์Šต ์ƒํƒœ ์กฐํšŒ + /// + /// [month]: ์กฐํšŒํ•  ์›” (์ฒซ ๋ฒˆ์งธ ๋‚ ์งœ๋กœ ํ‘œํ˜„, ์˜ˆ: DateTime(2025, 11, 1)) + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ํ•ด๋‹น ์›”์˜ ๋ชจ๋“  ๋‚ ์งœ์— ๋Œ€ํ•œ DailyLearningStatus ๋ฆฌ์ŠคํŠธ + /// ๋‚ ์งœ ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌ๋˜์–ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. + /// ๊ฐ DailyLearningStatus.date๋Š” ์ •๊ทœํ™”๋œ DateTime(year, month, day)์ž…๋‹ˆ๋‹ค. + Future> call(DateTime month); + + /// ํŠน์ • ๋‚ ์งœ์˜ ํ•™์Šต ์ƒํƒœ ์กฐํšŒ + /// + /// [date]: ์กฐํšŒํ•  ๋‚ ์งœ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ํ•ด๋‹น ๋‚ ์งœ์˜ DailyLearningStatus + /// date๋Š” ์ •๊ทœํ™”๋œ DateTime(year, month, day)์ž…๋‹ˆ๋‹ค. + Future getStatusForDate(DateTime date); +} + diff --git a/frontend/lib/domain/learning/learning_completion_service.dart b/frontend/lib/domain/learning/learning_completion_service.dart new file mode 100644 index 0000000..2e123b5 --- /dev/null +++ b/frontend/lib/domain/learning/learning_completion_service.dart @@ -0,0 +1,79 @@ +import '../../models/assessment.dart'; +import '../grading_history/grading_history_entity.dart'; + +/// ํ•™์Šต ์™„๋ฃŒ ์—ฌ๋ถ€ ํŒ๋‹จ Service ์ธํ„ฐํŽ˜์ด์Šค +/// +/// Domain Layer์˜ ์ถ”์ƒ ์ธํ„ฐํŽ˜์ด์Šค๋กœ, +/// "์–ด๋–ค ๋‚ ์„ ์™„๋ฃŒ๋กœ ๋ณผ ๊ฒƒ์ธ๊ฐ€"๋ผ๋Š” ๋„๋ฉ”์ธ ๊ทœ์น™์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. +/// +/// ์ฃผ์˜: ์ด ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ˆœ์ˆ˜ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. +/// ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€์ง€ ์•Š์œผ๋ฉฐ, ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋งŒ์œผ๋กœ ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค. +abstract class LearningCompletionService { + /// ํŠน์ • ๋‚ ์งœ๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋Š”์ง€ ํŒ๋‹จ + /// + /// [date]: ํŒ๋‹จํ•  ๋‚ ์งœ (์ •๊ทœํ™”๋œ DateTime) + /// [assessmentsByDate]: ๋‚ ์งœ๋ณ„ Assessment ๋งต (YYYY-MM-DD ํ˜•์‹์˜ ํ‚ค) + /// [gradingHistoriesByDate]: ๋‚ ์งœ๋ณ„ GradingHistory ๋งต (YYYY-MM-DD ํ˜•์‹์˜ ํ‚ค) + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉด true + /// + /// ๊ทœ์น™: + /// 1. GradingHistory๊ฐ€ ์žˆ์œผ๋ฉด โ†’ GradingHistory ๊ธฐ์ค€์œผ๋กœ ํŒ๋‹จ (์šฐ์„ ์ˆœ์œ„ 1) + /// - ํ•ด๋‹น ๋‚ ์งœ์— gradingDate๊ฐ€ ์žˆ๋Š” GradingHistory๊ฐ€ 1๊ฐœ ์ด์ƒ ์žˆ์œผ๋ฉด ์™„๋ฃŒ + /// 2. GradingHistory๊ฐ€ ์—†์œผ๋ฉด โ†’ Assessment ๊ธฐ์ค€์œผ๋กœ ํŒ๋‹จ (์šฐ์„ ์ˆœ์œ„ 2) + /// - ํ•ด๋‹น ๋‚ ์งœ์˜ Assessment ์ค‘ ํ•˜๋‚˜๋ผ๋„ assessStatus == 'Y'์ด๋ฉด ์™„๋ฃŒ + /// 3. ๋‘˜ ๋‹ค ์—†์œผ๋ฉด โ†’ false + /// + /// ํ•˜๋ฃจ์— ์—ฌ๋Ÿฌ ๋ฒˆ ํ‘ผ ๊ฒฝ์šฐ: + /// - GradingHistory: ์—ฌ๋Ÿฌ history๊ฐ€ ์žˆ์–ด๋„ 1๊ฐœ ์ด์ƒ์ด๋ฉด ์™„๋ฃŒ๋กœ ํŒ๋‹จ + /// - Assessment: ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ์–ด๋„ ํ•˜๋‚˜๋ผ๋„ 'Y'๋ฉด ์™„๋ฃŒ๋กœ ํŒ๋‹จ + bool isCompleted({ + required DateTime date, + Map>? assessmentsByDate, + Map>? gradingHistoriesByDate, + }); + + /// ๋‚ ์งœ ๋ฒ”์œ„์˜ ์™„๋ฃŒ ์—ฌ๋ถ€ ๋งต ์กฐํšŒ + /// + /// [startDate]: ์‹œ์ž‘ ๋‚ ์งœ (์ •๊ทœํ™”๋œ DateTime) + /// [endDate]: ์ข…๋ฃŒ ๋‚ ์งœ (์ •๊ทœํ™”๋œ DateTime, ํฌํ•จ) + /// [assessmentsByDate]: ๋‚ ์งœ๋ณ„ Assessment ๋งต + /// [gradingHistoriesByDate]: ๋‚ ์งœ๋ณ„ GradingHistory ๋งต + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ๋‚ ์งœ๋ณ„ ์™„๋ฃŒ ์—ฌ๋ถ€ ๋งต (์ •๊ทœํ™”๋œ DateTime์„ ํ‚ค๋กœ ์‚ฌ์šฉ) + Map getCompletionMap({ + required DateTime startDate, + required DateTime endDate, + Map>? assessmentsByDate, + Map>? gradingHistoriesByDate, + }); + + /// ์—ฐ์† ํ•™์Šต์ผ ๊ณ„์‚ฐ + /// + /// [date]: ๊ธฐ์ค€ ๋‚ ์งœ (์ด ๋‚ ์งœ๋ถ€ํ„ฐ ์—ญ์ˆœ์œผ๋กœ ๊ณ„์‚ฐ, ์ •๊ทœํ™”๋œ DateTime) + /// [assessmentsByDate]: ๋‚ ์งœ๋ณ„ Assessment ๋งต + /// [gradingHistoriesByDate]: ๋‚ ์งœ๋ณ„ GradingHistory ๋งต + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ์—ฐ์† ํ•™์Šต์ผ ์ˆ˜ + int getConsecutiveDays({ + required DateTime date, + Map>? assessmentsByDate, + Map>? gradingHistoriesByDate, + }); + + /// ์—ฐ์† ํ•™์Šต์ผ ์—ฐ๊ฒฐ์„  ํ‘œ์‹œ ์—ฌ๋ถ€ ํŒ๋‹จ + /// + /// [date]: ํ˜„์žฌ ๋‚ ์งœ (์ •๊ทœํ™”๋œ DateTime) + /// [nextDate]: ๋‹ค์Œ ๋‚ ์งœ (์ •๊ทœํ™”๋œ DateTime) + /// [assessmentsByDate]: ๋‚ ์งœ๋ณ„ Assessment ๋งต + /// [gradingHistoriesByDate]: ๋‚ ์งœ๋ณ„ GradingHistory ๋งต + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ๋‘ ๋‚ ์งœ ๋ชจ๋‘ ์™„๋ฃŒ๋˜๊ณ  ๊ฐ™์€ ์›”์— ์†ํ•˜๋ฉด true + bool shouldShowConnector({ + required DateTime date, + required DateTime nextDate, + Map>? assessmentsByDate, + Map>? gradingHistoriesByDate, + }); +} + diff --git a/frontend/lib/domain/notification/notification_entity.dart b/frontend/lib/domain/notification/notification_entity.dart new file mode 100644 index 0000000..83bf366 --- /dev/null +++ b/frontend/lib/domain/notification/notification_entity.dart @@ -0,0 +1,136 @@ +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'dart:convert'; +import 'notification_type.dart'; +import '../../utils/app_logger.dart'; + +/// ์•Œ๋ฆผ ์—”ํ‹ฐํ‹ฐ (๋„๋ฉ”์ธ ๋ชจ๋ธ) +class NotificationEntity { + final String id; + final NotificationType type; + final String title; + final String message; + final DateTime time; + final bool isRead; + final Map? data; + + const NotificationEntity({ + required this.id, + required this.type, + required this.title, + required this.message, + required this.time, + required this.isRead, + this.data, + }); + + /// Immutable copyWith ๋ฉ”์„œ๋“œ + NotificationEntity copyWith({ + String? id, + NotificationType? type, + String? title, + String? message, + DateTime? time, + bool? isRead, + Map? data, + }) { + return NotificationEntity( + id: id ?? this.id, + type: type ?? this.type, + title: title ?? this.title, + message: message ?? this.message, + time: time ?? this.time, + isRead: isRead ?? this.isRead, + data: data ?? this.data, + ); + } + + /// JSON์œผ๋กœ ๋ณ€ํ™˜ + Map toJson() { + return { + 'id': id, + 'type': type.toStringValue(), + 'title': title, + 'message': message, + 'time': time.toIso8601String(), + 'isRead': isRead, + if (data != null) 'data': data, + }; + } + + /// JSON์—์„œ ์ƒ์„ฑ + factory NotificationEntity.fromJson(Map json) { + return NotificationEntity( + id: json['id'] as String, + type: NotificationTypeUtil.fromString(json['type'] as String), + title: json['title'] as String, + message: json['message'] as String, + time: DateTime.parse(json['time'] as String), + isRead: json['isRead'] as bool? ?? false, + data: json['data'] as Map?, + ); + } + + /// FCM RemoteMessage์—์„œ ์ƒ์„ฑ + factory NotificationEntity.fromRemoteMessage(RemoteMessage message) { + appLog( + '[notification:notification_entity][timecheck] fromRemoteMessage ํ˜ธ์ถœ', + ); + appLog( + '[notification:notification_entity][timecheck] ๋ฉ”์‹œ์ง€ data: ${json.encode(message.data)}', + ); + if (message.notification != null) { + appLog( + '[notification:notification_entity][timecheck] notification.title: ${message.notification!.title}', + ); + appLog( + '[notification:notification_entity][timecheck] notification.body: ${message.notification!.body}', + ); + } + appLog( + '[notification:notification_entity] ์ „์ฒด ๋ฉ”์‹œ์ง€ JSON: ${json.encode({ + 'messageId': message.messageId, + 'data': message.data, + 'notification': message.notification != null ? {'title': message.notification!.title, 'body': message.notification!.body} : null, + 'sentTime': message.sentTime?.toIso8601String(), + })}', + ); + + final data = message.data; + final notification = message.notification; + + // ID ์ƒ์„ฑ: messageId ์šฐ์„ , ์—†์œผ๋ฉด data['notificationId'], ์—†์œผ๋ฉด timestamp ๊ธฐ๋ฐ˜ + final id = + message.messageId ?? + data['notificationId'] ?? + 'fcm_${DateTime.now().millisecondsSinceEpoch}'; + + // ์ œ๋ชฉ ์ถ”์ถœ: data['title'] ์šฐ์„ , ์—†์œผ๋ฉด notification.title, ์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ + final title = data['title'] as String? ?? notification?.title ?? '์•Œ๋ฆผ'; + + // ํƒ€์ž… ์ถ”์ถœ: data['type'] ์šฐ์„ , ์—†์œผ๋ฉด title ๊ธฐ๋ฐ˜์œผ๋กœ ํŒ๋‹จ, ์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ + final typeString = data['type'] as String?; + final type = typeString != null + ? NotificationTypeUtil.fromString(typeString) + : NotificationTypeUtil.fromTitle(title); + + // ๋ฉ”์‹œ์ง€ ์ถ”์ถœ: data['message'] ์šฐ์„ , ์—†์œผ๋ฉด notification.body, ์—†์œผ๋ฉด ๊ธฐ๋ณธ๊ฐ’ + final messageText = + data['message'] as String? ?? + data['body'] as String? ?? + notification?.body ?? + ''; + + // ์‹œ๊ฐ„: sentTime ์šฐ์„ , ์—†์œผ๋ฉด ํ˜„์žฌ ์‹œ๊ฐ„ + final time = message.sentTime ?? DateTime.now(); + + return NotificationEntity( + id: id, + type: type, + title: title, + message: messageText, + time: time, + isRead: false, // ์ƒˆ ์•Œ๋ฆผ์€ ํ•ญ์ƒ ์ฝ์ง€ ์•Š์Œ + data: data.isNotEmpty ? data : null, + ); + } +} diff --git a/frontend/lib/domain/notification/notification_repository.dart b/frontend/lib/domain/notification/notification_repository.dart new file mode 100644 index 0000000..bf04fec --- /dev/null +++ b/frontend/lib/domain/notification/notification_repository.dart @@ -0,0 +1,23 @@ +import 'notification_entity.dart'; + +/// ์•Œ๋ฆผ ์ €์žฅ์†Œ ์ธํ„ฐํŽ˜์ด์Šค +abstract class NotificationRepository { + /// ์•Œ๋ฆผ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ (์ตœ์‹ ์ˆœ) + Future> fetchNotifications(); + + /// ์•Œ๋ฆผ ์ €์žฅ + Future saveNotification(NotificationEntity notification); + + /// ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ + Future markAsRead(String id); + + /// ์ „์ฒด ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ + Future markAllAsRead(); + + /// ์•Œ๋ฆผ ์‚ญ์ œ + Future delete(String id); + + /// ์ „์ฒด ์•Œ๋ฆผ ์‚ญ์ œ + Future clearAll(); +} + diff --git a/frontend/lib/domain/notification/notification_type.dart b/frontend/lib/domain/notification/notification_type.dart new file mode 100644 index 0000000..50191ee --- /dev/null +++ b/frontend/lib/domain/notification/notification_type.dart @@ -0,0 +1,75 @@ +/// ์•Œ๋ฆผ ํƒ€์ž… +enum NotificationType { + homework, // ์ˆ™์ œ ๊ด€๋ จ + learningReminder, // ํ•™์Šต ๋ฆฌ๋งˆ์ธ๋” + academyNotice, // ํ•™์› ๊ณต์ง€์‚ฌํ•ญ + grading, // ์ฑ„์  ์™„๋ฃŒ + achievement, // ํ•™์Šต ๋ชฉํ‘œ ๋‹ฌ์„ฑ +} + +/// NotificationType ํ™•์žฅ ๋ฉ”์„œ๋“œ +extension NotificationTypeExtension on NotificationType { + /// NotificationType์„ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ + String toStringValue() { + switch (this) { + case NotificationType.homework: + return 'homework'; + case NotificationType.learningReminder: + return 'learningReminder'; + case NotificationType.academyNotice: + return 'academyNotice'; + case NotificationType.grading: + return 'grading'; + case NotificationType.achievement: + return 'achievement'; + } + } +} + +/// NotificationType ์œ ํ‹ธ๋ฆฌํ‹ฐ +class NotificationTypeUtil { + /// ๋ฌธ์ž์—ด์—์„œ NotificationType์œผ๋กœ ๋ณ€ํ™˜ + static NotificationType fromString(String value) { + switch (value.toLowerCase()) { + case 'homework': + return NotificationType.homework; + case 'learningreminder': + case 'learning_reminder': + return NotificationType.learningReminder; + case 'academynotice': + case 'academy_notice': + return NotificationType.academyNotice; + case 'grading': + return NotificationType.grading; + case 'achievement': + return NotificationType.achievement; + default: + return NotificationType.learningReminder; // ๊ธฐ๋ณธ๊ฐ’ + } + } + + /// ์ œ๋ชฉ(title)์—์„œ NotificationType์œผ๋กœ ๋ณ€ํ™˜ + static NotificationType fromTitle(String title) { + final lowerTitle = title.toLowerCase(); + + // ์šฐ์„ ์ˆœ์œ„: ๋” ๊ตฌ์ฒด์ ์ธ ํ‚ค์›Œ๋“œ๋ถ€ํ„ฐ ํ™•์ธ + if (lowerTitle.contains('์ฑ„์ ') || lowerTitle.contains('ํ•ด์„ค')) { + return NotificationType.grading; + } + if (lowerTitle.contains('์ˆ™์ œ')) { + return NotificationType.homework; + } + if (lowerTitle.contains('๋ชฉํ‘œ ๋‹ฌ์„ฑ')) { + return NotificationType.achievement; + } + if (lowerTitle.contains('๋ฆฌ๋งˆ์ธ๋”')) { + return NotificationType.learningReminder; + } + if (lowerTitle.contains('ํ•™์›') || lowerTitle.contains('๊ณต์ง€์‚ฌํ•ญ')) { + return NotificationType.academyNotice; + } + + // ๊ธฐ๋ณธ๊ฐ’ + return NotificationType.learningReminder; + } +} diff --git a/frontend/lib/domain/question/question_identifier.dart b/frontend/lib/domain/question/question_identifier.dart new file mode 100644 index 0000000..ae1de59 --- /dev/null +++ b/frontend/lib/domain/question/question_identifier.dart @@ -0,0 +1,27 @@ +/// ๋ฌธ์ œ๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ๋„๋ฉ”์ธ Value Object +class QuestionIdentifier { + /// ๋ฌธ์ œ์ง‘ ID + final int bookId; + + /// ์ฑ•ํ„ฐ ID + final int chapterId; + + /// ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ + final int page; + + /// ๋ฌธ์ œ ๋ฒˆํ˜ธ + final int questionNumber; + + /// ์„œ๋ธŒ ๋ฌธํ•ญ ๋ฒˆํ˜ธ (0์ด๋ฉด ์„œ๋ธŒ ๋ฌธํ•ญ ์—†์Œ) + final int subQuestionNumber; + + const QuestionIdentifier({ + required this.bookId, + required this.chapterId, + required this.page, + required this.questionNumber, + required this.subQuestionNumber, + }); +} + + diff --git a/frontend/lib/domain/section_image/get_section_image_use_case.dart b/frontend/lib/domain/section_image/get_section_image_use_case.dart new file mode 100644 index 0000000..e7c8ba8 --- /dev/null +++ b/frontend/lib/domain/section_image/get_section_image_use_case.dart @@ -0,0 +1,30 @@ +import 'section_image_entity.dart'; +import 'section_image_repository.dart'; + +/// Section ์ด๋ฏธ์ง€ URL์„ ์กฐํšŒํ•˜๋Š” UseCase +class GetSectionImageUseCase { + final SectionImageRepository _repository; + + GetSectionImageUseCase({ + required SectionImageRepository repository, + }) : _repository = repository; + + /// Section ์ด๋ฏธ์ง€ URL ์กฐํšŒ + /// + /// ๋ฐ˜ํ™˜: ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์œผ๋ฉด SectionImageEntity, ์—†์œผ๋ฉด null + Future call({ + required int academyUserId, + required int studentResponseId, + required int questionNumber, + required int subQuestionNumber, + }) { + return _repository.getSectionImageUrl( + academyUserId: academyUserId, + studentResponseId: studentResponseId, + questionNumber: questionNumber, + subQuestionNumber: subQuestionNumber, + ); + } +} + + diff --git a/frontend/lib/domain/section_image/section_image_entity.dart b/frontend/lib/domain/section_image/section_image_entity.dart new file mode 100644 index 0000000..6213d8e --- /dev/null +++ b/frontend/lib/domain/section_image/section_image_entity.dart @@ -0,0 +1,10 @@ +/// Section ์ด๋ฏธ์ง€ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ +class SectionImageEntity { + final String imageUrl; // ์™„์„ฑ๋œ ์ด๋ฏธ์ง€ URL + + const SectionImageEntity({ + required this.imageUrl, + }); +} + + diff --git a/frontend/lib/domain/section_image/section_image_repository.dart b/frontend/lib/domain/section_image/section_image_repository.dart new file mode 100644 index 0000000..f905de1 --- /dev/null +++ b/frontend/lib/domain/section_image/section_image_repository.dart @@ -0,0 +1,23 @@ +import 'section_image_entity.dart'; + +/// Section ์ด๋ฏธ์ง€ Repository ์ธํ„ฐํŽ˜์ด์Šค +abstract class SectionImageRepository { + /// Section ์ด๋ฏธ์ง€ URL ์กฐํšŒ + /// + /// [academyUserId]: ํ•™์› ์‚ฌ์šฉ์ž ID + /// [studentResponseId]: ํ•™์ƒ ์‘๋‹ต ID + /// [questionNumber]: ๋ฌธ์ œ ๋ฒˆํ˜ธ + /// [subQuestionNumber]: ์†Œ๋ฌธ์ œ ๋ฒˆํ˜ธ (0์ด๋ฉด ๋ฉ”์ธ ๋ฌธ์ œ) + /// + /// ๋ฐ˜ํ™˜: Section ์ด๋ฏธ์ง€ ์—”ํ‹ฐํ‹ฐ (์ด๋ฏธ์ง€๊ฐ€ ์—†์œผ๋ฉด null) + /// + /// ์ฐธ๊ณ : ์ด๋ฏธ์ง€๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋Š” ์ •์ƒ์ ์ธ ์ผ€์ด์Šค๋กœ ๊ฐ„์ฃผํ•˜์—ฌ null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + Future getSectionImageUrl({ + required int academyUserId, + required int studentResponseId, + required int questionNumber, + required int subQuestionNumber, + }); +} + + diff --git a/frontend/lib/domain/student_answer/get_student_answers_for_response_use_case.dart b/frontend/lib/domain/student_answer/get_student_answers_for_response_use_case.dart new file mode 100644 index 0000000..cb7d905 --- /dev/null +++ b/frontend/lib/domain/student_answer/get_student_answers_for_response_use_case.dart @@ -0,0 +1,16 @@ +import 'student_answer_entity.dart'; +import 'student_answer_repository.dart'; + +/// studentResponseId๋กœ ํ•™์ƒ ๋‹ต์•ˆ ๋ชฉ๋ก์„ ์กฐํšŒํ•˜๋Š” UseCase +class GetStudentAnswersForResponseUseCase { + final StudentAnswerRepository _repository; + + GetStudentAnswersForResponseUseCase({ + required StudentAnswerRepository repository, + }) : _repository = repository; + + /// studentResponseId๋กœ ํ•™์ƒ ๋‹ต์•ˆ ๋ชฉ๋ก ์กฐํšŒ + Future> call(int studentResponseId) { + return _repository.getStudentAnswersByResponseId(studentResponseId); + } +} diff --git a/frontend/lib/domain/student_answer/student_answer_entity.dart b/frontend/lib/domain/student_answer/student_answer_entity.dart new file mode 100644 index 0000000..a48058a --- /dev/null +++ b/frontend/lib/domain/student_answer/student_answer_entity.dart @@ -0,0 +1,35 @@ +/// ํ•™์ƒ ๋‹ต์•ˆ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ +class StudentAnswerEntity { + final int studentAnswerId; // ํ•„์ˆ˜ (0์ด๋ฉด ์œ ํšจํ•˜์ง€ ์•Š์Œ) + final int studentResponseId; // ํ•„์ˆ˜ (0์ด๋ฉด ์œ ํšจํ•˜์ง€ ์•Š์Œ) + final int? chapterId; + final int page; + final int questionNumber; + final int subQuestionNumber; + final String answer; // ๋ฌธ์ž์—ด (๊ฐ๊ด€์‹/์ฃผ๊ด€์‹ ๋ชจ๋‘ ํฌํ•จ) + final String? sectionUrl; // ๋ฌธ์ œ ์ด๋ฏธ์ง€ URL (ํ–ฅํ›„ ํ™•์žฅ) + final bool? isCorrect; // null = ๋‹ต์•ˆ ์—†์Œ, true = ๋งž์Œ, false = ํ‹€๋ฆผ + final double score; + + const StudentAnswerEntity({ + required this.studentAnswerId, + required this.studentResponseId, + this.chapterId, + required this.page, + required this.questionNumber, + required this.subQuestionNumber, + required this.answer, + this.sectionUrl, + required this.isCorrect, + required this.score, + }); + + /// answer๊ฐ€ ๋น„์–ด์žˆ๋Š”์ง€ ํ™•์ธ (์ธ์‹ ์‹คํŒจ ์—ฌ๋ถ€ ํŒ๋‹จ์šฉ) + /// + /// ํ˜„์žฌ๋Š” answer๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด ์ธ์‹ ์‹คํŒจ๋กœ ๊ฐ„์ฃผํ•˜์ง€๋งŒ, + /// ๋‚˜์ค‘์— ์„œ๋ฒ„์—์„œ ๋ณ„๋„์˜ ์ธ์‹ ์‹คํŒจ ํ”Œ๋ž˜๊ทธ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๊ทธ๊ฑธ ์‚ฌ์šฉํ•  ์˜ˆ์ • + /// + /// ์ฐธ๊ณ : UI ๋ ˆ์ด์–ด์—์„œ๋Š” ๊ณต๋ฐฑ๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ๋„ ๋นˆ ๊ฐ’์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, + /// Domain ๋ ˆ์ด์–ด์—์„œ๋Š” ๊ณต๋ฐฑ๋„ ์œ ํšจํ•œ ๋‹ต์œผ๋กœ ์ทจ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค. + bool get isEmptyAnswer => answer.isEmpty; +} diff --git a/frontend/lib/domain/student_answer/student_answer_query.dart b/frontend/lib/domain/student_answer/student_answer_query.dart new file mode 100644 index 0000000..8e8c98e --- /dev/null +++ b/frontend/lib/domain/student_answer/student_answer_query.dart @@ -0,0 +1,37 @@ +/// ํ•™์ƒ ๋‹ต์•ˆ ์กฐํšŒ ์กฐ๊ฑด (ํƒ€์ž… ์•ˆ์ „ํ•œ Query ๊ฐ์ฒด) +/// +/// ํ•„ํ„ฐ ์กฐ๊ฑด์„ ๋ช…์‹œ์ ์œผ๋กœ ํƒ€์ž…์œผ๋กœ ํ‘œํ˜„ํ•˜์—ฌ +/// ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์œผ๋กœ ์ด๋™ +abstract class StudentAnswerQuery { + const StudentAnswerQuery(); + + /// chapterId + academyUserId๋กœ ์กฐํšŒ + factory StudentAnswerQuery.byChapter({ + required int chapterId, + required int academyUserId, + }) = ChapterAndAcademyQuery; + + /// studentResponseId๋กœ ์กฐํšŒ + factory StudentAnswerQuery.byResponse({ + required int studentResponseId, + }) = ResponseIdQuery; +} + +/// ์ฑ•ํ„ฐ์™€ ํ•™์› ์‚ฌ์šฉ์ž ID๋กœ ์กฐํšŒ +class ChapterAndAcademyQuery extends StudentAnswerQuery { + final int chapterId; + final int academyUserId; + + const ChapterAndAcademyQuery({ + required this.chapterId, + required this.academyUserId, + }); +} + +/// ํ•™์ƒ ์‘๋‹ต ID๋กœ ์กฐํšŒ +class ResponseIdQuery extends StudentAnswerQuery { + final int studentResponseId; + + const ResponseIdQuery({required this.studentResponseId}); +} + diff --git a/frontend/lib/domain/student_answer/student_answer_repository.dart b/frontend/lib/domain/student_answer/student_answer_repository.dart new file mode 100644 index 0000000..2628a05 --- /dev/null +++ b/frontend/lib/domain/student_answer/student_answer_repository.dart @@ -0,0 +1,28 @@ +import 'student_answer_entity.dart'; +import 'student_answer_update.dart'; +import 'student_answer_query.dart'; + +/// Student Answer Repository ์ธํ„ฐํŽ˜์ด์Šค +abstract class StudentAnswerRepository { + /// studentResponseId๋กœ ํ•™์ƒ ๋‹ต์•ˆ ๋ชฉ๋ก ์กฐํšŒ + Future> getStudentAnswersByResponseId( + int studentResponseId, + ); + + /// Query ๊ฐ์ฒด ๊ธฐ๋ฐ˜ ํ•™์ƒ ๋‹ต์•ˆ ์กฐํšŒ + /// + /// [query]: ์กฐํšŒ ์กฐ๊ฑด (chapterId + academyUserId ๋˜๋Š” studentResponseId) + /// + /// ๋ฐ˜ํ™˜: ํ•™์ƒ ๋‹ต์•ˆ ์—”ํ‹ฐํ‹ฐ ๋ฆฌ์ŠคํŠธ + Future> getStudentAnswers( + StudentAnswerQuery query, + ); + + /// ์ˆ˜์ •๋œ ๋‹ต์•ˆ๋“ค์„ ์„œ๋ฒ„์— ์ €์žฅ + /// + /// [updates]: ์ˆ˜์ •๋œ ๋‹ต์•ˆ ๋ชฉ๋ก (studentAnswerId์™€ ์ƒˆ๋กœ์šด answer ํฌํ•จ) + /// + /// ์ฐธ๊ณ : ํ˜„์žฌ๋Š” answer๋งŒ ์ˆ˜์ •ํ•˜๊ณ , is_correct(์ •๋‹ต ์—ฌ๋ถ€)๋Š” ์„œ๋ฒ„ ๊ธฐ์ค€ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. + /// ํ–ฅํ›„ ์ •๋‹ต ์—ฌ๋ถ€ ์žฌ๊ณ„์‚ฐ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜๋ฉด ๋ณ„๋„ API๋กœ ํ™•์žฅ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. + Future updateStudentAnswers(List updates); +} diff --git a/frontend/lib/domain/student_answer/student_answer_update.dart b/frontend/lib/domain/student_answer/student_answer_update.dart new file mode 100644 index 0000000..a318673 --- /dev/null +++ b/frontend/lib/domain/student_answer/student_answer_update.dart @@ -0,0 +1,10 @@ +/// ๋‹ต์•ˆ ์ˆ˜์ • ์ •๋ณด (๋„๋ฉ”์ธ Value Object) +class StudentAnswerUpdate { + final int studentAnswerId; + final String newAnswer; // ์ˆ˜์ •๋œ ๋‹ต์•ˆ + + const StudentAnswerUpdate({ + required this.studentAnswerId, + required this.newAnswer, + }); +} diff --git a/frontend/lib/domain/student_answer/update_single_student_answer_use_case.dart b/frontend/lib/domain/student_answer/update_single_student_answer_use_case.dart new file mode 100644 index 0000000..465c193 --- /dev/null +++ b/frontend/lib/domain/student_answer/update_single_student_answer_use_case.dart @@ -0,0 +1,59 @@ +import '../../services/student_answer_api.dart'; + +/// ๋‹จ์ผ ํ•™์ƒ ๋‹ต์•ˆ์„ ์ˆ˜์ •ํ•˜๋Š” UseCase +class UpdatedStudentAnswer { + final int studentAnswerId; + final int studentResponseId; + final int questionNumber; + final int subQuestionNumber; + final String recognizedAnswer; + final bool? isCorrect; + final double score; + + UpdatedStudentAnswer({ + required this.studentAnswerId, + required this.studentResponseId, + required this.questionNumber, + required this.subQuestionNumber, + required this.recognizedAnswer, + required this.isCorrect, + required this.score, + }); +} + +class UpdateSingleStudentAnswerUseCase { + final StudentAnswerApi _api; + + UpdateSingleStudentAnswerUseCase({required StudentAnswerApi api}) + : _api = api; + + Future call({ + required int studentAnswerId, + required int studentResponseId, + required int questionNumber, + required int subQuestionNumber, + required String newAnswer, + required int chapterId, + }) async { + final dto = await _api.updateSingleStudentAnswer( + studentAnswerId: studentAnswerId, + studentResponseId: studentResponseId, + questionNumber: questionNumber, + subQuestionNumber: subQuestionNumber, + answer: newAnswer, + chapterId: chapterId, + ); + + return UpdatedStudentAnswer( + studentAnswerId: dto.studentAnswerId, + studentResponseId: dto.studentResponseId, + questionNumber: dto.questionNumber, + subQuestionNumber: dto.subQuestionNumber, + recognizedAnswer: dto.answer, + isCorrect: dto.correct, + score: dto.score, + ); + } +} + + diff --git a/frontend/lib/domain/student_answer/update_student_answers_use_case.dart b/frontend/lib/domain/student_answer/update_student_answers_use_case.dart new file mode 100644 index 0000000..c65f1dc --- /dev/null +++ b/frontend/lib/domain/student_answer/update_student_answers_use_case.dart @@ -0,0 +1,18 @@ +import 'student_answer_repository.dart'; +import 'student_answer_update.dart'; + +/// ์ˆ˜์ •๋œ ๋‹ต์•ˆ๋“ค์„ ์„œ๋ฒ„์— ์ €์žฅํ•˜๋Š” UseCase +class UpdateStudentAnswersUseCase { + final StudentAnswerRepository _repository; + + UpdateStudentAnswersUseCase({required StudentAnswerRepository repository}) + : _repository = repository; + + /// ์ˆ˜์ •๋œ ๋‹ต์•ˆ๋“ค์„ ์„œ๋ฒ„์— ์ €์žฅ + /// + /// [updates]: ์ˆ˜์ •๋œ ๋‹ต์•ˆ ๋ชฉ๋ก + Future call(List updates) async { + if (updates.isEmpty) return; + await _repository.updateStudentAnswers(updates); + } +} diff --git a/frontend/lib/domain/workbook/workbook_repository.dart b/frontend/lib/domain/workbook/workbook_repository.dart new file mode 100644 index 0000000..1f91b71 --- /dev/null +++ b/frontend/lib/domain/workbook/workbook_repository.dart @@ -0,0 +1,38 @@ +import 'workbook_summary_entity.dart'; + +/// Workbook Repository ์ธํ„ฐํŽ˜์ด์Šค +/// +/// ๋ฌธ์ œ์ง‘ ์š”์•ฝ ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋Š” Repository์˜ ์ถ”์ƒ ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. +abstract class WorkbookRepository { + /// ์—ฌ๋Ÿฌ academyUserId์— ๋Œ€ํ•œ ๋ฌธ์ œ์ง‘ ์š”์•ฝ ๋ชฉ๋ก ์กฐํšŒ (ํ•œ ๋ฒˆ์—) + /// + /// ์—ฌ๋Ÿฌ academyUserId๋ฅผ ํ•œ ๋ฒˆ์— ์กฐํšŒํ•˜์—ฌ ๊ฐ academyUserId๋ณ„๋กœ + /// WorkbookSummaryEntity ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + /// + /// [academyUserIds]: ์กฐํšŒํ•  academyUserId ๋ฆฌ์ŠคํŠธ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: Map> + Future>> getWorkbookSummariesByAcademyUserIds( + List academyUserIds, + ); + + /// ์บ์‹œ์—์„œ ๋ฌธ์ œ์ง‘ ์š”์•ฝ ๋ชฉ๋ก ์กฐํšŒ + /// + /// [academyUserId]: ์กฐํšŒํ•  academyUserId + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ์บ์‹œ๋œ WorkbookSummaryEntity ๋ฆฌ์ŠคํŠธ ๋˜๋Š” null + Future?> getCachedWorkbookSummaries(int academyUserId); + + /// ๋ฌธ์ œ์ง‘ ์š”์•ฝ ๋ชฉ๋ก ์บ์‹œ ์ €์žฅ + /// + /// [academyUserId]: ์ €์žฅํ•  academyUserId + /// [summaries]: ์ €์žฅํ•  WorkbookSummaryEntity ๋ฆฌ์ŠคํŠธ + Future cacheWorkbookSummaries( + int academyUserId, + List summaries, + ); + + /// ์บ์‹œ ์ดˆ๊ธฐํ™” + Future clearCache(); +} + diff --git a/frontend/lib/domain/workbook/workbook_summary_entity.dart b/frontend/lib/domain/workbook/workbook_summary_entity.dart new file mode 100644 index 0000000..153ec73 --- /dev/null +++ b/frontend/lib/domain/workbook/workbook_summary_entity.dart @@ -0,0 +1,91 @@ +/// ๋ฌธ์ œ์ง‘ ์š”์•ฝ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ (UI ํ‘œ์‹œ์šฉ) +/// +/// API ์‘๋‹ต์˜ book ์ •๋ณด๋ฅผ ๋„๋ฉ”์ธ ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. +class WorkbookSummaryEntity { + final int? bookId; + final String bookName; + final String? coverImageUrl; // book_image_url + final int totalPages; // book_page + final int totalSolvedPages; // total_solved_pages + final DateTime? lastStudyDate; // latest_updated_at + final int academyUserId; + final String? className; // ์ƒ์œ„ ๋ ˆ์ด์–ด์—์„œ ์ฃผ์ž… + final String? bookSemester; // book_semester + + WorkbookSummaryEntity({ + this.bookId, + required this.bookName, + this.coverImageUrl, + required this.totalPages, + required this.totalSolvedPages, + this.lastStudyDate, + required this.academyUserId, + this.className, + this.bookSemester, + }); + + /// ์ง„ํ–‰๋ฅ  ๊ณ„์‚ฐ (0~100) + /// + /// ๊ทœ์น™: + /// - totalPages๊ฐ€ null/0์ด๋ฉด โ†’ 0 ๋ฐ˜ํ™˜ + /// - totalSolvedPages / totalPages * 100 (์†Œ์ˆ˜์  ๋ฐ˜์˜ฌ๋ฆผ) + int get progress { + if (totalPages <= 0) return 0; + return ((totalSolvedPages / totalPages) * 100).round().clamp(0, 100); + } + + /// ๋งˆ์ง€๋ง‰ ํ•™์Šต์ผ ํฌ๋งทํŒ… (YYYY.MM.DD) + String get formattedLastStudyDate { + if (lastStudyDate == null) return ''; + final date = lastStudyDate!; + return '${date.year}.${date.month.toString().padLeft(2, '0')}.${date.day.toString().padLeft(2, '0')}'; + } + + /// ์ธ๋„ค์ผ ๊ฒฝ๋กœ ๊ฒฐ์ • ์ „๋žต + /// + /// 1. coverImageUrl(book_image_url)์ด ์žˆ์œผ๋ฉด โ†’ ๋„คํŠธ์›Œํฌ URL ๋ฐ˜ํ™˜ + /// 2. ์—†์œผ๋ฉด โ†’ bookId ๊ธฐ๋ฐ˜ asset ๊ฒฝ๋กœ ๋งคํ•‘ (๊ธฐ๋ณธ๊ฐ’) + String get thumbnailPath { + if (coverImageUrl != null && coverImageUrl!.isNotEmpty) { + return coverImageUrl!; + } + // Asset ๊ฒฝ๋กœ ๋งคํ•‘ (fallback) + return _getAssetPathForBook(bookId); + } + + /// bookId โ†’ asset ๊ฒฝ๋กœ ๋งคํ•‘ (fallback์šฉ) + String _getAssetPathForBook(int? bookId) { + // TODO: bookId ๊ธฐ๋ฐ˜ ๋งคํ•‘ ๋กœ์ง (ํ•„์š”์‹œ) + return 'assets/images/bookcovers/BookCover_Blacklabel.png'; + } + + Map toJson() { + return { + 'book_id': bookId, + 'book_name': bookName, + 'cover_image_url': coverImageUrl, + 'total_pages': totalPages, + 'total_solved_pages': totalSolvedPages, + 'last_study_date': lastStudyDate?.toIso8601String(), + 'academy_user_id': academyUserId, + 'class_name': className, + 'book_semester': bookSemester, + }; + } + + factory WorkbookSummaryEntity.fromJson(Map json) { + return WorkbookSummaryEntity( + bookId: json['book_id'] as int?, + bookName: json['book_name'] as String? ?? '', + coverImageUrl: json['cover_image_url'] as String?, + totalPages: json['total_pages'] as int? ?? 0, + totalSolvedPages: json['total_solved_pages'] as int? ?? 0, + lastStudyDate: json['last_study_date'] != null + ? DateTime.parse(json['last_study_date']).toLocal() + : null, + academyUserId: json['academy_user_id'] as int? ?? 0, + className: json['class_name'] as String?, + bookSemester: json['book_semester'] as String?, + ); + } +} diff --git a/frontend/lib/firebase_options.dart b/frontend/lib/firebase_options.dart new file mode 100644 index 0000000..df9b611 --- /dev/null +++ b/frontend/lib/firebase_options.dart @@ -0,0 +1,66 @@ +import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; +import 'package:flutter/foundation.dart' + show defaultTargetPlatform, kIsWeb, TargetPlatform; + +/// Default [FirebaseOptions] for use with your Firebase apps. +/// +/// Example: +/// ```dart +/// import 'firebase_options.dart'; +/// // ... +/// await Firebase.initializeApp( +/// options: DefaultFirebaseOptions.currentPlatform, +/// ); +/// ``` +class DefaultFirebaseOptions { + static FirebaseOptions get currentPlatform { + if (kIsWeb) { + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for web - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + } + switch (defaultTargetPlatform) { + case TargetPlatform.android: + return android; + case TargetPlatform.iOS: + return ios; + case TargetPlatform.macOS: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for macos - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.windows: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for windows - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + case TargetPlatform.linux: + throw UnsupportedError( + 'DefaultFirebaseOptions have not been configured for linux - ' + 'you can reconfigure this by running the FlutterFire CLI again.', + ); + default: + throw UnsupportedError( + 'DefaultFirebaseOptions are not supported for this platform.', + ); + } + } + + static const FirebaseOptions android = FirebaseOptions( + apiKey: 'AIzaSyAYs3bpt4mcglJvZaQXFc6eha2FCVZf72Y', + appId: '1:120799260544:android:a8e550dc78b59824b19b65', + messagingSenderId: '120799260544', + projectId: 'gradi-bd52c', + storageBucket: 'gradi-bd52c.firebasestorage.app', + ); + + static const FirebaseOptions ios = FirebaseOptions( + apiKey: 'AIzaSyAYs3bpt4mcglJvZaQXFc6eha2FCVZf72Y', + appId: '1:120799260544:ios:6dba36b595142ec0b19b65', + messagingSenderId: '120799260544', + projectId: 'gradi-bd52c', + storageBucket: 'gradi-bd52c.firebasestorage.app', + iosBundleId: 'com.gradi.gradiFrontend', + ); +} diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart new file mode 100644 index 0000000..3635798 --- /dev/null +++ b/frontend/lib/main.dart @@ -0,0 +1,147 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/foundation.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:io'; +import 'firebase_options.dart'; +import 'routes/app_routes.dart'; +import 'theme/app_theme.dart'; +import 'config/di_container.dart'; +import 'services/fcm_service.dart'; + +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + + // 1. SharedPreferences ๋™๊ธฐ ์ธ์Šคํ„ด์Šค ํ™•๋ณด + final sharedPrefs = await SharedPreferences.getInstance(); + + // 2. DI Container ์ดˆ๊ธฐํ™” (SharedPreferences ํฌํ•จ) + await setupDependencies(sharedPrefs: sharedPrefs); + + // ๐Ÿ”ฅ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋งŒ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ + // ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ kDebugMode๋กœ ๊ฐ์‹ธ๊ธฐ + if (kDebugMode) { + HttpOverrides.global = MyHttpOverrides(); + } + + // Firebase ์ดˆ๊ธฐํ™” (์ด๋ฏธ ์ดˆ๊ธฐํ™”๋˜์–ด ์žˆ์œผ๋ฉด ์Šคํ‚ต) + try { + // ์ด๋ฏธ ์ดˆ๊ธฐํ™”๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ + if (Firebase.apps.isEmpty) { + await Firebase.initializeApp( + options: DefaultFirebaseOptions.currentPlatform, + ); + debugPrint('โœ… Firebase ์ดˆ๊ธฐํ™” ์„ฑ๊ณต'); + } else { + debugPrint('โ„น๏ธ Firebase๋Š” ์ด๋ฏธ ์ดˆ๊ธฐํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.'); + } + } catch (e) { + debugPrint('โŒ Firebase ์ดˆ๊ธฐํ™” ์‹คํŒจ: $e'); + // ์ค‘๋ณต ์ดˆ๊ธฐํ™” ์˜ค๋ฅ˜๋Š” ๋ฌด์‹œ (Hot Reload/Restart ์‹œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ) + if (e.toString().contains('duplicate-app')) { + debugPrint('โ„น๏ธ Firebase๊ฐ€ ์ด๋ฏธ ์ดˆ๊ธฐํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. (Hot Reload/Restart)'); + } else { + // iOS์—์„œ GoogleService-Info.plist๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ + if (defaultTargetPlatform == TargetPlatform.iOS) { + debugPrint( + 'โš ๏ธ iOS: GoogleService-Info.plist ํŒŒ์ผ์ด Xcode ํ”„๋กœ์ ํŠธ์— ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.', + ); + debugPrint(' ํŒŒ์ผ ๊ฒฝ๋กœ: ios/Runner/GoogleService-Info.plist'); + debugPrint(' Xcode์—์„œ: Runner.xcworkspace๋ฅผ ์—ด๊ณ  ํŒŒ์ผ์ด ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ'); + } + rethrow; + } + } + + // FCM ์ดˆ๊ธฐํ™” + try { + await getIt().initialize(); + } catch (e) { + debugPrint('โŒ FCM ์ดˆ๊ธฐํ™” ์‹คํŒจ: $e'); + // FCM ์ดˆ๊ธฐํ™” ์‹คํŒจํ•ด๋„ ์•ฑ์€ ๊ณ„์† ์‹คํ–‰ + } + + // ์‚ฌ์šฉ์ž ์ •๋ณด ์ดˆ๊ธฐํ™”๋Š” ๋กœ๋”ฉ ํŽ˜์ด์ง€์—์„œ ์ฒ˜๋ฆฌ + // (์ž๋™ ๋กœ๊ทธ์ธ ์‹œ ๋กœ๋”ฉ ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œํ•˜๋ฉด์„œ API ํ˜ธ์ถœ) + + // ์„ธ๋กœ ๋ฐฉํ–ฅ ๊ณ ์ • + await SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + ]); + + runApp(const GradiApp()); +} + +class GradiApp extends StatelessWidget { + const GradiApp({super.key}); + + @override + Widget build(BuildContext context) { + // Set system UI overlay style + SystemChrome.setSystemUIOverlayStyle( + const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarIconBrightness: Brightness.dark, + systemNavigationBarColor: Colors.white, + systemNavigationBarIconBrightness: Brightness.dark, + ), + ); + + return MaterialApp( + title: 'GRADI', + debugShowCheckedModeBanner: false, + theme: AppTheme.lightTheme, + + // Routing configuration + initialRoute: AppRoutes.loading, // ์ž๋™ ๋กœ๊ทธ์ธ ๋กœ์ง ์‹คํ–‰์„ ์œ„ํ•ด ๋กœ๋”ฉ ํŽ˜์ด์ง€๋กœ ์‹œ์ž‘ + routes: AppRoutes.routes, + onGenerateRoute: AppRoutes.onGenerateRoute, + + // Handle unknown routes + onUnknownRoute: (settings) => + MaterialPageRoute(builder: (context) => const _UnknownRoutePage()), + ); + } +} + +class _UnknownRoutePage extends StatelessWidget { + const _UnknownRoutePage(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('ํŽ˜์ด์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค')), + body: const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, size: 64, color: AppTheme.errorColor), + SizedBox(height: 16), + Text( + '์š”์ฒญํ•˜์‹  ํŽ˜์ด์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), + ), + SizedBox(height: 8), + Text( + 'URL์„ ํ™•์ธํ•˜๊ณ  ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.', + style: TextStyle(fontSize: 14, color: AppTheme.textSecondary), + ), + ], + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค +// ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ kDebugMode๋กœ ๊ฐ์‹ธ๊ธฐ +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/models/assessment.dart b/frontend/lib/models/assessment.dart new file mode 100644 index 0000000..778e4bd --- /dev/null +++ b/frontend/lib/models/assessment.dart @@ -0,0 +1,149 @@ +/// Assessment ๋ฐ์ดํ„ฐ ๋ชจ๋ธ +/// +/// ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์˜จ ํ‰๊ฐ€/๊ณผ์ œ ์ •๋ณด๋ฅผ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค. +class Assessment { + final String bookId; + final String bookCoverImage; + final String assessName; // ์ˆ™์ œ ์ด๋ฆ„ (assessChapter์—์„œ ๋ณ€๊ฒฝ) + final String assessPage; // "15-25" ํ˜•์‹ (์‹œ์ž‘ํŽ˜์ด์ง€-๋ํŽ˜์ด์ง€) + final String assessClass; // ํด๋ž˜์Šค๋ช… (assigneeId๋ฅผ ํ†ตํ•ด API๋กœ ์กฐํšŒ) + // assessStatus ์ข…๋ฅ˜: + // - 'N': No, ์•„์ง ์ˆ™์ œ๊ฐ€ ์™„๋ฃŒ๋˜์ง€ ์•Š์Œ + // - 'Y': Yes, ์ˆ™์ œ๊ฐ€ ์™„๋ฃŒ๋จ + final String assessStatus; + + Assessment({ + required this.bookId, + required this.bookCoverImage, + required this.assessName, + required this.assessPage, + required this.assessClass, + required this.assessStatus, + }); + + /// JSON์—์„œ Assessment ๊ฐ์ฒด ์ƒ์„ฑ + /// + /// ๋‘ ๊ฐ€์ง€ ํ˜•์‹์„ ์ง€์›: + /// 1. API ์‘๋‹ต ํ˜•์‹ (camelCase): assessName, assessStartPage, assigneeId, book.bookId ๋“ฑ + /// 2. ์บ์‹œ ์ €์žฅ ํ˜•์‹ (snake_case): assess_name, assess_page, assess_class ๋“ฑ + factory Assessment.fromJson(Map json) { + + // 1. assessPage ํŒŒ์‹ฑ (๋‘ ๊ฐ€์ง€ ํ˜•์‹ ์ง€์›) + String assessPage; + if (json.containsKey('assessStartPage') && + json.containsKey('assessEndPage')) { + // API ์‘๋‹ต ํ˜•์‹: assessStartPage, assessEndPage + final startPage = json['assessStartPage']?.toString() ?? '0'; + final endPage = json['assessEndPage']?.toString() ?? '0'; + assessPage = '$startPage-$endPage'; + } else if (json.containsKey('assess_page')) { + // ์บ์‹œ ํ˜•์‹: assess_page (์ด๋ฏธ "15-25" ํ˜•์‹) + assessPage = json['assess_page']?.toString() ?? '0-0'; + } else { + assessPage = '0-0'; + } + + // 2. assessClass ํŒŒ์‹ฑ (๋‘ ๊ฐ€์ง€ ํ˜•์‹ ์ง€์›) + String assessClass; + if (json.containsKey('assigneeId')) { + // API ์‘๋‹ต ํ˜•์‹: assigneeId + assessClass = json['assigneeId']?.toString() ?? ''; + } else if (json.containsKey('assess_class')) { + // ์บ์‹œ ํ˜•์‹: assess_class (์ด๋ฏธ className์ด๊ฑฐ๋‚˜ assigneeId) + assessClass = json['assess_class']?.toString() ?? ''; + } else { + assessClass = ''; + } + + // 3. book ์ •๋ณด ํŒŒ์‹ฑ (๋‘ ๊ฐ€์ง€ ํ˜•์‹ ์ง€์›) + String bookId; + String bookImageUrl; + if (json.containsKey('book') && json['book'] is Map) { + // API ์‘๋‹ต ํ˜•์‹: book ๊ฐ์ฒด + final book = json['book'] as Map; + bookId = book['bookId']?.toString() ?? ''; + bookImageUrl = book['bookImageUrl'] as String? ?? ''; + } else { + // ์บ์‹œ ํ˜•์‹: book_id, book_cover_image + bookId = json['book_id']?.toString() ?? ''; + bookImageUrl = json['book_cover_image']?.toString() ?? ''; + } + + // 4. assessName ํŒŒ์‹ฑ (๋‘ ๊ฐ€์ง€ ํ˜•์‹ ์ง€์›) + final assessName = + json['assessName']?.toString() ?? json['assess_name']?.toString() ?? ''; + + // 5. assessStatus ํŒŒ์‹ฑ (๋‘ ๊ฐ€์ง€ ํ˜•์‹ ์ง€์›) + final assessStatus = + json['assessStatus']?.toString() ?? + json['assess_status']?.toString() ?? + 'N'; + + + return Assessment( + bookId: bookId, + bookCoverImage: bookImageUrl, + assessName: assessName, + assessPage: assessPage, + assessClass: assessClass, + assessStatus: assessStatus, + ); + } + + /// ํด๋ž˜์Šค๋ช…์„ ์—…๋ฐ์ดํŠธํ•œ ์ƒˆ Assessment ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ + Assessment copyWith({String? assessClass}) { + return Assessment( + bookId: bookId, + bookCoverImage: bookCoverImage, + assessName: assessName, + assessPage: assessPage, + assessClass: assessClass ?? this.assessClass, + assessStatus: assessStatus, + ); + } + + /// Assessment ๊ฐ์ฒด๋ฅผ JSON์œผ๋กœ ๋ณ€ํ™˜ + Map toJson() { + return { + 'book_id': bookId, + 'book_cover_image': bookCoverImage, + 'assess_name': assessName, + 'assess_page': assessPage, + 'assess_class': assessClass, + 'assess_status': assessStatus, + }; + } + + @override + String toString() { + return 'Assessment(bookId: $bookId, name: $assessName, status: $assessStatus)'; + } +} + +/// ๋‚ ์งœ๋ณ„ Assessment ๋ฐ์ดํ„ฐ +class DateAssessment { + final String date; // 'YYYY-MM-DD' ํ˜•์‹ + final List assessments; + + DateAssessment({required this.date, required this.assessments}); + + /// JSON์—์„œ DateAssessment ๊ฐ์ฒด ์ƒ์„ฑ + factory DateAssessment.fromJson(Map json) { + return DateAssessment( + date: json['date'] ?? '', + assessments: + (json['assessments'] as List?) + ?.map((item) => Assessment.fromJson(item)) + .toList() ?? + [], + ); + } + + /// DateAssessment ๊ฐ์ฒด๋ฅผ JSON์œผ๋กœ ๋ณ€ํ™˜ + Map toJson() { + return { + 'date': date, + 'assessments': assessments.map((a) => a.toJson()).toList(), + }; + } +} diff --git a/frontend/lib/models/user.dart b/frontend/lib/models/user.dart new file mode 100644 index 0000000..d002b04 --- /dev/null +++ b/frontend/lib/models/user.dart @@ -0,0 +1,59 @@ +/// ์‚ฌ์šฉ์ž ์ •๋ณด ๋ชจ๋ธ +/// +/// ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์˜จ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค. +class User { + final int userId; + final String name; + final String? email; + final String? accountId; + final String? phoneNumber; + final String? birthDate; + final String? profileImageUrl; + + User({ + required this.userId, + required this.name, + this.email, + this.accountId, + this.phoneNumber, + this.birthDate, + this.profileImageUrl, + }); + + /// JSON์—์„œ User ๊ฐ์ฒด ์ƒ์„ฑ + factory User.fromJson(Map json) { + final dynamic userIdValue = json['user_id'] ?? json['userId']; + final int parsedUserId = userIdValue is int + ? userIdValue + : int.tryParse(userIdValue?.toString() ?? '') ?? 0; + + return User( + userId: parsedUserId, + name: json['name'] as String, + email: json['email'] as String?, + accountId: json['account_id'] as String? ?? json['accountId'] as String?, + phoneNumber: + json['phone_number'] as String? ?? json['phoneNumber'] as String?, + birthDate: json['birth_date'] as String? ?? json['birthDate'] as String?, + profileImageUrl: json['profile_image_url'] as String?, + ); + } + + /// User ๊ฐ์ฒด๋ฅผ JSON์œผ๋กœ ๋ณ€ํ™˜ + Map toJson() { + return { + 'user_id': userId, + 'name': name, + 'email': email, + 'account_id': accountId, + 'phone_number': phoneNumber, + 'birth_date': birthDate, + 'profile_image_url': profileImageUrl, + }; + } + + @override + String toString() { + return 'User(userId: $userId, name: $name, email: $email, accountId: $accountId, phoneNumber: $phoneNumber, birthDate: $birthDate, profileImageUrl: $profileImageUrl)'; + } +} diff --git a/frontend/lib/routes/app_routes.dart b/frontend/lib/routes/app_routes.dart new file mode 100644 index 0000000..d06da56 --- /dev/null +++ b/frontend/lib/routes/app_routes.dart @@ -0,0 +1,307 @@ +import 'package:flutter/material.dart'; +import '../screens/auth/login_page.dart'; +import '../screens/auth/signup_page.dart'; +import '../screens/auth/signup_terms_page.dart'; +import '../screens/auth/signup_success_page.dart'; +import '../screens/auth/reset_password_page.dart'; +import '../screens/auth/password_reset_form_page.dart'; +import '../screens/auth/password_reset_success_page.dart'; +import '../screens/account/find_id_page.dart'; +import '../screens/account/find_id_error_page.dart'; +import '../screens/account/find_id_verification_page.dart'; +import '../screens/account/find_id_result_page.dart'; +import '../screens/account/find_password_page.dart'; +import '../screens/account/find_password_error_page.dart'; +import '../screens/account/find_password_verification_page.dart'; +import '../screens/account/find_password_reset_page.dart'; +import '../screens/main_navigation_page.dart'; +import '../screens/home_page.dart'; +import '../screens/academy/academy_page.dart'; +import '../screens/academy/academy_list_page.dart'; +import '../screens/academy/academy_detail_page.dart'; +import '../screens/workbook/workbook_page.dart'; +import '../screens/workbook/workbook_detail_page.dart'; +import 'package:get_it/get_it.dart'; +import '../config/app_dependencies.dart'; +import '../screens/workbook/chapter_detail_page.dart'; +import '../screens/workbook/question_detail_page.dart'; +import '../application/explanation/question_explanation_controller.dart'; + +// QuestionStatus enum์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด chapter_detail_page import +// (QuestionStatus๋Š” chapter_detail_page.dart์— ์ •์˜๋˜์–ด ์žˆ์Œ) +import '../screens/mypage/mypage.dart'; +import '../screens/mypage/display_settings_page.dart'; +import '../screens/mypage/homework_status_page.dart'; +import '../screens/mypage/learning_statistics_page.dart'; +import '../screens/mypage/account_management_page.dart'; +import '../screens/mypage/academy_management_page.dart'; +import '../screens/mypage/notification_settings_page.dart'; +import '../screens/notification/notification_page.dart'; +import '../screens/upload/upload_images_page.dart'; +import '../screens/grading_history/edit_grading_result_page.dart'; +import '../screens/continuous_learning_detail_page.dart'; +import '../screens/loading_page.dart'; +import '../screens/problem_solution_temp_page.dart'; +import '../domain/learning/get_monthly_learning_status_use_case.dart'; + +class AppRoutes { + static const String mainNavigation = '/'; + static const String loading = '/loading'; + static const String login = '/login'; + static const String signup = '/signup'; + static const String signupTerms = '/signup-terms'; + static const String signupSuccess = '/signup-success'; + static const String home = '/home'; + static const String academy = '/academy'; + static const String academyList = '/academy/list'; + static const String academyDetail = '/academy/detail'; + static const String workbook = '/workbook'; + static const String workbookDetail = '/workbook/detail'; + static const String chapterDetail = '/workbook/chapter-detail'; + static const String questionDetail = '/workbook/question-detail'; + static const String mypage = '/mypage'; + static const String displaySettings = '/mypage/display-settings'; + static const String homeworkStatus = '/mypage/homework-status'; + static const String learningStatistics = '/mypage/learning-statistics'; + static const String accountManagement = '/mypage/account-management'; + static const String academyManagement = '/mypage/academy-management'; + static const String notificationSettings = '/mypage/notification-settings'; + static const String notification = '/notification'; + static const String continuousLearningDetail = '/continuous-learning-detail'; + static const String findId = '/find-id'; + static const String findIdError = '/find-id-error'; + static const String findIdVerification = '/find-id-verification'; + static const String findIdResult = '/find-id-result'; + static const String findPassword = '/find-password'; + static const String findPasswordError = '/find-password-error'; + static const String findPasswordVerification = '/find-password-verification'; + static const String findPasswordReset = '/find-password-reset'; + static const String passwordResetForm = '/password-reset-form'; + static const String passwordResetSuccess = '/password-reset-success'; + static const String resetPassword = '/reset-password'; + static const String uploadImages = '/upload/images'; + static const String editGradingResult = '/upload/edit-result'; + static const String problemTemp = '/problem-temp'; + + static Map get routes => { + mainNavigation: (context) => const MainNavigationPage(), + loading: (context) => const LoadingPage(), + login: (context) => const LoginPage(), + signup: (context) => const SignUpPage(), + signupTerms: (context) => const SignUpTermsPage(), + signupSuccess: (context) => const SignUpSuccessPage(), + home: (context) => const HomePage(), + academy: (context) => const AcademyPage(), + academyList: (context) => const AcademyListPage(), + workbook: (context) => const WorkbookPage(), + mypage: (context) => const MyPage(), + displaySettings: (context) => const DisplaySettingsPage(), + homeworkStatus: (context) => const HomeworkStatusPage(), + learningStatistics: (context) => const LearningStatisticsPage(), + accountManagement: (context) => const AccountManagementPage(), + academyManagement: (context) => const AcademyManagementPage(), + notificationSettings: (context) => const NotificationSettingsPage(), + notification: (context) => const NotificationPage(), + findId: (context) => const FindIDPage(), + findIdError: (context) => const FindIDErrorPage(), + findPassword: (context) => const FindPasswordPage(), + findPasswordError: (context) => const FindPasswordErrorPage(), + uploadImages: (context) => const UploadImagesPage(), + problemTemp: (context) => const ProblemSolutionTempPage(), + }; + + static Route? onGenerateRoute(RouteSettings settings) { + final getIt = GetIt.instance; + switch (settings.name) { + case findIdVerification: + return MaterialPageRoute( + builder: (context) => const FindIDVerificationPage(), + settings: settings, + ); + case findIdResult: + final args = settings.arguments as Map?; + return MaterialPageRoute( + builder: (context) => FindIDResultPage( + userName: args?['userName'] ?? '', + userId: args?['userId'] ?? '', + ), + ); + case findPasswordVerification: + return MaterialPageRoute( + builder: (context) => const FindPasswordVerificationPage(), + settings: settings, + ); + case resetPassword: + return MaterialPageRoute( + builder: (context) => const ResetPasswordPage(), + settings: settings, + ); + case findPasswordReset: + return MaterialPageRoute( + builder: (context) => const FindPasswordResetPage(), + ); + case passwordResetForm: + return MaterialPageRoute( + builder: (context) => const PasswordResetFormPage(), + settings: settings, + ); + case passwordResetSuccess: + return MaterialPageRoute( + builder: (context) => const PasswordResetSuccessPage(), + ); + case academyDetail: + final args = settings.arguments as AcademyData?; + if (args == null) { + return null; + } + return MaterialPageRoute( + builder: (context) => AcademyDetailPage(academy: args), + ); + case workbookDetail: + final args = settings.arguments as Map?; + if (args == null) { + return null; + } + + final bookId = args['bookId'] as int?; + final academyUserId = args['academyUserId'] as int?; + + if (bookId == null || academyUserId == null) { + // ํ•„์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ์—๋Ÿฌ ์ฒ˜๋ฆฌ + return MaterialPageRoute( + builder: (context) => const Scaffold( + body: Center(child: Text('๋ฌธ์ œ์ง‘ ์ •๋ณด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.')), + ), + ); + } + + return MaterialPageRoute( + builder: (context) => WorkbookDetailPage( + workbookName: args['workbookName'] as String, + thumbnailPath: args['thumbnailPath'] as String?, + bookId: bookId, + academyUserId: academyUserId, + getChaptersUseCase: + AppDependencies.getChaptersForBookUseCase, + ), + ); + case chapterDetail: + final args = settings.arguments as Map?; + if (args == null) { + return null; + } + + final chapterId = args['chapterId'] as int?; + final academyUserId = args['academyUserId'] as int?; + + if (chapterId == null || academyUserId == null) { + return MaterialPageRoute( + builder: (context) => const Scaffold( + body: Center(child: Text('์ฑ•ํ„ฐ ์ •๋ณด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.')), + ), + ); + } + + return MaterialPageRoute( + builder: (context) => ChapterDetailPage( + chapterId: chapterId, + academyUserId: academyUserId, + workbookName: args['workbookName'] as String, + chapterName: args['chapterName'] as String, + getChapterQuestionStatusesUseCase: + AppDependencies.getChapterQuestionStatusesUseCase, + ), + ); + case questionDetail: + final args = settings.arguments as Map?; + if (args == null) { + return MaterialPageRoute( + builder: (context) => const Scaffold( + body: Center(child: Text('๋ฌธ์ œ ์ •๋ณด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.')), + ), + ); + } + + final chapterId = args['chapterId'] as int?; + final academyUserId = args['academyUserId'] as int?; + final workbookName = args['workbookName'] as String?; + final chapterName = args['chapterName'] as String?; + final questionNumber = args['questionNumber'] as int?; + final status = args['status'] as QuestionStatus?; + final studentResponseId = args['studentResponseId'] as int?; + + if (chapterId == null || + academyUserId == null || + workbookName == null || + chapterName == null || + questionNumber == null || + status == null) { + return MaterialPageRoute( + builder: (context) => const Scaffold( + body: Center(child: Text('๋ฌธ์ œ ์ •๋ณด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.')), + ), + ); + } + + final explanationController = getIt(); + + return MaterialPageRoute( + builder: (context) => QuestionDetailPage( + chapterId: chapterId, + academyUserId: academyUserId, + workbookName: workbookName, + chapterName: chapterName, + questionNumber: questionNumber, + status: status, + initialStudentResponseId: studentResponseId, + explanationController: explanationController, + ), + ); + case editGradingResult: + final args = settings.arguments as Map?; + if (args == null || + args['studentResponseId'] == null || + args['academyUserId'] == null) { + // studentResponseId ๋˜๋Š” academyUserId๊ฐ€ ์—†์œผ๋ฉด ์—๋Ÿฌ ์ฒ˜๋ฆฌ + return MaterialPageRoute( + builder: (context) => Scaffold( + body: Center( + child: Text( + args == null || args['studentResponseId'] == null + ? 'ํ•™์ƒ ์‘๋‹ต ID๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.' + : 'ํ•™์› ์‚ฌ์šฉ์ž ID๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.', + ), + ), + ), + settings: settings, + ); + } + + return MaterialPageRoute( + builder: (context) => EditGradingResultPage( + studentResponseId: args['studentResponseId'] as int, + academyUserId: args['academyUserId'] as int, + getStudentAnswersUseCase: + AppDependencies.getStudentAnswersForResponseUseCase, + updateStudentAnswersUseCase: + AppDependencies.updateStudentAnswersUseCase, + getSectionImageUseCase: + AppDependencies.getSectionImageUseCase, + updateSingleStudentAnswerUseCase: + AppDependencies.updateSingleStudentAnswerUseCase, + ), + settings: settings, + ); + case continuousLearningDetail: + return MaterialPageRoute( + builder: (context) => ContinuousLearningDetailPage( + monthlyStatusUseCase: + getIt(), + ), + settings: settings, + ); + default: + return null; + } + } +} diff --git a/frontend/lib/screens/academy/academy_detail_page.dart b/frontend/lib/screens/academy/academy_detail_page.dart new file mode 100644 index 0000000..8bc8276 --- /dev/null +++ b/frontend/lib/screens/academy/academy_detail_page.dart @@ -0,0 +1,824 @@ +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import 'academy_list_page.dart'; +import '../../services/academy_service.dart'; +import '../../services/auth_service.dart'; +import '../../utils/app_logger.dart'; + +class AcademyDetailPage extends StatefulWidget { + final AcademyData academy; + + const AcademyDetailPage({super.key, required this.academy}); + + @override + State createState() => _AcademyDetailPageState(); +} + +class _AcademyDetailPageState extends State { + final GetIt _getIt = GetIt.instance; + + late final AcademyService _academyService; + late final AuthService _authService; + bool _isLoading = false; + + // ํ•™์› ์Šค์ผ€์ค„ ๊ด€๋ จ ์ƒํƒœ + AcademyScheduleResponse? _academySchedule; + bool _isLoadingSchedule = false; + String? _scheduleError; + + // ํ•™์› ์ด๋ฏธ์ง€ ๊ด€๋ จ ์ƒํƒœ + List _academyImageUrls = []; + bool _isLoadingImages = false; + String? _imageError; + final PageController _imagePageController = PageController(); + int _currentImageIndex = 0; + + @override + void initState() { + super.initState(); + _academyService = _getIt(); + _authService = _getIt(); + _loadAcademySchedule(); + _loadAcademyImages(); + } + + @override + void dispose() { + _imagePageController.dispose(); + super.dispose(); + } + + /// ํ•™์› ์Šค์ผ€์ค„ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + Future _loadAcademySchedule() async { + appLog('[academy:academy_detail_page] _loadAcademySchedule ์‹œ์ž‘'); + + // academyCode null ์ฒดํฌ (String? ํƒ€์ž…์ด๋ฏ€๋กœ ํ•„์š”) + if (widget.academy.academyCode == null) { + appLog('[academy:academy_detail_page] academyCode๊ฐ€ null'); + if (!mounted) return; + setState(() { + _scheduleError = 'ํ•™์› ์ฝ”๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'; + }); + return; + } + + appLog( + '[academy:academy_detail_page] academyCode: ${widget.academy.academyCode}', + ); + + if (!mounted) return; + setState(() { + _isLoadingSchedule = true; + _scheduleError = null; + }); + + try { + final schedule = await _academyService.getAcademySchedule( + widget.academy.academyCode!, + ); + + appLog( + '[academy:academy_detail_page] API ํ˜ธ์ถœ ์™„๋ฃŒ - academyName: ${schedule.academy.academyName}, schedules ๊ฐœ์ˆ˜: ${schedule.schedules.length}', + ); + + // ์Šค์ผ€์ค„ ์ƒ์„ธ ๋กœ๊ทธ + for (final s in schedule.schedules) { + appLog( + '[academy:academy_detail_page] Schedule - dayOfWeek: ${s.dayOfWeek} (${s.dayName}), startTime: ${s.startTime}, endTime: ${s.endTime}', + ); + } + + if (!mounted) return; + setState(() { + _academySchedule = schedule; + _isLoadingSchedule = false; + }); + + appLog('[academy:academy_detail_page] UI ์—…๋ฐ์ดํŠธ ์™„๋ฃŒ'); + } catch (e) { + appLog('[academy:academy_detail_page] ์—๋Ÿฌ ๋ฐœ์ƒ: $e'); + if (!mounted) return; + setState(() { + _isLoadingSchedule = false; + // ์‚ฌ์šฉ์ž์šฉ ๊ฐ„๋‹จํ•œ ๋ฉ”์‹œ์ง€ (์ƒ์„ธ ์—๋Ÿฌ๋Š” ๋กœ๊ทธ์—๋งŒ) + _scheduleError = 'ํ•™์› ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'; + }); + } + } + + /// ํ•™์› ์ด๋ฏธ์ง€ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + Future _loadAcademyImages() async { + // academyCode null ์ฒดํฌ + if (widget.academy.academyCode == null) { + if (!mounted) return; + setState(() { + _imageError = 'ํ•™์› ์ฝ”๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'; + }); + return; + } + + if (!mounted) return; + setState(() { + _isLoadingImages = true; + _imageError = null; + }); + + try { + final imageResponse = await _academyService.getAcademyImages( + widget.academy.academyCode!, + ); + + if (!mounted) return; + setState(() { + _academyImageUrls = imageResponse.academyImageUrls; + _isLoadingImages = false; + }); + } catch (e) { + if (!mounted) return; + setState(() { + _isLoadingImages = false; + _imageError = '์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + // ํ—ค๋” + _buildHeader(context), + + // ๋ฉ”์ธ ์ฝ˜ํ…์ธ  + Expanded( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ํ•™์› ์ด๋ฏธ์ง€ + _buildAcademyImage(), + + Padding( + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ํ•™์› ๊ธฐ๋ณธ ์ •๋ณด ์นด๋“œ + _buildAcademyInfo(), + + const SizedBox(height: 16), + + // ๋“ฑ๋ก ๋ฒ„ํŠผ + _buildRegisterButton(context), + + const SizedBox(height: 20), + ], + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader(BuildContext context) { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 10), + decoration: const BoxDecoration(color: Colors.white), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ + GestureDetector( + onTap: () => Navigator.of(context).pop(), + child: const Icon( + Icons.arrow_back_ios, + color: Color(0xFF333333), + size: 24, + ), + ), + + // ์ œ๋ชฉ - ํ•™์›๋ช…๊ณผ ID + RichText( + text: TextSpan( + children: [ + TextSpan( + text: widget.academy.name, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + if (widget.academy.academyCode != null) + TextSpan( + text: ' #${widget.academy.academyCode}', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Colors.grey[400], + ), + ), + ], + ), + ), + + // ํ–„๋ฒ„๊ฑฐ ๋ฉ”๋‰ด + IconButton( + icon: const Icon(Icons.menu, color: Color(0xFF333333)), + onPressed: () { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('๋ฉ”๋‰ด ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์˜ˆ์ •'))); + }, + ), + ], + ), + ); + } + + Widget _buildAcademyImage() { + // ๋กœ๋”ฉ ์ƒํƒœ + if (_isLoadingImages) { + return Container( + width: double.infinity, + height: 200, + color: const Color(0xFFE0E5EB), + child: const Center(child: CircularProgressIndicator()), + ); + } + + // ์—๋Ÿฌ ์ƒํƒœ ๋˜๋Š” ์ด๋ฏธ์ง€๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ + if (_imageError != null || _academyImageUrls.isEmpty) { + return Container( + width: double.infinity, + height: 200, + color: const Color(0xFFE0E5EB), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.image_outlined, + size: 48, + color: Color(0xFF999999), + ), + const SizedBox(height: 8), + Text( + _imageError ?? '์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ], + ), + ), + ); + } + + // ์ด๋ฏธ์ง€๊ฐ€ 1๊ฐœ์ธ ๊ฒฝ์šฐ ์Šฌ๋ผ์ด๋” ์—†์ด ํ‘œ์‹œ + if (_academyImageUrls.length == 1) { + return Container( + width: double.infinity, + height: 200, + child: Image.network( + _academyImageUrls[0], + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + color: const Color(0xFFE0E5EB), + child: const Center( + child: Icon( + Icons.image_outlined, + size: 48, + color: Color(0xFF999999), + ), + ), + ); + }, + ), + ); + } + + // ์ด๋ฏธ์ง€๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ธ ๊ฒฝ์šฐ ์Šฌ๋ผ์ด๋”๋กœ ํ‘œ์‹œ + return SizedBox( + width: double.infinity, + height: 200, + child: Stack( + children: [ + // ์ด๋ฏธ์ง€ ์Šฌ๋ผ์ด๋” + PageView.builder( + controller: _imagePageController, + itemCount: _academyImageUrls.length, + onPageChanged: (index) { + setState(() { + _currentImageIndex = index; + }); + }, + itemBuilder: (context, index) { + return Image.network( + _academyImageUrls[index], + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + color: const Color(0xFFE0E5EB), + child: const Center( + child: Icon( + Icons.image_outlined, + size: 48, + color: Color(0xFF999999), + ), + ), + ); + }, + ); + }, + ), + // ์ธ๋””์ผ€์ดํ„ฐ (ํ•˜๋‹จ ์ค‘์•™) + Positioned( + bottom: 12, + left: 0, + right: 0, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate(_academyImageUrls.length, (index) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 4), + width: 8, + height: 8, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: _currentImageIndex == index + ? Colors.white + : Colors.white.withOpacity(0.5), + ), + ); + }), + ), + ), + ], + ), + ); + } + + Widget _buildAcademyInfo() { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(13), + offset: const Offset(0, 2), + blurRadius: 8, + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ์ฃผ์†Œ ์„น์…˜ + _buildInfoRow( + Icons.location_on, + '์ฃผ์†Œ', + _academySchedule?.academy != null + ? '${_academySchedule!.academy.academyRoadAddress} ${_academySchedule!.academy.academyDetailAddress}' + .trim() + : widget.academy.address, + ), + + const SizedBox(height: 16), + const Divider(color: Color(0xFFE9ECEF), height: 1), + const SizedBox(height: 16), + + // ์†Œ๊ฐœ ์„น์…˜ + _buildInfoRow( + Icons.info_outline, + '์†Œ๊ฐœ', + _academySchedule?.academy != null && + _academySchedule!.academy.academyDescription.isNotEmpty + ? _academySchedule!.academy.academyDescription + : '${widget.academy.name}์— ๋Œ€ํ•œ ์†Œ๊ฐœ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.', + ), + + const SizedBox(height: 16), + const Divider(color: Color(0xFFE9ECEF), height: 1), + const SizedBox(height: 16), + + // ์˜์—…์‹œ๊ฐ„ ์„น์…˜ + _buildOperatingHours(), + + const SizedBox(height: 16), + const Divider(color: Color(0xFFE9ECEF), height: 1), + const SizedBox(height: 16), + + // ์—ฐ๋ฝ์ฒ˜ ์„น์…˜ + _buildContactSection(), + ], + ), + ); + } + + Widget _buildInfoRow(IconData icon, String label, String value) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(icon, color: const Color(0xFF666666), size: 20), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + Text( + value, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ], + ), + ), + ], + ); + } + + Widget _buildOperatingHours() { + // ๋กœ๋”ฉ ์ƒํƒœ + if (_isLoadingSchedule) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.access_time, color: Color(0xFF666666), size: 20), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '์˜์—…์‹œ๊ฐ„', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + const Text( + '์˜์—…์‹œ๊ฐ„์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค...', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ], + ), + ), + ], + ); + } + + // ์—๋Ÿฌ ์ƒํƒœ + if (_scheduleError != null) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.access_time, color: Color(0xFF666666), size: 20), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '์˜์—…์‹œ๊ฐ„', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + const Text( + '์˜์—…์‹œ๊ฐ„ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ], + ), + ), + ], + ); + } + + // ์Šค์ผ€์ค„์ด ์—†๋Š” ๊ฒฝ์šฐ + if (_academySchedule == null || _academySchedule!.schedules.isEmpty) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.access_time, color: Color(0xFF666666), size: 20), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '์˜์—…์‹œ๊ฐ„', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + const Text( + '๋“ฑ๋ก๋œ ์˜์—…์‹œ๊ฐ„์ด ์—†์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ], + ), + ), + ], + ); + } + + // ์Šค์ผ€์ค„ ๊ทธ๋ฃนํ•‘ ๋ฐ ์ •๋ ฌ + final schedules = _academySchedule!.schedules; + + // dayOfWeek ๊ธฐ์ค€์œผ๋กœ ๊ทธ๋ฃนํ•‘ + final Map> groupedByDay = {}; + for (final schedule in schedules) { + if (schedule.dayOfWeek >= 0 && schedule.dayOfWeek <= 6) { + groupedByDay.putIfAbsent(schedule.dayOfWeek, () => []); + groupedByDay[schedule.dayOfWeek]!.add(schedule); + } + } + + // ์š”์ผ๋ณ„๋กœ startTime ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ (๋ฌธ์ž์—ด ๋น„๊ต, HH:MM:SS ํฌ๋งท ์ „์ œ) + groupedByDay.forEach((day, daySchedules) { + daySchedules.sort((a, b) => a.startTime.compareTo(b.startTime)); + }); + + // ์š”์ผ ์ˆœ์„œ: ์›”์š”์ผ(1) ~ ํ† ์š”์ผ(6), ์ผ์š”์ผ(0)์€ ๋งˆ์ง€๋ง‰ + final sortedDays = groupedByDay.keys.toList() + ..sort((a, b) { + if (a == 0) return 1; // ์ผ์š”์ผ์€ ๋’ค๋กœ + if (b == 0) return -1; + return a.compareTo(b); + }); + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.access_time, color: Color(0xFF666666), size: 20), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '์˜์—…์‹œ๊ฐ„', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + // ์š”์ผ๋ณ„๋กœ ํ‘œ์‹œ + ...sortedDays.map((day) { + final daySchedules = groupedByDay[day]!; + final dayName = daySchedules.first.dayName; + final timeRanges = daySchedules + .map( + (s) => '${s.formattedStartTime} - ${s.formattedEndTime}', + ) + .join(', '); + + return Padding( + padding: const EdgeInsets.only(bottom: 2), + child: Text( + '$dayName : $timeRanges', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ); + }).toList(), + ], + ), + ), + ], + ); + } + + Widget _buildContactSection() { + final academy = _academySchedule?.academy; + final phone = (academy?.academyPhone.isNotEmpty == true) + ? academy!.academyPhone + : '์ „ํ™” ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'; + final email = (academy?.academyEmail.isNotEmpty == true) + ? academy!.academyEmail + : '์ด๋ฉ”์ผ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'; + final website = (academy?.academyWebsite.isNotEmpty == true) + ? academy!.academyWebsite + : '์›น์‚ฌ์ดํŠธ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'; + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon(Icons.phone, color: Color(0xFF666666), size: 20), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '์—ฐ๋ฝ์ฒ˜', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + Text( + 'Phone: $phone', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + const SizedBox(height: 2), + Text( + 'Email: $email', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + const SizedBox(height: 2), + Text( + 'Website: $website', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ], + ), + ), + ], + ); + } + + Future _handleRegister() async { + // academyCode๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ + if (widget.academy.academyCode == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('ํ•™์› ์ •๋ณด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.'), + backgroundColor: Colors.red, + ), + ); + return; + } + + setState(() { + _isLoading = true; + }); + + try { + // user_id ๊ฐ€์ ธ์˜ค๊ธฐ + final userId = await _authService.getUserId(); + if (userId == null) { + throw Exception('์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + + // ํ•™์› ๋“ฑ๋ก ์š”์ฒญ + await _academyService.joinAcademyRequest( + academy_id: widget.academy.academyCode!, + user_id: int.parse(userId), + ); + + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('${widget.academy.name} ๋“ฑ๋ก ์š”์ฒญ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'), + backgroundColor: Colors.green, + ), + ); + // ๋“ฑ๋ก ์„ฑ๊ณต ํ›„ ์ด์ „ ํŽ˜์ด์ง€๋กœ ๋Œ์•„๊ฐ€๊ธฐ (์„ฑ๊ณต ์—ฌ๋ถ€ ์ „๋‹ฌ) + Navigator.of(context).pop(true); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(e.toString().replaceAll('Exception: ', '')), + backgroundColor: Colors.red, + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + Widget _buildRegisterButton(BuildContext context) { + return Container( + width: double.infinity, + height: 56, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF7C3AED)], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + borderRadius: BorderRadius.circular(12), + ), + child: ElevatedButton( + onPressed: _isLoading ? null : _handleRegister, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: _isLoading + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + : const Text( + 'ํ•™์› ๋“ฑ๋กํ•˜๊ธฐ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Colors.white, + ), + ), + ), + ); + } +} diff --git a/frontend/lib/screens/academy/academy_list_page.dart b/frontend/lib/screens/academy/academy_list_page.dart new file mode 100644 index 0000000..1144e5c --- /dev/null +++ b/frontend/lib/screens/academy/academy_list_page.dart @@ -0,0 +1,517 @@ +import 'package:flutter/material.dart'; +import 'dart:io'; +import '../../widgets/back_button.dart'; +import '../../services/location_service.dart'; +import '../../services/academy_service.dart'; + +class AcademyListPage extends StatefulWidget { + const AcademyListPage({super.key}); + + @override + State createState() => _AcademyListPageState(); +} + +class _AcademyListPageState extends State { + final TextEditingController _searchController = TextEditingController(); + final LocationService _locationService = LocationService(); + final AcademyService _academyService = AcademyService(); + + List _filteredAcademies = []; + List _allAcademies = []; + bool _isLoading = true; + String? _errorMessage; + + @override + void initState() { + super.initState(); + _fetchNearbyAcademies(); + } + + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } + + /// ๊ทผ์ฒ˜ ํ•™์› ๋ฆฌ์ŠคํŠธ ์กฐํšŒ + Future _fetchNearbyAcademies() async { + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ) + HttpOverrides.global = MyHttpOverrides(); + + // ํ˜„์žฌ ์œ„์น˜ ๊ฐ€์ ธ์˜ค๊ธฐ + final position = await _locationService.getCurrentLocation(); + + if (position == null) { + setState(() { + _isLoading = false; + _errorMessage = '์œ„์น˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์œ„์น˜ ๊ถŒํ•œ์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.'; + }); + return; + } + + // API ํ˜ธ์ถœํ•˜์—ฌ ๊ทผ์ฒ˜ ํ•™์› ๋ฆฌ์ŠคํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ + final academies = await _academyService.getNearbyAcademies( + latitude: position.latitude, + longitude: position.longitude, + ); + + // ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ AcademyData๋กœ ๋ณ€ํ™˜ + _allAcademies = academies.map((academy) { + return AcademyData( + name: academy.academyName, + distance: '${academy.distanceKm.toStringAsFixed(1)}km', + address: academy.academyRoadAddress, + thumbnail: 'assets/images/academy1.jpg', // ๊ธฐ๋ณธ ์ธ๋„ค์ผ + academyCode: academy.academyCode, + ); + }).toList(); + + // ๊ฑฐ๋ฆฌ์ˆœ์œผ๋กœ ์ •๋ ฌ (์ด๋ฏธ ์„œ๋ฒ„์—์„œ ์ •๋ ฌ๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ํ™•์‹คํžˆ ํ•˜๊ธฐ ์œ„ํ•ด) + _allAcademies.sort((a, b) { + final distanceA = double.parse(a.distance.replaceAll('km', '')); + final distanceB = double.parse(b.distance.replaceAll('km', '')); + return distanceA.compareTo(distanceB); + }); + + setState(() { + _filteredAcademies = _allAcademies; + _isLoading = false; + }); + } catch (e) { + setState(() { + _isLoading = false; + _errorMessage = e.toString().replaceAll('Exception: ', ''); + }); + } + } + + void _onSearchChanged(String query) { + setState(() { + if (query.isEmpty) { + _filteredAcademies = _allAcademies; + } else { + _filteredAcademies = _allAcademies + .where( + (academy) => + academy.name.toLowerCase().contains(query.toLowerCase()), + ) + .toList(); + } + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + // ํ—ค๋” + _buildHeader(), + + // ๋ฉ”์ธ ์ฝ˜ํ…์ธ  + Expanded( + child: SingleChildScrollView( + padding: EdgeInsets.symmetric( + horizontal: MediaQuery.of(context).size.width * 0.05, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: MediaQuery.of(context).size.height * 0.03, + ), + + // ๊ฒ€์ƒ‰๋ฐ” + _buildSearchBar(), + + Container( + height: MediaQuery.of(context).size.height * 0.03, + ), + + // ํ•™์› ๋ชฉ๋ก ๋˜๋Š” ๋กœ๋”ฉ/์—๋Ÿฌ ์ƒํƒœ + _isLoading + ? _buildLoadingState() + : _errorMessage != null + ? _buildErrorState() + : _buildAcademyList(), + + Container( + height: MediaQuery.of(context).size.height * 0.025, + ), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: EdgeInsets.fromLTRB( + MediaQuery.of(context).size.width * 0.05, + MediaQuery.of(context).size.height * 0.021, + MediaQuery.of(context).size.width * 0.05, + MediaQuery.of(context).size.height * 0.012, + ), + decoration: const BoxDecoration(color: Colors.white), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + const CustomBackButton(), + const SizedBox(width: 20), + const Text( + 'ํ•™์› ๋“ฑ๋กํ•˜๊ธฐ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + ], + ), + IconButton( + icon: const Icon(Icons.menu, color: Color(0xFF333333)), + onPressed: () { + // TODO: ๋ฉ”๋‰ด ๊ธฐ๋Šฅ ๊ตฌํ˜„ + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('๋ฉ”๋‰ด ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์˜ˆ์ •'))); + }, + ), + ], + ), + ); + } + + Widget _buildSearchBar() { + return Container( + constraints: BoxConstraints( + maxHeight: MediaQuery.of(context).size.height * 0.045, + minHeight: 30, + ), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(50), + ), + child: TextField( + controller: _searchController, + onChanged: _onSearchChanged, + decoration: const InputDecoration( + hintText: 'ํ•™์› ์ด๋ฆ„์„ ๋“ฑ๋กํ•ด์ฃผ์„ธ์š”', + hintStyle: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: Color(0xFF666666), + ), + prefixIcon: Icon(Icons.search, color: Color(0xFF666666), size: 23), + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(horizontal: 22, vertical: 11), + ), + ), + ); + } + + Widget _buildLoadingState() { + return const Center( + child: Padding( + padding: EdgeInsets.all(40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + CircularProgressIndicator(), + SizedBox(height: 16), + Text( + '๊ทผ์ฒ˜ ํ•™์›์„ ์ฐพ๋Š” ์ค‘...', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ], + ), + ), + ); + } + + Widget _buildErrorState() { + return Center( + child: Padding( + padding: const EdgeInsets.all(40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.error_outline, size: 64, color: Color(0xFFADADAD)), + const SizedBox(height: 16), + Text( + _errorMessage ?? '์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF666666), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 24), + ElevatedButton( + onPressed: _fetchNearbyAcademies, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF333333), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 12, + ), + ), + child: const Text( + '๋‹ค์‹œ ์‹œ๋„', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildAcademyList() { + if (_filteredAcademies.isEmpty) { + return const Center( + child: Padding( + padding: EdgeInsets.all(40.0), + child: Text( + '๊ทผ์ฒ˜์— ํ•™์›์ด ์—†์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ), + ); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ์„น์…˜ ์ œ๋ชฉ + const Text( + 'ํ˜„์œ„์น˜ ๊ทผ์ฒ˜์— ์žˆ๋Š” ํ•™์›์ด์—์š”', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + + const SizedBox(height: 16), + + // ํ•™์› ์นด๋“œ ๋ชฉ๋ก + ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: _filteredAcademies.length, + separatorBuilder: (context, index) => + Container(height: MediaQuery.of(context).size.height * 0.02), + itemBuilder: (context, index) { + return _buildAcademyCard(_filteredAcademies[index]); + }, + ), + ], + ); + } + + Widget _buildAcademyCard(AcademyData academy) { + return GestureDetector( + onTap: () async { + // ํ•™์› ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ณ  ๋“ฑ๋ก ์„ฑ๊ณต ์—ฌ๋ถ€๋ฅผ ๋ฐ›์Œ + final result = await Navigator.pushNamed( + context, + '/academy/detail', + arguments: academy, + ); + // ๋“ฑ๋ก ์„ฑ๊ณต ์‹œ academy_page์˜ ์บ์‹œ ๊ฐฑ์‹ ์„ ์œ„ํ•ด ๊ฒฐ๊ณผ ์ „๋‹ฌ + if (result == true && mounted) { + // academy_list_page์—์„œ academy_page๋กœ ๊ฒฐ๊ณผ ์ „๋‹ฌ + Navigator.of(context).pop(true); + } + }, + child: Container( + padding: EdgeInsets.all(MediaQuery.of(context).size.width * 0.025), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(10), + ), + child: Row( + children: [ + // ํ•™์› ์ธ๋„ค์ผ + _buildAcademyThumbnail(academy), + + Container(width: MediaQuery.of(context).size.width * 0.04), + + // ํ•™์› ์ •๋ณด + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ํ•™์›๋ช… + Text( + academy.name, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + + Container(height: MediaQuery.of(context).size.height * 0.035), + + // ๊ฑฐ๋ฆฌ์™€ ์ฃผ์†Œ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + academy.distance, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFFADADAD), + ), + ), + Container( + height: MediaQuery.of(context).size.height * 0.005, + ), + Text( + academy.address, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFFADADAD), + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ); + } + + Widget _buildAcademyThumbnail(AcademyData academy) { + return FutureBuilder( + future: academy.academyCode != null + ? _academyService + .getAcademyImages(academy.academyCode!) + .then((response) => response.mainImageUrl) + .catchError((e) { + return null; + }) + : Future.value(null), + builder: (context, snapshot) { + final imageUrl = snapshot.data; + final isLoading = snapshot.connectionState == ConnectionState.waiting; + + return Container( + width: MediaQuery.of(context).size.width * 0.25, + height: MediaQuery.of(context).size.width * 0.25, + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.25, + minWidth: 80, + maxHeight: MediaQuery.of(context).size.width * 0.25, + minHeight: 80, + ), + decoration: BoxDecoration( + color: const Color(0xFF666666), + borderRadius: BorderRadius.circular(5), + ), + child: isLoading + ? const Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ) + : imageUrl != null && imageUrl.isNotEmpty + ? ClipRRect( + borderRadius: BorderRadius.circular(5), + child: Image.network( + imageUrl, + fit: BoxFit.cover, + width: double.infinity, + height: double.infinity, + errorBuilder: (context, error, stackTrace) { + return const Icon( + Icons.school, + color: Colors.white, + size: 40, + ); + }, + ), + ) + : const Icon(Icons.school, color: Colors.white, size: 40), + ); + }, + ); + } +} + +class AcademyData { + final String name; + final String distance; + final String address; + final String thumbnail; + final String? academyCode; // ํ•™์› ์ฝ”๋“œ + + AcademyData({ + required this.name, + required this.distance, + required this.address, + required this.thumbnail, + this.academyCode, + }); +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ) +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/academy/academy_page.dart b/frontend/lib/screens/academy/academy_page.dart new file mode 100644 index 0000000..b5f3b04 --- /dev/null +++ b/frontend/lib/screens/academy/academy_page.dart @@ -0,0 +1,626 @@ +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert'; +import 'dart:io'; +import '../../widgets/app_header.dart'; +import '../../widgets/app_header_title.dart'; +import '../../widgets/app_header_menu_button.dart'; +import '../../services/auth_service.dart'; +import '../../services/academy_service.dart'; + +class AcademyPage extends StatefulWidget { + const AcademyPage({super.key}); + + @override + State createState() => _AcademyPageState(); +} + +class _AcademyPageState extends State { + final List _registeredAcademies = []; + final GetIt _getIt = GetIt.instance; + + late final AuthService _authService; + late final AcademyService _academyService; + + bool _isLoading = false; + bool _hasLoadedOnce = false; // ๋ฉ”๋ชจ๋ฆฌ ์บ์‹ฑ: ์ด๋ฏธ ๋กœ๋“œํ–ˆ๋Š”์ง€ ํ™•์ธ + bool _hasRefreshedOnReturn = false; // didChangeDependencies์—์„œ ์ด๋ฏธ ๊ฐฑ์‹ ํ–ˆ๋Š”์ง€ ํ™•์ธ + String? _errorMessage; + + static const String _cacheKeyBase = 'user_academies_cache'; + + @override + void initState() { + super.initState(); + _authService = _getIt(); + _academyService = _getIt(); + _loadAcademies(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ ๋Œ์•„์˜ฌ ๋•Œ๋งŒ ํ•œ ๋ฒˆ ๊ฐฑ์‹  (๊ณผ๋„ํ•œ API ํ˜ธ์ถœ ๋ฐฉ์ง€) + if (!_hasRefreshedOnReturn) { + _hasRefreshedOnReturn = true; + _loadAcademies(forceRefresh: true); + } + } + + /// ์™ธ๋ถ€์—์„œ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•œ ์ƒˆ๋กœ๊ณ ์นจ ๋ฉ”์„œ๋“œ + /// ํƒญ ์ „ํ™˜ ์‹œ MainNavigationPage์—์„œ ํ˜ธ์ถœ + void refresh() { + _hasRefreshedOnReturn = false; // ํ”Œ๋ž˜๊ทธ ๋ฆฌ์…‹ + _loadAcademies(forceRefresh: true); + } + + /// ํ•™์› ๋ชฉ๋ก ๋กœ๋“œ (์บ์‹œ์—์„œ๋งŒ ๋กœ๋“œ) + /// [forceRefresh]๊ฐ€ true์ด๋ฉด API ํ˜ธ์ถœํ•˜์—ฌ ์ตœ์‹  ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ + Future _loadAcademies({bool forceRefresh = false}) async { + // [์ผ€์ด์Šค 1] ๊ธฐ๋ณธ: SharedPreferences์—์„œ ์บ์‹œ ๋กœ๋“œ + // [์ผ€์ด์Šค 2] ๊ฐ™์€ ์„ธ์…˜ ๋‚ด ์žฌ์ง„์ž…: ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ ์‚ฌ์šฉ (API ํ˜ธ์ถœ ์—†์Œ) + // [์ผ€์ด์Šค 3] ๊ฐ•์ œ ๊ฐฑ์‹ : API ํ˜ธ์ถœํ•˜์—ฌ ์ตœ์‹  ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ + + if (_hasLoadedOnce && !forceRefresh) { + // ๊ฐ™์€ ์„ธ์…˜ ๋‚ด ์žฌ์ง„์ž…: ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ ์‚ฌ์šฉ + return; + } + + // ๊ฐ•์ œ ๊ฐฑ์‹  ์‹œ _hasLoadedOnce ํ”Œ๋ž˜๊ทธ ๋ฆฌ์…‹ + if (forceRefresh) { + _hasLoadedOnce = false; + } + + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + final userId = await _authService.getUserId(); + if (userId == null) { + setState(() { + _isLoading = false; + _errorMessage = '์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'; + }); + return; + } + final cacheKey = '${_cacheKeyBase}_$userId'; + if (forceRefresh) { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ) + HttpOverrides.global = MyHttpOverrides(); + + try { + final academies = await _academyService.getUserAcademies(userId); + + // API ์‘๋‹ต์„ AcademyItem์œผ๋กœ ๋ณ€ํ™˜ (์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐœ์„ ) + final academyItems = []; + for (var academy in academies) { + try { + final item = AcademyItem( + name: academy.academyName, + distance: '', // API ์‘๋‹ต์— ๊ฑฐ๋ฆฌ ์ •๋ณด๊ฐ€ ์—†์œผ๋ฏ€๋กœ ๋นˆ ๋ฌธ์ž์—ด + address: academy.academyRoadAddress, + thumbnail: null, + registerStatus: academy.registerStatus, + academyCode: academy.academyCode, + ); + academyItems.add(item); + } catch (e) { + // ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ๊ณ„์† ์ง„ํ–‰ + } + } + + // ๋ฉ”๋ชจ๋ฆฌ ๋ฐ SharedPreferences์— ์ €์žฅ + setState(() { + _registeredAcademies.clear(); + _registeredAcademies.addAll(academyItems); + _hasLoadedOnce = true; + _isLoading = false; + }); + + await _saveToCache(academyItems, cacheKey); + } catch (e) { + setState(() { + _isLoading = false; + _errorMessage = e.toString().replaceAll('Exception: ', ''); + }); + } + } else { + // ๊ธฐ๋ณธ: SharedPreferences์—์„œ ์บ์‹œ ๋กœ๋“œ + final cachedData = await _loadFromCache(cacheKey); + if (cachedData.isNotEmpty) { + setState(() { + _registeredAcademies.clear(); + _registeredAcademies.addAll(cachedData); + _hasLoadedOnce = true; + _isLoading = false; + }); + } else { + // ์บ์‹œ๊ฐ€ ์—†์œผ๋ฉด ๋นˆ ์ƒํƒœ ํ‘œ์‹œ + setState(() { + _registeredAcademies.clear(); + _isLoading = false; + }); + } + } + } catch (e) { + setState(() { + _isLoading = false; + _errorMessage = e.toString().replaceAll('Exception: ', ''); + }); + } + } + + /// SharedPreferences์—์„œ ์บ์‹œ ๋กœ๋“œ + Future> _loadFromCache(String cacheKey) async { + try { + final prefs = await SharedPreferences.getInstance(); + final cachedJson = prefs.getString(cacheKey); + if (cachedJson == null) { + if (prefs.containsKey(_cacheKeyBase)) { + await prefs.remove(_cacheKeyBase); + } + return []; + } + + final List data = json.decode(cachedJson); + return data.map((item) => AcademyItem.fromJson(item)).toList(); + } catch (e) { + return []; + } + } + + /// SharedPreferences์— ์บ์‹œ ์ €์žฅ + Future _saveToCache( + List academies, + String cacheKey, + ) async { + try { + final prefs = await SharedPreferences.getInstance(); + final jsonData = json.encode( + academies.map((academy) => academy.toJson()).toList(), + ); + await prefs.setString(cacheKey, jsonData); + if (prefs.containsKey(_cacheKeyBase)) { + await prefs.remove(_cacheKeyBase); + } + } catch (e) { + // ์บ์‹œ ์ €์žฅ ์‹คํŒจ๋Š” ๋ฌด์‹œ + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + // ํ—ค๋” + _buildHeader(), + + // ๋ฉ”์ธ ์ฝ˜ํ…์ธ  + Expanded( + child: RefreshIndicator( + onRefresh: () async { + await _loadAcademies(forceRefresh: true); + }, + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), // Pull-to-refresh๋ฅผ ์œ„ํ•ด ํ•ญ์ƒ ์Šคํฌ๋กค ๊ฐ€๋Šฅํ•˜๋„๋ก + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + children: [ + const SizedBox(height: 18), + + // ๋กœ๋”ฉ ์ƒํƒœ + if (_isLoading) + const Padding( + padding: EdgeInsets.all(40.0), + child: CircularProgressIndicator(), + ) + // ์—๋Ÿฌ ์ƒํƒœ + else if (_errorMessage != null) + _buildErrorState() + // ํ•™์› ๋ชฉ๋ก ๋˜๋Š” ๋นˆ ์ƒํƒœ + else if (_registeredAcademies.isEmpty) + _buildEmptyState() + else + _buildAcademyList(), + + const SizedBox(height: 20), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return const AppHeader( + title: AppHeaderTitle('ํ•™์›', textAlign: TextAlign.center), + trailing: AppHeaderMenuButton(), + ); + } + + Widget _buildErrorState() { + return Column( + children: [ + Container( + width: double.infinity, + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFFFF5F5), + border: Border.all(color: const Color(0xFFFFCCCC)), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + children: [ + const Icon( + Icons.error_outline, + color: Color(0xFFFF6B6B), + size: 32, + ), + const SizedBox(height: 12), + Text( + _errorMessage ?? '์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFFF6B6B), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 12), + ElevatedButton( + onPressed: _loadAcademies, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFFF6B6B), + foregroundColor: Colors.white, + ), + child: const Text('๋‹ค์‹œ ์‹œ๋„'), + ), + ], + ), + ), + ], + ); + } + + Widget _buildEmptyState() { + return Column( + children: [ + // "๋“ฑ๋ก๋œ ํ•™์›์ด ์—†์Šต๋‹ˆ๋‹ค." ์นด๋“œ + Container( + width: double.infinity, + height: 81, + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: Text( + '๋“ฑ๋ก๋œ ํ•™์›์ด ์—†์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Color(0xFF585B69), + ), + ), + ), + ), + + const SizedBox(height: 15), + + // "+" ๋ฒ„ํŠผ ์นด๋“œ + GestureDetector( + onTap: () async { + // ํ•™์› ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ณ  ๋“ฑ๋ก ์„ฑ๊ณต ์—ฌ๋ถ€๋ฅผ ๋ฐ›์Œ + final result = await Navigator.pushNamed(context, '/academy/list'); + // ๋“ฑ๋ก ์„ฑ๊ณต ์‹œ ์บ์‹œ ๊ฐฑ์‹  + if (result == true) { + await _loadAcademies(forceRefresh: true); + } + }, + child: Container( + width: double.infinity, + height: 46, + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: Icon(Icons.add, size: 24, color: Color(0xFF585B69)), + ), + ), + ), + ], + ); + } + + Widget _buildAcademyList() { + return Column( + children: [ + // ๋“ฑ๋ก๋œ ํ•™์› ์นด๋“œ ๋ชฉ๋ก + ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: _registeredAcademies.length, + separatorBuilder: (context, index) => const SizedBox(height: 16), + itemBuilder: (context, index) { + return _buildAcademyCard(_registeredAcademies[index]); + }, + ), + + const SizedBox(height: 16), + + // "+" ๋ฒ„ํŠผ ์นด๋“œ + GestureDetector( + onTap: () async { + // ํ•™์› ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ณ  ๋“ฑ๋ก ์„ฑ๊ณต ์—ฌ๋ถ€๋ฅผ ๋ฐ›์Œ + final result = await Navigator.pushNamed(context, '/academy/list'); + // ๋“ฑ๋ก ์„ฑ๊ณต ์‹œ ์บ์‹œ ๊ฐฑ์‹  + if (result == true) { + await _loadAcademies(forceRefresh: true); + } + }, + child: Container( + width: double.infinity, + height: 46, + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: Icon(Icons.add, size: 24, color: Color(0xFF585B69)), + ), + ), + ), + ], + ); + } + + Widget _buildAcademyCard(AcademyItem academy) { + // registerStatus์— ๋”ฐ๋ผ ์Šคํƒ€์ผ ๊ฒฐ์ • + // 'Y' (Yes): ์„ ๋ช…ํ•˜๊ฒŒ, 'P' (Pending): ํ๋ฆฌ๊ฒŒ + final bool isPending = academy.registerStatus == 'P'; + final double opacity = isPending ? 0.5 : 1.0; + final bool isSelectable = + academy.registerStatus == 'Y' && academy.academyCode != null; + + return Opacity( + opacity: opacity, + child: GestureDetector( + onTap: isSelectable + ? () async { + // ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์›๋งŒ ์„ ํƒ ๊ฐ€๋Šฅ + if (academy.academyCode != null) { + await _academyService.saveDefaultAcademyCode( + academy.academyCode!, + ); + + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('${academy.name}์ด(๊ฐ€) ๊ธฐ๋ณธ ํ•™์›์œผ๋กœ ์„ค์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'), + backgroundColor: Colors.green, + duration: const Duration(seconds: 2), + ), + ); + } + } + } + : null, + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: Row( + children: [ + // ํ•™์› ์ธ๋„ค์ผ + _buildAcademyThumbnail(academy), + + const SizedBox(width: 15), + + // ํ•™์› ์ •๋ณด + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ํ•™์›๋ช… ๋ฐ ์ƒํƒœ ํ‘œ์‹œ + Row( + children: [ + Expanded( + child: Text( + academy.name, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Color(0xFF585B69), + ), + ), + ), + // ์ƒํƒœ ๋ฑƒ์ง€ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: isPending + ? const Color(0xFFFFF3CD) + : const Color(0xFFD4EDDA), + borderRadius: BorderRadius.circular(4), + ), + child: Text( + isPending ? '๋Œ€๊ธฐ์ค‘' : '๋“ฑ๋ก์™„๋ฃŒ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 10, + color: isPending + ? const Color(0xFF856404) + : const Color(0xFF155724), + ), + ), + ), + ], + ), + + const SizedBox(height: 28), + + // ๊ฑฐ๋ฆฌ (์žˆ์„ ๊ฒฝ์šฐ๋งŒ ํ‘œ์‹œ) + if (academy.distance.isNotEmpty) ...[ + Text( + academy.distance, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF585B69), + ), + ), + const SizedBox(height: 4), + ], + + // ์ฃผ์†Œ + Text( + academy.address, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF585B69), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } + + Widget _buildAcademyThumbnail(AcademyItem academy) { + return FutureBuilder( + future: academy.academyCode != null + ? _academyService + .getAcademyImages(academy.academyCode!) + .then((response) => response.mainImageUrl) + .catchError((e) { + return null; + }) + : Future.value(null), + builder: (context, snapshot) { + final imageUrl = snapshot.data; + final isLoading = snapshot.connectionState == ConnectionState.waiting; + + return Container( + width: 97, + height: 97, + decoration: BoxDecoration( + color: const Color(0xFFE1E7ED), + borderRadius: BorderRadius.circular(5), + ), + child: isLoading + ? const Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ), + ) + : imageUrl != null && imageUrl.isNotEmpty + ? ClipRRect( + borderRadius: BorderRadius.circular(5), + child: Image.network( + imageUrl, + fit: BoxFit.cover, + width: 97, + height: 97, + errorBuilder: (context, error, stackTrace) { + return const Icon( + Icons.school, + color: Colors.white, + size: 40, + ); + }, + ), + ) + : const Icon(Icons.school, color: Colors.white, size: 40), + ); + }, + ); + } +} + +class AcademyItem { + final String name; + final String distance; + final String address; + final String? thumbnail; + final String registerStatus; // 'Y' ๋˜๋Š” 'P' + final String? academyCode; // ํ•™์› ์ฝ”๋“œ + + AcademyItem({ + required this.name, + required this.distance, + required this.address, + this.thumbnail, + required this.registerStatus, + this.academyCode, + }); + + /// JSON์œผ๋กœ ๋ณ€ํ™˜ (SharedPreferences ์ €์žฅ์šฉ) + Map toJson() { + return { + 'name': name, + 'distance': distance, + 'address': address, + 'thumbnail': thumbnail, + 'registerStatus': registerStatus, + 'academyCode': academyCode, + }; + } + + /// JSON์—์„œ ์ƒ์„ฑ (SharedPreferences ๋กœ๋“œ์šฉ) + factory AcademyItem.fromJson(Map json) { + return AcademyItem( + name: json['name'] ?? '', + distance: json['distance'] ?? '', + address: json['address'] ?? '', + thumbnail: json['thumbnail'], + registerStatus: json['registerStatus'] ?? 'P', + academyCode: json['academyCode']?.toString(), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ) +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/account/find_id_error_page.dart b/frontend/lib/screens/account/find_id_error_page.dart new file mode 100644 index 0000000..4325e26 --- /dev/null +++ b/frontend/lib/screens/account/find_id_error_page.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/next_button.dart'; + +class FindIDErrorPage extends StatefulWidget { + const FindIDErrorPage({super.key}); + + @override + State createState() => _FindIDErrorPageState(); +} + +class _FindIDErrorPageState extends State { + void _handleBack() { + Navigator.pop(context); + } + + void _handleRetry() { + Navigator.pop(context); // Go back to FindIDPage to retry + } + + void _handleBackToLogin() { + Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + const SizedBox(height: 20), + Row( + children: [ + custom.CustomBackButton(onPressed: _handleBack), + const SizedBox(width: 20), + const PageTitle(text: '์•„์ด๋”” ์ฐพ๊ธฐ'), + ], + ), + const SizedBox(height: 40), + const Icon( + Icons.error_outline, + size: 64, + color: Color(0xFFFF4258), + ), + const SizedBox(height: 24), + const Text( + '์ž…๋ ฅํ•œ ์ด๋ฉ”์ผ๋กœ\n์•„์ด๋””๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: Color(0xFF5C5C5C), + ), + ), + const SizedBox(height: 8), + const Text( + '์ž…๋ ฅํ•˜์‹  ์ •๋ณด๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š”.', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFA0A0A0), + ), + ), + const SizedBox(height: 40), + NextButton(text: '๋‹ค์‹œ ์‹œ๋„', onPressed: _handleRetry), + const SizedBox(height: 16), + TextButton( + onPressed: _handleBackToLogin, + child: const Text( + '๋กœ๊ทธ์ธ์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 16, + color: Color(0xFF666EDE), + ), + ), + ), + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/frontend/lib/screens/account/find_id_page.dart b/frontend/lib/screens/account/find_id_page.dart new file mode 100644 index 0000000..3c2a527 --- /dev/null +++ b/frontend/lib/screens/account/find_id_page.dart @@ -0,0 +1,252 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/labeled_input_field.dart'; +import '../../widgets/next_button.dart'; +import '../../config/api_config.dart'; + +class FindIDPage extends StatefulWidget { + const FindIDPage({super.key}); + + @override + State createState() => _FindIDPageState(); +} + +class _FindIDPageState extends State { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _emailController = TextEditingController(); + + // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ƒํƒœ + String? _nameError; + String? _emailError; + bool _isNameFieldError = false; + bool _isEmailFieldError = false; + bool _isLoading = false; + + @override + void dispose() { + _nameController.dispose(); + _emailController.dispose(); + super.dispose(); + } + + void _handleBack() { + Navigator.of(context).pop(); + } + + bool _isValidEmail(String email) { + // ์ด๋ฉ”์ผ ํ˜•์‹ ๊ฒ€์ฆ: @๊ฐ€ ํฌํ•จ๋˜๊ณ  ์•ž๋’ค๋กœ ์ตœ์†Œ ํ•œ ๊ธ€์ž ์ด์ƒ + final emailRegex = RegExp(r'^.+@.+$'); + return emailRegex.hasMatch(email); + } + + void _clearErrors() { + setState(() { + _nameError = null; + _emailError = null; + _isNameFieldError = false; + _isEmailFieldError = false; + }); + } + + bool _validateInputs() { + bool isValid = true; + _clearErrors(); + + // ์ด๋ฆ„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_nameController.text.trim().isEmpty) { + setState(() { + _nameError = '์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'; + _isNameFieldError = true; + }); + isValid = false; + } + + // ์ด๋ฉ”์ผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_emailController.text.trim().isEmpty) { + setState(() { + _emailError = '์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'; + _isEmailFieldError = true; + }); + isValid = false; + } else if (!_isValidEmail(_emailController.text.trim())) { + setState(() { + _emailError = '์˜ฌ๋ฐ”๋ฅธ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isEmailFieldError = true; + }); + isValid = false; + } + + return isValid; + } + + Future _handleNext() async { + if (!_validateInputs()) { + return; + } + + setState(() { + _isLoading = true; + }); + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ ํ•„์š”) + HttpOverrides.global = MyHttpOverrides(); + + // ์„œ๋ฒ„ IP ์„ค์ • (ํ•„์š”์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ) + final url = ApiConfig.getSendCodeFindAccountUri(); + + // ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„ + final Map requestData = { + 'name': _nameController.text.trim(), + 'email': _emailController.text.trim(), + }; + + developer.log( + 'Find ID attempted with name: ${_nameController.text.trim()}', + ); + developer.log('Sending POST request to: $url'); + developer.log('Request data: $requestData'); + + // HTTP POST ์š”์ฒญ + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (mounted) { + setState(() { + _isLoading = false; + }); + } + + if (!mounted) return; + + // ์‘๋‹ต ์ฒ˜๋ฆฌ + if (response.statusCode == 200) { + final responseData = json.decode(response.body); + developer.log( + 'Find ID request successful. Response data: $responseData', + ); + + // success ์ปฌ๋Ÿผ์ด true์ธ์ง€ ํ™•์ธ + if (responseData['success'] == true) { + // ์„ฑ๊ณต ์‹œ ์ธ์ฆ ํŽ˜์ด์ง€๋กœ ์ด๋™ + final userName = _nameController.text.trim(); + final email = _emailController.text.trim(); + developer.log( + 'Navigating to verification page with userName: $userName, email: $email', + ); + Navigator.pushNamed( + context, + '/find-id-verification', + arguments: {'userName': userName, 'email': email}, + ); + } else { + // success๊ฐ€ false์ธ ๊ฒฝ์šฐ ์—๋Ÿฌ ํŽ˜์ด์ง€๋กœ ์ด๋™ + developer.log('Find ID failed: success is false'); + Navigator.pushNamed(context, '/find-id-error'); + } + } else if (response.statusCode == 500) { + // 500 ์—๋Ÿฌ ์‹œ ์—๋Ÿฌ ํŽ˜์ด์ง€๋กœ ์ด๋™ + developer.log('Find ID failed: User not found (500 error)'); + if (!mounted) return; + Navigator.pushNamed(context, '/find-id-error'); + } else { + // ๊ธฐํƒ€ ์—๋Ÿฌ + developer.log('Find ID failed with status: ${response.statusCode}'); + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: ${response.statusCode}')), + ); + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + developer.log('Find ID error: $e'); + if (!mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜: $e'))); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + const SizedBox(height: 20), + Row( + children: [ + custom.CustomBackButton(onPressed: _handleBack), + const SizedBox(width: 20), + const PageTitle(text: '์•„์ด๋”” ์ฐพ๊ธฐ'), + ], + ), + const SizedBox(height: 20), + LabeledInputField( + label: '์ด๋ฆ„*', + placeholder: '์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _nameController, + keyboardType: TextInputType.text, + isError: _isNameFieldError, + errorMessage: _nameError, + ), + const SizedBox(height: 24), + LabeledInputField( + label: '์ด๋ฉ”์ผ*', + placeholder: '์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _emailController, + keyboardType: TextInputType.emailAddress, + isError: _isEmailFieldError, + errorMessage: _emailError, + ), + const SizedBox(height: 20), + NextButton( + text: _isLoading ? '์ฒ˜๋ฆฌ ์ค‘...' : '๋‹ค์Œ', + onPressed: _isLoading ? null : _handleNext, + ), + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/account/find_id_result_page.dart b/frontend/lib/screens/account/find_id_result_page.dart new file mode 100644 index 0000000..f110a19 --- /dev/null +++ b/frontend/lib/screens/account/find_id_result_page.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/user_id_card.dart'; +import '../../widgets/login_button.dart'; + +class FindIDResultPage extends StatefulWidget { + final String userName; + final String userId; + + const FindIDResultPage({ + super.key, + required this.userName, + required this.userId, + }); + + @override + State createState() => _FindIDResultPageState(); +} + +class _FindIDResultPageState extends State { + String? _userName; + String? _userId; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // arguments์—์„œ ๋ฐ์ดํ„ฐ ์ถ”์ถœ + final args = + ModalRoute.of(context)?.settings.arguments as Map?; + if (args != null) { + _userName = args['userName'] as String?; + _userId = args['userId'] as String?; + } + } + + void _handleBack() { + Navigator.of(context).pop(); + } + + void _handleLogin() { + // Navigate to login page + Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false); + } + + @override + Widget build(BuildContext context) { + final screenHeight = + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom; + + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: screenHeight), + child: IntrinsicHeight( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + // Back Button and Title + Row( + children: [ + custom.CustomBackButton(onPressed: _handleBack), + const SizedBox(width: 20), + const PageTitle(text: '์•„์ด๋”” ์ฐพ๊ธฐ'), + ], + ), + + const SizedBox(height: 20), + // User ID Card + UserIDCard( + userName: _userName ?? widget.userName, + userId: _userId ?? widget.userId, + ), + + const SizedBox(height: 100), // Spacing before button + // Login Button + Padding( + padding: const EdgeInsets.only(bottom: 29), + child: LoginButton( + text: '๋กœ๊ทธ์ธํ•˜๊ธฐ', + onPressed: _handleLogin, + ), + ), + ], + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/frontend/lib/screens/account/find_id_verification_page.dart b/frontend/lib/screens/account/find_id_verification_page.dart new file mode 100644 index 0000000..38fb599 --- /dev/null +++ b/frontend/lib/screens/account/find_id_verification_page.dart @@ -0,0 +1,283 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/verification_code_input.dart'; +import '../../widgets/next_button.dart'; +import '../../config/api_config.dart'; + +class FindIDVerificationPage extends StatefulWidget { + const FindIDVerificationPage({super.key}); + + @override + State createState() => _FindIDVerificationPageState(); +} + +class _FindIDVerificationPageState extends State { + String _verificationCode = ''; + bool _isLoading = false; + String? _userName; + String? _email; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // arguments์—์„œ ๋ฐ์ดํ„ฐ ์ถ”์ถœ + final args = + ModalRoute.of(context)?.settings.arguments as Map?; + if (args != null) { + _userName = args['userName'] as String?; + _email = args['email'] as String?; + developer.log( + 'FindIDVerificationPage - userName: $_userName, email: $_email', + ); + developer.log('FindIDVerificationPage - args: $args'); + } else { + developer.log('FindIDVerificationPage - No arguments received'); + } + } + + void _handleBack() { + Navigator.of(context).pop(); + } + + void _handleNext() async { + if (_verificationCode.length != 6) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('6์ž๋ฆฌ ์ธ์ฆ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + if (mounted) { + setState(() { + _isLoading = true; + }); + } + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ ํ•„์š”) + HttpOverrides.global = MyHttpOverrides(); + + // ์„œ๋ฒ„ IP ์„ค์ • (ํ•„์š”์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ) + final url = ApiConfig.getVerifyFindAccountUri(); + + // ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„ + final Map requestData = { + 'email': _email ?? '', + 'code': _verificationCode.toString(), + }; + + developer.log('Sending verification request: $requestData'); + developer.log('Request URL: $url'); + developer.log('Email before request: $_email'); + developer.log('Verification code: $_verificationCode'); + developer.log( + 'Request headers: {\'Content-Type\': \'application/json\'}', + ); + + // API ํ˜ธ์ถœ + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response headers: ${response.headers}'); + developer.log('Response body: ${response.body}'); + + if (!mounted) return; + + if (response.statusCode == 200) { + final responseData = json.decode(response.body); + + if (responseData['success'] == true) { + // ์„ฑ๊ณต ์‹œ ๊ฒฐ๊ณผ ํŽ˜์ด์ง€๋กœ ์ด๋™ + Navigator.pushNamed( + context, + '/find-id-result', + arguments: { + 'userName': responseData['data']['name'] ?? _userName ?? '', + 'userId': responseData['data']['account_id'] ?? '', + }, + ); + } else { + // ์ธ์ฆ ์‹คํŒจ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์ธ์ฆ๋ฒˆํ˜ธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } + } else { + // ์„œ๋ฒ„ ์˜ค๋ฅ˜ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์„œ๋ฒ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } + } catch (e) { + developer.log('Error during verification: $e'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + void _handleResendCode() { + // Handle resend code logic here + developer.log('Resend code requested'); + } + + void _onCodeChanged(String code) { + if (mounted) { + setState(() { + _verificationCode = code; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + // Back Button and Title + Row( + children: [ + custom.CustomBackButton(onPressed: _handleBack), + const SizedBox(width: 20), + const PageTitle(text: '์•„์ด๋”” ์ฐพ๊ธฐ'), + ], + ), + + const SizedBox(height: 20), + // Welcome Message + Text( + '${_userName ?? ''}๋‹˜, ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 24, + fontWeight: FontWeight.w600, + color: Color(0xFF5C5C5C), + height: 1.193, + ), + ), + + const SizedBox(height: 7), + // Instructions + const Text( + '์ด๋ฉ”์ผ๋กœ ๋ณด๋‚ด๋“œ๋ฆฐ 6์ž ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color(0xFF5C5C5C), + height: 1.193, + ), + ), + + const SizedBox(height: 24), + // Verification Code Input + VerificationCodeInput( + length: 6, + onChanged: _onCodeChanged, + width: 320, + height: 50, + ), + + const SizedBox(height: 13), + // Resend Code Link + GestureDetector( + onTap: _handleResendCode, + child: RichText( + text: TextSpan( + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 16, + fontWeight: FontWeight.w500, + color: Color(0xFFADADAD), + height: 1.193, + ), + children: [ + const TextSpan(text: '์ธ์ฆ๋ฒˆํ˜ธ๋ฅผ ๋ฐ›์ง€ ๋ชปํ–ˆ๋‚˜์š”? '), + TextSpan( + text: '์žฌ์ „์†ก', + style: TextStyle( + color: const Color(0xFFADADAD), + decoration: TextDecoration.underline, + ), + ), + ], + ), + ), + ), + + const SizedBox(height: 161), + // Next Button + NextButton( + text: _isLoading ? '์ฒ˜๋ฆฌ ์ค‘...' : '๋‹ค์Œ', + onPressed: (_verificationCode.length == 6 && !_isLoading) + ? _handleNext + : null, + ), + + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/account/find_password_error_page.dart b/frontend/lib/screens/account/find_password_error_page.dart new file mode 100644 index 0000000..b76fd7e --- /dev/null +++ b/frontend/lib/screens/account/find_password_error_page.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/next_button.dart'; + +class FindPasswordErrorPage extends StatefulWidget { + const FindPasswordErrorPage({super.key}); + + @override + State createState() => _FindPasswordErrorPageState(); +} + +class _FindPasswordErrorPageState extends State { + void _handleBack() { + Navigator.pop(context); + } + + void _handleRetry() { + Navigator.pop(context); // Go back to FindPasswordPage to retry + } + + void _handleBackToLogin() { + Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + const SizedBox(height: 20), + Row( + children: [ + custom.CustomBackButton(onPressed: _handleBack), + const SizedBox(width: 20), + const PageTitle(text: '๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ'), + ], + ), + const SizedBox(height: 40), + const Icon( + Icons.error_outline, + size: 64, + color: Color(0xFFFF4258), + ), + const SizedBox(height: 24), + const Text( + '์ž…๋ ฅํ•œ ์ •๋ณด๋กœ\n๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: Color(0xFF5C5C5C), + ), + ), + const SizedBox(height: 8), + const Text( + '์ž…๋ ฅํ•˜์‹  ์ •๋ณด๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š”.', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFA0A0A0), + ), + ), + const SizedBox(height: 40), + NextButton(text: '๋‹ค์‹œ ์‹œ๋„', onPressed: _handleRetry), + const SizedBox(height: 16), + TextButton( + onPressed: _handleBackToLogin, + child: const Text( + '๋กœ๊ทธ์ธ์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 16, + color: Color(0xFF666EDE), + ), + ), + ), + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/frontend/lib/screens/account/find_password_page.dart b/frontend/lib/screens/account/find_password_page.dart new file mode 100644 index 0000000..d916ffa --- /dev/null +++ b/frontend/lib/screens/account/find_password_page.dart @@ -0,0 +1,277 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/labeled_input_field.dart'; +import '../../widgets/next_button.dart'; +import '../../config/api_config.dart'; + +class FindPasswordPage extends StatefulWidget { + const FindPasswordPage({super.key}); + + @override + State createState() => _FindPasswordPageState(); +} + +class _FindPasswordPageState extends State { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _emailController = TextEditingController(); + final TextEditingController _idController = TextEditingController(); + + // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ƒํƒœ + String? _nameError; + String? _emailError; + String? _idError; + bool _isNameFieldError = false; + bool _isEmailFieldError = false; + bool _isIdFieldError = false; + bool _isLoading = false; + + @override + void dispose() { + _nameController.dispose(); + _emailController.dispose(); + _idController.dispose(); + super.dispose(); + } + + void _handleBack() { + Navigator.pop(context); + } + + bool _isValidEmail(String email) { + // ์ด๋ฉ”์ผ ํ˜•์‹ ๊ฒ€์ฆ: @๊ฐ€ ํฌํ•จ๋˜๊ณ  ์•ž๋’ค๋กœ ์ตœ์†Œ ํ•œ ๊ธ€์ž ์ด์ƒ + final emailRegex = RegExp(r'^.+@.+$'); + return emailRegex.hasMatch(email); + } + + void _clearErrors() { + setState(() { + _nameError = null; + _emailError = null; + _idError = null; + _isNameFieldError = false; + _isEmailFieldError = false; + _isIdFieldError = false; + }); + } + + bool _validateInputs() { + bool isValid = true; + _clearErrors(); + + // ์ด๋ฆ„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_nameController.text.trim().isEmpty) { + setState(() { + _nameError = '์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'; + _isNameFieldError = true; + }); + isValid = false; + } + + // ์ด๋ฉ”์ผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_emailController.text.trim().isEmpty) { + setState(() { + _emailError = '์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'; + _isEmailFieldError = true; + }); + isValid = false; + } else if (!_isValidEmail(_emailController.text.trim())) { + setState(() { + _emailError = '์˜ฌ๋ฐ”๋ฅธ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isEmailFieldError = true; + }); + isValid = false; + } + + // ์•„์ด๋”” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_idController.text.trim().isEmpty) { + setState(() { + _idError = '์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'; + _isIdFieldError = true; + }); + isValid = false; + } + + return isValid; + } + + Future _handleNext() async { + if (!_validateInputs()) { + return; + } + + setState(() { + _isLoading = true; + }); + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ ํ•„์š”) + HttpOverrides.global = MyHttpOverrides(); + + // ์„œ๋ฒ„ IP ์„ค์ • (ํ•„์š”์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ) + final url = ApiConfig.getSendCodeResetPasswordUri(); + + // ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„ + final Map requestData = { + 'name': _nameController.text.trim(), + 'email': _emailController.text.trim(), + 'account_id': _idController.text.trim(), + }; + + developer.log( + 'Find Password attempted with name: ${_nameController.text.trim()}', + ); + developer.log('Sending POST request to: $url'); + developer.log('Request data: $requestData'); + + // HTTP POST ์š”์ฒญ + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (!mounted) return; + + setState(() { + _isLoading = false; + }); + + // ์‘๋‹ต ์ฒ˜๋ฆฌ + if (response.statusCode == 200) { + final responseData = json.decode(response.body); + developer.log( + 'Find Password request successful. Response data: $responseData', + ); + + // success ์ปฌ๋Ÿผ์ด true์ธ์ง€ ํ™•์ธ + if (responseData['success'] == true) { + // ์„ฑ๊ณต ์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ ํŽ˜์ด์ง€๋กœ ์ด๋™ + Navigator.pushNamed( + context, + '/find-password-verification', + arguments: { + 'userName': _nameController.text.trim(), + 'userId': _idController.text.trim(), + 'email': _emailController.text.trim(), + }, + ); + } else { + // success๊ฐ€ false์ธ ๊ฒฝ์šฐ ์—๋Ÿฌ ํŽ˜์ด์ง€๋กœ ์ด๋™ + developer.log('Find Password failed: success is false'); + Navigator.pushNamed(context, '/find-password-error'); + } + } else if (response.statusCode == 500) { + // 500 ์—๋Ÿฌ ์‹œ ์—๋Ÿฌ ํŽ˜์ด์ง€๋กœ ์ด๋™ + developer.log('Find Password failed: User not found (500 error)'); + Navigator.pushNamed(context, '/find-password-error'); + } else { + // ๊ธฐํƒ€ ์—๋Ÿฌ + developer.log( + 'Find Password failed with status: ${response.statusCode}', + ); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: ${response.statusCode}')), + ); + } + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + developer.log('Find Password error: $e'); + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜: $e'))); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + const SizedBox(height: 20), + Row( + children: [ + custom.CustomBackButton(onPressed: _handleBack), + const SizedBox(width: 20), + const PageTitle(text: '๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ'), + ], + ), + const SizedBox(height: 20), + LabeledInputField( + label: '์ด๋ฆ„*', + placeholder: '์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _nameController, + keyboardType: TextInputType.text, + isError: _isNameFieldError, + errorMessage: _nameError, + ), + const SizedBox(height: 24), + LabeledInputField( + label: '์ด๋ฉ”์ผ*', + placeholder: '์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _emailController, + keyboardType: TextInputType.emailAddress, + isError: _isEmailFieldError, + errorMessage: _emailError, + ), + const SizedBox(height: 24), + LabeledInputField( + label: '์•„์ด๋””*', + placeholder: '์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _idController, + keyboardType: TextInputType.text, + isError: _isIdFieldError, + errorMessage: _idError, + ), + const SizedBox(height: 20), + NextButton( + text: _isLoading ? '์ฒ˜๋ฆฌ ์ค‘...' : '๋‹ค์Œ', + onPressed: _isLoading ? null : _handleNext, + ), + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/account/find_password_reset_page.dart b/frontend/lib/screens/account/find_password_reset_page.dart new file mode 100644 index 0000000..d7eb389 --- /dev/null +++ b/frontend/lib/screens/account/find_password_reset_page.dart @@ -0,0 +1,392 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/labeled_input_field.dart'; +import '../../widgets/next_button.dart'; +import '../../config/api_config.dart'; + +class FindPasswordResetPage extends StatefulWidget { + const FindPasswordResetPage({super.key}); + + @override + State createState() => _FindPasswordResetPageState(); +} + +class _FindPasswordResetPageState extends State { + final TextEditingController _newPasswordController = TextEditingController(); + final TextEditingController _confirmPasswordController = + TextEditingController(); + + // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ƒํƒœ + String? _newPasswordError; + String? _confirmPasswordError; + bool _isNewPasswordFieldError = false; + bool _isConfirmPasswordFieldError = false; + bool _isLoading = false; + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ + List _passwordPolicyErrors = []; + + // ์ „๋‹ฌ๋ฐ›์€ ์‚ฌ์šฉ์ž ์ •๋ณด + String? _userId; + + @override + void initState() { + super.initState(); + // ์ „๋‹ฌ๋ฐ›์€ arguments ์ฒ˜๋ฆฌ + WidgetsBinding.instance.addPostFrameCallback((_) { + final arguments = + ModalRoute.of(context)?.settings.arguments as Map?; + if (arguments != null) { + setState(() { + _userId = arguments['userId']; + }); + } + }); + } + + @override + void dispose() { + _newPasswordController.dispose(); + _confirmPasswordController.dispose(); + super.dispose(); + } + + void _handleBack() { + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ฐพ๊ธฐ ํŽ˜์ด์ง€๋กœ ์ด๋™ (์ž…๋ ฅํผ์€ ๋ชจ๋‘ ๊ณต๋ฐฑ ์ƒํƒœ) + Navigator.pushNamedAndRemoveUntil( + context, + '/find-password', + (route) => false, + ); + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ + List _validatePasswordPolicy(String password) { + List errors = []; + + if (password.length < 8) { + errors.add('8์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[A-Z]').hasMatch(password)) { + errors.add('๋Œ€๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[a-z]').hasMatch(password)) { + errors.add('์†Œ๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[0-9]').hasMatch(password)) { + errors.add('์ˆซ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[!@#$%^&*(),.?":{}|<>]').hasMatch(password)) { + errors.add('ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + + return errors; + } + + // ์‹ค์‹œ๊ฐ„ ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + void _onNewPasswordChanged(String value) { + setState(() { + _passwordPolicyErrors = _validatePasswordPolicy(value); + _newPasswordError = null; + _isNewPasswordFieldError = false; + }); + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ํ•„๋“œ๋„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฒ€์‚ฌ + if (_confirmPasswordController.text.isNotEmpty) { + _onConfirmPasswordChanged(_confirmPasswordController.text); + } + } + + // ์‹ค์‹œ๊ฐ„ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ๊ฒ€์‚ฌ + void _onConfirmPasswordChanged(String value) { + setState(() { + if (value.isNotEmpty && _newPasswordController.text != value) { + _confirmPasswordError = '์ž…๋ ฅ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค'; + _isConfirmPasswordFieldError = true; + } else { + _confirmPasswordError = null; + _isConfirmPasswordFieldError = false; + } + }); + } + + void _clearErrors() { + setState(() { + _newPasswordError = null; + _confirmPasswordError = null; + _isNewPasswordFieldError = false; + _isConfirmPasswordFieldError = false; + _passwordPolicyErrors = []; + }); + } + + bool _validateInputs() { + bool isValid = true; + _clearErrors(); + + // ์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_newPasswordController.text.trim().isEmpty) { + setState(() { + _newPasswordError = '๋ณ€๊ฒฝํ•  ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isNewPasswordFieldError = true; + }); + isValid = false; + } else { + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ + List policyErrors = _validatePasswordPolicy( + _newPasswordController.text, + ); + if (policyErrors.isNotEmpty) { + setState(() { + _passwordPolicyErrors = policyErrors; + }); + isValid = false; + } + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_confirmPasswordController.text.trim().isEmpty) { + setState(() { + _isConfirmPasswordFieldError = true; // ํ…Œ๋‘๋ฆฌ๋งŒ ๋นจ๊ฐ„์ƒ‰์œผ๋กœ, ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋Š” ํ‘œ์‹œํ•˜์ง€ ์•Š์Œ + }); + isValid = false; + } else if (_newPasswordController.text != _confirmPasswordController.text) { + setState(() { + _confirmPasswordError = '์ž…๋ ฅ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค'; + _isConfirmPasswordFieldError = true; + }); + isValid = false; + } + + return isValid; + } + + Future _handleNext() async { + if (!_validateInputs()) { + return; + } + + setState(() { + _isLoading = true; + }); + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ ํ•„์š”) + HttpOverrides.global = MyHttpOverrides(); + + // ์„œ๋ฒ„ IP ์„ค์ • (ํ•„์š”์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ) + final url = ApiConfig.getChangeResetPasswordUri(); + + // TODO: JSON ํ˜•์‹ ๋ฏธ์ • - ์„œ๋ฒ„ API ์ŠคํŽ™์— ๋งž๊ฒŒ ์ˆ˜์ • ํ•„์š” + // ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„ + final Map requestData = { + 'account_id': _userId ?? '', + 'new_password': _newPasswordController.text.trim(), + }; + + developer.log('Password reset attempted for user: $_userId'); + developer.log('Sending POST request to: $url'); + developer.log('Request data: $requestData'); + + // HTTP POST ์š”์ฒญ + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (mounted) { + setState(() { + _isLoading = false; + }); + } + + if (!mounted) return; + + // ์‘๋‹ต ์ฒ˜๋ฆฌ + if (response.statusCode == 200) { + final responseData = json.decode(response.body); + developer.log( + 'Password reset successful. Response data: $responseData', + ); + + // success ์ปฌ๋Ÿผ์ด true์ธ์ง€ ํ™•์ธ + if (responseData['success'] == true) { + // ์„ฑ๊ณต ํŽ˜์ด์ง€๋กœ ์ด๋™ + Navigator.pushNamed(context, '/password-reset-success'); + } else { + // success๊ฐ€ false์ธ ๊ฒฝ์šฐ ์—๋Ÿฌ ์ฒ˜๋ฆฌ + if (!mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.'))); + } + } else if (response.statusCode == 500) { + // TODO: 500 ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ตฌํ˜„ ํ•„์š” - ๋ฏธ๋ž˜์— ๊ตฌํ˜„ ์š”์ฒญ๋จ + developer.log('Password reset failed with 500 error'); + if (!mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('์„œ๋ฒ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'))); + } else { + // ๊ธฐํƒ€ ์—๋Ÿฌ ์ฒ˜๋ฆฌ + developer.log( + 'Password reset failed with status: ${response.statusCode}', + ); + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ์‹คํŒจ: ${response.statusCode}')), + ); + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + developer.log('Password reset error: $e'); + if (!mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜: $e'))); + } + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ์—๋Ÿฌ ํ‘œ์‹œ ์œ„์ ฏ + Widget _buildPasswordPolicyErrors() { + if (_passwordPolicyErrors.isEmpty) { + return const SizedBox.shrink(); + } + + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _passwordPolicyErrors.map((error) { + return Padding( + padding: const EdgeInsets.only(bottom: 4.0), + child: Text( + 'โ€ข $error', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ); + }).toList(), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 24), // Top spacing + // Back Button + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: custom.CustomBackButton(onPressed: _handleBack), + ), + + const SizedBox(height: 7), + // Page Title + const Padding( + padding: EdgeInsets.symmetric(horizontal: 30), + child: PageTitle(text: '๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ', textAlign: TextAlign.left), + ), + + const SizedBox(height: 48), + // New Password Input Field + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LabeledInputField( + label: '๋ณ€๊ฒฝํ•  ๋น„๋ฐ€๋ฒˆํ˜ธ*', + placeholder: '๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _newPasswordController, + obscureText: true, + keyboardType: TextInputType.visiblePassword, + isError: + _isNewPasswordFieldError || + _passwordPolicyErrors.isNotEmpty, + errorMessage: _newPasswordError, + onChanged: _onNewPasswordChanged, + ), + _buildPasswordPolicyErrors(), + ], + ), + ), + + const SizedBox(height: 24), // Space between password fields + // Confirm Password Input Field + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: LabeledInputField( + label: '๋ณ€๊ฒฝํ•  ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ*', + placeholder: '๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋‹ค์‹œ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _confirmPasswordController, + obscureText: true, + keyboardType: TextInputType.visiblePassword, + isError: _isConfirmPasswordFieldError, + errorMessage: _confirmPasswordError, + onChanged: _onConfirmPasswordChanged, + ), + ), + + const SizedBox( + height: 140, + ), // Space between input fields and next button + // Next Button + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: NextButton( + text: _isLoading ? '์ฒ˜๋ฆฌ ์ค‘...' : '๋‹ค์Œ', + onPressed: _isLoading ? null : _handleNext, + ), + ), + + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/account/find_password_verification_page.dart b/frontend/lib/screens/account/find_password_verification_page.dart new file mode 100644 index 0000000..3d64414 --- /dev/null +++ b/frontend/lib/screens/account/find_password_verification_page.dart @@ -0,0 +1,253 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/verification_code_input.dart'; +import '../../widgets/next_button.dart'; +import '../../config/api_config.dart'; + +class FindPasswordVerificationPage extends StatefulWidget { + const FindPasswordVerificationPage({super.key}); + + @override + State createState() => + _FindPasswordVerificationPageState(); +} + +class _FindPasswordVerificationPageState + extends State { + String _verificationCode = ''; + bool _isLoading = false; + String? _userName; + String? _email; + String? _userId; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // arguments์—์„œ ๋ฐ์ดํ„ฐ ์ถ”์ถœ + final args = + ModalRoute.of(context)?.settings.arguments as Map?; + if (args != null) { + _userName = args['userName'] as String?; + _email = args['email'] as String?; + _userId = args['userId'] as String?; + } + } + + void _handleBack() { + Navigator.pop(context); + } + + void _handleNext() async { + if (_verificationCode.length != 6) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('6์ž๋ฆฌ ์ธ์ฆ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + setState(() { + _isLoading = true; + }); + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ ํ•„์š”) + HttpOverrides.global = MyHttpOverrides(); + + // ์„œ๋ฒ„ IP ์„ค์ • (ํ•„์š”์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ) + final url = ApiConfig.getVerifyResetPasswordUri(); + + // ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„ + final Map requestData = { + 'email': _email ?? '', + 'code': _verificationCode, + }; + + developer.log('Sending password verification request: $requestData'); + + // API ํ˜ธ์ถœ + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (!mounted) return; + + if (response.statusCode == 200) { + final responseData = json.decode(response.body); + + if (responseData['success'] == true) { + // token ์ถ”์ถœ ๋ฐ ์ €์žฅ + final token = responseData['data']?['token']; + if (token != null) { + developer.log('Token received: ${token.substring(0, 20)}...'); + // ์„ฑ๊ณต ์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ • ํŽ˜์ด์ง€๋กœ ์ด๋™ (token ํฌํ•จ) + Navigator.pushNamed( + context, + '/reset-password', + arguments: {'userId': _userId, 'email': _email, 'token': token}, + ); + } else { + // token์ด ์—†๋Š” ๊ฒฝ์šฐ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์„œ๋ฒ„ ์‘๋‹ต์— ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } + } else { + // ์ธ์ฆ ์‹คํŒจ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์ธ์ฆ๋ฒˆํ˜ธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } + } else { + // ์„œ๋ฒ„ ์˜ค๋ฅ˜ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์„œ๋ฒ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } + } catch (e) { + developer.log('Error during password verification: $e'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + void _handleResendCode() { + // TODO: Implement resend verification code + developer.log('Resending verification code...'); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + const SizedBox(height: 20), + Row( + children: [ + custom.CustomBackButton(onPressed: _handleBack), + const SizedBox(width: 20), + const PageTitle(text: '๋น„๋ฐ€๋ฒˆํ˜ธ ์ฐพ๊ธฐ'), + ], + ), + const SizedBox(height: 20), + Text( + '${_userName ?? ''}๋‹˜, ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 24, + color: Color(0xFF5C5C5C), + ), + ), + const SizedBox(height: 7), + const Text( + '์ด๋ฉ”์ผ๋กœ ๋ณด๋‚ด๋“œ๋ฆฐ 6์ž ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF5C5C5C), + ), + ), + const SizedBox(height: 24), + VerificationCodeInput( + length: 6, + onChanged: (code) { + setState(() { + _verificationCode = code; + }); + }, + width: 320, + height: 50, + ), + const SizedBox(height: 20), + GestureDetector( + onTap: _handleResendCode, + child: const Text( + '์ธ์ฆ๋ฒˆํ˜ธ๋ฅผ ๋ฐ›์ง€ ๋ชปํ–ˆ๋‚˜์š”? ์žฌ์ „์†ก', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 16, + color: Color(0xFFADADAD), + ), + ), + ), + const SizedBox(height: 20), + NextButton( + text: _isLoading ? '์ฒ˜๋ฆฌ ์ค‘...' : '๋‹ค์Œ', + onPressed: (_verificationCode.length == 6 && !_isLoading) + ? _handleNext + : null, + ), + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/auth/login_page.dart b/frontend/lib/screens/auth/login_page.dart new file mode 100644 index 0000000..fb9c70c --- /dev/null +++ b/frontend/lib/screens/auth/login_page.dart @@ -0,0 +1,466 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/app_logo.dart'; +import '../../widgets/input_field.dart'; +import '../../widgets/login_button.dart'; +import '../../widgets/sns_button.dart'; +import '../../widgets/links_section.dart'; +import '../../services/auth_service.dart'; +import '../../services/user_service.dart'; +import '../../widgets/sns_divider.dart'; +import '../../config/api_config.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({super.key}); + + @override + State createState() => _LoginPageState(); +} + +class _LoginPageState extends State { + final TextEditingController _usernameController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + + // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ƒํƒœ + bool _isUsernameFieldError = false; + bool _isPasswordFieldError = false; + bool _isLoading = false; + + // ์ž๋™ ๋กœ๊ทธ์ธ ๋ฐ ์•„์ด๋”” ์ €์žฅ ์„ค์ • + bool _isAutoLoginEnabled = false; + bool _isSaveAccountIdEnabled = false; + + @override + void initState() { + super.initState(); + _loadSettings(); + } + + @override + void dispose() { + _usernameController.dispose(); + _passwordController.dispose(); + super.dispose(); + } + + /// ์ €์žฅ๋œ ์„ค์ • ๋ฐ ์•„์ด๋”” ๋กœ๋“œ + Future _loadSettings() async { + final authService = AuthService(); + + // ์ €์žฅ๋œ ์„ค์ • ๋กœ๋“œ + final autoLoginEnabled = await authService.isAutoLoginEnabled(); + final saveAccountIdEnabled = await authService.isSaveAccountIdEnabled(); + + // ์ €์žฅ๋œ ์•„์ด๋”” ๋กœ๋“œ + final savedAccountId = await authService.getSavedAccountId(); + + setState(() { + _isAutoLoginEnabled = autoLoginEnabled; + _isSaveAccountIdEnabled = saveAccountIdEnabled; + if (savedAccountId != null && savedAccountId.isNotEmpty) { + _usernameController.text = savedAccountId; + } + }); + } + + void _clearErrors() { + setState(() { + _isUsernameFieldError = false; + _isPasswordFieldError = false; + }); + } + + bool _validateInputs() { + bool isValid = true; + _clearErrors(); + + // ์•„์ด๋”” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_usernameController.text.trim().isEmpty) { + setState(() { + _isUsernameFieldError = true; + }); + isValid = false; + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_passwordController.text.trim().isEmpty) { + setState(() { + _isPasswordFieldError = true; + }); + isValid = false; + } + + return isValid; + } + + Future _handleLogin() async { + // ์ž…๋ ฅ ๊ฐ’ ๊ฒ€์ฆ + if (!_validateInputs()) { + return; + } + + setState(() { + _isLoading = true; + }); + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ ํ•„์š”) + HttpOverrides.global = MyHttpOverrides(); + + // API URL (ApiConfig์—์„œ ์ค‘์•™ ๊ด€๋ฆฌ) + final url = ApiConfig.getSignInUri(); + + // ์ด๋ฏธ์ง€ JSON ํ˜•์‹์— ๋งž์ถฐ ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„ + final Map requestData = { + 'account_id': _usernameController.text.trim(), + 'password': _passwordController.text.trim(), + }; + + developer.log( + 'Login attempted with username: ${_usernameController.text.trim()}', + ); + developer.log('Sending POST request to: $url'); + developer.log('Request data: $requestData'); + + // HTTP POST ์š”์ฒญ + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (!mounted) return; + + setState(() { + _isLoading = false; + }); + + // ์‘๋‹ต ์ฒ˜๋ฆฌ + if (response.statusCode == 200) { + try { + final responseData = json.decode(response.body); + + if (responseData['accessToken'] != null && + responseData['refreshToken'] != null) { + // ํ† ํฐ ์ €์žฅ + final accessToken = responseData['accessToken']; + final refreshToken = responseData['refreshToken']; + + // AuthService๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ† ํฐ ์ €์žฅ + final authService = AuthService(); + + // ์ž๋™ ๋กœ๊ทธ์ธ ์„ค์ • ์ €์žฅ + await authService.setAutoLogin(_isAutoLoginEnabled); + + // ์•„์ด๋”” ์ €์žฅ ์„ค์ •์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌ + if (_isSaveAccountIdEnabled) { + await authService.setSaveAccountId(true); + await authService.saveAccountId(_usernameController.text.trim()); + } else { + await authService.setSaveAccountId(false); + await authService.clearSavedAccountId(); + } + + // ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ํ•ญ์ƒ ํ† ํฐ ์ €์žฅ (ํ˜„์žฌ ์„ธ์…˜ ์œ ์ง€) + // ์ž๋™ ๋กœ๊ทธ์ธ ์„ค์ •์€ ๋‹ค์Œ ์•ฑ ์‹œ์ž‘ ์‹œ์—๋งŒ ์˜ํ–ฅ + await authService.saveAccessToken(accessToken); + await authService.saveRefreshToken(refreshToken); + + developer.log('Login successful - tokens received and saved'); + developer.log('Access Token: ${accessToken.substring(0, 20)}...'); + developer.log('Refresh Token: ${refreshToken.substring(0, 20)}...'); + developer.log('Auto login enabled: $_isAutoLoginEnabled'); + developer.log('Save account ID enabled: $_isSaveAccountIdEnabled'); + + // ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ + try { + await UserService().fetchUserFromServer(); + developer.log('User info fetched successfully after login'); + } catch (e) { + developer.log('Failed to fetch user info after login: $e'); + // ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจํ•ด๋„ ๋กœ๊ทธ์ธ์€ ์„ฑ๊ณต์œผ๋กœ ์ฒ˜๋ฆฌ + } + + // ๋ฉ”์ธ ๋„ค๋น„๊ฒŒ์ด์…˜ ํ™”๋ฉด์œผ๋กœ ์ด๋™ + if (mounted) { + Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false); + } + } else { + // ํ† ํฐ์ด ์—†๋Š” ๊ฒฝ์šฐ + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('๋กœ๊ทธ์ธ ์‘๋‹ต์— ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค'))); + } + } + } catch (e) { + developer.log('JSON parsing error: $e'); + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('์„œ๋ฒ„ ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค'))); + } + } + } else if (response.statusCode == 401 || response.statusCode == 403) { + // ์ธ์ฆ ์‹คํŒจ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('์•„์ด๋”” ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค')), + ); + } + } else { + // ๊ธฐํƒ€ ์˜ค๋ฅ˜ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('์„œ๋ฒ„ ์˜ค๋ฅ˜: ${response.statusCode}')), + ); + } + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + developer.log('Login error: $e'); + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜: $e'))); + } + } + } + + void _handleKakaoLogin() { + // Handle Kakao login logic here + developer.log('Kakao login attempted'); + } + + void _handleGoogleLogin() { + // Handle Google login logic here + developer.log('Google login attempted'); + } + + void _handleSignUp() { + Navigator.pushNamed(context, '/signup'); + } + + void _handleFindID() { + Navigator.pushNamed(context, '/find-id'); + } + + void _handleFindPW() { + Navigator.pushNamed(context, '/find-password'); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Center( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 60), // Top spacing + // App Logo + const AppLogo(), + + const SizedBox( + height: 80, + ), // Space between logo and input fields + // Input Fields + Container( + width: MediaQuery.of(context).size.width * 0.9, + constraints: const BoxConstraints( + maxWidth: 400, + minWidth: 300, + ), + child: Column( + children: [ + // Username Input + InputField( + placeholder: '์•„์ด๋””', + controller: _usernameController, + keyboardType: TextInputType.text, + isError: _isUsernameFieldError, + ), + + const SizedBox(height: 20), + + // Password Input + InputField( + placeholder: '๋น„๋ฐ€๋ฒˆํ˜ธ', + controller: _passwordController, + obscureText: true, + isError: _isPasswordFieldError, + ), + ], + ), + ), + + const SizedBox( + height: 35, + ), // Space between input fields and login button + // Login Button + LoginButton( + text: _isLoading ? '๋กœ๊ทธ์ธ ์ค‘...' : '๋กœ๊ทธ์ธ', + onPressed: _isLoading ? null : _handleLogin, + ), + + const SizedBox( + height: 20, + ), // Space between login button and checkboxes + // ์ž๋™ ๋กœ๊ทธ์ธ ๋ฐ ์•„์ด๋”” ์ €์žฅ ์ฒดํฌ๋ฐ•์Šค + Container( + width: MediaQuery.of(context).size.width * 0.9, + constraints: const BoxConstraints( + maxWidth: 400, + minWidth: 300, + ), + child: Column( + children: [ + // ์ž๋™ ๋กœ๊ทธ์ธ ์ฒดํฌ๋ฐ•์Šค + Row( + children: [ + Checkbox( + value: _isAutoLoginEnabled, + onChanged: (value) { + setState(() { + _isAutoLoginEnabled = value ?? false; + }); + }, + activeColor: const Color(0xFFAC5BF8), + ), + GestureDetector( + onTap: () { + setState(() { + _isAutoLoginEnabled = !_isAutoLoginEnabled; + }); + }, + child: const Text( + '์ž๋™ ๋กœ๊ทธ์ธ', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF333333), + ), + ), + ), + ], + ), + // ์•„์ด๋”” ์ €์žฅ ์ฒดํฌ๋ฐ•์Šค + Row( + children: [ + Checkbox( + value: _isSaveAccountIdEnabled, + onChanged: (value) { + setState(() { + _isSaveAccountIdEnabled = value ?? false; + }); + }, + activeColor: const Color(0xFFAC5BF8), + ), + GestureDetector( + onTap: () { + setState(() { + _isSaveAccountIdEnabled = + !_isSaveAccountIdEnabled; + }); + }, + child: const Text( + '์•„์ด๋”” ์ €์žฅ', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF333333), + ), + ), + ), + ], + ), + ], + ), + ), + + const SizedBox( + height: 20, + ), // Space between checkboxes and links + // Links Section + LinksSection( + onSignUp: _handleSignUp, + onFindID: _handleFindID, + onFindPW: _handleFindPW, + ), + + const SizedBox( + height: 40, + ), // Space between links and SNS divider + // SNS Divider + const SNSDivider(), + + const SizedBox( + height: 30, + ), // Space between divider and SNS buttons + // SNS Buttons + Container( + constraints: const BoxConstraints( + maxWidth: 200, + minWidth: 150, + ), + height: 50, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Kakao Button + SNSButton( + provider: SNSProvider.kakao, + onPressed: _handleKakaoLogin, + ), + + const SizedBox(width: 20), // ๋ฒ„ํŠผ ๊ฐ„๊ฒฉ + // Google Button + SNSButton( + provider: SNSProvider.google, + onPressed: _handleGoogleLogin, + ), + ], + ), + ), + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/auth/password_reset_form_page.dart b/frontend/lib/screens/auth/password_reset_form_page.dart new file mode 100644 index 0000000..e7a159a --- /dev/null +++ b/frontend/lib/screens/auth/password_reset_form_page.dart @@ -0,0 +1,399 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/next_button.dart'; +import '../../widgets/input_field.dart'; +import '../../config/api_config.dart'; + +class PasswordResetFormPage extends StatefulWidget { + const PasswordResetFormPage({super.key}); + + @override + State createState() => _PasswordResetFormPageState(); +} + +class _PasswordResetFormPageState extends State { + final TextEditingController _newPasswordController = TextEditingController(); + final TextEditingController _confirmPasswordController = + TextEditingController(); + bool _isLoading = false; + String? _token; + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ + List _passwordPolicyErrors = []; + String? _confirmPasswordError; + bool _isConfirmPasswordFieldError = false; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // arguments์—์„œ token ์ถ”์ถœ + final args = + ModalRoute.of(context)?.settings.arguments as Map?; + if (args != null) { + _token = args['token'] as String?; + } + } + + @override + void dispose() { + _newPasswordController.dispose(); + _confirmPasswordController.dispose(); + super.dispose(); + } + + void _handleBack() { + // ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ + Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false); + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ + List _validatePasswordPolicy(String password) { + List errors = []; + + if (password.length < 8) { + errors.add('8์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[A-Z]').hasMatch(password)) { + errors.add('๋Œ€๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[a-z]').hasMatch(password)) { + errors.add('์†Œ๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[0-9]').hasMatch(password)) { + errors.add('์ˆซ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[!@#$%^&*(),.?":{}|<>]').hasMatch(password)) { + errors.add('ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + + return errors; + } + + // ์‹ค์‹œ๊ฐ„ ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + void _onPasswordChanged(String value) { + setState(() { + _passwordPolicyErrors = _validatePasswordPolicy(value); + }); + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ํ•„๋“œ๋„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฒ€์‚ฌ + if (_confirmPasswordController.text.isNotEmpty) { + _onConfirmPasswordChanged(_confirmPasswordController.text); + } + } + + // ์‹ค์‹œ๊ฐ„ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ๊ฒ€์‚ฌ + void _onConfirmPasswordChanged(String value) { + setState(() { + if (value.isNotEmpty && _newPasswordController.text != value) { + _confirmPasswordError = '์ž…๋ ฅ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค'; + _isConfirmPasswordFieldError = true; + } else { + _confirmPasswordError = null; + _isConfirmPasswordFieldError = false; + } + }); + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ์—๋Ÿฌ ํ‘œ์‹œ ์œ„์ ฏ + Widget _buildPasswordPolicyErrors() { + if (_passwordPolicyErrors.isEmpty) { + return const SizedBox.shrink(); + } + + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _passwordPolicyErrors.map((error) { + return Padding( + padding: const EdgeInsets.only(bottom: 4.0), + child: Text( + 'โ€ข $error', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ); + }).toList(), + ), + ); + } + + Future _handleResetPassword() async { + // ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ + if (_newPasswordController.text.trim().isEmpty) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ + List policyErrors = _validatePasswordPolicy( + _newPasswordController.text, + ); + if (policyErrors.isNotEmpty) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ…์„ ๋งŒ์กฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + if (_confirmPasswordController.text.trim().isEmpty) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + if (_newPasswordController.text != _confirmPasswordController.text) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + if (_token == null) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + setState(() { + _isLoading = true; + }); + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ + HttpOverrides.global = MyHttpOverrides(); + + final url = ApiConfig.getResetPasswordUri(); + + // ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„ + final Map requestData = { + 'token': _token!, + 'new_password': _newPasswordController.text.trim(), + }; + + developer.log('Sending password reset request: $requestData'); + + // API ํ˜ธ์ถœ + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (!mounted) return; + + if (response.statusCode == 200) { + final responseData = json.decode(response.body); + + if (responseData['success'] == true) { + // ์„ฑ๊ณต ์‹œ ์„ฑ๊ณต ํŽ˜์ด์ง€๋กœ ์ด๋™ + if (mounted) { + Navigator.pushNamedAndRemoveUntil( + context, + '/password-reset-success', + (route) => false, + ); + } + } else { + // ์‹คํŒจ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } + } else { + // ์„œ๋ฒ„ ์˜ค๋ฅ˜ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์„œ๋ฒ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } + } catch (e) { + developer.log('Error during password reset: $e'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 24), // Top spacing + // Back Button + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: custom.CustomBackButton(onPressed: _handleBack), + ), + + const SizedBox(height: 7), + // Page Title + const Padding( + padding: EdgeInsets.symmetric(horizontal: 30), + child: PageTitle(text: '๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ', textAlign: TextAlign.left), + ), + + const SizedBox(height: 48), + // Instruction Message + const Padding( + padding: EdgeInsets.symmetric(horizontal: 30), + child: Text( + '์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 24, + height: 1.193359375, + color: Color(0xFF5C5C5C), + ), + ), + ), + + const SizedBox(height: 40), + // New Password Input + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InputField( + placeholder: '์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ', + controller: _newPasswordController, + obscureText: true, + onChanged: _onPasswordChanged, + isError: _passwordPolicyErrors.isNotEmpty, + ), + _buildPasswordPolicyErrors(), + ], + ), + ), + + const SizedBox(height: 20), // Space between input fields + // Confirm Password Input + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InputField( + placeholder: '๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ', + controller: _confirmPasswordController, + obscureText: true, + onChanged: _onConfirmPasswordChanged, + isError: _isConfirmPasswordFieldError, + ), + if (_confirmPasswordError != null) ...[ + const SizedBox(height: 8), + Text( + _confirmPasswordError!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ], + ], + ), + ), + + const SizedBox(height: 40), + // Reset Password Button + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: NextButton( + text: _isLoading ? '์ฒ˜๋ฆฌ ์ค‘...' : '๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ', + onPressed: _isLoading ? null : _handleResetPassword, + ), + ), + + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/auth/password_reset_success_page.dart b/frontend/lib/screens/auth/password_reset_success_page.dart new file mode 100644 index 0000000..82849ee --- /dev/null +++ b/frontend/lib/screens/auth/password_reset_success_page.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import '../../widgets/login_button.dart'; + +class PasswordResetSuccessPage extends StatelessWidget { + const PasswordResetSuccessPage({super.key}); + + void _handleLogin(BuildContext context) { + // ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ + Navigator.of(context).pushNamedAndRemoveUntil('/login', (route) => false); + } + + @override + Widget build(BuildContext context) { + final screenHeight = + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom; + + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: screenHeight), + child: IntrinsicHeight( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 120), // Top spacing + // Success Icon + Container( + width: 100, + height: 100, + decoration: BoxDecoration( + color: const Color(0xFF6B4EFF), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.check, + color: Colors.white, + size: 60, + ), + ), + + const SizedBox(height: 40), + // Success Message + const Text( + '๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ์™„๋ฃŒ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 28, + color: Color(0xFF2C2C2C), + ), + ), + + const SizedBox(height: 20), + // Sub Message + const Padding( + padding: EdgeInsets.symmetric(horizontal: 40), + child: Text( + '์ƒˆ๋กœ์šด ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ\n๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 16, + height: 1.5, + color: Color(0xFF7C7C7C), + ), + ), + ), + + const Expanded(child: SizedBox()), // Push button to bottom + // Login Button + Padding( + padding: const EdgeInsets.only(bottom: 40), + child: LoginButton( + text: '๋กœ๊ทธ์ธํ•˜๊ธฐ', + onPressed: () => _handleLogin(context), + ), + ), + ], + ), + ), + ), + ), + ), + ); + } +} diff --git a/frontend/lib/screens/auth/reset_password_page.dart b/frontend/lib/screens/auth/reset_password_page.dart new file mode 100644 index 0000000..56fa8b5 --- /dev/null +++ b/frontend/lib/screens/auth/reset_password_page.dart @@ -0,0 +1,388 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/input_field.dart'; +import '../../widgets/next_button.dart'; +import '../../config/api_config.dart'; + +class ResetPasswordPage extends StatefulWidget { + const ResetPasswordPage({super.key}); + + @override + State createState() => _ResetPasswordPageState(); +} + +class _ResetPasswordPageState extends State { + final TextEditingController _newPasswordController = TextEditingController(); + final TextEditingController _confirmPasswordController = + TextEditingController(); + bool _isLoading = false; + String? _token; + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ + List _passwordPolicyErrors = []; + String? _confirmPasswordError; + bool _isConfirmPasswordFieldError = false; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // arguments์—์„œ ๋ฐ์ดํ„ฐ ์ถ”์ถœ + final args = + ModalRoute.of(context)?.settings.arguments as Map?; + if (args != null) { + _token = args['token'] as String?; + developer.log( + 'Received token: ${_token != null ? "${_token!.substring(0, 20)}..." : "null"}', + ); + } + } + + @override + void dispose() { + _newPasswordController.dispose(); + _confirmPasswordController.dispose(); + super.dispose(); + } + + void _handleBack() { + Navigator.pop(context); + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ + List _validatePasswordPolicy(String password) { + List errors = []; + + if (password.length < 8) { + errors.add('8์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[A-Z]').hasMatch(password)) { + errors.add('๋Œ€๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[a-z]').hasMatch(password)) { + errors.add('์†Œ๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[0-9]').hasMatch(password)) { + errors.add('์ˆซ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[!@#$%^&*(),.?":{}|<>]').hasMatch(password)) { + errors.add('ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + + return errors; + } + + // ์‹ค์‹œ๊ฐ„ ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + void _onPasswordChanged(String value) { + setState(() { + _passwordPolicyErrors = _validatePasswordPolicy(value); + }); + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ํ•„๋“œ๋„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฒ€์‚ฌ + if (_confirmPasswordController.text.isNotEmpty) { + _onConfirmPasswordChanged(_confirmPasswordController.text); + } + } + + // ์‹ค์‹œ๊ฐ„ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ๊ฒ€์‚ฌ + void _onConfirmPasswordChanged(String value) { + setState(() { + if (value.isNotEmpty && _newPasswordController.text != value) { + _confirmPasswordError = '์ž…๋ ฅ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค'; + _isConfirmPasswordFieldError = true; + } else { + _confirmPasswordError = null; + _isConfirmPasswordFieldError = false; + } + }); + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ์—๋Ÿฌ ํ‘œ์‹œ ์œ„์ ฏ + Widget _buildPasswordPolicyErrors() { + if (_passwordPolicyErrors.isEmpty) { + return const SizedBox.shrink(); + } + + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _passwordPolicyErrors.map((error) { + return Padding( + padding: const EdgeInsets.only(bottom: 4.0), + child: Text( + 'โ€ข $error', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ); + }).toList(), + ), + ); + } + + void _handleResetPassword() async { + // ๊ธฐ๋ณธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_newPasswordController.text.trim().isEmpty) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ + List policyErrors = _validatePasswordPolicy( + _newPasswordController.text, + ); + if (policyErrors.isNotEmpty) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ…์„ ๋งŒ์กฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + if (_confirmPasswordController.text.trim().isEmpty) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + if (_newPasswordController.text != _confirmPasswordController.text) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + if (_token == null) { + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + return; + } + + setState(() { + _isLoading = true; + }); + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ ํ•„์š”) + HttpOverrides.global = MyHttpOverrides(); + + // ์„œ๋ฒ„ IP ์„ค์ • (ํ•„์š”์— ๋”ฐ๋ผ ๋ณ€๊ฒฝ) + final url = ApiConfig.getResetPasswordUri(); + + // ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„ + final Map requestData = { + 'token': _token!, + 'new_password': _newPasswordController.text, + }; + + developer.log('Sending password change request: $requestData'); + + // API ํ˜ธ์ถœ + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (!mounted) return; + + if (response.statusCode == 200) { + final responseData = json.decode(response.body); + + if (responseData['success'] == true) { + // ์„ฑ๊ณต ์‹œ ์„ฑ๊ณต ํŽ˜์ด์ง€๋กœ ์ด๋™ + if (mounted) { + Navigator.of(context).pushNamedAndRemoveUntil( + '/password-reset-success', + (route) => false, + ); + } + } else { + // ์‹คํŒจ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } + } else { + // ์„œ๋ฒ„ ์˜ค๋ฅ˜ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('์„œ๋ฒ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } + } catch (e) { + developer.log('Error during password change: $e'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'), + backgroundColor: Color(0xFFFF4258), + ), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + const SizedBox(height: 20), + Row( + children: [ + custom.CustomBackButton(onPressed: _handleBack), + const SizedBox(width: 20), + const PageTitle(text: '๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ •'), + ], + ), + const SizedBox(height: 40), + const Text( + '์ƒˆ๋กœ์šด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์„ค์ •ํ•ด์ฃผ์„ธ์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: Color(0xFF5C5C5C), + ), + ), + const SizedBox(height: 8), + const Text( + '์•ˆ์ „ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ๊ณ„์ •์„ ๋ณดํ˜ธํ•˜์„ธ์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFA0A0A0), + ), + ), + const SizedBox(height: 40), + // New Password Input + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InputField( + placeholder: '์ƒˆ ๋น„๋ฐ€๋ฒˆํ˜ธ', + controller: _newPasswordController, + obscureText: true, + onChanged: _onPasswordChanged, + isError: _passwordPolicyErrors.isNotEmpty, + ), + _buildPasswordPolicyErrors(), + ], + ), + const SizedBox(height: 20), + // Confirm Password Input + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + InputField( + placeholder: '๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ', + controller: _confirmPasswordController, + obscureText: true, + onChanged: _onConfirmPasswordChanged, + isError: _isConfirmPasswordFieldError, + ), + if (_confirmPasswordError != null) ...[ + const SizedBox(height: 8), + Text( + _confirmPasswordError!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ], + ], + ), + const SizedBox(height: 40), + NextButton( + text: _isLoading ? '์ฒ˜๋ฆฌ ์ค‘...' : 'ํ™•์ธ', + onPressed: _isLoading ? null : _handleResetPassword, + ), + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/auth/signup_page.dart b/frontend/lib/screens/auth/signup_page.dart new file mode 100644 index 0000000..c6f02b2 --- /dev/null +++ b/frontend/lib/screens/auth/signup_page.dart @@ -0,0 +1,1085 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/labeled_input_field.dart'; +import '../../widgets/next_button.dart'; +import '../../config/api_config.dart'; + +class SignUpPage extends StatefulWidget { + const SignUpPage({super.key}); + + @override + State createState() => _SignUpPageState(); +} + +class _SignUpPageState extends State { + final TextEditingController _nameController = TextEditingController(); + final TextEditingController _idController = TextEditingController(); + final TextEditingController _emailController = TextEditingController(); + final TextEditingController _emailCodeController = TextEditingController(); + final TextEditingController _phoneController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + final TextEditingController _confirmPasswordController = + TextEditingController(); + + // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ƒํƒœ + String? _idError; + String? _emailError; + String? _emailCodeError; + String? _phoneError; + String? _passwordError; + String? _confirmPasswordError; + bool _isIdFieldError = false; + bool _isEmailFieldError = false; + bool _isEmailCodeFieldError = false; + bool _isPhoneFieldError = false; + bool _isPasswordFieldError = false; + bool _isConfirmPasswordFieldError = false; + + // API ํ˜ธ์ถœ ์ƒํƒœ + bool _isCheckingIdDuplicate = false; + bool _isSendingEmailCode = false; + bool _isIdDuplicateChecked = false; + bool _isEmailVerified = false; + bool _isEmailCodeEnabled = false; + bool _isVerifyingEmailCode = false; + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ + List _passwordPolicyErrors = []; + String? _emailCodeSuccessMessage; + + @override + void dispose() { + _nameController.dispose(); + _idController.dispose(); + _emailController.dispose(); + _emailCodeController.dispose(); + _phoneController.dispose(); + _passwordController.dispose(); + _confirmPasswordController.dispose(); + super.dispose(); + } + + void _handleBack() { + Navigator.pop(context); + } + + // ์ด๋ฉ”์ผ ํ˜•์‹ ๊ฒ€์ฆ + bool _isValidEmail(String email) { + final emailRegex = RegExp(r'^.+@.+$'); + return emailRegex.hasMatch(email); + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ๊ฒ€์‚ฌ + List _validatePasswordPolicy(String password) { + List errors = []; + + if (password.length < 8) { + errors.add('8์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[A-Z]').hasMatch(password)) { + errors.add('๋Œ€๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[a-z]').hasMatch(password)) { + errors.add('์†Œ๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[0-9]').hasMatch(password)) { + errors.add('์ˆซ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + if (!RegExp(r'[!@#$%^&*(),.?":{}|<>]').hasMatch(password)) { + errors.add('ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค'); + } + + return errors; + } + + // ์‹ค์‹œ๊ฐ„ ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + void _onPasswordChanged(String value) { + setState(() { + _passwordPolicyErrors = _validatePasswordPolicy(value); + _passwordError = null; + _isPasswordFieldError = false; + }); + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ํ•„๋“œ๋„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฒ€์‚ฌ + if (_confirmPasswordController.text.isNotEmpty) { + _onConfirmPasswordChanged(_confirmPasswordController.text); + } + } + + // ์‹ค์‹œ๊ฐ„ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ๊ฒ€์‚ฌ + void _onConfirmPasswordChanged(String value) { + setState(() { + if (value.isNotEmpty && _passwordController.text != value) { + _confirmPasswordError = '์ž…๋ ฅ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค'; + _isConfirmPasswordFieldError = true; + } else { + _confirmPasswordError = null; + _isConfirmPasswordFieldError = false; + } + }); + } + + // ์‹ค์‹œ๊ฐ„ ํœด๋Œ€ํฐ ๋ฒˆํ˜ธ ๊ฒ€์‚ฌ + void _onPhoneChanged(String value) { + setState(() { + if (value.isNotEmpty && !RegExp(r'^[0-9]+$').hasMatch(value)) { + _phoneError = '์ˆซ์ž๋งŒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isPhoneFieldError = true; + } else { + _phoneError = null; + _isPhoneFieldError = false; + } + }); + } + + void _clearErrors() { + setState(() { + _idError = null; + _emailError = null; + _emailCodeError = null; + _phoneError = null; + _passwordError = null; + _confirmPasswordError = null; + _isIdFieldError = false; + _isEmailFieldError = false; + _isEmailCodeFieldError = false; + _isPhoneFieldError = false; + _isPasswordFieldError = false; + _isConfirmPasswordFieldError = false; + _passwordPolicyErrors = []; + }); + } + + bool _validateInputs() { + bool isValid = true; + _clearErrors(); + + // ์ด๋ฆ„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_nameController.text.trim().isEmpty) { + // ์ด๋ฆ„์€ ๋ณ„๋„ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์—†์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฒ˜๋ฆฌ + isValid = false; + } + + // ์•„์ด๋”” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_idController.text.trim().isEmpty) { + setState(() { + _idError = '์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isIdFieldError = true; + }); + isValid = false; + } else if (!_isIdDuplicateChecked) { + setState(() { + _idError = '์•„์ด๋”” ์ค‘๋ณต ํ™•์ธ์„ ํ•ด์ฃผ์„ธ์š”'; + _isIdFieldError = true; + }); + isValid = false; + } + + // ์ด๋ฉ”์ผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_emailController.text.trim().isEmpty) { + setState(() { + _emailError = '์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isEmailFieldError = true; + }); + isValid = false; + } else if (!_isValidEmail(_emailController.text.trim())) { + setState(() { + _emailError = '์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isEmailFieldError = true; + }); + isValid = false; + } + + // ์ด๋ฉ”์ผ ์ธ์ฆ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (!_isEmailVerified) { + setState(() { + _emailCodeError = '์ด๋ฉ”์ผ ์ธ์ฆ์„ ์™„๋ฃŒํ•ด์ฃผ์„ธ์š”'; + _isEmailCodeFieldError = true; + }); + isValid = false; + } + + // ํœด๋Œ€ํฐ ๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_phoneController.text.trim().isEmpty) { + setState(() { + _phoneError = 'ํœด๋Œ€ํฐ ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isPhoneFieldError = true; + }); + isValid = false; + } else if (!RegExp(r'^[0-9]+$').hasMatch(_phoneController.text.trim())) { + setState(() { + _phoneError = '์ˆซ์ž๋งŒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isPhoneFieldError = true; + }); + isValid = false; + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_passwordController.text.trim().isEmpty) { + setState(() { + _passwordError = '๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isPasswordFieldError = true; + }); + isValid = false; + } else { + List policyErrors = _validatePasswordPolicy( + _passwordController.text, + ); + if (policyErrors.isNotEmpty) { + setState(() { + _passwordPolicyErrors = policyErrors; + }); + isValid = false; + } + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (_confirmPasswordController.text.trim().isEmpty) { + setState(() { + _confirmPasswordError = '๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isConfirmPasswordFieldError = true; + }); + isValid = false; + } else if (_passwordController.text != _confirmPasswordController.text) { + setState(() { + _confirmPasswordError = '์ž…๋ ฅ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค'; + _isConfirmPasswordFieldError = true; + }); + isValid = false; + } + + return isValid; + } + + // ์•„์ด๋”” ์ค‘๋ณต ๊ฒ€์‚ฌ + Future _checkIdDuplicate() async { + if (_idController.text.trim().isEmpty) { + setState(() { + _idError = '์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isIdFieldError = true; + }); + return; + } + + setState(() { + _isCheckingIdDuplicate = true; + _idError = null; + _isIdFieldError = false; + }); + + try { + HttpOverrides.global = _MyHttpOverrides(); + + final String accountId = _idController.text.trim(); + final url = ApiConfig.getCheckAccountIdUri(accountId); + + developer.log('GET $url'); + developer.log('Checking account ID: $accountId'); + + // HTTP GET ์š”์ฒญ + final response = await http.get( + url, + headers: {'Content-Type': 'application/json'}, + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (!mounted) return; + + setState(() { + _isCheckingIdDuplicate = false; + }); + + // ์‘๋‹ต ์ฒ˜๋ฆฌ + if (response.statusCode == 200) { + final responseData = json.decode(response.body); + + if (responseData['success'] == true) { + // ์„ฑ๊ณต: ์•„์ด๋”” ์‚ฌ์šฉ ๊ฐ€๋Šฅ + setState(() { + _isIdDuplicateChecked = true; + _idError = null; + _isIdFieldError = false; + }); + developer.log('Account ID is available: $accountId'); + } else { + // ์‹คํŒจ: ์ค‘๋ณต๋œ ์•„์ด๋”” + setState(() { + _isIdDuplicateChecked = false; + _idError = '์ค‘๋ณต๋œ ์•„์ด๋””์ž…๋‹ˆ๋‹ค.'; + _isIdFieldError = true; + }); + developer.log('Account ID is duplicated: $accountId'); + } + } else { + // ์„œ๋ฒ„ ์˜ค๋ฅ˜ + setState(() { + _isIdDuplicateChecked = false; + _idError = '์ค‘๋ณต ํ™•์ธ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค'; + _isIdFieldError = true; + }); + developer.log('Server error: ${response.statusCode}'); + } + } catch (e) { + if (mounted) { + setState(() { + _isCheckingIdDuplicate = false; + _idError = '์ค‘๋ณต ํ™•์ธ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค'; + _isIdFieldError = true; + _isIdDuplicateChecked = false; + }); + } + developer.log('Check ID duplicate error: $e'); + } + } + + // ์ด๋ฉ”์ผ ์ธ์ฆ๋ฒˆํ˜ธ ๋ฐœ์†ก + Future _sendEmailCode() async { + if (_emailController.text.trim().isEmpty) { + setState(() { + _emailError = '์ด๋ฉ”์ผ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isEmailFieldError = true; + }); + return; + } + + if (!_isValidEmail(_emailController.text.trim())) { + setState(() { + _emailError = '์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isEmailFieldError = true; + }); + return; + } + + setState(() { + _isSendingEmailCode = true; + _emailError = null; + _isEmailFieldError = false; + _isEmailCodeEnabled = false; + _emailCodeSuccessMessage = null; + }); + + try { + HttpOverrides.global = _MyHttpOverrides(); + + final url = ApiConfig.getSendCodeSignUpUri(); + final Map requestData = { + 'email': _emailController.text.trim(), + }; + + developer.log('POST $url'); + developer.log('Request: $requestData'); + + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (mounted) { + setState(() { + _isSendingEmailCode = false; + }); + } + if (!mounted) return; + + if (response.statusCode == 200) { + final data = json.decode(response.body); + if (data['success'] == true) { + setState(() { + _isEmailCodeEnabled = true; + _isEmailVerified = false; + _emailCodeController.clear(); + _emailError = null; + _isEmailFieldError = false; + }); + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('์ธ์ฆ๋ฒˆํ˜ธ๊ฐ€ ๋ฐœ์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'))); + } else { + setState(() { + _isEmailCodeEnabled = false; + _emailError = '์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.'; + _isEmailFieldError = true; + }); + } + } else { + setState(() { + _isEmailCodeEnabled = false; + _emailError = '์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.'; + _isEmailFieldError = true; + }); + } + } catch (e) { + if (mounted) { + setState(() { + _isSendingEmailCode = false; + _isEmailCodeEnabled = false; + _emailError = '์˜ฌ๋ฐ”๋ฅธ ์ด๋ฉ”์ผ์ธ์ง€ ํ™•์ธํ•ด์ฃผ์„ธ์š”.'; + _isEmailFieldError = true; + }); + } + developer.log('Send email code error: $e'); + } + } + + // ์ด๋ฉ”์ผ ์ธ์ฆ๋ฒˆํ˜ธ ํ™•์ธ + Future _verifyEmailCode() async { + if (_emailCodeController.text.trim().isEmpty) { + setState(() { + _emailCodeError = '์ธ์ฆ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”'; + _isEmailCodeFieldError = true; + }); + return; + } + + setState(() { + _emailCodeError = null; + _isEmailCodeFieldError = false; + }); + + try { + HttpOverrides.global = _MyHttpOverrides(); + + final url = ApiConfig.getVerifySignUpUri(); + + setState(() { + _isVerifyingEmailCode = true; + _emailCodeSuccessMessage = null; + }); + + final Map requestData = { + 'email': _emailController.text.trim(), + 'code': _emailCodeController.text.trim(), + }; + + developer.log('POST $url'); + developer.log('Request data: $requestData'); + developer.log('Email: ${_emailController.text.trim()}'); + developer.log('Code: ${_emailCodeController.text.trim()}'); + developer.log('Request body: ${json.encode(requestData)}'); + + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (response.statusCode != 200) { + developer.log('ERROR: Non-200 status code received'); + developer.log('Response headers: ${response.headers}'); + } + + if (mounted) { + setState(() { + _isVerifyingEmailCode = false; + }); + } + if (!mounted) return; + + if (response.statusCode == 200) { + final data = json.decode(response.body); + if (data['success'] == true) { + setState(() { + _isEmailVerified = true; + _isEmailCodeEnabled = false; // ์ž…๋ ฅ ํผ ๋น„ํ™œ์„ฑํ™” (๊ฐ’ ์œ ์ง€) + _emailCodeError = null; + _isEmailCodeFieldError = false; + _emailCodeSuccessMessage = '์ธ์ฆ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'; + }); + } else { + final errorMessage = data['error'] ?? '์ธ์ฆ๋ฒˆํ˜ธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค'; + setState(() { + _isEmailVerified = false; + _emailCodeError = errorMessage; + _isEmailCodeFieldError = true; + _emailCodeSuccessMessage = null; + }); + developer.log('Verification failed: $errorMessage'); + } + } else if (response.statusCode == 500) { + // ์„œ๋ฒ„ ์—๋Ÿฌ + setState(() { + _isEmailVerified = false; + _emailCodeError = '์„œ๋ฒ„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'; + _isEmailCodeFieldError = true; + _emailCodeSuccessMessage = null; + }); + developer.log('Server error 500: ${response.body}'); + } else { + setState(() { + _isEmailVerified = false; + _emailCodeError = '์ธ์ฆ๋ฒˆํ˜ธ ํ™•์ธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. (์—๋Ÿฌ ์ฝ”๋“œ: ${response.statusCode})'; + _isEmailCodeFieldError = true; + _emailCodeSuccessMessage = null; + }); + } + } catch (e) { + if (mounted) { + setState(() { + _isVerifyingEmailCode = false; + _isEmailVerified = false; + _emailCodeError = '์ธ์ฆ๋ฒˆํ˜ธ ํ™•์ธ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค'; + _isEmailCodeFieldError = true; + _emailCodeSuccessMessage = null; + }); + } + developer.log('Verify email code error: $e'); + } + } + + void _handleSignUp() { + if (!_validateInputs()) { + return; + } + + // ๋ชจ๋“  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ†ต๊ณผ ์‹œ ๊ถŒํ•œ ๋™์˜ ํŽ˜์ด์ง€๋กœ ์ด๋™ + Navigator.pushNamed( + context, + '/signup-terms', + arguments: { + 'name': _nameController.text.trim(), + 'id': _idController.text.trim(), + 'email': _emailController.text.trim(), + 'phone': _phoneController.text.trim(), + 'password': _passwordController.text.trim(), + }, + ); + } + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ •์ฑ… ์—๋Ÿฌ ํ‘œ์‹œ ์œ„์ ฏ + Widget _buildPasswordPolicyErrors() { + if (_passwordPolicyErrors.isEmpty) { + return const SizedBox.shrink(); + } + + return Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _passwordPolicyErrors.map((error) { + return Padding( + padding: const EdgeInsets.only(bottom: 4.0), + child: Text( + 'โ€ข $error', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ); + }).toList(), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30.0), + child: Column( + children: [ + const SizedBox(height: 20), + Row( + children: [ + custom.CustomBackButton(onPressed: _handleBack), + const SizedBox(width: 20), + const PageTitle(text: 'ํšŒ์›๊ฐ€์ž…'), + ], + ), + const SizedBox(height: 20), + LabeledInputField( + label: '์ด๋ฆ„*', + placeholder: '์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _nameController, + keyboardType: TextInputType.text, + ), + const SizedBox(height: 24), + // ์•„์ด๋”” ์ž…๋ ฅ ํ•„๋“œ์™€ ์ค‘๋ณต ํ™•์ธ ๋ฒ„ํŠผ + Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + flex: 7, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Label + const Text( + '์•„์ด๋””*', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w600, + height: 1.193, + color: Color(0xFF5C5C5C), + ), + ), + + const SizedBox(height: 8), + + // Input Field + Container( + height: 50, + decoration: BoxDecoration( + color: const Color(0xFFF3F3F3), + borderRadius: BorderRadius.circular(5), + border: _isIdFieldError + ? Border.all( + color: const Color(0xFFFF4258), + width: 1, + ) + : null, + ), + child: TextField( + controller: _idController, + keyboardType: TextInputType.text, + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: _isIdFieldError + ? const Color(0xFFFF4258) + : const Color(0xFFA0A0A0), + ), + decoration: InputDecoration( + hintText: '์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + hintStyle: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: Color(0xFFA0A0A0), + ), + border: InputBorder.none, + contentPadding: + const EdgeInsets.symmetric( + horizontal: 18, + vertical: 16, + ), + ), + onChanged: (value) { + // ์•„์ด๋””๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ค‘๋ณต ํ™•์ธ ์ƒํƒœ ์ดˆ๊ธฐํ™” + if (_isIdDuplicateChecked) { + setState(() { + _isIdDuplicateChecked = false; + }); + } + }, + ), + ), + ], + ), + ), + + const SizedBox(width: 12), + + Expanded( + flex: 3, + child: SizedBox( + height: 50, + child: ElevatedButton( + onPressed: _isCheckingIdDuplicate + ? null + : _checkIdDuplicate, + style: ElevatedButton.styleFrom( + backgroundColor: _isIdDuplicateChecked + ? const Color(0xFF10B981) + : const Color(0xFF6366F1), + foregroundColor: Colors.white, + elevation: 0, + padding: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: Text( + _isCheckingIdDuplicate + ? 'ํ™•์ธ ์ค‘...' + : _isIdDuplicateChecked + ? '์‚ฌ์šฉ ๊ฐ€๋Šฅ' + : '์ค‘๋ณต ํ™•์ธ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ), + ], + ), + + // Error Message (Row ๋ฐ–์œผ๋กœ ์ด๋™) + if (_isIdFieldError && _idError != null) ...[ + const SizedBox(height: 8), + Align( + alignment: Alignment.centerLeft, + child: Text( + _idError!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ), + ], + ], + ), + const SizedBox(height: 24), + // ์ด๋ฉ”์ผ ์ž…๋ ฅ ํ•„๋“œ์™€ ์ธ์ฆ๋ฒˆํ˜ธ ๋ฐœ์†ก ๋ฒ„ํŠผ + Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + flex: 7, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Label + const Text( + '์ด๋ฉ”์ผ*', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w600, + height: 1.193, + color: Color(0xFF5C5C5C), + ), + ), + + const SizedBox(height: 8), + + // Input Field + Container( + height: 50, + decoration: BoxDecoration( + color: const Color(0xFFF3F3F3), + borderRadius: BorderRadius.circular(5), + border: _isEmailFieldError + ? Border.all( + color: const Color(0xFFFF4258), + width: 1, + ) + : null, + ), + child: TextField( + controller: _emailController, + keyboardType: TextInputType.emailAddress, + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: _isEmailFieldError + ? const Color(0xFFFF4258) + : const Color(0xFFA0A0A0), + ), + decoration: InputDecoration( + hintText: '์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + hintStyle: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: Color(0xFFA0A0A0), + ), + border: InputBorder.none, + contentPadding: + const EdgeInsets.symmetric( + horizontal: 18, + vertical: 16, + ), + ), + onChanged: (value) { + // ์ด๋ฉ”์ผ์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ธ์ฆ ์ƒํƒœ ์ดˆ๊ธฐํ™” + if (_isEmailVerified) { + setState(() { + _isEmailVerified = false; + _emailCodeController.clear(); + }); + } + }, + ), + ), + ], + ), + ), + + const SizedBox(width: 12), + + Expanded( + flex: 3, + child: SizedBox( + height: 50, + child: ElevatedButton( + onPressed: _isSendingEmailCode + ? null + : _sendEmailCode, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF6366F1), + foregroundColor: Colors.white, + elevation: 0, + padding: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: Text( + _isSendingEmailCode ? '๋ฐœ์†ก ์ค‘...' : '์ธ์ฆ๋ฒˆํ˜ธ ๋ฐœ์†ก', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ), + ], + ), + + // Error Message (Row ๋ฐ–์œผ๋กœ ์ด๋™) + if (_isEmailFieldError && _emailError != null) ...[ + const SizedBox(height: 8), + Align( + alignment: Alignment.centerLeft, + child: Text( + _emailError!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ), + ], + ], + ), + const SizedBox(height: 16), + // ์ธ์ฆ๋ฒˆํ˜ธ ์ž…๋ ฅ ํ•„๋“œ + ํ™•์ธ ๋ฒ„ํŠผ + Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + flex: 7, + child: Container( + height: 50, + decoration: BoxDecoration( + border: _isEmailCodeFieldError + ? Border.all( + color: const Color(0xFFFF4258), + width: 1, + ) + : Border.all( + color: const Color(0xFFE5E7EB), + width: 1, + ), + borderRadius: BorderRadius.circular(8), + ), + child: TextField( + controller: _emailCodeController, + enabled: + _isEmailCodeEnabled || _isEmailVerified, + keyboardType: TextInputType.number, + decoration: const InputDecoration( + hintText: '์ธ์ฆ๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + hintStyle: TextStyle( + fontFamily: 'Pretendard', + fontSize: 16, + fontWeight: FontWeight.w400, + color: Color(0xFF9CA3AF), + ), + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 16, + vertical: 14, + ), + ), + onSubmitted: (value) { + if (value.isNotEmpty && + (_isEmailCodeEnabled || + _isEmailVerified)) { + _verifyEmailCode(); + } + }, + ), + ), + ), + + const SizedBox(width: 12), + + Expanded( + flex: 3, + child: SizedBox( + height: 50, + child: ElevatedButton( + onPressed: + (!_isEmailCodeEnabled || + _isVerifyingEmailCode) + ? null + : _verifyEmailCode, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF6366F1), + foregroundColor: Colors.white, + elevation: 0, + padding: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: Text( + _isVerifyingEmailCode ? 'ํ™•์ธ ์ค‘...' : '์ธ์ฆ๋ฒˆํ˜ธ ํ™•์ธ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ), + ], + ), + + // Error Message (Row ๋ฐ–์œผ๋กœ ์ด๋™) + if (_isEmailCodeFieldError && + _emailCodeError != null) ...[ + const SizedBox(height: 8), + Align( + alignment: Alignment.centerLeft, + child: Text( + _emailCodeError!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ), + ], + + // Success Message + if (_emailCodeSuccessMessage != null) ...[ + const SizedBox(height: 8), + Align( + alignment: Alignment.centerLeft, + child: Text( + _emailCodeSuccessMessage!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFF10B981), + ), + ), + ), + ], + ], + ), + + const SizedBox(height: 24), + LabeledInputField( + label: 'ํœด๋Œ€์ „ํ™”*', + placeholder: '์ „ํ™”๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _phoneController, + keyboardType: TextInputType.phone, + isError: _isPhoneFieldError, + errorMessage: _phoneError, + onChanged: _onPhoneChanged, + ), + const SizedBox(height: 24), + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํ•„๋“œ์™€ ์ •์ฑ… ์—๋Ÿฌ ํ‘œ์‹œ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LabeledInputField( + label: '๋น„๋ฐ€๋ฒˆํ˜ธ*', + placeholder: '๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _passwordController, + keyboardType: TextInputType.visiblePassword, + obscureText: true, + isError: + _isPasswordFieldError || + _passwordPolicyErrors.isNotEmpty, + errorMessage: _passwordError, + onChanged: _onPasswordChanged, + ), + _buildPasswordPolicyErrors(), + ], + ), + const SizedBox(height: 24), + LabeledInputField( + label: '๋น„๋ฐ€๋ฒˆํ˜ธ ํ™•์ธ*', + placeholder: '๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋‹ค์‹œ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”', + controller: _confirmPasswordController, + keyboardType: TextInputType.visiblePassword, + obscureText: true, + isError: _isConfirmPasswordFieldError, + errorMessage: _confirmPasswordError, + onChanged: _onConfirmPasswordChanged, + ), + const SizedBox(height: 20), + NextButton(text: '๋‹ค์Œ', onPressed: _handleSignUp), + const SizedBox(height: 60), // Bottom spacing + ], + ), + ), + ), + ), + ), + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ) +class _MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/auth/signup_success_page.dart b/frontend/lib/screens/auth/signup_success_page.dart new file mode 100644 index 0000000..a59010d --- /dev/null +++ b/frontend/lib/screens/auth/signup_success_page.dart @@ -0,0 +1,94 @@ +import 'package:flutter/material.dart'; +import '../../widgets/next_button.dart'; + +class SignUpSuccessPage extends StatelessWidget { + const SignUpSuccessPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: MediaQuery.of(context).size.width * 0.075, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container(height: MediaQuery.of(context).size.height * 0.15), + + // ์„ฑ๊ณต ์•„์ด์ฝ˜ + Container( + width: MediaQuery.of(context).size.width * 0.25, + height: MediaQuery.of(context).size.width * 0.25, + decoration: BoxDecoration( + color: const Color(0xFF10B981), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.check, + color: Colors.white, + size: 48, + ), + ), + + Container(height: MediaQuery.of(context).size.height * 0.04), + + // ์™„๋ฃŒ ๋ฉ”์‹œ์ง€ + const Text( + 'ํšŒ์›๊ฐ€์ž…์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 24, + fontWeight: FontWeight.w700, + color: Color(0xFF333333), + ), + textAlign: TextAlign.center, + ), + + Container(height: MediaQuery.of(context).size.height * 0.02), + + // ๋ถ€๊ฐ€ ์„ค๋ช… + Text( + 'GRADI์™€ ํ•จ๊ป˜ ํ•™์Šต ์—ฌ์ •์„ ์‹œ์ž‘ํ•ด๋ณด์„ธ์š”', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 16, + fontWeight: FontWeight.w400, + color: Colors.grey[600], + ), + textAlign: TextAlign.center, + ), + + Container(height: MediaQuery.of(context).size.height * 0.08), + + // ๋กœ๊ทธ์ธํ•˜๊ธฐ ๋ฒ„ํŠผ + NextButton( + text: '๋กœ๊ทธ์ธํ•˜๊ธฐ', + onPressed: () => _handleLogin(context), + ), + + Container(height: MediaQuery.of(context).size.height * 0.075), + ], + ), + ), + ), + ), + ), + ); + } + + void _handleLogin(BuildContext context) { + // ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ (๋ชจ๋“  ์ด์ „ ํŽ˜์ด์ง€ ์Šคํƒ ์ œ๊ฑฐ) + Navigator.pushNamedAndRemoveUntil(context, '/login', (route) => false); + } +} diff --git a/frontend/lib/screens/auth/signup_terms_page.dart b/frontend/lib/screens/auth/signup_terms_page.dart new file mode 100644 index 0000000..8fbaec8 --- /dev/null +++ b/frontend/lib/screens/auth/signup_terms_page.dart @@ -0,0 +1,379 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'dart:io'; +import '../../widgets/back_button.dart' as custom; +import '../../widgets/page_title.dart'; +import '../../widgets/next_button.dart'; +import '../../config/api_config.dart'; + +class SignUpTermsPage extends StatefulWidget { + const SignUpTermsPage({super.key}); + + @override + State createState() => _SignUpTermsPageState(); +} + +class _SignUpTermsPageState extends State { + bool _isAllTermsAgreed = false; + bool _isRequiredTermsAgreed = false; + bool _isMarketingTermsAgreed = false; + bool _isLoading = false; + + @override + Widget build(BuildContext context) { + // ํšŒ์›๊ฐ€์ž… ์ •๋ณด ๋ฐ›๊ธฐ + final Map signupData = + ModalRoute.of(context)!.settings.arguments as Map; + + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints( + minHeight: + MediaQuery.of(context).size.height - + MediaQuery.of(context).padding.top - + MediaQuery.of(context).padding.bottom, + ), + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: MediaQuery.of(context).size.width * 0.075, + ), + child: Column( + children: [ + Container(height: MediaQuery.of(context).size.height * 0.021), + Row( + children: [ + custom.CustomBackButton( + onPressed: () => Navigator.pop(context), + ), + Container( + width: MediaQuery.of(context).size.width * 0.05, + ), + const PageTitle(text: '๊ถŒํ•œ ๋™์˜'), + ], + ), + Container(height: MediaQuery.of(context).size.height * 0.04), + + // ์ „์ฒด ๋™์˜ ์ฒดํฌ๋ฐ•์Šค + _buildAllTermsCheckbox(), + Container(height: MediaQuery.of(context).size.height * 0.02), + + // ๊ตฌ๋ถ„์„  + Container(height: 1, color: const Color(0xFFE5E7EB)), + Container(height: MediaQuery.of(context).size.height * 0.02), + + // ํ•„์ˆ˜ ์•ฝ๊ด€๋“ค + _buildRequiredTerms(), + Container(height: MediaQuery.of(context).size.height * 0.03), + + // ์„ ํƒ ์•ฝ๊ด€ + _buildOptionalTerms(), + Container(height: MediaQuery.of(context).size.height * 0.04), + + // ์™„๋ฃŒ ๋ฒ„ํŠผ + NextButton( + text: _isLoading ? '๊ฐ€์ž… ์ค‘...' : '์™„๋ฃŒ', + onPressed: (_isRequiredTermsAgreed && !_isLoading) + ? () => _handleComplete(signupData) + : null, + ), + Container(height: MediaQuery.of(context).size.height * 0.075), + ], + ), + ), + ), + ), + ), + ); + } + + Widget _buildAllTermsCheckbox() { + return GestureDetector( + onTap: () { + setState(() { + _isAllTermsAgreed = !_isAllTermsAgreed; + _isRequiredTermsAgreed = _isAllTermsAgreed; + _isMarketingTermsAgreed = _isAllTermsAgreed; + }); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: MediaQuery.of(context).size.height * 0.015, + ), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + Container(width: MediaQuery.of(context).size.width * 0.048), + Container( + width: MediaQuery.of(context).size.width * 0.06, + height: MediaQuery.of(context).size.width * 0.06, + decoration: BoxDecoration( + color: _isAllTermsAgreed + ? const Color(0xFF6366F1) + : Colors.white, + border: Border.all( + color: _isAllTermsAgreed + ? const Color(0xFF6366F1) + : const Color(0xFFE5E7EB), + width: 2, + ), + borderRadius: BorderRadius.circular(4), + ), + child: _isAllTermsAgreed + ? const Icon(Icons.check, color: Colors.white, size: 16) + : null, + ), + Container(width: MediaQuery.of(context).size.width * 0.04), + const Expanded( + child: Text( + '์ „์ฒด ๋™์˜', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color(0xFF333333), + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildRequiredTerms() { + return Column( + children: [ + _buildTermsItem( + title: '์„œ๋น„์Šค ์ด์šฉ์•ฝ๊ด€', + isRequired: true, + isChecked: _isRequiredTermsAgreed, + onChanged: (value) { + setState(() { + _isRequiredTermsAgreed = value; + _updateAllTermsState(); + }); + }, + ), + Container(height: MediaQuery.of(context).size.height * 0.02), + _buildTermsItem( + title: '๊ฐœ์ธ์ •๋ณด ์ฒ˜๋ฆฌ๋ฐฉ์นจ', + isRequired: true, + isChecked: _isRequiredTermsAgreed, + onChanged: (value) { + setState(() { + _isRequiredTermsAgreed = value; + _updateAllTermsState(); + }); + }, + ), + ], + ); + } + + Widget _buildOptionalTerms() { + return _buildTermsItem( + title: '๋งˆ์ผ€ํŒ… ์ •๋ณด ์ˆ˜์‹  ๋™์˜', + isRequired: false, + isChecked: _isMarketingTermsAgreed, + onChanged: (value) { + setState(() { + _isMarketingTermsAgreed = value; + _updateAllTermsState(); + }); + }, + ); + } + + Widget _buildTermsItem({ + required String title, + required bool isRequired, + required bool isChecked, + required Function(bool) onChanged, + }) { + return GestureDetector( + onTap: () => onChanged(!isChecked), + child: Row( + children: [ + Container( + width: MediaQuery.of(context).size.width * 0.06, + height: MediaQuery.of(context).size.width * 0.06, + decoration: BoxDecoration( + color: isChecked ? const Color(0xFF6366F1) : Colors.white, + border: Border.all( + color: isChecked + ? const Color(0xFF6366F1) + : const Color(0xFFE5E7EB), + width: 2, + ), + borderRadius: BorderRadius.circular(4), + ), + child: isChecked + ? const Icon(Icons.check, color: Colors.white, size: 16) + : null, + ), + Container(width: MediaQuery.of(context).size.width * 0.04), + Expanded( + child: Row( + children: [ + Text( + title, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFF333333), + ), + ), + if (isRequired) ...[ + Container(width: MediaQuery.of(context).size.width * 0.02), + const Text( + '(ํ•„์ˆ˜)', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w500, + color: Color(0xFFFF4258), + ), + ), + ], + const Spacer(), + const Icon( + Icons.chevron_right, + color: Color(0xFF9CA3AF), + size: 20, + ), + ], + ), + ), + ], + ), + ); + } + + void _updateAllTermsState() { + _isAllTermsAgreed = _isRequiredTermsAgreed && _isMarketingTermsAgreed; + } + + Future _handleComplete(Map signupData) async { + setState(() { + _isLoading = true; + }); + + try { + // ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ ํ•„์š”) + HttpOverrides.global = _MyHttpOverrides(); + + // ์„œ๋ฒ„ IP ์„ค์ • + final url = ApiConfig.getSignUpUri(); + + // ์ด๋ฏธ์ง€์˜ JSON ํ˜•์‹์— ๋งž์ถฐ ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ค€๋น„ + final Map requestData = { + 'name': signupData['name'], + 'account_id': signupData['id'], + 'email': signupData['email'], + 'password': signupData['password'], + 'phone_number': signupData['phone'], + }; + + developer.log('POST $url'); + developer.log('Request: $requestData'); + + // HTTP POST ์š”์ฒญ + final response = await http.post( + url, + headers: {'Content-Type': 'application/json'}, + body: json.encode(requestData), + ); + + developer.log('Response status: ${response.statusCode}'); + developer.log('Response body: ${response.body}'); + + if (!mounted) return; + + setState(() { + _isLoading = false; + }); + + if (response.statusCode == 200) { + if (mounted) { + Navigator.pushNamed(context, '/signup-success'); + } + developer.log('Sign-up successful (status 200)'); + } else { + // ์„œ๋ฒ„ ์˜ค๋ฅ˜ + if (mounted) { + _showErrorDialog(); + } + developer.log('Server error: ${response.statusCode}'); + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + }); + _showErrorDialog(); + } + developer.log('Sign-up error: $e'); + } + } + + void _showErrorDialog({String? message}) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text( + '์˜ค๋ฅ˜', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 18, + fontWeight: FontWeight.w600, + color: Color(0xFF333333), + ), + ), + content: Text( + message ?? '๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 16, + fontWeight: FontWeight.w400, + color: Color(0xFF666666), + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text( + 'ํ™•์ธ', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 16, + fontWeight: FontWeight.w600, + color: Color(0xFF6366F1), + ), + ), + ), + ], + ); + }, + ); + } +} + +// ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ์šฐํšŒ๋ฅผ ์œ„ํ•œ ํด๋ž˜์Šค (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ์ œ๊ฑฐ) +class _MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/frontend/lib/screens/continuous_learning_detail_page.dart b/frontend/lib/screens/continuous_learning_detail_page.dart new file mode 100644 index 0000000..616f642 --- /dev/null +++ b/frontend/lib/screens/continuous_learning_detail_page.dart @@ -0,0 +1,782 @@ +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import '../widgets/app_header.dart'; +import '../widgets/app_header_menu_button.dart'; +import '../widgets/back_button.dart'; +import '../services/continuous_learning_api.dart'; +import '../services/academy_service.dart'; +import '../services/auth_service.dart'; +import '../services/daily_learning_service.dart'; +import '../services/workbook_api.dart'; +import '../services/get_monthly_learning_status_use_case_impl.dart'; +import '../domain/learning/get_monthly_learning_status_use_case.dart'; +import '../domain/learning/daily_learning_status.dart'; +import '../utils/academy_utils.dart'; +import '../utils/app_logger.dart'; +import 'dart:developer' as developer; + +/// ์—ฐ์†ํ•™์Šต ์ƒ์„ธ ํŽ˜์ด์ง€ +/// +/// Figma ๋””์ž์ธ ๊ธฐ๋ฐ˜ ์บ˜๋ฆฐ๋” ๋ทฐ +class ContinuousLearningDetailPage extends StatefulWidget { + final GetMonthlyLearningStatusUseCase monthlyStatusUseCase; + + const ContinuousLearningDetailPage({ + super.key, + required this.monthlyStatusUseCase, + }); + + @override + State createState() => + _ContinuousLearningDetailPageState(); +} + +class _ContinuousLearningDetailPageState + extends State { + late int _currentMonth; + late int _currentYear; + + final GetIt _getIt = GetIt.instance; + + // Services (DI์—์„œ ์ฃผ์ž…) + late final AuthService _authService; + late final AcademyService _academyService; + late final ContinuousLearningApi _continuousLearningApi; + + // UseCase ์ ‘๊ทผ (widget์„ ํ†ตํ•ด) + GetMonthlyLearningStatusUseCase get _monthlyStatusUseCase => + widget.monthlyStatusUseCase; + + // ํ˜„์žฌ ์›”์˜ ์ƒํƒœ ์บ์‹œ + Map? _currentMonthStatuses; + + // Statistics data + int _totalDays = 0; + int _totalProblems = 0; + bool _isLoadingStatistics = false; + + // Selected date learning data + DateTime? _selectedDate; + DailyLearningResult? _selectedDateResult; + bool _isLoadingSelectedDate = false; + + @override + void initState() { + super.initState(); + _authService = _getIt(); + _academyService = _getIt(); + _continuousLearningApi = _getIt(); + // ํ˜„์žฌ ๋‚ ์งœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ดˆ๊ธฐ ์›”/๋…„ ์„ค์ • + final now = DateTime.now(); + _currentMonth = now.month; + _currentYear = now.year; + + // ํ†ต๊ณ„ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + _loadStatistics(); + // ํ˜„์žฌ ์›”์˜ ํ•™์Šต ์ƒํƒœ ๋กœ๋“œ + _loadMonthlyStatuses(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ ๋Œ์•„์˜ฌ ๋•Œ ๊ฐ•์ œ ์ƒˆ๋กœ๊ณ ์นจ + _loadStatistics(forceRefresh: true); + _loadMonthlyStatuses(); + } + + /// UseCase๋กœ ํ˜„์žฌ ์›”์˜ ํ•™์Šต ์ƒํƒœ ๋กœ๋“œ + Future _loadMonthlyStatuses() async { + try { + // ์‚ฌ์šฉ์ž ํ•™์› ์ •๋ณด ์กฐํšŒ + final userId = await _authService.getUserId(); + if (userId == null) { + setState(() { + _currentMonthStatuses = {}; + }); + return; + } + + final academies = await _academyService.getUserAcademies(userId); + final registeredAcademies = academies + .where((a) => a.registerStatus == 'Y') + .toList(); + + if (registeredAcademies.isEmpty) { + setState(() { + _currentMonthStatuses = {}; + }); + return; + } + + // academyId์™€ academyUserIds ์กฐํšŒ + final userAcademyId = await getUserAcademyId( + academyService: _academyService, + registeredAcademies: registeredAcademies, + ); + + if (userAcademyId == null) { + setState(() { + _currentMonthStatuses = {}; + }); + return; + } + + final academyUserIds = registeredAcademies + .map((a) => a.academy_user_id) + .whereType() + .toList(); + + // UseCase ๊ตฌํ˜„์ฒด์˜ callWithContext ํ˜ธ์ถœ + final month = DateTime(_currentYear, _currentMonth, 1); + if (_monthlyStatusUseCase is GetMonthlyLearningStatusUseCaseImpl) { + final statuses = + await (_monthlyStatusUseCase as GetMonthlyLearningStatusUseCaseImpl) + .callWithContext( + month: month, + academyId: userAcademyId, + academyUserIds: academyUserIds, + ); + + setState(() { + _currentMonthStatuses = { + for (var status in statuses) + DailyLearningStatus.normalizeDate(status.date): status, + }; + }); + } else { + // ๊ธฐ๋ณธ UseCase ์ธํ„ฐํŽ˜์ด์Šค ์‚ฌ์šฉ (๋นˆ ์ƒํƒœ) + final statuses = await _monthlyStatusUseCase.call(month); + setState(() { + _currentMonthStatuses = { + for (var status in statuses) + DailyLearningStatus.normalizeDate(status.date): status, + }; + }); + } + } catch (e) { + // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ๋นˆ ์ƒํƒœ ์œ ์ง€ + } + } + + /// ํ†ต๊ณ„ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + Future _loadStatistics({bool forceRefresh = false}) async { + if (_isLoadingStatistics) return; + + setState(() { + _isLoadingStatistics = true; + }); + + try { + // 1. UserId๋กœ academyUserIds ์กฐํšŒ + final userId = await _authService.getUserId(); + if (userId == null) { + throw Exception('์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + final academies = await _academyService.getUserAcademies(userId); + final academyUserIds = academies + .where((a) => a.registerStatus == 'Y') + .map((a) => a.academy_user_id) + .whereType() + .toList(); + + if (academyUserIds.isEmpty) { + setState(() { + _totalDays = 0; + _totalProblems = 0; + _isLoadingStatistics = false; + }); + return; + } + + // 2. ์—ฌ๋Ÿฌ academyUserId์— ๋Œ€ํ•œ ํ†ต๊ณ„ ์กฐํšŒ (๋ณ‘๋ ฌ) + appLog( + '[continuous_learning:continuous_learning_detail_page] ํ†ต๊ณ„ ์กฐํšŒ ์‹œ์ž‘ - academyUserIds: $academyUserIds', + ); + final summariesMap = await _continuousLearningApi + .fetchGradingHistorySummaries(academyUserIds); + + // 3. ๋ฐ์ดํ„ฐ ํ•ฉ์‚ฐ + int totalDays = 0; + double totalScore = 0.0; + + summariesMap.forEach((academyUserId, summary) { + appLog( + '[continuous_learning:continuous_learning_detail_page] academyUserId: $academyUserId - totalScore: ${summary.totalScore}, daysSinceStartOfYear: ${summary.daysSinceStartOfYear}', + ); + // days_since_start_of_year๋Š” ๊ฐ€์žฅ ํฐ ๊ฐ’ ์‚ฌ์šฉ (๊ฐ€์žฅ ์˜ค๋ž˜๋œ ์‹œ์ž‘์ผ ๊ธฐ์ค€) + if (summary.daysSinceStartOfYear > totalDays) { + totalDays = summary.daysSinceStartOfYear; + } + // total_score๋Š” ํ•ฉ์‚ฐ + totalScore += summary.totalScore; + }); + + appLog( + '[continuous_learning:continuous_learning_detail_page] ํ†ต๊ณ„ ํ•ฉ์‚ฐ ์™„๋ฃŒ - totalDays: $totalDays, totalScore: $totalScore', + ); + + // 4. UI ์—…๋ฐ์ดํŠธ + setState(() { + _totalDays = totalDays; + _totalProblems = totalScore.round(); // total_score๋ฅผ ๋ฌธ์ œ ์ˆ˜๋กœ ์‚ฌ์šฉ + _isLoadingStatistics = false; + }); + } catch (e) { + appLog( + '[continuous_learning:continuous_learning_detail_page] ํ†ต๊ณ„ ๋กœ๋“œ ์‹คํŒจ: $e', + ); + developer.log('โŒ [ContinuousLearningDetailPage] ํ†ต๊ณ„ ๋กœ๋“œ ์‹คํŒจ: $e'); + setState(() { + _isLoadingStatistics = false; + // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ๊ธฐ๋ณธ๊ฐ’ ์œ ์ง€ + }); + } + } + + @override + Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + final screenHeight = MediaQuery.of(context).size.height; + + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded( + child: SingleChildScrollView( + padding: EdgeInsets.symmetric(horizontal: screenWidth * 0.05), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: screenHeight * 0.03), + _buildCalendarSection(), + SizedBox(height: screenHeight * 0.033), + _buildStatisticsSection(), + if (_selectedDate != null) ...[ + SizedBox(height: screenHeight * 0.016), + _buildSelectedDateLearningSection(), + ], + SizedBox(height: screenHeight * 0.02), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return AppHeader( + leading: CustomBackButton(), + title: const Text( + '์—ฐ์†ํ•™์Šต', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF585B69), + ), + ), + trailing: const AppHeaderMenuButton(), + titleAlignment: 'left', + ); + } + + Widget _buildCalendarSection() { + final screenHeight = MediaQuery.of(context).size.height; + + return Container( + padding: EdgeInsets.fromLTRB( + 8, + screenHeight * 0.029, + 8, + screenHeight * 0.018, + ), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + children: [ + // ์›”/๋…„ ํ‘œ์‹œ์™€ ์ด์ „/๋‹ค์Œ ๋‹ฌ ๋ฒ„ํŠผ + _buildCalendarHeader(), + SizedBox(height: screenHeight * 0.018), + // ์š”์ผ ํ‘œ์‹œ + _buildWeekDays(), + SizedBox(height: screenHeight * 0.037), + // ๋‚ ์งœ ๊ทธ๋ฆฌ๋“œ (7์—ด x 5ํ–‰) + _buildDateGrid(), + ], + ), + ); + } + + Widget _buildCalendarHeader() { + final screenWidth = MediaQuery.of(context).size.width; + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // ์ด์ „ ๋‹ฌ ๋ฒ„ํŠผ + IconButton( + icon: Icon(Icons.chevron_left, size: screenWidth * 0.037), + onPressed: () { + setState(() { + if (_currentMonth > 1) { + _currentMonth--; + } else { + _currentMonth = 12; + _currentYear--; + } + }); + _loadMonthlyStatuses(); + }, + ), + const SizedBox(width: 32), + // ์›”/๋…„ ํ‘œ์‹œ + Column( + children: [ + Text( + '$_currentMonth์›”', + style: const TextStyle( + fontFamily: 'Inter', + fontWeight: FontWeight.w500, + fontSize: 22, + color: Color(0xFF000000), + height: 1.0, + ), + ), + Text( + '$_currentYear', + style: const TextStyle( + fontFamily: 'Inter', + fontWeight: FontWeight.w400, + fontSize: 13, + color: Color(0xFF000000), + height: 1.23, + ), + ), + ], + ), + const SizedBox(width: 32), + // ๋‹ค์Œ ๋‹ฌ ๋ฒ„ํŠผ + IconButton( + icon: Icon(Icons.chevron_right, size: screenWidth * 0.037), + onPressed: () { + setState(() { + if (_currentMonth < 12) { + _currentMonth++; + } else { + _currentMonth = 1; + _currentYear++; + } + }); + _loadMonthlyStatuses(); + }, + ), + ], + ); + } + + Widget _buildWeekDays() { + final weekDays = ['์›”', 'ํ™”', '์ˆ˜', '๋ชฉ', '๊ธˆ', 'ํ† ', '์ผ']; + + return Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: weekDays.map((day) { + return SizedBox( + width: MediaQuery.of(context).size.width / 15, + child: Text( + day, + style: const TextStyle( + fontFamily: 'Inter', + fontWeight: FontWeight.w600, + fontSize: 15, + color: Color(0xFF707070), + ), + textAlign: TextAlign.center, + ), + ); + }).toList(), + ); + } + + Widget _buildDateGrid() { + final firstDayOfMonth = DateTime(_currentYear, _currentMonth, 1); + final lastDayOfMonth = DateTime(_currentYear, _currentMonth + 1, 0); + + // ์ฒซ ๋ฒˆ์งธ ๋‚ ์˜ ์š”์ผ (์›”์š”์ผ = 1, ์ผ์š”์ผ = 7) + // Flutter์˜ weekday: ์›”์š”์ผ=1, ํ™”์š”์ผ=2, ..., ์ผ์š”์ผ=7 + // ์šฐ๋ฆฌ๋Š” ์›”์š”์ผ์„ 0์œผ๋กœ ๋ณ€ํ™˜ (0~6) + final firstWeekday = firstDayOfMonth.weekday == 7 + ? 0 + : firstDayOfMonth.weekday - 1; + + // ํ•„์š”ํ•œ ์ฃผ ์ˆ˜ ๊ณ„์‚ฐ: ์ฒซ ๋ฒˆ์งธ ๋‚ ์˜ ์œ„์น˜ + ๋งˆ์ง€๋ง‰ ๋‚ ์˜ ์œ„์น˜๋ฅผ ๊ณ ๋ ค + // ์ด ๋‚ ์งœ ์ˆ˜ + ์ฒซ ๋ฒˆ์งธ ๋‚  ์ด์ „์˜ ๋นˆ ์นธ ์ˆ˜๋ฅผ 7๋กœ ๋‚˜๋ˆˆ ํ›„ ์˜ฌ๋ฆผ + final totalDays = lastDayOfMonth.day; + final totalCells = firstWeekday + totalDays; + final weeksNeeded = (totalCells / 7).ceil(); + + // ์ด์ „ ๋‹ฌ์˜ ๋งˆ์ง€๋ง‰ ๋‚ ์งœ๋“ค ๊ณ„์‚ฐ + final prevMonth = _currentMonth == 1 ? 12 : _currentMonth - 1; + final prevYear = _currentMonth == 1 ? _currentYear - 1 : _currentYear; + final daysInPrevMonth = DateTime(prevYear, prevMonth + 1, 0).day; + + // Table ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ •ํ™•ํ•œ ๊ทธ๋ฆฌ๋“œ ์ •๋ ฌ + return Table( + border: TableBorder.all(color: Colors.transparent), + columnWidths: {for (int i = 0; i < 7; i++) i: const FlexColumnWidth(1.0)}, + children: List.generate(weeksNeeded, (weekIndex) { + return TableRow( + children: List.generate(7, (dayIndex) { + final cellIndex = weekIndex * 7 + dayIndex; + final day = cellIndex - firstWeekday + 1; + + // ์ด์ „ ๋‹ฌ์˜ ๋‚ ์งœ + if (day <= 0) { + final dayInPrevMonth = daysInPrevMonth + day; + return _buildDateCell( + day: dayInPrevMonth, + isCurrentMonth: false, + isCompleted: false, + ); + } + // ๋‹ค์Œ ๋‹ฌ์˜ ๋‚ ์งœ + else if (day > totalDays) { + final dayInNextMonth = day - totalDays; + return _buildDateCell( + day: dayInNextMonth, + isCurrentMonth: false, + isCompleted: false, + ); + } + // ํ˜„์žฌ ๋‹ฌ์˜ ๋‚ ์งœ + else { + final date = DateTime(_currentYear, _currentMonth, day); + final isCompleted = _isDateCompleted(day); + return _buildDateCell( + day: day, + isCurrentMonth: true, + isCompleted: isCompleted, + date: date, + ); + } + }), + ); + }), + ); + } + + /// ๋‚ ์งœ๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋Š”์ง€ ํŒ๋‹จ + bool _isDateCompleted(int day) { + final date = DailyLearningStatus.normalizeDate( + DateTime(_currentYear, _currentMonth, day), + ); + return _currentMonthStatuses?[date]?.isCompleted ?? false; + } + + /// ๋‚ ์งœ ์…€ ํƒญ ํ•ธ๋“ค๋Ÿฌ + void _onDateCellTapped(DateTime date) { + _showDateLearningDialog(date); + } + + /// ๋‚ ์งœ ํด๋ฆญ ์‹œ ํ•™์Šต ๋ฐ์ดํ„ฐ ํ‘œ์‹œ + /// + /// [date]: ์„ ํƒ๋œ ๋‚ ์งœ (์–ด๋–ค ํƒ€์ž„์กด์ด๋“  ์ƒ๊ด€์—†์Œ, KST๋กœ ๋ณ€ํ™˜๋จ) + Future _showDateLearningDialog(DateTime date) async { + // ๊ฐ™์€ ๋‚ ์งœ๋ฅผ ๋‹ค์‹œ ํด๋ฆญํ•˜๋ฉด ์ˆจ๊ธฐ๊ธฐ + if (_selectedDate != null && + _selectedDate!.year == date.year && + _selectedDate!.month == date.month && + _selectedDate!.day == date.day) { + setState(() { + _selectedDate = null; + _selectedDateResult = null; + }); + return; + } + + setState(() { + _selectedDate = date; + _isLoadingSelectedDate = true; + _selectedDateResult = null; + }); + + // ๋ฐ์ดํ„ฐ ๋กœ๋“œ + final learningService = _getIt(); + final result = await learningService.getDailyLearningData(date); + + // ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์™„๋ฃŒ ํ›„ ์ƒํƒœ ์—…๋ฐ์ดํŠธ + if (!mounted) return; + + setState(() { + _selectedDateResult = result; + _isLoadingSelectedDate = false; + }); + } + + Widget _buildDateCell({ + required int day, + required bool isCurrentMonth, + required bool isCompleted, + DateTime? date, + }) { + return GestureDetector( + onTap: date != null && isCurrentMonth + ? () => _onDateCellTapped(date) + : null, + child: Padding( + padding: const EdgeInsets.only(bottom: 32), + child: Stack( + alignment: Alignment.center, + children: [ + // ๋‚ ์งœ ๋ฐ•์Šค + if (isCurrentMonth) + Container( + width: 41, + height: 43, + decoration: isCompleted + ? BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + // ๋กœ๊ณ  ๊ทธ๋ผ๋ฐ์ด์…˜: linear-gradient(121.67deg, #AC5BF8 19.64%, #636ACF 77.54%) + colors: [Color(0xFFAC5BF8), Color(0xFF636ACF)], + stops: [0.1964, 0.7754], + ), + borderRadius: BorderRadius.circular(10), + ) + : BoxDecoration( + color: const Color(0xFFE1E7ED), // ํšŒ์ƒ‰ + borderRadius: BorderRadius.circular(10), + ), + ), + // ๋‚ ์งœ ํ…์ŠคํŠธ + Text( + '$day', + style: TextStyle( + fontFamily: 'Inter', + fontWeight: FontWeight.w500, + fontSize: 15, + color: isCurrentMonth + ? (isCompleted ? Colors.white : const Color(0xFF000000)) + : const Color(0xFF707070), + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + } + + Widget _buildStatisticsSection() { + final screenWidth = MediaQuery.of(context).size.width; + final screenHeight = MediaQuery.of(context).size.height; + + return Container( + padding: EdgeInsets.fromLTRB( + screenWidth * 0.087, + screenHeight * 0.011, + screenWidth * 0.087, + screenHeight * 0.011, + ), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: _isLoadingStatistics + ? const Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Color(0xFFAC5BF8)), + ), + ), + ) + : Text( + '$_totalDays์ผ๋™์•ˆ $_totalProblems๋ฌธ์ œ๋ฅผ ํ’€์—ˆ์–ด์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + height: 1.2, + foreground: Paint() + ..shader = LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF636ACF)], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ).createShader(const Rect.fromLTWH(0, 0, 1000, 70)), + ), + ), + ); + } + + Widget _buildSelectedDateLearningSection() { + if (_isLoadingSelectedDate) { + return const Center( + child: Padding( + padding: EdgeInsets.all(20), + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Color(0xFFAC5BF8)), + ), + ), + ), + ); + } + + if (_selectedDateResult == null) { + return const SizedBox.shrink(); + } + + final result = _selectedDateResult!; + + // ์—๋Ÿฌ ์ƒํƒœ + if (result.hasError) { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + children: [ + const Icon(Icons.error_outline, color: Color(0xFFFF6B6B), size: 48), + const SizedBox(height: 12), + Text( + result.errorMessage ?? '๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFFF6B6B), + ), + textAlign: TextAlign.center, + ), + ], + ), + ); + } + + // ๋นˆ ์ƒํƒœ + if (!result.hasData) { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Text( + 'ํ•ด๋‹น ๋‚ ์งœ์— ํ•™์Šต ๊ธฐ๋ก์ด ์—†์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ); + } + + // ๋ฐ์ดํ„ฐ ์žˆ์Œ + final books = DailyLearningService.extractBooks(result); + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: books + .map((book) => _buildSelectedDateLearningItem(book)) + .toList(), + ); + } + + Widget _buildSelectedDateLearningItem(BookData book) { + final progress = book.bookPage > 0 + ? book.totalSolvedPages / book.bookPage + : 0.0; + + final screenHeight = MediaQuery.of(context).size.height; + + return Container( + margin: EdgeInsets.only(bottom: screenHeight * 0.016), + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ์ฑ… ์ด๋ฆ„ + Text( + book.bookName ?? '๋ฌธ์ œ์ง‘ ${book.bookId}', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + // ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ” + Row( + children: [ + Expanded( + child: Container( + height: 12, + decoration: const BoxDecoration( + color: Color(0xFFE9ECEF), + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + child: FractionallySizedBox( + widthFactor: progress.clamp(0.0, 1.0), + alignment: Alignment.centerLeft, + child: Container( + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF636ACF)], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + borderRadius: const BorderRadius.all( + Radius.circular(10), + ), + ), + ), + ), + ), + ), + ], + ), + const SizedBox(height: 8), + // ์ง„ํ–‰ ์ •๋ณด + Text( + '${book.totalSolvedPages} / ${book.bookPage} ํŽ˜์ด์ง€', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: Color(0xFF666666), + ), + ), + ], + ), + ); + } +} diff --git a/frontend/lib/screens/grading_history/edit_grading_result_page.dart b/frontend/lib/screens/grading_history/edit_grading_result_page.dart new file mode 100644 index 0000000..7bd853b --- /dev/null +++ b/frontend/lib/screens/grading_history/edit_grading_result_page.dart @@ -0,0 +1,789 @@ +import 'package:flutter/material.dart'; +import '../../domain/student_answer/get_student_answers_for_response_use_case.dart'; +import '../../domain/student_answer/update_student_answers_use_case.dart'; +import '../../domain/student_answer/update_single_student_answer_use_case.dart'; +import '../../domain/section_image/get_section_image_use_case.dart'; +import 'models/grading_result.dart'; + +class EditGradingResultPage extends StatefulWidget { + final int studentResponseId; // ํ•„์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ + final int academyUserId; // ์ถ”๊ฐ€ + final GetStudentAnswersForResponseUseCase getStudentAnswersUseCase; + final UpdateStudentAnswersUseCase updateStudentAnswersUseCase; + final GetSectionImageUseCase getSectionImageUseCase; // ์ถ”๊ฐ€ + final UpdateSingleStudentAnswerUseCase updateSingleStudentAnswerUseCase; + + const EditGradingResultPage({ + super.key, + required this.studentResponseId, + required this.academyUserId, // ์ถ”๊ฐ€ + required this.getStudentAnswersUseCase, + required this.updateStudentAnswersUseCase, + required this.getSectionImageUseCase, // ์ถ”๊ฐ€ + required this.updateSingleStudentAnswerUseCase, + }); + + @override + State createState() => _EditGradingResultPageState(); +} + +class _EditGradingResultPageState extends State { + // ์ƒํƒœ ๋ณ€์ˆ˜ + bool _isLoading = false; + bool _isSavingSingle = false; // ๋‹จ์ผ ์ˆ˜์ • ์ €์žฅ ์ค‘ + String? _errorMessage; + List _results = []; + List _originalResults = []; // ์›๋ณธ ๋ฐ์ดํ„ฐ (์ˆ˜์ • ์—ฌ๋ถ€ ํŒ๋‹จ์šฉ) + + bool get _isSaving => _isSavingSingle; + + // UI ์ƒํƒœ + int? _selectedProblemIndex; + final TextEditingController _answerController = TextEditingController(); + bool _isEditingAnswer = false; + + // Section ์ด๋ฏธ์ง€ ์บ์‹ฑ ๋ฐ ์ƒํƒœ ๊ด€๋ฆฌ + final Map _sectionImageUrls = {}; // ์บ์‹œ: cacheKey -> imageUrl + final Map _imageLoadingStates = {}; // ๋กœ๋”ฉ ์ƒํƒœ + final Map _imageErrors = {}; // ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ + + @override + void initState() { + super.initState(); + _loadStudentAnswers(); + } + + @override + void dispose() { + _answerController.dispose(); + super.dispose(); + } + + /// API๋กœ ํ•™์ƒ ๋‹ต์•ˆ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + Future _loadStudentAnswers() async { + if (!mounted) return; + + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + final entities = await widget.getStudentAnswersUseCase.call( + widget.studentResponseId, + ); + + if (!mounted) return; + + // Entity๋ฅผ UI ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ + final results = entities + .map((entity) => GradingResult.fromEntity(entity)) + .toList(); + + // ์ •๋ ฌ: (questionNumber, subQuestionNumber) ํŠœํ”Œ ์ •๋ ฌ + results.sort((a, b) { + final questionCompare = a.questionNumber.compareTo(b.questionNumber); + if (questionCompare != 0) return questionCompare; + return a.subQuestionNumber.compareTo(b.subQuestionNumber); + }); + + setState(() { + _results = results; + _originalResults = results + .map( + (r) => GradingResult( + questionNumber: r.questionNumber, + subQuestionNumber: r.subQuestionNumber, + studentAnswerId: r.studentAnswerId, + chapterId: r.chapterId, + recognizedAnswer: r.recognizedAnswer, + correctStatus: r.correctStatus, + ), + ) + .toList(); // ๊นŠ์€ ๋ณต์‚ฌ + _isLoading = false; + }); + } catch (e) { + if (!mounted) return; + + setState(() { + _errorMessage = '๋‹ต์•ˆ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'; + _isLoading = false; + }); + } + } + + + void _updateAnswer() { + if (_selectedProblemIndex == null) return; + + final index = _selectedProblemIndex!; + final newAnswer = _answerController.text.trim(); + final oldAnswer = _results[index].recognizedAnswer.trim(); + + if (newAnswer.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('๋‹ต์•ˆ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.')), + ); + return; + } + + if (newAnswer == oldAnswer) { + // ๋ฒ„ํŠผ ๋น„ํ™œ์„ฑ ์ƒํƒœ๊ฐ€ ๊ธฐ๋ณธ์ด์ง€๋งŒ ๋ฐฉ์–ด์ ์œผ๋กœ ํ•œ ๋ฒˆ ๋” ์ฒดํฌ + return; + } + + _updateAnswerInternal(index: index, newAnswer: newAnswer); + } + + Future _updateAnswerInternal({ + required int index, + required String newAnswer, + }) async { + if (!mounted) return; + + setState(() { + _isSavingSingle = true; + }); + + try { + final current = _results[index]; + + // chapterId๊ฐ€ null์ด๊ฑฐ๋‚˜ 0์ด๋ฉด ์—๋Ÿฌ ๋ฐœ์ƒ + if (current.chapterId == null || current.chapterId == 0) { + throw Exception('์ฑ•ํ„ฐ ์ •๋ณด๊ฐ€ ์—†์–ด ๋‹ต์•ˆ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + final updated = + await widget.updateSingleStudentAnswerUseCase.call( + studentAnswerId: current.studentAnswerId, + studentResponseId: widget.studentResponseId, + questionNumber: current.questionNumber, + subQuestionNumber: current.subQuestionNumber, + newAnswer: newAnswer, + chapterId: current.chapterId!, + ); + + if (!mounted) return; + + // ์ƒˆ๋กœ์šด GradingResult ๊ฐ์ฒด ์ƒ์„ฑํ•˜์—ฌ ๊ต์ฒด (Flutter๊ฐ€ ๋ณ€๊ฒฝ ๊ฐ์ง€ํ•˜๋„๋ก) + final currentResult = _results[index]; + + // ์„œ๋ฒ„ ์‘๋‹ต์˜ isCorrect ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ correctStatus ๊ณ„์‚ฐ + final newCorrectStatus = updated.isCorrect == true ? '์ •๋‹ต' : '์˜ค๋‹ต'; + + final updatedResult = GradingResult( + questionNumber: currentResult.questionNumber, + subQuestionNumber: currentResult.subQuestionNumber, + studentAnswerId: currentResult.studentAnswerId, + chapterId: currentResult.chapterId, + recognizedAnswer: updated.recognizedAnswer, + correctStatus: newCorrectStatus, + ); + + final updatedOriginalResult = GradingResult( + questionNumber: currentResult.questionNumber, + subQuestionNumber: currentResult.subQuestionNumber, + studentAnswerId: currentResult.studentAnswerId, + chapterId: currentResult.chapterId, + recognizedAnswer: updated.recognizedAnswer, + correctStatus: newCorrectStatus, + ); + + setState(() { + _results[index] = updatedResult; + _originalResults[index] = updatedOriginalResult; + _isEditingAnswer = false; + _answerController.clear(); + _isSavingSingle = false; + }); + + // ์„ฑ๊ณต ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('๋‹ต์•ˆ์ด ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.'), + duration: Duration(seconds: 2), + backgroundColor: Color(0xFF4CAF50), + ), + ); + } + } catch (e) { + if (!mounted) return; + setState(() { + _isSavingSingle = false; + }); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('์ €์žฅ ์‹คํŒจ'), + content: const Text( + '๋‹ต์•ˆ ์ˆ˜์ •์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('ํ™•์ธ'), + ), + ], + ), + ); + } + } + + /// Section ์ด๋ฏธ์ง€ ๋กœ๋“œ + /// + /// ๋ฌธ์ œ ๋ฒˆํ˜ธ๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. + /// ์บ์‹œ์— ์žˆ์œผ๋ฉด ์žฌ์š”์ฒญํ•˜์ง€ ์•Š๊ณ , ๋กœ๋”ฉ ์ค‘์ด๋ฉด ์ค‘๋ณต ์š”์ฒญ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. + Future _loadSectionImage( + int questionNumber, + int subQuestionNumber, + ) async { + // ์บ์‹œ ํ‚ค ์ƒ์„ฑ: subQuestionNumber๊ฐ€ 0์ด๋ฉด questionNumber๋งŒ, ์•„๋‹ˆ๋ฉด "questionNumber-subQuestionNumber" + final cacheKey = subQuestionNumber == 0 + ? questionNumber.toString() + : '$questionNumber-$subQuestionNumber'; + + // ์ด๋ฏธ ์บ์‹œ์— ์žˆ๊ฑฐ๋‚˜ ๋กœ๋”ฉ ์ค‘์ด๋ฉด ์Šคํ‚ต + if (_sectionImageUrls.containsKey(cacheKey) || + _imageLoadingStates[cacheKey] == true) { + return; + } + + // ๋กœ๋”ฉ ์ƒํƒœ ์„ค์ • + if (!mounted) return; + setState(() { + _imageLoadingStates[cacheKey] = true; + _imageErrors[cacheKey] = null; + }); + + try { + // UseCase ํ˜ธ์ถœ + final entity = await widget.getSectionImageUseCase.call( + academyUserId: widget.academyUserId, + studentResponseId: widget.studentResponseId, + questionNumber: questionNumber, + subQuestionNumber: subQuestionNumber, + ); + + if (!mounted) return; + + setState(() { + _imageLoadingStates[cacheKey] = false; + if (entity == null) { + // ์ด๋ฏธ์ง€๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ (404) - ์ •์ƒ ์ผ€์ด์Šค + _imageErrors[cacheKey] = '์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'; + } else { + // ์ด๋ฏธ์ง€ URL ์ €์žฅ + _sectionImageUrls[cacheKey] = entity.imageUrl; + } + }); + } catch (e) { + if (!mounted) return; + + setState(() { + _imageLoadingStates[cacheKey] = false; + _imageErrors[cacheKey] = '์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'; + }); + } + } + + @override + Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + final screenHeight = MediaQuery.of(context).size.height; + + // ๋กœ๋”ฉ ์ƒํƒœ (์ดˆ๊ธฐ ๋กœ๋”ฉ) + if (_isLoading && _results.isEmpty) { + return Scaffold( + backgroundColor: Colors.white, + body: const Center(child: CircularProgressIndicator()), + ); + } + + // ์—๋Ÿฌ ์ƒํƒœ + if (_errorMessage != null && _results.isEmpty) { + return Scaffold( + backgroundColor: Colors.white, + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(_errorMessage!), + ElevatedButton( + onPressed: _loadStudentAnswers, + child: const Text('๋‹ค์‹œ ์‹œ๋„'), + ), + ], + ), + ), + ); + } + + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Stack( + children: [ + Column( + children: [ + _buildHeader(screenWidth, screenHeight), + Expanded( + child: SingleChildScrollView( + child: Column( + children: [ + SizedBox(height: screenHeight * 0.015), + _buildResultsTable(screenWidth, screenHeight), + if (_selectedProblemIndex != null) ...[ + SizedBox(height: screenHeight * 0.02), + _buildProblemDetail(screenWidth, screenHeight), + ], + SizedBox(height: screenHeight * 0.02), + ], + ), + ), + ), + ], + ), + // ์ €์žฅ ์ค‘ ์˜ค๋ฒ„๋ ˆ์ด + if (_isSaving) + Container( + color: Colors.black.withOpacity(0.3), + child: const Center(child: CircularProgressIndicator()), + ), + ], + ), + ), + ); + } + + Widget _buildHeader(double screenWidth, double screenHeight) { + return Container( + padding: EdgeInsets.fromLTRB( + screenWidth * 0.075, + screenHeight * 0.021, + screenWidth * 0.075, + screenHeight * 0.012, + ), + decoration: const BoxDecoration( + color: Color(0xFFF8F9FA), + boxShadow: [ + BoxShadow( + color: Color(0x1A000000), + offset: Offset(0, 4), + blurRadius: 4, + ), + ], + ), + child: Stack( + children: [ + Positioned( + left: 0, + child: GestureDetector( + onTap: () => Navigator.of(context).pop(), + child: Container( + width: 38, + height: 38, + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: const Icon( + Icons.arrow_back_ios_new, + size: 18, + color: Color(0xFF5C5C5C), + ), + ), + ), + ), + const Center( + child: Text( + '์ฑ„์  ๊ฒฐ๊ณผ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF585B69), + ), + ), + ), + ], + ), + ); + } + + Widget _buildResultsTable(double screenWidth, double screenHeight) { + final unrecognizedCount = _results.where((r) => r.isEmptyAnswer).length; + + return Container( + width: screenWidth * 0.9, + margin: EdgeInsets.symmetric(horizontal: screenWidth * 0.05), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '์ธ์‹ํ•˜์ง€ ๋ชปํ•œ ๋‹ต: ${unrecognizedCount.toString().padLeft(2, '0')}๊ฐœ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Color(0xFF585B69), + ), + ), + SizedBox(height: screenHeight * 0.01), + Container( + padding: EdgeInsets.symmetric( + horizontal: screenWidth * 0.047, + vertical: screenHeight * 0.017, + ), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildTableColumn( + '๋ฌธ์ œ ๋ฒˆํ˜ธ', + _results + .map((r) => r.displayNumber) + .toList(), // displayNumber ์‚ฌ์šฉ + const Color(0xFF585B69), + ), + Container( + width: 1, + height: screenHeight * 0.293, + color: const Color(0xFFE1E7ED), + margin: EdgeInsets.symmetric(horizontal: screenWidth * 0.087), + ), + _buildTableColumn( + '์ธ์‹ํ•œ ๋‹ต', + _results.map((r) => r.recognizedAnswer).toList(), + const Color(0xFF7F818E), + ), + Container( + width: 1, + height: screenHeight * 0.293, + color: const Color(0xFFE1E7ED), + margin: EdgeInsets.symmetric(horizontal: screenWidth * 0.087), + ), + _buildTableColumn( + '์ •๋‹ต ์—ฌ๋ถ€', + _results.map((r) => r.correctStatus).toList(), + const Color(0xFF7F818E), + highlightWrong: true, + ), + ], + ), + ), + ], + ), + ); + } + + Widget _buildTableColumn( + String header, + List items, + Color textColor, { + bool highlightWrong = false, + }) { + return Expanded( + child: Column( + children: [ + GestureDetector( + onTap: highlightWrong ? null : () {}, + child: Text( + header, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 12, + color: Color(0xFF585B69), + ), + textAlign: TextAlign.center, + ), + ), + const SizedBox(height: 8), + ...List.generate(items.length, (index) { + final isWrong = highlightWrong && items[index] == '์˜ค๋‹ต'; + return GestureDetector( + onTap: () { + if (_isSaving) return; + setState(() { + _selectedProblemIndex = index; + _isEditingAnswer = false; + _answerController.clear(); + }); + // ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ปฌ๋Ÿผ์—์„œ๋งŒ ์ด๋ฏธ์ง€ ๋กœ๋“œ + if (!highlightWrong) { + final result = _results[index]; + _loadSectionImage( + result.questionNumber, + result.subQuestionNumber, + ); + } + }, + child: Container( + margin: const EdgeInsets.only(bottom: 8), + child: Text( + items[index], + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: highlightWrong + ? FontWeight.w600 + : FontWeight.w500, + fontSize: 12, + color: isWrong ? const Color(0xFFFF4258) : textColor, + ), + textAlign: TextAlign.center, + ), + ), + ); + }), + ], + ), + ); + } + + Widget _buildProblemDetail(double screenWidth, double screenHeight) { + if (_selectedProblemIndex == null) return const SizedBox.shrink(); + + return Container( + width: screenWidth * 0.9, + margin: EdgeInsets.symmetric(horizontal: screenWidth * 0.05), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + '${_results[_selectedProblemIndex!].displayNumber}๋ฒˆ ๋ฌธ์ œ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Color(0xFF585B69), + ), + ), + const SizedBox(width: 10), + GestureDetector( + onTap: () { + setState(() { + _isEditingAnswer = !_isEditingAnswer; + if (_isEditingAnswer) { + _answerController.text = + _results[_selectedProblemIndex!].recognizedAnswer; + } + }); + }, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 3, + ), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(5), + ), + child: const Text( + '๋‹ต์•ˆ ์žฌ์ž…๋ ฅ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 11, + color: Color(0xFF585B69), + ), + ), + ), + ), + ], + ), + SizedBox(height: screenHeight * 0.013), + + // ๋ฌธ์ œ ์ด๋ฏธ์ง€ ํ‘œ์‹œ (๋„คํŠธ์›Œํฌ ์ด๋ฏธ์ง€) + Builder( + builder: (context) { + final result = _results[_selectedProblemIndex!]; + final cacheKey = result.subQuestionNumber == 0 + ? result.questionNumber.toString() + : '${result.questionNumber}-${result.subQuestionNumber}'; + + final imageUrl = _sectionImageUrls[cacheKey]; + final isLoading = _imageLoadingStates[cacheKey] == true; + final errorMessage = _imageErrors[cacheKey]; + + // ๋กœ๋”ฉ ์ค‘ + if (isLoading) { + return Container( + width: screenWidth * 0.9, + height: screenHeight * 0.3, + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Center(child: CircularProgressIndicator()), + ); + } + + // ์—๋Ÿฌ (์ด๋ฏธ์ง€ ์—†์Œ ๋˜๋Š” ๋กœ๋“œ ์‹คํŒจ) + if (errorMessage != null) { + return Container( + width: screenWidth * 0.9, + height: screenHeight * 0.3, + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.image_not_supported, + size: 48, + color: Color(0xFF999999), + ), + const SizedBox(height: 8), + Text( + errorMessage, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ], + ), + ), + ); + } + + // ์ด๋ฏธ์ง€ ํ‘œ์‹œ + if (imageUrl != null) { + return Container( + width: screenWidth * 0.9, + constraints: BoxConstraints(maxHeight: screenHeight * 0.3), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Image.network( + imageUrl, + fit: BoxFit.contain, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return const Center(child: CircularProgressIndicator()); + }, + errorBuilder: (context, error, stackTrace) { + return Container( + color: const Color(0xFFF8F9FA), + child: const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.image_not_supported, + size: 48, + color: Color(0xFF999999), + ), + SizedBox(height: 8), + Text( + '์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ], + ), + ), + ); + }, + ), + ), + ); + } + + // ์ด๋ฏธ์ง€๊ฐ€ ์•„์ง ๋กœ๋“œ๋˜์ง€ ์•Š์Œ (์ดˆ๊ธฐ ์ƒํƒœ) + return const SizedBox.shrink(); + }, + ), + + // ๋‹ต์•ˆ ์ž…๋ ฅ ํผ + if (_isEditingAnswer) ...[ + SizedBox(height: screenHeight * 0.01), + Container( + width: screenWidth * 0.9, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFAC5BF8), width: 2), + borderRadius: BorderRadius.circular(5), + ), + child: Row( + children: [ + Expanded( + child: TextField( + controller: _answerController, + decoration: const InputDecoration( + hintText: '๋‹ต์•ˆ์„ ์ž…๋ ฅํ•˜์„ธ์š”', + border: InputBorder.none, + hintStyle: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF585B69), + ), + ), + ), + GestureDetector( + onTap: _updateAnswer, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF636ACF)], + ), + borderRadius: BorderRadius.circular(4), + ), + child: const Text( + '์ˆ˜์ •', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 12, + color: Colors.white, + ), + ), + ), + ), + ], + ), + ), + ], + ], + ), + ); + } + +} diff --git a/frontend/lib/screens/grading_history/grading_history_page.dart b/frontend/lib/screens/grading_history/grading_history_page.dart new file mode 100644 index 0000000..734e2aa --- /dev/null +++ b/frontend/lib/screens/grading_history/grading_history_page.dart @@ -0,0 +1,443 @@ +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import '../../widgets/app_header.dart'; +import '../../widgets/app_header_title.dart'; +import '../../widgets/back_button.dart'; +import '../../theme/app_theme.dart'; +import '../../services/auth_service.dart'; +import '../../services/academy_service.dart'; +import '../../services/grading_history_repository_impl.dart'; +import '../../domain/grading_history/grading_history_entity.dart'; +import '../../config/app_dependencies.dart'; +import 'edit_grading_result_page.dart'; +import 'models/grading_history_item.dart'; +import '../../utils/app_logger.dart'; +import 'dart:developer' as developer; + +/// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ํŽ˜์ด์ง€ +/// ์‚ฌ์šฉ์ž๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ์ฑ„์ ํ•œ ๋ชจ๋“  ๊ธฐ๋ก์„ ์‹œ๊ฐ„์ˆœ์œผ๋กœ ํ‘œ์‹œํ•˜๋Š” ํŽ˜์ด์ง€ +/// +/// ๊ตฌ์„ฑ: +/// 1. ํ—ค๋”: "์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ" ํƒ€์ดํ‹€ +/// 2. ์ฑ„์  ๊ธฐ๋ก ๋ชฉ๋ก: ๋‚ ์งœ๋ณ„ ๊ทธ๋ฃนํ•‘, ๋ฌธ์ œ์ง‘๋ช…, ํด๋ž˜์Šค๋ช…, ํŽ˜์ด์ง€ ๋ฒ”์œ„, ์ฑ„์  ์‹œ๊ฐ„ ๋“ฑ +class GradingHistoryPage extends StatefulWidget { + const GradingHistoryPage({super.key}); + + @override + State createState() => _GradingHistoryPageState(); +} + +class _GradingHistoryPageState extends State { + bool _isLoading = false; + List _historyItems = []; + String? _errorMessage; + + // DI + final GetIt _getIt = GetIt.instance; + + // Services (DI์—์„œ ์ฃผ์ž…) + late final AuthService _authService; + late final AcademyService _academyService; + late final GradingHistoryRepositoryImpl _repository; + + @override + void initState() { + super.initState(); + _authService = _getIt(); + _academyService = _getIt(); + _repository = _getIt(); + _loadGradingHistory(); + } + + /// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + Future _loadGradingHistory() async { + if (!mounted) return; + + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + // 1. userId๋กœ academyUserIds ์กฐํšŒ + final userId = await _authService.getUserId(); + if (userId == null) { + throw Exception('์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + if (!mounted) return; + + final academies = await _academyService.getUserAcademies(userId); + final academyUserIds = academies + .where((a) => a.registerStatus == 'Y') + .map((a) => a.academy_user_id) + .whereType() + .toList(); + + if (academyUserIds.isEmpty) { + if (!mounted) return; + setState(() { + _historyItems = []; + _isLoading = false; + }); + return; + } + + // 2. Repository ํ˜ธ์ถœ (Map> ๋ฐ˜ํ™˜) + final historiesMap = await _repository + .getGradingHistoriesByAcademyUserIds(academyUserIds); + + if (!mounted) return; + + // 3. Map์„ flat ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜ + final allEntities = []; + historiesMap.values.forEach((entities) { + allEntities.addAll(entities); + }); + + // 4. ๋‚ ์งœ์ˆœ ์ •๋ ฌ (์ตœ์‹ ์ˆœ) - UI ๋ ˆ์ด์–ด์—์„œ ์ฒ˜๋ฆฌ + allEntities.sort((a, b) => b.gradingDate.compareTo(a.gradingDate)); + + // 5. UI ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ + final items = allEntities + .map((entity) => GradingHistoryItem.fromEntity(entity)) + .toList(); + + if (!mounted) return; + + setState(() { + _historyItems = items; + _isLoading = false; + }); + } catch (e, stack) { + // ์ƒ์„ธ ๋กœ๊ทธ๋Š” appLog/developer.log๋กœ๋งŒ ๋‚จ๊น€ + appLog('[grading_history:grading_history_page] load error: $e\n$stack'); + developer.log('โŒ [GradingHistoryPage] load error: $e\n$stack'); + + if (!mounted) return; + + setState(() { + // ์‚ฌ์šฉ์ž์šฉ ๊ฐ„๋‹จํ•œ ๋ฉ”์‹œ์ง€๋งŒ ํ‘œ์‹œ + _errorMessage = '์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'; + _isLoading = false; + }); + } + } + + /// ๋‚ ์งœ๋ณ„๋กœ ๊ทธ๋ฃนํ•‘ + Map> _groupByDate( + List items, + ) { + final Map> grouped = {}; + + for (final item in items) { + final dateKey = _formatDateKey(item.gradingDate); + if (!grouped.containsKey(dateKey)) { + grouped[dateKey] = []; + } + grouped[dateKey]!.add(item); + } + + // ๊ฐ ๋‚ ์งœ ๊ทธ๋ฃน ๋‚ด์—์„œ ์‹œ๊ฐ„์ˆœ ์ •๋ ฌ (์ตœ์‹ ์ˆœ) + for (final key in grouped.keys) { + grouped[key]!.sort((a, b) => b.gradingDate.compareTo(a.gradingDate)); + } + + return grouped; + } + + /// ๋‚ ์งœ ํ‚ค ํฌ๋งทํŒ… (์˜ˆ: "2025๋…„ 11์›” 29์ผ") + String _formatDateKey(DateTime date) { + return '${date.year}๋…„ ${date.month}์›” ${date.day}์ผ'; + } + + /// ๋‚ ์งœ ํ—ค๋” ํฌ๋งทํŒ… + String _formatDateHeader(DateTime date) { + final now = DateTime.now(); + final today = DateTime(now.year, now.month, now.day); + final targetDate = DateTime(date.year, date.month, date.day); + + if (targetDate == today) { + return '์˜ค๋Š˜'; + } else if (targetDate == today.subtract(const Duration(days: 1))) { + return '์–ด์ œ'; + } else { + return _formatDateKey(date); + } + } + + /// ์‹œ๊ฐ„์„ ํ•œ๊ตญ์–ด ์˜ค์ „/์˜คํ›„ ํ˜•์‹์œผ๋กœ ํฌ๋งทํŒ… + /// ์˜ˆ: "์˜ค์ „ 9:32", "์˜คํ›„ 2:15" + String _formatTimeToKoreanAmPm(DateTime date) { + final isAm = date.hour < 12; + final hour12 = date.hour % 12 == 0 ? 12 : date.hour % 12; + final minute = date.minute.toString().padLeft(2, '0'); + final prefix = isAm ? '์˜ค์ „' : '์˜คํ›„'; + return '$prefix $hour12:$minute'; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: AppTheme.whiteColor, + body: SafeArea( + child: Column( + children: [ + // ํ—ค๋” + AppHeader( + leading: const CustomBackButton(), + title: const AppHeaderTitle('์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ'), + ), + + // ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ๋ชฉ๋ก + Expanded( + child: _isLoading + ? const Center( + child: CircularProgressIndicator( + color: AppTheme.primaryColor, + ), + ) + : _errorMessage != null + ? _buildErrorState() + : _historyItems.isEmpty + ? _buildEmptyState() + : _buildHistoryList(), + ), + ], + ), + ), + ); + } + + /// ์—๋Ÿฌ ์ƒํƒœ ์œ„์ ฏ + Widget _buildErrorState() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error_outline, size: 64, color: AppTheme.errorColor), + const SizedBox(height: 16), + Text( + '์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค', + style: Theme.of( + context, + ).textTheme.bodyLarge?.copyWith(color: AppTheme.textPrimary), + ), + const SizedBox(height: 8), + Text( + _errorMessage ?? '์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜', + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: AppTheme.textSecondary), + textAlign: TextAlign.center, + ), + const SizedBox(height: 24), + ElevatedButton( + onPressed: () { + _loadGradingHistory(); + }, + child: const Text('๋‹ค์‹œ ์‹œ๋„'), + ), + ], + ), + ); + } + + /// ๋นˆ ์ƒํƒœ ์œ„์ ฏ + Widget _buildEmptyState() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.history, size: 64, color: AppTheme.textSecondary), + const SizedBox(height: 16), + Text( + '์ฑ„์  ๊ธฐ๋ก์ด ์—†์Šต๋‹ˆ๋‹ค', + style: Theme.of( + context, + ).textTheme.bodyLarge?.copyWith(color: AppTheme.textSecondary), + ), + ], + ), + ); + } + + /// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ๋ฆฌ์ŠคํŠธ + Widget _buildHistoryList() { + final grouped = _groupByDate(_historyItems); + final sortedDates = grouped.keys.toList() + ..sort((a, b) { + // ๋‚ ์งœ ๋ฌธ์ž์—ด์„ ํŒŒ์‹ฑํ•ด์„œ ๋น„๊ต (์ตœ์‹ ์ˆœ) + final dateA = _parseDateKey(a); + final dateB = _parseDateKey(b); + return dateB.compareTo(dateA); + }); + + return ListView.builder( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + itemCount: sortedDates.length, + itemBuilder: (context, index) { + final dateKey = sortedDates[index]; + final items = grouped[dateKey]!; + final firstItem = items.first; + final dateHeader = _formatDateHeader(firstItem.gradingDate); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ๋‚ ์งœ ํ—ค๋” + Padding( + padding: EdgeInsets.only(bottom: 12, top: index > 0 ? 24 : 0), + child: Text( + dateHeader, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: AppTheme.textPrimary, + fontWeight: FontWeight.w600, + ), + ), + ), + + // ํ•ด๋‹น ๋‚ ์งœ์˜ ์ฑ„์  ๊ธฐ๋ก๋“ค + ...items.map((item) => _buildHistoryItem(item)), + ], + ); + }, + ); + } + + /// ๋‚ ์งœ ํ‚ค ํŒŒ์‹ฑ + DateTime _parseDateKey(String dateKey) { + // "2025๋…„ 11์›” 29์ผ" ํ˜•์‹์„ ํŒŒ์‹ฑ + try { + final parts = dateKey + .replaceAll('๋…„', '') + .replaceAll('์›”', '') + .replaceAll('์ผ', '') + .trim() + .split(' '); + if (parts.length >= 3) { + final year = int.parse(parts[0]); + final month = int.parse(parts[1]); + final day = int.parse(parts[2]); + return DateTime(year, month, day); + } + } catch (e) { + // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ํ˜„์žฌ ๋‚ ์งœ ๋ฐ˜ํ™˜ + } + return DateTime.now(); + } + + /// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ์•„์ดํ…œ ์œ„์ ฏ + Widget _buildHistoryItem(GradingHistoryItem item) { + final screenWidth = MediaQuery.of(context).size.width; + + return GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => EditGradingResultPage( + studentResponseId: item.studentResponseId, + academyUserId: item.academyUserId, + getStudentAnswersUseCase: + AppDependencies.getStudentAnswersForResponseUseCase, + updateStudentAnswersUseCase: + AppDependencies.updateStudentAnswersUseCase, + getSectionImageUseCase: + AppDependencies.getSectionImageUseCase, + updateSingleStudentAnswerUseCase: + AppDependencies.updateSingleStudentAnswerUseCase, + ), + ), + ); + }, + child: Container( + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: AppTheme.backgroundColor, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + // ์™ผ์ชฝ: ์ฑ… ํ‘œ์ง€ ์ด๋ฏธ์ง€ + Container( + width: screenWidth * 0.15, // Figma ๊ธฐ์ค€ ์ƒ๋Œ€ ํฌ๊ธฐ + height: screenWidth * 0.15, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: AppTheme.textSecondary.withOpacity(0.1), + ), + child: + item.bookCoverImageUrl != null && + item.bookCoverImageUrl!.startsWith('http') + ? ClipRRect( + borderRadius: BorderRadius.circular(4), + child: Image.network( + item.bookCoverImageUrl!, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Icon( + Icons.book, + color: AppTheme.textSecondary, + ); + }, + ), + ) + : Icon(Icons.book, color: AppTheme.textSecondary), + ), + const SizedBox(width: 12), + + // ๊ฐ€์šด๋ฐ: 4์ค„ ์ •๋ณด + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 1. workbookName + Text( + item.workbookName, + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: AppTheme.textPrimary, + fontWeight: FontWeight.w600, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 4), + // 2. className + Text( + item.className ?? 'ํด๋ž˜์Šค ์ •๋ณด ์—†์Œ', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: AppTheme.textSecondary, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 4), + // 3. pageRange + Text( + '${item.pageRange}ํŽ˜์ด์ง€', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: AppTheme.textSecondary, + ), + ), + const SizedBox(height: 4), + // 4. gradingDate (์˜ค์ „/์˜คํ›„ ํ˜•์‹) + Text( + _formatTimeToKoreanAmPm(item.gradingDate), + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: AppTheme.textSecondary, + ), + ), + ], + ), + ), + + // ์˜ค๋ฅธ์ชฝ: chevron_right ์•„์ด์ฝ˜ + Icon(Icons.chevron_right, color: AppTheme.textSecondary, size: 24), + ], + ), + ), + ); + } +} diff --git a/frontend/lib/screens/grading_history/models/grading_history_item.dart b/frontend/lib/screens/grading_history/models/grading_history_item.dart new file mode 100644 index 0000000..26e8d2c --- /dev/null +++ b/frontend/lib/screens/grading_history/models/grading_history_item.dart @@ -0,0 +1,44 @@ +import '../../../../domain/grading_history/grading_history_entity.dart'; + +/// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ UI ๋ชจ๋ธ +/// +/// ๊ธฐ์กด grading_history_page.dart์˜ GradingHistoryItem์„ ์™„์ „ํžˆ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค. +class GradingHistoryItem { + final int studentResponseId; + final int academyUserId; // ์ถ”๊ฐ€ + final String workbookName; // bookName + final String? className; + final int startPage; + final int endPage; + final String? bookCoverImageUrl; + final DateTime gradingDate; + + /// ํŽ˜์ด์ง€ ๋ฒ”์œ„ ๋ฌธ์ž์—ด (์˜ˆ: "14-20", start == end์ด๋ฉด "14"๋งŒ ํ‘œ์‹œ) + String get pageRange => + startPage == endPage ? '$endPage' : '$startPage-$endPage'; + + const GradingHistoryItem({ + required this.studentResponseId, + required this.academyUserId, // ์ถ”๊ฐ€ + required this.workbookName, + this.className, + required this.startPage, + required this.endPage, + this.bookCoverImageUrl, + required this.gradingDate, + }); + + /// ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์—์„œ UI ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ + factory GradingHistoryItem.fromEntity(GradingHistoryEntity entity) { + return GradingHistoryItem( + studentResponseId: entity.studentResponseId, + academyUserId: entity.academyUserId, // ์ถ”๊ฐ€ + workbookName: entity.bookName ?? '์ฑ… ์ด๋ฆ„ ์—†์Œ', + className: entity.className, + startPage: entity.startPage, + endPage: entity.endPage, + bookCoverImageUrl: entity.bookCoverImageUrl, + gradingDate: entity.gradingDate, + ); + } +} diff --git a/frontend/lib/screens/grading_history/models/grading_result.dart b/frontend/lib/screens/grading_history/models/grading_result.dart new file mode 100644 index 0000000..473ab1d --- /dev/null +++ b/frontend/lib/screens/grading_history/models/grading_result.dart @@ -0,0 +1,53 @@ +import '../../../domain/student_answer/student_answer_entity.dart'; + +/// UI ์ „์šฉ ๋ชจ๋ธ (EditGradingResultPage์—์„œ ์‚ฌ์šฉ) +class GradingResult { + final int questionNumber; + final int subQuestionNumber; + final int studentAnswerId; // ์ˆ˜์ • ์‹œ ํ•„์š” + final int? chapterId; // ๋‹จ์ผ ์ˆ˜์ • API ํ˜ธ์ถœ ์‹œ ์‚ฌ์šฉ + String recognizedAnswer; // ์ˆ˜์ • ๊ฐ€๋Šฅ + final String correctStatus; // '์ •๋‹ต' ๋˜๋Š” '์˜ค๋‹ต' + // ์ฐธ๊ณ : ๋‹ต์•ˆ ์ˆ˜์ • ์‹œ ์„œ๋ฒ„์—์„œ ์ •๋‹ต ์—ฌ๋ถ€๋ฅผ ์žฌ๊ณ„์‚ฐํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + + GradingResult({ + required this.questionNumber, + required this.subQuestionNumber, + required this.studentAnswerId, + required this.chapterId, + required this.recognizedAnswer, + required this.correctStatus, + }); + + /// ๋ฌธ์ œ ๋ฒˆํ˜ธ ํ‘œ์‹œ ๋ฌธ์ž์—ด + /// + /// ์˜ˆ: questionNumber=1, subQuestionNumber=0 โ†’ "1" + /// questionNumber=1, subQuestionNumber=2 โ†’ "1-2" + String get displayNumber { + if (subQuestionNumber == 0) { + return questionNumber.toString(); + } + return '$questionNumber-$subQuestionNumber'; + } + + /// answer๊ฐ€ ๋น„์–ด์žˆ๋Š”์ง€ ํ™•์ธ (์ธ์‹ ์‹คํŒจ ์—ฌ๋ถ€ ํŒ๋‹จ์šฉ) + /// + /// getter๋กœ ๊ตฌํ˜„ํ•˜์—ฌ recognizedAnswer ๋ณ€๊ฒฝ ์‹œ ์ž๋™์œผ๋กœ ๋ฐ˜์˜๋จ + /// UI ๋ ˆ์ด์–ด์—์„œ๋Š” ๊ณต๋ฐฑ๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ๋„ ๋นˆ ๊ฐ’์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. + bool get isEmptyAnswer => recognizedAnswer.trim().isEmpty; + + /// StudentAnswerEntity์—์„œ UI ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ + factory GradingResult.fromEntity(StudentAnswerEntity entity) { + // ์ •๋‹ต ์—ฌ๋ถ€: is_correct์— ๋”ฐ๋ผ + final correctStatus = entity.isCorrect == true ? '์ •๋‹ต' : '์˜ค๋‹ต'; + + return GradingResult( + questionNumber: entity.questionNumber, + subQuestionNumber: entity.subQuestionNumber, + studentAnswerId: entity.studentAnswerId, + chapterId: entity.chapterId, + recognizedAnswer: entity.answer, + correctStatus: correctStatus, + ); + } +} diff --git a/frontend/lib/screens/home_page.dart b/frontend/lib/screens/home_page.dart new file mode 100644 index 0000000..da74d06 --- /dev/null +++ b/frontend/lib/screens/home_page.dart @@ -0,0 +1,1445 @@ +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import '../routes/app_routes.dart'; +import '../widgets/app_header.dart'; +import '../widgets/app_header_menu_button.dart'; +import '../widgets/continuous_learning_widget_v2.dart'; +import '../services/assessment_repository.dart'; +import '../services/academy_service.dart'; +import '../services/auth_service.dart'; +import '../services/daily_learning_service.dart'; +import '../domain/learning/get_monthly_learning_status_use_case.dart'; +import '../models/assessment.dart'; +import '../utils/academy_utils.dart'; +import '../utils/app_logger.dart'; +import 'dart:developer' as developer; + +/// ํ™ˆ ํ™”๋ฉด - ๊ฐœ์„ ๋œ UI/UX +/// +/// ์ฃผ์š” ๊ธฐ๋Šฅ: +/// 1. ์—ฐ์†ํ•™์Šต ์œ„์ ฏ - ๋‚ ์งœ ๊ธฐ๋ฐ˜ ์Šค์™€์ดํ”„ ์บ˜๋ฆฐ๋” +/// 2. ์˜ค๋Š˜์˜ ์ˆ™์ œ - ๋ฌธ์ œ์ง‘ ํ‘œ์ง€ + ์ƒ์„ธ ์ •๋ณด ์นด๋“œ +/// 3. ๋ˆ„์  ํ•™์Šต๋Ÿ‰ - 2๋‹จ๊ณ„ ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ” + +/// ํ•™์› ์ƒํƒœ enum +enum AcademyState { + loading, // ์ดˆ๊ธฐํ™” ์ค‘ + none, // ํ•™์› ์—†์Œ + ready, // ํ•™์› ์žˆ์Œ, ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์™„๋ฃŒ + error, // ์—๋Ÿฌ ๋ฐœ์ƒ +} + +class HomePage extends StatefulWidget { + const HomePage({super.key}); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State { + final GetIt _getIt = GetIt.instance; + + late final AssessmentRepository _assessmentRepository; + late final AcademyService _academyService; + late final AuthService _authService; + final Map> _dateAssessments = {}; + DateTime _selectedDate = DateTime.now(); + bool _isLoadingAssessments = false; + + // UseCase ์ธ์Šคํ„ด์Šค (DI์—์„œ ์ฃผ์ž…) + late final GetMonthlyLearningStatusUseCase _monthlyStatusUseCase; + + // ํ•™์› ์ƒํƒœ ๊ด€๋ฆฌ (enum ์‚ฌ์šฉ) + AcademyState _academyState = AcademyState.loading; + String _academyName = 'ํ•™์›'; + List _registeredAcademies = []; // ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์› ๋ชฉ๋ก + + // ์„ ํƒ๋œ ๋‚ ์งœ์˜ ํ•™์Šต ๋ฐ์ดํ„ฐ + DailyLearningResult? _selectedDateLearningResult; + bool _isLoadingSelectedDateLearning = false; + + @override + void initState() { + super.initState(); + _assessmentRepository = _getIt(); + _academyService = _getIt(); + _authService = _getIt(); + _monthlyStatusUseCase = _getIt(); + _academyService.defaultAcademyVersion.addListener(_onDefaultAcademyChanged); + // ๋‹จ์ผ ์ง„์ž…์ ๋งŒ ํ˜ธ์ถœ + _initializeAcademyData(forceRefresh: false); + } + + @override + void dispose() { + _academyService.defaultAcademyVersion.removeListener( + _onDefaultAcademyChanged, + ); + super.dispose(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ ๋Œ์•„์˜ฌ ๋•Œ ๊ฐ•์ œ ์ƒˆ๋กœ๊ณ ์นจ + _initializeAcademyData(forceRefresh: true); + } + + /// ์˜ค๋Š˜์˜ ์ˆ™์ œ ์ •๋ณด ๋™๊ธฐํ™” + /// ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ ๋Œ์•„์˜ฌ ๋•Œ ์„ ํƒ๋œ ๋‚ ์งœ์˜ Assessment ๋ฐ์ดํ„ฐ๋ฅผ ์ตœ์‹  ์ •๋ณด๋กœ ๊ฐฑ์‹  + Future _synchronizeTodayHomework() async { + if (_academyState != AcademyState.ready) return; + + // _loadDateData๋ฅผ forceRefresh๋กœ ํ˜ธ์ถœํ•˜์—ฌ ์ตœ์‹  ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ + await _loadDateData(_selectedDate, forceRefresh: true); + } + + /// ์™ธ๋ถ€์—์„œ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•œ ์ƒˆ๋กœ๊ณ ์นจ ๋ฉ”์„œ๋“œ + /// ํƒญ ์ „ํ™˜ ์‹œ MainNavigationPage์—์„œ ํ˜ธ์ถœ + void refresh() { + developer.log('๐Ÿ”„ [HomePage] refresh() called from external'); + _initializeAcademyData(forceRefresh: true); + } + + /// ์™ธ๋ถ€์—์„œ ํŠน์ • ๋‚ ์งœ๋ฅผ ์—ด๋„๋ก ์š”์ฒญํ•  ๋•Œ ์‚ฌ์šฉ + void focusOnDate(DateTime date) { + developer.log('๐ŸŽฏ [HomePage] focusOnDate ์š”์ฒญ: $date'); + final normalized = DateTime(date.year, date.month, date.day); + setState(() { + _selectedDate = normalized; + }); + _loadDateData(normalized); + } + + void _onDefaultAcademyChanged() { + if (!mounted) return; + developer.log('๐Ÿ” [HomePage] ๋””ํดํŠธ ํ•™์› ๋ณ€๊ฒฝ ๊ฐ์ง€, ๋ฐ์ดํ„ฐ ์žฌ์ดˆ๊ธฐํ™”'); + _dateAssessments.clear(); + _initializeAcademyData(forceRefresh: true); + } + + /// ํ•™์› ๊ด€๋ จ ์ „์ฒด ์ดˆ๊ธฐํ™” (๋‹จ์ผ ์ง„์ž…์ ) + /// + /// ๋ชจ๋“  ํ•™์› ๊ด€๋ จ ๋กœ์ง์˜ ์ง„์ž…์ : + /// - initState์—์„œ ํ˜ธ์ถœ + /// - didChangeDependencies์—์„œ ํ˜ธ์ถœ + /// - ์ˆ˜๋™ ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ํ˜ธ์ถœ + Future _initializeAcademyData({bool forceRefresh = false}) async { + // 1. ์ƒํƒœ ์ดˆ๊ธฐํ™” (ํ•ญ์ƒ ๋ช…์‹œ์ ์œผ๋กœ) + if (mounted) { + setState(() { + _academyState = AcademyState.loading; + }); + } + + try { + // 2. ํ•™์› ๋ชฉ๋ก ๋กœ๋“œ (API or ์บ์‹œ) + List? academies; + + if (forceRefresh) { + // API ํ˜ธ์ถœ + final userId = await _authService.getUserId(); + if (userId == null) { + developer.log('โš ๏ธ ์‚ฌ์šฉ์ž ID๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + // ์‚ฌ์šฉ์ž ID ์—†์Œ โ†’ ์บ์‹œ์—์„œ ๋กœ๋“œ + academies = await _academyService.loadAcademiesFromCache(); + } else { + try { + academies = await _academyService.getUserAcademies(userId); + } catch (e) { + developer.log('โš ๏ธ API ํ˜ธ์ถœ ์‹คํŒจ, ์บ์‹œ์—์„œ ๋กœ๋“œ ์‹œ๋„: $e'); + academies = await _academyService.loadAcademiesFromCache(); + } + } + } else { + // ์บ์‹œ์—์„œ๋งŒ ๋กœ๋“œ + academies = await _academyService.loadAcademiesFromCache(); + } + + // 3. early return ์‹œ ์ƒํƒœ ์ •๋ฆฌ (๋ช…์‹œ์ ์œผ๋กœ) + if (academies == null) { + if (mounted) { + setState(() { + _academyState = AcademyState.none; + _registeredAcademies = []; + }); + } + return; + } + + // 4. ํ•™์› ๋ชฉ๋ก ์ฒ˜๋ฆฌ + await _processAcademyList(academies, shouldSaveCache: forceRefresh); + } catch (e) { + developer.log('โŒ ํ•™์› ์ •๋ณด ์ดˆ๊ธฐํ™” ์‹คํŒจ: $e'); + if (mounted) { + setState(() { + _academyState = AcademyState.error; + _registeredAcademies = []; + }); + + // ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('ํ•™์› ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: ${e.toString()}'), + backgroundColor: Colors.red, + action: SnackBarAction( + label: '๋‹ค์‹œ ์‹œ๋„', + onPressed: () => _initializeAcademyData(forceRefresh: true), + ), + ), + ); + } + } + } + + /// ํ•™์› ๋ชฉ๋ก ์ฒ˜๋ฆฌ (์บ์‹œ ์ €์žฅ + ํ•„ํ„ฐ๋ง + ๋””ํดํŠธ ํ•™์› ์„ค์ •) + /// + /// [academies]: ์ „์ฒด ํ•™์› ๋ชฉ๋ก (registerStatus 'Y'/'P' ๋ชจ๋‘ ํฌํ•จ) + /// [shouldSaveCache]: ์บ์‹œ์— ์ €์žฅํ• ์ง€ ์—ฌ๋ถ€ (API์—์„œ ๊ฐ€์ ธ์˜จ ๊ฒฝ์šฐ๋งŒ true) + Future _processAcademyList( + List academies, { + required bool shouldSaveCache, + }) async { + // 1. ์บ์‹œ ์ €์žฅ (mounted์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์‹คํ–‰) + if (shouldSaveCache) { + await _academyService.saveAcademiesToCache(academies); + } + + // 2. mounted ์ฒดํฌ (UI ์—…๋ฐ์ดํŠธ ์ „์—๋งŒ) + if (!mounted) return; + + // 3. ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์›๋งŒ ํ•„ํ„ฐ๋ง + final registeredAcademies = academies + .where((academy) => academy.registerStatus == 'Y') + .toList(); + + setState(() { + _registeredAcademies = registeredAcademies; + }); + + // 4. ๋””ํดํŠธ ํ•™์› ์„ค์ • + if (registeredAcademies.isNotEmpty) { + await _setupDefaultAcademy(registeredAcademies); + } else { + // ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์›์ด ์—†์Œ + setState(() { + _academyState = AcademyState.none; + }); + } + } + + /// ๋””ํดํŠธ ํ•™์› ์„ค์ • ๋ฐ ๊ด€๋ จ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + /// + /// [academies]: ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์› ๋ชฉ๋ก (registerStatus == 'Y') + Future _setupDefaultAcademy(List academies) async { + if (!mounted) return; + + // 1. ๋””ํดํŠธ ํ•™์› ์„ ํƒ + final defaultAcademyCode = await _academyService.selectDefaultAcademyAsync( + academies, + ); + + if (defaultAcademyCode == null) { + // ๋””ํดํŠธ ํ•™์›์„ ์„ ํƒํ•  ์ˆ˜ ์—†์Œ (๋กœ์ง ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ) + developer.log('โš ๏ธ ๋””ํดํŠธ ํ•™์› ์„ ํƒ ์‹คํŒจ: ํ•™์› ๋ชฉ๋ก์€ ์žˆ์ง€๋งŒ ์„ ํƒํ•  ์ˆ˜ ์—†์Œ'); + if (mounted) { + setState(() { + _academyState = AcademyState.error; + // _registeredAcademies๋Š” ์œ ์ง€ (๋””๋ฒ„๊น…์šฉ) + }); + } + return; + } + + // 2. ๋””ํดํŠธ ํ•™์› ์ €์žฅ + await _academyService.saveDefaultAcademyCode(defaultAcademyCode); + + // 3. ํ•™์›๋ช… ์„ค์ • (๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ฐพ๊ธฐ) + final academy = academies.firstWhere( + (a) => a.academyCode == defaultAcademyCode, + orElse: () => academies.first, // fallback + ); + + if (mounted) { + setState(() { + _academyName = academy.academyName; + _academyState = AcademyState.ready; + }); + + // 4. Assessment ๋ฐ์ดํ„ฐ ๋กœ๋“œ + await _loadRemainingMonthData(); + + // 5. ์„ ํƒ๋œ ๋‚ ์งœ์˜ ํ•™์Šต ๋ฐ์ดํ„ฐ ๋กœ๋“œ + await _loadSelectedDateLearningData(_selectedDate); + + // 6. ์˜ค๋Š˜์˜ ์ˆ™์ œ ์ •๋ณด ๋™๊ธฐํ™” (์ตœ์‹  ์ •๋ณด๋กœ ๊ฐฑ์‹ ) + await _synchronizeTodayHomework(); + } + } + + // _loadAcademyName, _hasAcademy, _isCheckingAcademy๋Š” + // ์ด์ „ ๊ตฌ์กฐ์—์„œ ์‚ฌ์šฉ๋˜์—ˆ์œผ๋‚˜ ํ˜„์žฌ ๋กœ์ง์—์„œ๋Š” ์‚ฌ์šฉ๋˜์ง€ ์•Š์•„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค. + + /// ์ด๋ฒˆ ๋‹ฌ๊ณผ ๋‹ค์Œ ๋‹ฌ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + /// + /// ๋ณ€๊ฒฝ: ์›” ๋‹จ์œ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋„๋ก ์ˆ˜์ • + Future _loadRemainingMonthData() async { + if (_isLoadingAssessments) return; + + // ํ•™์›์ด ์—†์œผ๋ฉด Assessment ํ˜ธ์ถœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ + if (_academyState != AcademyState.ready) { + developer.log('โš ๏ธ ํ•™์›์ด ์—†์–ด Assessment ๋ฐ์ดํ„ฐ ๋กœ๋“œ๋ฅผ ๊ฑด๋„ˆ๋œ€'); + return; + } + + setState(() { + _isLoadingAssessments = true; + }); + + try { + final userAcademyId = await getUserAcademyId( + academyService: _academyService, + registeredAcademies: _registeredAcademies, + ); + + // ํ•™์› ID๊ฐ€ ์—†์œผ๋ฉด ๊ฑด๋„ˆ๋›ฐ๊ธฐ + if (userAcademyId == null) { + developer.log('โš ๏ธ ํ•™์› ID๊ฐ€ ์—†์–ด Assessment ๋ฐ์ดํ„ฐ ๋กœ๋“œ๋ฅผ ๊ฑด๋„ˆ๋œ€'); + return; + } + + final now = DateTime.now(); + + // ํ˜„์žฌ ๋‹ฌ์˜ ์ฒซ ๋ฒˆ์งธ ๋‚  (UTC) + final currentMonthStart = DateTime.utc(now.year, now.month, 1); + + // ์ด์ „/๋‹ค์Œ ๋‹ฌ ๊ณ„์‚ฐ (set ํ•จ์ˆ˜ ์‚ฌ์šฉ) + final previousMonthStart = _getPreviousMonth(currentMonthStart); + final nextMonthStart = _getNextMonth(currentMonthStart); + + // ์บ์‹œ ์ดˆ๊ธฐํ™” (๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ์™€ SharedPreferences) + await _assessmentRepository.clearAll(); + developer.log('๐Ÿ”„ [HomePage] Assessment ์บ์‹œ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ'); + + // ์ด์ „ ๋‹ฌ, ํ˜„์žฌ ๋‹ฌ, ๋‹ค์Œ ๋‹ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ‘๋ ฌ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ + final results = await Future.wait([ + _assessmentRepository.getForMonth( + academyId: userAcademyId, + dateTime: previousMonthStart, + ), + _assessmentRepository.getForMonth( + academyId: userAcademyId, + dateTime: currentMonthStart, + ), + _assessmentRepository.getForMonth( + academyId: userAcademyId, + dateTime: nextMonthStart, + ), + ]); + + // ์„ธ ๋‹ฌ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•ฉ์น˜๊ธฐ + setState(() { + _dateAssessments.addAll(results[0]); // ์ด์ „ ๋‹ฌ + _dateAssessments.addAll(results[1]); // ํ˜„์žฌ ๋‹ฌ + _dateAssessments.addAll(results[2]); // ๋‹ค์Œ ๋‹ฌ + }); + + developer.log('โœ… [HomePage] ์ด์ „/์ด๋ฒˆ/๋‹ค์Œ ๋‹ฌ Assessment ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์™„๋ฃŒ'); + developer.log('๐Ÿ“Š [HomePage] ํ˜„์žฌ _dateAssessments ์ƒํƒœ:'); + + _dateAssessments.forEach((date, assessments) { + developer.log('[HomePage] - $date: ${assessments.length}๊ฐœ ๊ณผ์ œ'); + for (var assessment in assessments) { + developer.log( + '[HomePage] โ€ข ${assessment.assessName} (${assessment.assessClass}) - ์ƒํƒœ: ${assessment.assessStatus}', + ); + } + }); + } catch (e) { + developer.log('โš ๏ธ ์ด๋ฒˆ ๋‹ฌ ๋‚จ์€ ๋‚ ์งœ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ: $e'); + } finally { + setState(() { + _isLoadingAssessments = false; + }); + } + } + + /// ๋‹ค์Œ ๋‹ฌ ๊ณ„์‚ฐ ํ—ฌํผ ํ•จ์ˆ˜ + DateTime _getNextMonth(DateTime dateTime) { + if (dateTime.month == 12) { + return DateTime.utc(dateTime.year + 1, 1, 1); + } else { + return DateTime.utc(dateTime.year, dateTime.month + 1, 1); + } + } + + /// ์ด์ „ ๋‹ฌ ๊ณ„์‚ฐ ํ—ฌํผ ํ•จ์ˆ˜ + DateTime _getPreviousMonth(DateTime dateTime) { + if (dateTime.month == 1) { + return DateTime.utc(dateTime.year - 1, 12, 1); + } else { + return DateTime.utc(dateTime.year, dateTime.month - 1, 1); + } + } + + /// ๋‚ ์งœ ์„ ํƒ ์‹œ ํ˜ธ์ถœ + /// ์—ฐ์†ํ•™์Šต ์œ„์ ฏ์—์„œ ๋‚ ์งœ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค + void _onDateSelected(DateTime date) { + final dateStr = _formatDate(date); + appLog('[continuous_learning:home_page] ๋‚ ์งœ ์„ ํƒ๋จ - $dateStr (์—ฐ์†ํ•™์Šต ์œ„์ ฏ์—์„œ ํด๋ฆญ)'); + + setState(() { + _selectedDate = date; + }); + + // ๋‚ ์งœ ์„ ํƒ ์‹œ ํ•ญ์ƒ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋กœ ๋™๊ธฐํ™” + _loadDateData(date, forceRefresh: true); + + // ์„ ํƒ๋œ ๋‚ ์งœ์˜ ํ•™์Šต ๋ฐ์ดํ„ฐ ๋กœ๋“œ + _loadSelectedDateLearningData(date); + } + + /// ํŠน์ • ๋‚ ์งœ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + /// + /// [date]: ๋กœ๋“œํ•  ๋‚ ์งœ + /// [forceRefresh]: true๋ฉด ์บ์‹œ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์„œ๋ฒ„์—์„œ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค + Future _loadDateData(DateTime date, {bool forceRefresh = false}) async { + final dateStr = _formatDate(date); + + // ํ•™์›์ด ์—†์œผ๋ฉด ๊ฑด๋„ˆ๋›ฐ๊ธฐ + if (_academyState != AcademyState.ready) { + return; + } + + try { + final userAcademyId = await getUserAcademyId( + academyService: _academyService, + registeredAcademies: _registeredAcademies, + ); + + // ํ•™์› ID๊ฐ€ ์—†์œผ๋ฉด ๋นˆ ๋ฆฌ์ŠคํŠธ ์„ค์ • + if (userAcademyId == null) { + setState(() { + _dateAssessments[dateStr] = []; + }); + return; + } + + final assessments = await _assessmentRepository.getForDate( + academyId: userAcademyId, + date: dateStr, + forceRefresh: forceRefresh, + ); + + setState(() { + _dateAssessments[dateStr] = assessments; + }); + + if (forceRefresh) { + developer.log( + 'โœ… [HomePage] ๋‚ ์งœ ๋ฐ์ดํ„ฐ ๊ฐ•์ œ ์ƒˆ๋กœ๊ณ ์นจ ์™„๋ฃŒ: $dateStr - ${assessments.length}๊ฐœ ๊ณผ์ œ', + ); + } + } catch (e) { + developer.log('โš ๏ธ ๋‚ ์งœ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ: $e'); + // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ๋นˆ ๋ฆฌ์ŠคํŠธ ์„ค์ • + setState(() { + _dateAssessments[dateStr] = []; + }); + } + } + + /// ์„ ํƒ๋œ ๋‚ ์งœ์˜ ํ•™์Šต ๋ฐ์ดํ„ฐ ๋กœ๋“œ + /// + /// [date]: ์กฐํšŒํ•  ๋‚ ์งœ (์–ด๋–ค ํƒ€์ž„์กด์ด๋“  ์ƒ๊ด€์—†์Œ, KST๋กœ ๋ณ€ํ™˜๋จ) + /// ๊ธฐ๊ธฐ ํƒ€์ž„์กด๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ํ•ญ์ƒ KST ๊ธฐ์ค€์œผ๋กœ ์กฐํšŒ๋ฉ๋‹ˆ๋‹ค. + Future _loadSelectedDateLearningData(DateTime date) async { + if (_isLoadingSelectedDateLearning) return; + if (_academyState != AcademyState.ready) return; + + // setState ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ + setState(() { + _isLoadingSelectedDateLearning = true; + _selectedDateLearningResult = null; // ์ด์ „ ๊ฒฐ๊ณผ ์ดˆ๊ธฐํ™” + }); + + try { + final learningService = _getIt(); + final result = await learningService.getDailyLearningData(date); + + // setState ํ•œ ๋ฒˆ๋งŒ ํ˜ธ์ถœ (์„ฑ๊ณต/์‹คํŒจ ๋ชจ๋‘) + if (mounted) { + setState(() { + _selectedDateLearningResult = result; + _isLoadingSelectedDateLearning = false; + }); + } + } catch (e) { + developer.log('โš ๏ธ ์„ ํƒ๋œ ๋‚ ์งœ์˜ ํ•™์Šต ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ: $e'); + if (mounted) { + setState(() { + _selectedDateLearningResult = DailyLearningResult.error( + '๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.', + ); + _isLoadingSelectedDateLearning = false; + }); + } + } + } + + /// ๋‚ ์งœ ํฌ๋งทํŒ… (YYYY-MM-DD) + String _formatDate(DateTime date) { + return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; + } + + /// ์„ ํƒ๋œ ๋‚ ์งœ์˜ ์™„๋ฃŒ๋œ ๋‚ ์งœ Set ๊ณ„์‚ฐ + Set _getCompletedDates() { + final completedDates = []; + _dateAssessments.forEach((date, assessments) { + // ๊ณผ์ œ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์„ ๋•Œ, "๋ชจ๋“  ๊ณผ์ œ๊ฐ€ Y"์ธ ๋‚ ๋งŒ ์™„๋ฃŒ๋กœ ๊ฐ„์ฃผ + if (assessments.isNotEmpty && + assessments.every((a) => a.assessStatus == 'Y')) { + completedDates.add(date); + } + }); + return completedDates.toSet(); + } + + /// ์„ ํƒ๋œ ๋‚ ์งœ์˜ ์ˆ™์ œ ๋งˆ๊ฐ์ผ Set ๊ณ„์‚ฐ + Set _getHomeworkDeadlines() { + final deadlines = []; + _dateAssessments.forEach((date, assessments) { + if (assessments.isNotEmpty) { + deadlines.add(date); + } + }); + return deadlines.toSet(); + } + + @override + Widget build(BuildContext context) { + final screenHeight = MediaQuery.of(context).size.height; + + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded(child: _buildBody(screenHeight)), + ], + ), + ), + ); + } + + Widget _buildBody(double screenHeight) { + switch (_academyState) { + case AcademyState.loading: + return const Center(child: CircularProgressIndicator()); + + case AcademyState.none: + return _buildNoAcademyState(); + + case AcademyState.error: + return _buildErrorState(); + + case AcademyState.ready: + return RefreshIndicator( + onRefresh: () async { + await _initializeAcademyData(forceRefresh: true); + }, + child: SingleChildScrollView( + physics: + const AlwaysScrollableScrollPhysics(), // Pull-to-refresh๋ฅผ ์œ„ํ•ด ํ•ญ์ƒ ์Šคํฌ๋กค ๊ฐ€๋Šฅํ•˜๋„๋ก + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: screenHeight * 0.0297), // 26px โ†’ 2.97% + ContinuousLearningWidgetV2( + consecutiveDays: _getConsecutiveDays(), + homeworkDeadlines: _getHomeworkDeadlines(), + onDateSelected: _onDateSelected, + selectedDate: _selectedDate, + // ์ƒˆ ๊ตฌ์กฐ: UseCase ์‚ฌ์šฉ + monthlyStatusUseCase: _monthlyStatusUseCase, + // ํ•˜์œ„ ํ˜ธํ™˜์„ฑ (์ถ”ํ›„ ์ œ๊ฑฐ ์˜ˆ์ •) + completedDates: _getCompletedDates(), + dateAssessments: _dateAssessments, + ), + SizedBox(height: screenHeight * 0.0297), // 26px โ†’ 2.97% + _buildTodayHomeworkSection(), + SizedBox(height: screenHeight * 0.0297), // 26px โ†’ 2.97% + _buildAccumulatedLearningSection(), + const SizedBox(height: 20), + ], + ), + ), + ); + } + } + + Widget _buildErrorState() { + return Center( + child: Padding( + padding: const EdgeInsets.all(40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.error_outline, size: 64, color: Color(0xFFFF6B6B)), + const SizedBox(height: 24), + const Text( + 'ํ•™์› ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: Color(0xFF333333), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 32), + ElevatedButton( + onPressed: () => _initializeAcademyData(forceRefresh: true), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFAC5BF8), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 12, + ), + ), + child: const Text( + '๋‹ค์‹œ ์‹œ๋„', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + // โœ… Rule 1: ์•„์ด์ฝ˜ ์‚ฌ์ด์ฆˆ๋„ ์ƒ๋Œ€ ํฌ๊ธฐ๋กœ + final iconSize = MediaQuery.of(context).size.width * 0.06; + + // ํ•™์›์ด ์ •์ƒ์ ์œผ๋กœ ์„ค์ •๋œ ์ƒํƒœ์ธ์ง€ ์—ฌ๋ถ€ + final hasAcademy = + _academyState == AcademyState.ready && _registeredAcademies.isNotEmpty; + + // ํ•™์›์ด 2๊ฐœ ์ด์ƒ์ผ ๋•Œ๋งŒ ๋“œ๋กญ๋‹ค์šด ํ™œ์„ฑํ™” (๋‹จ, ํ•™์›์ด ์žˆ์„ ๋•Œ๋งŒ) + final canShowDropdown = hasAcademy && _registeredAcademies.length > 1; + + return AppHeader( + titleAlignment: hasAcademy ? 'left' : 'center', + title: !hasAcademy + // ํ•™์›์ด ์—†์„ ๋•Œ๋Š” ํ•™์› ์ด๋ฆ„("Gradi ํ•™์›" ๋“ฑ)์„ ํ‘œ์‹œํ•˜์ง€ ์•Š๊ณ  + // ๋‹จ์ˆœํžˆ ํ™ˆ ํƒ€์ดํ‹€๋งŒ ํ‘œ์‹œ + ? const Text( + 'ํ™ˆ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ) + : canShowDropdown + ? PopupMenuButton( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + _academyName, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + const SizedBox(width: 8), + Icon( + Icons.keyboard_arrow_down, + color: const Color(0xFF333333), + size: iconSize, + ), + ], + ), + itemBuilder: (context) { + return _registeredAcademies.map((academy) { + return PopupMenuItem( + value: academy.academyCode, + child: FutureBuilder( + future: _academyService.getDefaultAcademyCode(), + builder: (context, snapshot) { + final currentAcademyCode = snapshot.data; + final isSelected = + academy.academyCode == currentAcademyCode; + + return Row( + children: [ + Expanded( + child: Text( + academy.academyName, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.w400, + fontSize: 14, + color: isSelected + ? const Color(0xFFAC5BF8) + : const Color(0xFF333333), + ), + ), + ), + if (isSelected) + const Icon( + Icons.check, + color: Color(0xFFAC5BF8), + size: 20, + ), + ], + ); + }, + ), + ); + }).toList(); + }, + onSelected: (academyCode) { + _onAcademySelected(academyCode); + }, + ) + : Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + _academyName, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + const SizedBox(width: 8), + Icon( + Icons.keyboard_arrow_down, + color: const Color(0xFF333333), + size: iconSize, + ), + ], + ), + trailing: const AppHeaderMenuButton(), + ); + } + + /// ํ•™์› ์„ ํƒ ์‹œ ํ˜ธ์ถœ (๋“œ๋กญ๋‹ค์šด์—์„œ ์„ ํƒ) + Future _onAcademySelected(String academyCode) async { + try { + // ๋””ํดํŠธ ํ•™์› ์ €์žฅ + await _academyService.saveDefaultAcademyCode(academyCode); + + // ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•™์› ์ฐพ๊ธฐ + final academy = _registeredAcademies.firstWhere( + (a) => a.academyCode == academyCode, + ); + + if (mounted) { + setState(() { + _academyName = academy.academyName; + // _academyState๋Š” ready ์œ ์ง€ + }); + + // Assessment ๋ฐ์ดํ„ฐ ๋‹ค์‹œ ๋กœ๋“œ + _dateAssessments.clear(); + await _loadRemainingMonthData(); + + // ์˜ค๋Š˜์˜ ์ˆ™์ œ ์ •๋ณด ๋™๊ธฐํ™” + await _synchronizeTodayHomework(); + + developer.log('โœ… ํ•™์› ๋ณ€๊ฒฝ ์™„๋ฃŒ: ${academy.academyName}'); + } + } catch (e) { + developer.log('โš ๏ธ ํ•™์› ์„ ํƒ ์ฒ˜๋ฆฌ ์‹คํŒจ: $e'); + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('ํ•™์› ๋ณ€๊ฒฝ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: ${e.toString()}'), + backgroundColor: Colors.red, + ), + ); + } + } + } + + /// ํ•™์›์ด ์—†์„ ๋•Œ ํ‘œ์‹œํ•  ์•ˆ๋‚ด ์œ„์ ฏ + Widget _buildNoAcademyState() { + return Center( + child: Padding( + padding: const EdgeInsets.all(40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.school_outlined, + size: 64, + color: Color(0xFFADADAD), + ), + const SizedBox(height: 24), + const Text( + 'ํ•™์›์„ ๋“ฑ๋กํ•ด์ฃผ์„ธ์š”', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: Color(0xFF333333), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 12), + const Text( + 'ํ•™์›์„ ๋“ฑ๋กํ•˜๋ฉด ์ˆ™์ œ์™€ ํ•™์Šต ์ •๋ณด๋ฅผ\nํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 32), + ElevatedButton( + onPressed: () { + Navigator.pushNamed(context, '/academy/list'); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFAC5BF8), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 24, + vertical: 12, + ), + ), + child: const Text( + 'ํ•™์› ๋“ฑ๋กํ•˜๊ธฐ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + ), + ], + ), + ), + ); + } + + /// ์˜ค๋Š˜์˜ ์ˆ™์ œ ์„น์…˜ + Widget _buildTodayHomeworkSection() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + '์˜ค๋Š˜์˜ ์ˆ™์ œ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + InkWell( + onTap: () { + Navigator.pushNamed(context, AppRoutes.homeworkStatus); + }, + borderRadius: BorderRadius.circular(24), + child: Padding( + padding: const EdgeInsets.all(4), + child: Icon( + Icons.chevron_right, + color: Colors.grey[600], + size: MediaQuery.of(context).size.width * 0.06, + ), + ), + ), + ], + ), + const SizedBox(height: 12), + + // TODO: DB์—์„œ ์„ ํƒ๋œ ๋‚ ์งœ์˜ ์ˆ™์ œ ๋ชฉ๋ก ์กฐํšŒ + _buildHomeworkList(), + ], + ); + } + + Widget _buildHomeworkList() { + // ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์—ฌ๋ถ€ ํ™•์ธ + developer.log('๐Ÿ”ต [HomePage] _buildHomeworkList() ํ˜ธ์ถœ๋จ'); + developer.log('๐Ÿ”ต [HomePage] _academyState: $_academyState'); + + // ํ•™์›์ด ์—†์„ ๋•Œ ์•ˆ๋‚ด ํ‘œ์‹œ + if (_academyState != AcademyState.ready) { + developer.log('โš ๏ธ [HomePage] _academyState๊ฐ€ ready๊ฐ€ ์•„๋‹˜. early return'); + return Container( + width: double.infinity, + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: Text( + 'ํ•™์›์„ ๋“ฑ๋กํ•ด์ฃผ์„ธ์š”', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } + + // ์„ ํƒ๋œ ๋‚ ์งœ์˜ Assessment ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ + final dateStr = _formatDate(_selectedDate); + final assessments = _dateAssessments[dateStr] ?? []; + + developer.log('๐Ÿ“‹ [HomePage] ์„ ํƒ๋œ ๋‚ ์งœ: $dateStr'); + developer.log('๐Ÿ“‹ [HomePage] ์„ ํƒ๋œ ๋‚ ์งœ์˜ ๊ณผ์ œ ์ˆ˜: ${assessments.length}'); + developer.log( + '๐Ÿ“‹ [HomePage] ์„ ํƒ๋œ ๋‚ ์งœ์˜ ๊ณผ์ œ ๋ชฉ๋ก: ${assessments.map((e) => e.assessName).toList()}', + ); + developer.log( + '๐Ÿ“‹ [HomePage] _dateAssessments ์ „์ฒด ํ‚ค: ${_dateAssessments.keys.toList()}', + ); + + for (var assessment in assessments) { + developer.log('๐Ÿ“‹ [HomePage] ๊ณผ์ œ ์ด๋ฆ„: ${assessment.assessName}'); + developer.log('๐Ÿ“‹ [HomePage] ๊ณผ์ œ ํด๋ž˜์Šค: ${assessment.assessClass}'); + developer.log('๐Ÿ“‹ [HomePage] ๊ณผ์ œ ์ƒํƒœ: ${assessment.assessStatus}'); + developer.log('๐Ÿ“‹ [HomePage] ๊ณผ์ œ ํŽ˜์ด์ง€: ${assessment.assessPage}'); + developer.log('๐Ÿ“‹ [HomePage] ๊ณผ์ œ ์ธ๋„ค์ผ: ${assessment.bookCoverImage}'); + } + + if (assessments.isEmpty) { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: Text( + 'ํ•ด๋‹น ๋‚ ์งœ์— ์ˆ™์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } + + // Assessment๋ฅผ ํด๋ž˜์Šค๋ช…์œผ๋กœ ๋จผ์ € ๊ทธ๋ฃนํ™”, ๊ทธ ๋‹ค์Œ bookId๋กœ ๊ทธ๋ฃนํ™” + final Map>> groupedByClass = {}; + for (var assessment in assessments) { + // ํด๋ž˜์Šค๋ช…์ด ์—†์œผ๋ฉด ํ•™์› ์ด๋ฆ„ ์‚ฌ์šฉ + final className = assessment.assessClass.isNotEmpty + ? assessment.assessClass + : _academyName; + + if (!groupedByClass.containsKey(className)) { + groupedByClass[className] = {}; + } + + final classGroup = groupedByClass[className]!; + if (!classGroup.containsKey(assessment.bookId)) { + classGroup[assessment.bookId] = []; + } + classGroup[assessment.bookId]!.add(assessment); + } + + // ๊ฐ ํด๋ž˜์Šค๋ณ„๋กœ ์„น์…˜ ์ƒ์„ฑ + return Column( + children: groupedByClass.entries.map((classEntry) { + final className = classEntry.key; + final bookGroups = classEntry.value; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ํด๋ž˜์Šค๋ช… ํ—ค๋” + Padding( + padding: EdgeInsets.only( + bottom: 12, + top: classEntry == groupedByClass.entries.first ? 0 : 20, + ), + child: Text( + className, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + ), + // ๊ฐ ๋ฌธ์ œ์ง‘๋ณ„๋กœ ์นด๋“œ ์ƒ์„ฑ + ...bookGroups.entries.map((entry) { + final bookId = entry.key; + final bookAssessments = entry.value; + + return Container( + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ๋ฌธ์ œ์ง‘๋ณ„ Assessment ๋ชฉ๋ก + ...bookAssessments.asMap().entries.map((entry) { + final index = entry.key; + final assessment = entry.value; + // ํ•ญ์ƒ ์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์˜จ ์ตœ์‹  ์ƒํƒœ๋ฅผ ์‚ฌ์šฉ + final isCompleted = assessment.assessStatus == 'Y'; + + return Padding( + padding: const EdgeInsets.only(bottom: 10), + child: _buildWorkbookItemFromAssessment( + assessment, + bookId, + index, + isCompleted, + ), + ); + }).toList(), + ], + ), + ); + }).toList(), + ], + ); + }).toList(), + ); + } + + /// assessPage๋ฅผ "P.15~P.25" ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ + String _formatAssessPage(String assessPage) { + if (assessPage.isEmpty || !assessPage.contains('-')) { + return assessPage; + } + + final parts = assessPage.split('-'); + if (parts.length == 2) { + final startPage = parts[0].trim(); + final endPage = parts[1].trim(); + return 'P.$startPage~P.$endPage'; + } + + return assessPage; + } + + /// ๋ฌธ์ œ์ง‘ ์•„์ดํ…œ (Assessment ๊ธฐ๋ฐ˜) + Widget _buildWorkbookItemFromAssessment( + Assessment assessment, + String bookId, + int index, + bool isCompleted, + ) { + final screenWidth = MediaQuery.of(context).size.width; + final thumbnailWidth = screenWidth * 0.12; + final thumbnailHeight = thumbnailWidth * 1.34; + + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ๋ฌธ์ œ์ง‘ ์ธ๋„ค์ผ + ClipRRect( + borderRadius: BorderRadius.circular(5), + child: assessment.bookCoverImage.startsWith('http') + ? Image.network( + assessment.bookCoverImage, + width: thumbnailWidth, + height: thumbnailHeight, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + width: thumbnailWidth, + height: thumbnailHeight, + color: Colors.grey[300], + child: const Icon(Icons.book, color: Colors.grey), + ); + }, + ) + : Image.asset( + assessment.bookCoverImage, + width: thumbnailWidth, + height: thumbnailHeight, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + width: thumbnailWidth, + height: thumbnailHeight, + color: Colors.grey[300], + child: const Icon(Icons.book, color: Colors.grey), + ); + }, + ), + ), + const SizedBox(width: 12), + + // ์ฑ•ํ„ฐ + ํŽ˜์ด์ง€ ์ •๋ณด + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + assessment.assessName, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + Text( + _formatAssessPage(assessment.assessPage), + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: Color(0xFF999999), + ), + ), + ], + ), + ), + + // ์ฒดํฌ๋ฐ•์Šค (์‚ฌ์šฉ์ž ์กฐ์ž‘ ๋ถˆ๊ฐ€, assessStatus์— ๋”ฐ๋ผ ์ž๋™์œผ๋กœ ํ‘œ์‹œ๋จ) + Container( + width: screenWidth * 0.06, + height: screenWidth * 0.06, + decoration: BoxDecoration( + color: isCompleted ? const Color(0xFFAC5BF8) : Colors.white, + border: Border.all( + color: isCompleted + ? const Color(0xFFAC5BF8) + : const Color(0xFFCED4DA), + width: 2, + ), + borderRadius: BorderRadius.circular(5), + ), + child: isCompleted + ? Icon(Icons.check, size: screenWidth * 0.04, color: Colors.white) + : null, + ), + ], + ); + } + + /// ์˜ค๋Š˜์˜ ํ•™์Šต ์„น์…˜ + Widget _buildAccumulatedLearningSection() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + '์˜ค๋Š˜์˜ ํ•™์Šต', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + Icon( + Icons.chevron_right, + color: Colors.grey[600], + size: MediaQuery.of(context).size.width * 0.06, + ), + ], + ), + const SizedBox(height: 12), + + // TODO: DB์—์„œ ์„ ํƒ๋œ ๋‚ ์งœ์— ํ•™์Šตํ•œ ๋ฌธ์ œ์ง‘ ๋ชฉ๋ก ์กฐํšŒ + _buildLearningProgressCard(), + ], + ); + } + + Widget _buildLearningProgressCard() { + // ๋กœ๋”ฉ ์ค‘ + if (_isLoadingSelectedDateLearning) { + return Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Center(child: CircularProgressIndicator()), + ); + } + + // ๊ฒฐ๊ณผ๊ฐ€ ์—†์Œ + if (_selectedDateLearningResult == null) { + return const SizedBox.shrink(); + } + + // ์—๋Ÿฌ ์ƒํƒœ + if (_selectedDateLearningResult!.hasError) { + return Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + children: [ + const Icon(Icons.error_outline, color: Color(0xFFFF6B6B)), + const SizedBox(height: 8), + Text( + _selectedDateLearningResult!.errorMessage ?? '๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFFF6B6B), + ), + textAlign: TextAlign.center, + ), + ], + ), + ); + } + + // ๋นˆ ์ƒํƒœ (ํ•™์Šต ๊ธฐ๋ก ์—†์Œ) + if (!_selectedDateLearningResult!.hasData) { + return Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: Text( + 'ํ•ด๋‹น ๋‚ ์งœ์— ํ•™์Šต ๊ธฐ๋ก์ด ์—†์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } + + // ๋ฐ์ดํ„ฐ ์žˆ์Œ - ๊ฐ€์žฅ ๋งŽ์ด ํ•™์Šตํ•œ ์ฑ… ์„ ํƒ + final books = DailyLearningService.extractBooks( + _selectedDateLearningResult!, + ); + final selectedBook = DailyLearningService.selectMostLearnedBook(books); + + if (selectedBook == null) { + return Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: const Center( + child: Text( + 'ํ•™์Šต ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } + + // Progress ๊ณ„์‚ฐ + final progress = selectedBook.bookPage > 0 + ? selectedBook.totalSolvedPages / selectedBook.bookPage + : 0.0; + + final screenWidth = MediaQuery.of(context).size.width; + final thumbnailWidth = screenWidth * 0.17; + final thumbnailHeight = thumbnailWidth * 1.33; + + return Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE1E7ED)), + borderRadius: BorderRadius.circular(10), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ๋ฌธ์ œ์ง‘ ์ธ๋„ค์ผ + ClipRRect( + borderRadius: BorderRadius.circular(5), + child: + selectedBook.bookImageUrl != null && + selectedBook.bookImageUrl!.startsWith('http') + ? Image.network( + selectedBook.bookImageUrl!, + width: thumbnailWidth, + height: thumbnailHeight, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + width: thumbnailWidth, + height: thumbnailHeight, + color: Colors.grey[300], + child: Icon( + Icons.book, + color: Colors.grey, + size: thumbnailWidth * 0.57, + ), + ); + }, + ) + : Container( + width: thumbnailWidth, + height: thumbnailHeight, + color: Colors.grey[300], + child: Icon( + Icons.book, + color: Colors.grey, + size: thumbnailWidth * 0.57, + ), + ), + ), + const SizedBox(width: 15), + + // ํ•™์Šต ์ •๋ณด ๋ฐ ํ”„๋กœ๊ทธ๋ ˆ์Šค + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ๋ฌธ์ œ์ง‘๋ช… + Text( + selectedBook.bookName ?? '๋ฌธ์ œ์ง‘ ${selectedBook.bookId}', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + + // ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ” + LayoutBuilder( + builder: (context, constraints) { + final progressHeight = constraints.maxWidth * 0.04; + return Stack( + children: [ + // ์ „์ฒด ๋ฐฐ๊ฒฝ (ํšŒ์ƒ‰) + Container( + height: progressHeight, + decoration: BoxDecoration( + color: const Color(0xFFE9ECEF), + borderRadius: BorderRadius.circular(10), + ), + ), + // ์ง„ํ–‰๋ฅ  (๋ณด๋ผ์ƒ‰) + FractionallySizedBox( + widthFactor: progress.clamp(0.0, 1.0), + child: Container( + height: progressHeight, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF7C3AED)], + ), + borderRadius: BorderRadius.circular(10), + ), + ), + ), + ], + ); + }, + ), + const SizedBox(height: 8), + + // ์ง„ํ–‰ ์ •๋ณด + Text( + '${selectedBook.totalSolvedPages} / ${selectedBook.bookPage} ํŽ˜์ด์ง€', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 13, + color: Color(0xFF333333), + ), + ), + ], + ), + ), + ], + ), + ); + } + + // ํ—ฌํผ ๋ฉ”์„œ๋“œ๋“ค + + int _getConsecutiveDays() { + final completedDates = _getCompletedDates(); + if (completedDates.isEmpty) return 0; + + final completedSet = completedDates.toSet(); + DateTime today = DateTime.now(); + DateTime cursor = DateTime(today.year, today.month, today.day); + + final todayKey = _formatDate(cursor); + if (!completedSet.contains(todayKey)) { + cursor = cursor.subtract(const Duration(days: 1)); + } + + int streak = 0; + while (true) { + final key = _formatDate(cursor); + if (!completedSet.contains(key)) { + break; + } + streak++; + cursor = cursor.subtract(const Duration(days: 1)); + } + + return streak; + } +} diff --git a/frontend/lib/screens/loading_page.dart b/frontend/lib/screens/loading_page.dart new file mode 100644 index 0000000..6660cbf --- /dev/null +++ b/frontend/lib/screens/loading_page.dart @@ -0,0 +1,251 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:get_it/get_it.dart'; +import '../services/auth_service.dart'; +import '../services/user_service.dart'; +import '../services/assessment_repository.dart'; +import '../services/academy_service.dart'; +import '../services/fcm_service.dart'; +import 'dart:developer' as developer; + +/// ์•ฑ ์‹œ์ž‘ ์‹œ ๋กœ๋”ฉ ํŽ˜์ด์ง€ +/// +/// ๋™์ž‘ ๋ฐฉ์‹: +/// 1. ์ž๋™ ๋กœ๊ทธ์ธ์ด ์„ ํƒ๋œ ๊ฒฝ์šฐ (ํ† ํฐ์ด ์žˆ๋Š” ๊ฒฝ์šฐ): +/// - ๋กœ๋”ฉ ํŽ˜์ด์ง€๋ฅผ ํ‘œ์‹œํ•˜๋ฉด์„œ ํ•„์š”ํ•œ API ํ˜ธ์ถœ +/// - ์™„๋ฃŒ ํ›„ ๋ฉ”์ธ ๋„ค๋น„๊ฒŒ์ด์…˜ ํŽ˜์ด์ง€๋กœ ์ด๋™ +/// 2. ๋กœ๊ทธ์ธ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ: +/// - ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ +class LoadingPage extends StatefulWidget { + const LoadingPage({super.key}); + + @override + State createState() => _LoadingPageState(); +} + +class _LoadingPageState extends State { + final getIt = GetIt.instance; + + @override + void initState() { + super.initState(); + _initializeApp(); + } + + /// ์•ฑ ์ดˆ๊ธฐํ™” ๋กœ์ง + Future _initializeApp() async { + try { + final authService = getIt(); + final assessmentRepository = getIt(); + + // ์ž๋™ ๋กœ๊ทธ์ธ ์„ค์ • ํ™•์ธ + final isAutoLoginEnabled = await authService.isAutoLoginEnabled(); + + if (!mounted) return; + + if (!isAutoLoginEnabled) { + // ์ž๋™ ๋กœ๊ทธ์ธ ๋น„ํ™œ์„ฑํ™” โ†’ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ + developer.log('โ„น๏ธ ์ž๋™ ๋กœ๊ทธ์ธ ๋น„ํ™œ์„ฑํ™” - ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™'); + // ์ž๋™ ๋กœ๊ทธ์ธ์ด ๋น„ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ ํ† ํฐ์ด ๋‚จ์•„์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‚ญ์ œ + await authService.clearTokens(clearAutoLogin: false); + if (mounted) { + Navigator.pushNamedAndRemoveUntil( + context, + '/login', + (route) => false, + ); + } + return; + } + + // ์ž๋™ ๋กœ๊ทธ์ธ ํ™œ์„ฑํ™” โ†’ Access Token ํ™•์ธ + final accessToken = await authService.getAccessToken(); + + if (accessToken == null || accessToken.isEmpty) { + // ํ† ํฐ ์—†์Œ โ†’ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ + developer.log('โ„น๏ธ ํ† ํฐ ์—†์Œ - ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™'); + if (mounted) { + Navigator.pushNamedAndRemoveUntil( + context, + '/login', + (route) => false, + ); + } + return; + } + + // ํ† ํฐ ๋งŒ๋ฃŒ ํ™•์ธ ๋ฐ ๊ฐฑ์‹  + final isExpired = authService.isTokenExpired(accessToken); + + if (isExpired) { + developer.log('โš ๏ธ Access Token ๋งŒ๋ฃŒ๋จ - Refresh Token์œผ๋กœ ๊ฐฑ์‹  ์‹œ๋„...'); + final refreshed = await authService.refreshAccessToken(); + + if (!refreshed) { + // Refresh Token๋„ ๋งŒ๋ฃŒ๋˜์—ˆ๊ฑฐ๋‚˜ ๊ฐฑ์‹  ์‹คํŒจ โ†’ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ + developer.log('โŒ ํ† ํฐ ๊ฐฑ์‹  ์‹คํŒจ - ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™'); + await authService.clearTokens(); + if (mounted) { + Navigator.pushNamedAndRemoveUntil( + context, + '/login', + (route) => false, + ); + } + return; + } + + developer.log('โœ… Access Token ๊ฐฑ์‹  ์„ฑ๊ณต'); + } else { + developer.log('โœ… Access Token ์œ ํšจํ•จ'); + } + + // ์ž๋™ ๋กœ๊ทธ์ธ: ํ•„์š”ํ•œ API ํ˜ธ์ถœ + developer.log('๐Ÿ”„ ์ž๋™ ๋กœ๊ทธ์ธ ๊ฐ์ง€ - ์‚ฌ์šฉ์ž ์ •๋ณด ์ดˆ๊ธฐํ™” ์ค‘...'); + + try { + // ์‚ฌ์šฉ์ž ์ •๋ณด ์ดˆ๊ธฐํ™” (API ํ˜ธ์ถœ) + // fetchUserFromServer ๋‚ด๋ถ€์—์„œ ํ† ํฐ ๋งŒ๋ฃŒ ์‹œ ์ž๋™ ๊ฐฑ์‹  ์ฒ˜๋ฆฌ๋จ + await getIt().initialize(); + developer.log('โœ… ์‚ฌ์šฉ์ž ์ •๋ณด ์ดˆ๊ธฐํ™” ์™„๋ฃŒ'); + } catch (e) { + developer.log('โŒ ์‚ฌ์šฉ์ž ์ •๋ณด ์ดˆ๊ธฐํ™” ์‹คํŒจ: $e'); + // ์ดˆ๊ธฐํ™” ์‹คํŒจํ•ด๋„ ๋ฉ”์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ (์บ์‹œ๋œ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ) + } + + // ํ•™์› ๋ชฉ๋ก API ํ˜ธ์ถœ ๋ฐ ๋””ํดํŠธ ํ•™์› ์„ ํƒ + try { + final userId = await authService.getUserId(); + if (userId != null) { + developer.log('๐Ÿ”„ ํ•™์› ๋ชฉ๋ก ์กฐํšŒ ์ค‘...'); + final academyService = getIt(); + final academies = await academyService.getUserAcademies(userId); + + // SharedPreferences์— ํ•™์› ๋ชฉ๋ก ์ €์žฅ + await academyService.saveAcademiesToCache(academies); + developer.log('โœ… ํ•™์› ๋ชฉ๋ก ์บ์‹œ ์ €์žฅ ์™„๋ฃŒ (${academies.length}๊ฐœ)'); + + // ๋””ํดํŠธ ํ•™์› ์„ ํƒ ๋ฐ ์ €์žฅ + final defaultAcademyCode = await academyService + .selectDefaultAcademyAsync(academies); + if (defaultAcademyCode != null) { + await academyService.saveDefaultAcademyCode(defaultAcademyCode); + developer.log('โœ… ๋””ํดํŠธ ํ•™์› ์„ ํƒ ๋ฐ ์ €์žฅ ์™„๋ฃŒ (Code: $defaultAcademyCode)'); + + // ํ˜„์žฌ ๋‹ฌ๊ณผ ๋‹ค์Œ ๋‹ฌ์˜ Assessment ๋ฐ์ดํ„ฐ ๋กœ๋“œ (๋””ํดํŠธ ํ•™์› ์‚ฌ์šฉ) + try { + final now = DateTime.now(); + + // ํ˜„์žฌ ๋‹ฌ์˜ ์ฒซ ๋ฒˆ์งธ ๋‚  (UTC) + final currentMonthStart = DateTime.utc(now.year, now.month, 1); + + // ๋‹ค์Œ ๋‹ฌ ๊ณ„์‚ฐ (set ํ•จ์ˆ˜ ์‚ฌ์šฉ) + final nextMonthStart = _getNextMonth(currentMonthStart); + + // ํ˜„์žฌ ๋‹ฌ๊ณผ ๋‹ค์Œ ๋‹ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ‘๋ ฌ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ + await Future.wait([ + assessmentRepository.getForMonth( + academyId: defaultAcademyCode, + dateTime: currentMonthStart, + ), + assessmentRepository.getForMonth( + academyId: defaultAcademyCode, + dateTime: nextMonthStart, + ), + ]); + + developer.log('โœ… ํ˜„์žฌ ๋‹ฌ๊ณผ ๋‹ค์Œ ๋‹ฌ Assessment ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์™„๋ฃŒ'); + } catch (e) { + developer.log('โš ๏ธ Assessment ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ: $e'); + // ์‹คํŒจํ•ด๋„ ์•ฑ์€ ๊ณ„์† ์ง„ํ–‰ + } + } else { + developer.log('โš ๏ธ ๋””ํดํŠธ ํ•™์›์„ ์„ ํƒํ•  ์ˆ˜ ์—†์Œ (๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์›์ด ์—†์Œ)'); + } + } else { + developer.log('โš ๏ธ ์‚ฌ์šฉ์ž ID๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์–ด ํ•™์› ๋ชฉ๋ก ์กฐํšŒ๋ฅผ ๊ฑด๋„ˆ๋œ€'); + } + } catch (e) { + developer.log('โš ๏ธ ํ•™์› ๋ชฉ๋ก ์กฐํšŒ ์‹คํŒจ: $e'); + // ์‹คํŒจํ•ด๋„ ์•ฑ์€ ๊ณ„์† ์ง„ํ–‰ (์บ์‹œ๋œ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ ๊ฐ€๋Šฅ) + } + + // FCM ํ† ํฐ์„ ๋ฐฑ์—”๋“œ์™€ ๋™๊ธฐํ™” + try { + final fcmService = getIt(); + await fcmService.syncTokenWithServer(); + developer.log('โœ… FCM ํ† ํฐ ๋™๊ธฐํ™” ์™„๋ฃŒ'); + } catch (e) { + developer.log('โš ๏ธ FCM ํ† ํฐ ๋™๊ธฐํ™” ์‹คํŒจ: $e'); + // ์‹คํŒจํ•ด๋„ ์•ฑ์€ ๊ณ„์† ์ง„ํ–‰ + } + + // ๋ฉ”์ธ ๋„ค๋น„๊ฒŒ์ด์…˜ ํŽ˜์ด์ง€๋กœ ์ด๋™ + if (mounted) { + Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false); + } + } catch (e) { + developer.log('โŒ ์•ฑ ์ดˆ๊ธฐํ™” ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: $e'); + // ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ + if (mounted) { + Navigator.pushNamedAndRemoveUntil(context, '/login', (route) => false); + } + } + } + + /// ๋‹ค์Œ ๋‹ฌ ๊ณ„์‚ฐ ํ—ฌํผ ํ•จ์ˆ˜ + DateTime _getNextMonth(DateTime dateTime) { + if (dateTime.month == 12) { + return DateTime.utc(dateTime.year + 1, 1, 1); + } else { + return DateTime.utc(dateTime.year, dateTime.month + 1, 1); + } + } + + @override + Widget build(BuildContext context) { + // ์ƒํƒœ๋ฐ” ์Šคํƒ€์ผ ์„ค์ • (ํฐ์ƒ‰ ์•„์ด์ฝ˜) + SystemChrome.setSystemUIOverlayStyle( + const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarIconBrightness: Brightness.light, + systemNavigationBarColor: Colors.transparent, + systemNavigationBarIconBrightness: Brightness.light, + ), + ); + + return Scaffold( + body: Container( + width: double.infinity, + height: double.infinity, + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + // Figma: linear-gradient(153deg, rgba(172, 91, 248, 1) 9%, rgba(99, 106, 207, 1) 92%) + colors: [ + Color(0xFFAC5BF8), // rgba(172, 91, 248, 1) + Color(0xFF636ACF), // rgba(99, 106, 207, 1) + ], + stops: [0.09, 0.92], // 9%, 92% + transform: GradientRotation(2.67), // 153 degrees in radians + ), + ), + child: Center( + child: Text( + 'GRADI', + style: TextStyle( + fontFamily: 'AppleSDGothicNeoH00', + fontWeight: FontWeight.w400, + fontSize: 110.648, + height: 1.491, // line-height: 165px / 110.648px + letterSpacing: -0.06, // -6% + color: Colors.white, + ), + textAlign: TextAlign.center, + ), + ), + ), + ); + } +} diff --git a/frontend/lib/screens/main_navigation_page.dart b/frontend/lib/screens/main_navigation_page.dart new file mode 100644 index 0000000..3e31e4d --- /dev/null +++ b/frontend/lib/screens/main_navigation_page.dart @@ -0,0 +1,193 @@ +import 'package:flutter/material.dart'; +import '../widgets/bottom_navigation_widget.dart'; +import 'home_page.dart'; +import 'workbook/workbook_page.dart'; +import 'academy/academy_page.dart'; +import 'mypage/mypage.dart'; +import 'notification/notification_page.dart'; +import 'upload/upload_images_page.dart'; + +class MainNavigationPage extends StatefulWidget { + const MainNavigationPage({super.key}); + + @override + State createState() => _MainNavigationPageState(); +} + +class _MainNavigationPageState extends State { + int _currentIndex = 0; + bool _handledRouteArgs = false; + + // HomePage์˜ State์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ GlobalKey + final GlobalKey> _homePageKey = GlobalKey(); + // UploadImagesPage์˜ State์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ GlobalKey + final GlobalKey> _uploadPageKey = GlobalKey(); + // WorkbookPage์˜ State์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ GlobalKey + final GlobalKey> _workbookPageKey = GlobalKey(); + // AcademyPage์˜ State์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ GlobalKey + final GlobalKey> _academyPageKey = GlobalKey(); + // NotificationPage์˜ State์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ GlobalKey + final GlobalKey> _notificationPageKey = GlobalKey(); + + // ๋ชจ๋“  ํƒญ ํŽ˜์ด์ง€๋“ค + late final List _pages = [ + HomePage(key: _homePageKey), // GlobalKey ์ „๋‹ฌ + WorkbookPage(key: _workbookPageKey), // GlobalKey ์ „๋‹ฌ + UploadImagesPage(key: _uploadPageKey), // GlobalKey ์ „๋‹ฌ + AcademyPage(key: _academyPageKey), // GlobalKey ์ „๋‹ฌ + const MyPage(), + NotificationPage(key: _notificationPageKey), // GlobalKey ์ „๋‹ฌ + ]; + + @override + Widget build(BuildContext context) { + _handleRouteArgumentsIfNeeded(); + return Scaffold( + body: IndexedStack(index: _currentIndex, children: _pages), + bottomNavigationBar: BottomNavigationWidget( + currentIndex: _currentIndex, + onTabChanged: (index) { + setState(() { + _currentIndex = index; + }); + + // ํ™ˆ ํƒญ(์ธ๋ฑ์Šค 0)์œผ๋กœ ์ „ํ™˜ ์‹œ ์ƒˆ๋กœ๊ณ ์นจ + if (index == 0) { + final homeState = _homePageKey.currentState; + // dynamic์œผ๋กœ ์บ์ŠคํŒ…ํ•˜์—ฌ refresh() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ + if (homeState != null) { + try { + (homeState as dynamic).refresh(); + } catch (e) { + // refresh() ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ๋ฌด์‹œ + } + } + } + + // ๋ฌธ์ œ์ง‘ ํƒญ(์ธ๋ฑ์Šค 1)์œผ๋กœ ์ „ํ™˜ ์‹œ ์ƒˆ๋กœ๊ณ ์นจ + if (index == 1) { + final workbookState = _workbookPageKey.currentState; + // dynamic์œผ๋กœ ์บ์ŠคํŒ…ํ•˜์—ฌ refresh() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ + if (workbookState != null) { + try { + (workbookState as dynamic).refresh(); + } catch (e) { + // refresh() ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ๋ฌด์‹œ + } + } + } + + // ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ํƒญ(์ธ๋ฑ์Šค 2)์œผ๋กœ ์ „ํ™˜ ์‹œ ์ƒˆ๋กœ๊ณ ์นจ + if (index == 2) { + final uploadState = _uploadPageKey.currentState; + // dynamic์œผ๋กœ ์บ์ŠคํŒ…ํ•˜์—ฌ refresh() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ + if (uploadState != null) { + try { + (uploadState as dynamic).refresh(); + } catch (e) { + // refresh() ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ๋ฌด์‹œ + } + } + } + + // ํ•™์› ํƒญ(์ธ๋ฑ์Šค 3)์œผ๋กœ ์ „ํ™˜ ์‹œ ์ƒˆ๋กœ๊ณ ์นจ + if (index == 3) { + final academyState = _academyPageKey.currentState; + // dynamic์œผ๋กœ ์บ์ŠคํŒ…ํ•˜์—ฌ refresh() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ + if (academyState != null) { + try { + (academyState as dynamic).refresh(); + } catch (e) { + // refresh() ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ๋ฌด์‹œ + } + } + } + + // ์•Œ๋ฆผ ํƒญ(์ธ๋ฑ์Šค 5)์œผ๋กœ ์ „ํ™˜ ์‹œ ์ƒˆ๋กœ๊ณ ์นจ + if (index == 5) { + final notificationState = _notificationPageKey.currentState; + // dynamic์œผ๋กœ ์บ์ŠคํŒ…ํ•˜์—ฌ refresh() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ + if (notificationState != null) { + try { + (notificationState as dynamic).refresh(); + } catch (e) { + // refresh() ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ๋ฌด์‹œ + } + } + } + }, + ), + ); + } + + void _handleRouteArgumentsIfNeeded() { + if (_handledRouteArgs) return; + final args = ModalRoute.of(context)?.settings.arguments; + if (args is Map && args['targetDate'] is String) { + final targetDate = DateTime.tryParse(args['targetDate'] as String); + if (targetDate != null) { + _handledRouteArgs = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + _navigateHomeAndFocus(targetDate); + }); + } + } + } + + void _navigateHomeAndFocus(DateTime date) { + setState(() { + _currentIndex = 0; + }); + final homeState = _homePageKey.currentState; + if (homeState != null) { + try { + (homeState as dynamic).focusOnDate(date); + } catch (e) { + try { + (homeState as dynamic).refresh(); + } catch (_) {} + } + } + } +} + +// ๋ฏธ๊ตฌํ˜„ ํŽ˜์ด์ง€๋“ค์„ ์œ„ํ•œ ํ”Œ๋ ˆ์ด์Šคํ™€๋” +class PlaceholderPage extends StatelessWidget { + final String title; + + const PlaceholderPage({super.key, required this.title}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.construction, size: 64, color: Colors.grey[400]), + const SizedBox(height: 16), + Text( + '$title ํŽ˜์ด์ง€', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 8), + Text( + '๊ตฌํ˜„ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Colors.grey[600], + ), + ), + ], + ), + ), + ); + } +} diff --git a/frontend/lib/screens/mypage/academy_management_page.dart b/frontend/lib/screens/mypage/academy_management_page.dart new file mode 100644 index 0000000..b51e973 --- /dev/null +++ b/frontend/lib/screens/mypage/academy_management_page.dart @@ -0,0 +1,429 @@ +import 'package:flutter/material.dart'; +import '../../widgets/back_button.dart'; +import '../../services/academy_service.dart'; +import '../../services/auth_service.dart'; + +/// ํ•™์› ๊ด€๋ฆฌ ํŽ˜์ด์ง€ +/// ๋“ฑ๋ก๋œ ํ•™์› ๊ด€๋ฆฌ, ํ•™์› ์ถ”๊ฐ€/์‚ญ์ œ, ํ•™์› ์ „ํ™˜ ๋“ฑ์„ ๊ด€๋ฆฌํ•˜๋Š” ํŽ˜์ด์ง€ +class AcademyManagementPage extends StatefulWidget { + const AcademyManagementPage({super.key}); + + @override + State createState() => _AcademyManagementPageState(); +} + +class _AcademyManagementPageState extends State { + final AcademyService _academyService = AcademyService(); + final AuthService _authService = AuthService(); + + List _academies = []; + bool _isLoading = true; + String? _errorMessage; + String? _defaultAcademyCode; + + @override + void initState() { + super.initState(); + _loadAcademies(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded(child: _buildBody()), + ], + ), + ), + ); + } + + Widget _buildBody() { + if (_isLoading) { + return const Center(child: CircularProgressIndicator()); + } + if (_errorMessage != null) { + return Center( + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + _errorMessage!, + textAlign: TextAlign.center, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadAcademies, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFAC5BF8), + foregroundColor: Colors.white, + ), + child: const Text('๋‹ค์‹œ ์‹œ๋„'), + ), + ], + ), + ), + ); + } + if (_academies.isEmpty) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + '๋“ฑ๋ก๋œ ํ•™์›์ด ์—†์Šต๋‹ˆ๋‹ค.', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + const Text( + 'ํ•™์›์„ ๋“ฑ๋กํ•˜๋ฉด ์ˆ™์ œ์™€ ํ•™์Šต ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + const SizedBox(height: 24), + _buildAddAcademyButton(fullWidth: true), + ], + ), + ); + } + + return SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + const Text( + '๋“ฑ๋ก๋œ ํ•™์›', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + ..._academies.map((academy) => _buildAcademyCard(academy)), + const SizedBox(height: 24), + _buildAddAcademyButton(), + const SizedBox(height: 20), + ], + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 17), + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x0D000000), + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + child: Row( + children: const [ + CustomBackButton(), + SizedBox(width: 20), + Text( + 'ํ•™์› ๊ด€๋ฆฌ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + ], + ), + ); + } + + Widget _buildAcademyCard(UserAcademyResponse academy) { + final isActive = + academy.academyCode != null && + academy.academyCode == _defaultAcademyCode; + final isPending = academy.registerStatus != 'Y'; + return Container( + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all( + color: isActive ? const Color(0xFFAC5BF8) : const Color(0xFFE9ECEF), + width: isActive ? 2 : 1, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + academy.academyName, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + ), + if (isActive) + Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 4, + ), + decoration: BoxDecoration( + color: const Color(0xFFAC5BF8), + borderRadius: BorderRadius.circular(12), + ), + child: const Text( + 'ํ™œ์„ฑ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 12, + color: Colors.white, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Row( + children: [ + const Icon( + Icons.location_on_outlined, + size: 16, + color: Color(0xFF999999), + ), + const SizedBox(width: 4), + Expanded( + child: Text( + academy.academyRoadAddress.isNotEmpty + ? academy.academyRoadAddress + : '์ฃผ์†Œ ์ •๋ณด ์—†์Œ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ), + ], + ), + const SizedBox(height: 4), + const SizedBox(height: 12), + Row( + children: [ + if (isPending) + Expanded( + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 8, + ), + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color(0xFFFFF4E5), + borderRadius: BorderRadius.circular(8), + ), + child: const Text( + '๋“ฑ๋ก ์Šน์ธ ๋Œ€๊ธฐ์ค‘', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 13, + color: Color(0xFFFF9800), + ), + ), + ), + ) + else ...[ + Expanded( + child: OutlinedButton( + onPressed: isActive + ? null + : () => _setDefaultAcademy(academy.academyCode), + style: OutlinedButton.styleFrom( + foregroundColor: const Color(0xFFAC5BF8), + side: const BorderSide(color: Color(0xFFAC5BF8)), + ), + child: Text(isActive ? 'ํ™œ์„ฑํ™”๋จ' : 'ํ™œ์„ฑํ™”'), + ), + ), + const SizedBox(width: 8), + Expanded( + child: OutlinedButton( + onPressed: () => _showDeleteDialog(academy), + style: OutlinedButton.styleFrom( + foregroundColor: const Color(0xFFF44336), + side: const BorderSide(color: Color(0xFFF44336)), + ), + child: const Text('์‚ญ์ œ'), + ), + ), + ], + ], + ), + ], + ), + ); + } + + Widget _buildAddAcademyButton({bool fullWidth = false}) { + final button = OutlinedButton.icon( + onPressed: () => Navigator.pushNamed(context, '/academy/list'), + icon: const Icon(Icons.add), + label: const Text('ํ•™์› ์ถ”๊ฐ€ํ•˜๊ธฐ'), + style: OutlinedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + foregroundColor: const Color(0xFFAC5BF8), + side: const BorderSide(color: Color(0xFFAC5BF8)), + ), + ); + return SizedBox( + width: double.infinity, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: fullWidth ? 0 : 0), + child: button, + ), + ); + } + + void _showDeleteDialog(UserAcademyResponse academy) { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('ํ•™์› ์‚ญ์ œ'), + content: Text('${academy.academyName}์„(๋ฅผ) ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('์ทจ์†Œ'), + ), + TextButton( + onPressed: () { + _removeAcademy(academy); + Navigator.pop(context); + }, + style: TextButton.styleFrom( + foregroundColor: const Color(0xFFF44336), + ), + child: const Text('์‚ญ์ œ'), + ), + ], + ), + ); + } + + Future _loadAcademies() async { + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + _defaultAcademyCode = await _academyService.getDefaultAcademyCode(); + + final cached = await _academyService.loadAcademiesFromCache(); + if (cached != null) { + setState(() { + _academies = cached; + }); + } + + final userId = await _authService.getUserId(); + if (userId == null) { + throw Exception('์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + final academies = await _academyService.getUserAcademies(userId); + await _academyService.saveAcademiesToCache(academies); + setState(() { + _academies = academies; + _isLoading = false; + }); + } catch (e) { + setState(() { + _isLoading = false; + _errorMessage = 'ํ•™์› ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.\n$e'; + }); + } + } + + Future _setDefaultAcademy(String? academyCode) async { + if (academyCode == null) return; + await _academyService.saveDefaultAcademyCode(academyCode); + setState(() { + _defaultAcademyCode = academyCode; + }); + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('ํ™œ์„ฑ ํ•™์›์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค'))); + } + + Future _removeAcademy(UserAcademyResponse academy) async { + final academyUserId = academy.academy_user_id; + if (academyUserId == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('ํ•™์› ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.')), + ); + return; + } + + setState(() { + _isLoading = true; + }); + + try { + await _academyService.leaveAcademy(academyUserId); + await _loadAcademies(); + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('ํƒˆํ‡ด ์š”์ฒญ์ด ์ฒ˜๋ฆฌ ์ค‘์ž…๋‹ˆ๋‹ค.')), + ); + } catch (e) { + if (!mounted) return; + setState(() { + _isLoading = false; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('ํ•™์› ํƒˆํ‡ด์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.\n$e')), + ); + } + } +} diff --git a/frontend/lib/screens/mypage/account_management_page.dart b/frontend/lib/screens/mypage/account_management_page.dart new file mode 100644 index 0000000..757c1c7 --- /dev/null +++ b/frontend/lib/screens/mypage/account_management_page.dart @@ -0,0 +1,449 @@ +import 'package:flutter/material.dart'; +import '../../routes/app_routes.dart'; +import '../../services/auth_service.dart'; +import '../../services/user_service.dart'; +import '../../models/user.dart'; +import '../../widgets/back_button.dart'; + +/// ๊ณ„์ • ๊ด€๋ฆฌ ํŽ˜์ด์ง€ +/// ๊ฐœ์ธ์ •๋ณด ์ˆ˜์ •, ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ, ๊ณ„์ • ์„ค์ • ๋“ฑ์„ ๊ด€๋ฆฌํ•˜๋Š” ํŽ˜์ด์ง€ +class AccountManagementPage extends StatefulWidget { + const AccountManagementPage({super.key}); + + @override + State createState() => _AccountManagementPageState(); +} + +class _AccountManagementPageState extends State { + final UserService _userService = UserService(); + bool _isLoadingProfile = true; + bool _isLoggingOut = false; + String? _email; + String? _phoneNumber; + String? _birthDate; + + @override + void initState() { + super.initState(); + _userService.addListener(_handleUserUpdated); + _loadUserProfile(); + } + + @override + void dispose() { + _userService.removeListener(_handleUserUpdated); + super.dispose(); + } + + Future _loadUserProfile() async { + final cachedUser = _userService.getUser(); + if (cachedUser != null) { + setState(() { + _applyUserData(cachedUser); + _isLoadingProfile = false; + }); + } else { + setState(() { + _isLoadingProfile = true; + }); + } + + final fetchedUser = await _userService.fetchUserFromServer(); + if (!mounted) return; + + if (fetchedUser != null) { + setState(() { + _applyUserData(fetchedUser); + }); + } else if (cachedUser == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.')), + ); + } + + setState(() { + _isLoadingProfile = false; + }); + } + + void _handleUserUpdated(User? user) { + if (!mounted || user == null) return; + setState(() { + _applyUserData(user); + }); + } + + void _applyUserData(User user) { + _email = user.email; + _phoneNumber = user.phoneNumber; + _birthDate = user.birthDate; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + + // ๊ฐœ์ธ์ •๋ณด ์„น์…˜ + _buildSectionTitle('๊ฐœ์ธ์ •๋ณด'), + const SizedBox(height: 12), + _buildInfoItem( + '์ด๋ฉ”์ผ', + _isLoadingProfile ? null : _formatEmail(_email), + Icons.email_outlined, + ), + _buildInfoItem( + '์ „ํ™”๋ฒˆํ˜ธ', + _isLoadingProfile + ? null + : _formatPhoneNumber(_phoneNumber), + Icons.phone_outlined, + ), + _buildInfoItem( + '์ƒ๋…„์›”์ผ', + _isLoadingProfile ? null : _formatBirthDate(_birthDate), + Icons.cake_outlined, + ), + + const SizedBox(height: 32), + + // ๋ณด์•ˆ ์„น์…˜ + _buildSectionTitle('๋ณด์•ˆ'), + const SizedBox(height: 12), + _buildActionItem('๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ', Icons.lock_outlined, () { + // TODO: ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ํŽ˜์ด์ง€๋กœ ์ด๋™ + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์˜ˆ์ •')), + ); + }), + _buildActionItem('2๋‹จ๊ณ„ ์ธ์ฆ', Icons.security_outlined, () { + // TODO: 2๋‹จ๊ณ„ ์ธ์ฆ ์„ค์ • ํŽ˜์ด์ง€๋กœ ์ด๋™ + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('2๋‹จ๊ณ„ ์ธ์ฆ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์˜ˆ์ •')), + ); + }), + + const SizedBox(height: 32), + + // ๊ณ„์ • ์ž‘์—… + _buildSectionTitle('๊ณ„์ • ์ž‘์—…'), + const SizedBox(height: 12), + _buildActionItem( + '๋กœ๊ทธ์•„์›ƒ', + Icons.logout_outlined, + () { + _showLogoutDialog(); + }, + isDestructive: false, + isBusy: _isLoggingOut, + ), + _buildActionItem('ํšŒ์› ํƒˆํ‡ด', Icons.person_remove_outlined, () { + _showDeleteAccountDialog(); + }, isDestructive: true), + + const SizedBox(height: 20), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 17), + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x0D000000), + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + child: Row( + children: const [ + CustomBackButton(), + SizedBox(width: 20), + Text( + '๊ณ„์ • ๊ด€๋ฆฌ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + ], + ), + ); + } + + Widget _buildSectionTitle(String title) { + return Text( + title, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ); + } + + Widget _buildInfoItem(String label, String? value, IconData icon) { + return Container( + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Tooltip( + message: '$label ์•„์ด์ฝ˜', + child: Semantics( + label: '$label ์•„์ด์ฝ˜', + child: Icon(icon, size: 24, color: const Color(0xFF666666)), + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: Color(0xFF999999), + ), + ), + const SizedBox(height: 4), + Text( + value ?? '๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...', + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: value == null + ? const Color(0xFF999999) + : const Color(0xFF333333), + ), + ), + ], + ), + ), + ], + ), + ); + } + + Widget _buildActionItem( + String title, + IconData icon, + VoidCallback onTap, { + bool isDestructive = false, + bool isBusy = false, + }) { + return Container( + margin: const EdgeInsets.only(bottom: 12), + child: Material( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + child: InkWell( + onTap: isBusy ? null : onTap, + borderRadius: BorderRadius.circular(12), + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all( + color: isDestructive + ? const Color(0xFFF44336) + : const Color(0xFFE9ECEF), + ), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Icon( + icon, + size: 24, + color: isDestructive + ? const Color(0xFFF44336) + : const Color(0xFF666666), + ), + const SizedBox(width: 16), + Expanded( + child: Text( + title, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: isDestructive + ? const Color(0xFFF44336) + : const Color(0xFF333333), + ), + ), + ), + if (isBusy) + const SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Color(0xFF999999)), + ), + ) + else + Icon( + Icons.chevron_right, + size: 24, + color: isDestructive + ? const Color(0xFFF44336) + : const Color(0xFF999999), + ), + ], + ), + ), + ), + ), + ); + } + + void _showLogoutDialog() { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('๋กœ๊ทธ์•„์›ƒ'), + content: const Text('์ •๋ง ๋กœ๊ทธ์•„์›ƒ ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('์ทจ์†Œ'), + ), + TextButton( + onPressed: _isLoggingOut + ? null + : () { + Navigator.pop(context); + _performLogout(); + }, + child: const Text('๋กœ๊ทธ์•„์›ƒ'), + ), + ], + ), + ); + } + + Future _performLogout() async { + if (_isLoggingOut) return; + setState(() { + _isLoggingOut = true; + }); + + final messenger = ScaffoldMessenger.of(context); + try { + final authService = AuthService(); + await authService.signOutFromServer(); + await authService.clearTokens(); + if (!mounted) return; + Navigator.pushNamedAndRemoveUntil( + context, + AppRoutes.login, + (route) => false, + ); + } catch (e) { + if (!mounted) return; + messenger.showSnackBar(SnackBar(content: Text('๋กœ๊ทธ์•„์›ƒ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: $e'))); + } finally { + if (mounted) { + setState(() { + _isLoggingOut = false; + }); + } + } + } + + void _showDeleteAccountDialog() { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('ํšŒ์› ํƒˆํ‡ด'), + content: const Text('์ •๋ง ํƒˆํ‡ดํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?\n๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ญ์ œ๋˜๋ฉฐ ๋ณต๊ตฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('์ทจ์†Œ'), + ), + TextButton( + onPressed: () { + // TODO: ํšŒ์› ํƒˆํ‡ด ๋กœ์ง ๊ตฌํ˜„ + Navigator.pop(context); + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('ํšŒ์› ํƒˆํ‡ด ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์˜ˆ์ •'))); + }, + style: TextButton.styleFrom( + foregroundColor: const Color(0xFFF44336), + ), + child: const Text('ํƒˆํ‡ด'), + ), + ], + ), + ); + } + + String _formatEmail(String? rawEmail) { + if (rawEmail == null || rawEmail.trim().isEmpty) { + return '๋ฏธ๋“ฑ๋ก'; + } + return rawEmail.trim().toLowerCase(); + } + + String _formatPhoneNumber(String? rawNumber) { + if (rawNumber == null || rawNumber.trim().isEmpty) { + return '๋ฏธ๋“ฑ๋ก'; + } + final digits = rawNumber.replaceAll(RegExp(r'\D'), ''); + if (digits.length == 11) { + return '${digits.substring(0, 3)}-${digits.substring(3, 7)}-${digits.substring(7)}'; + } + return rawNumber; + } + + String _formatBirthDate(String? rawDate) { + if (rawDate == null || rawDate.trim().isEmpty) { + return '๋ฏธ๋“ฑ๋ก'; + } + try { + final date = DateTime.parse(rawDate); + return '${date.year.toString().padLeft(4, '0')}.' + '${date.month.toString().padLeft(2, '0')}.' + '${date.day.toString().padLeft(2, '0')}'; + } catch (_) { + return rawDate; + } + } +} diff --git a/frontend/lib/screens/mypage/display_settings_page.dart b/frontend/lib/screens/mypage/display_settings_page.dart new file mode 100644 index 0000000..95b41b2 --- /dev/null +++ b/frontend/lib/screens/mypage/display_settings_page.dart @@ -0,0 +1,224 @@ +import 'package:flutter/material.dart'; +import '../../widgets/back_button.dart'; + +/// ํ™”๋ฉด ์„ค์ • ํŽ˜์ด์ง€ +/// ํ…Œ๋งˆ, ํฐํŠธ ํฌ๊ธฐ, ํ™”๋ฉด ๋ฐ๊ธฐ ๋“ฑ์„ ์„ค์ •ํ•˜๋Š” ํŽ˜์ด์ง€ +class DisplaySettingsPage extends StatefulWidget { + const DisplaySettingsPage({super.key}); + + @override + State createState() => _DisplaySettingsPageState(); +} + +class _DisplaySettingsPageState extends State { + // TODO: ์„ค์ • ๊ฐ’๋“ค์„ SharedPreferences์— ์ €์žฅ + bool _darkMode = false; + double _fontSize = 1.0; // ๊ธฐ๋ณธ ํฌ๊ธฐ + bool _autoBrightness = true; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + + // ๋‹คํฌ ๋ชจ๋“œ + _buildSwitchSetting( + title: '๋‹คํฌ ๋ชจ๋“œ', + subtitle: '์–ด๋‘์šด ํ…Œ๋งˆ ์‚ฌ์šฉ', + value: _darkMode, + onChanged: (value) { + setState(() { + _darkMode = value; + }); + // TODO: ํ…Œ๋งˆ ๋ณ€๊ฒฝ ์ ์šฉ + }, + ), + + const SizedBox(height: 16), + + // ํฐํŠธ ํฌ๊ธฐ + _buildFontSizeSetting(), + + const SizedBox(height: 16), + + // ์ž๋™ ๋ฐ๊ธฐ + _buildSwitchSetting( + title: '์ž๋™ ๋ฐ๊ธฐ', + subtitle: '์ฃผ๋ณ€ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ํ™”๋ฉด ๋ฐ๊ธฐ ์ž๋™ ์กฐ์ ˆ', + value: _autoBrightness, + onChanged: (value) { + setState(() { + _autoBrightness = value; + }); + // TODO: ๋ฐ๊ธฐ ์„ค์ • ์ ์šฉ + }, + ), + + const SizedBox(height: 20), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 17), + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x0D000000), + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + child: Row( + children: const [ + CustomBackButton(), + SizedBox(width: 20), + Text( + 'ํ™”๋ฉด', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + ], + ), + ); + } + + Widget _buildSwitchSetting({ + required String title, + required String subtitle, + required bool value, + required ValueChanged onChanged, + }) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + Text( + subtitle, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF999999), + ), + ), + ], + ), + ), + Switch( + value: value, + onChanged: onChanged, + activeColor: const Color(0xFFAC5BF8), + ), + ], + ), + ); + } + + Widget _buildFontSizeSetting() { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'ํฐํŠธ ํฌ๊ธฐ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 16), + Row( + children: [ + const Text( + '์ž‘๊ฒŒ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF999999), + ), + ), + Expanded( + child: Slider( + value: _fontSize, + min: 0.8, + max: 1.2, + divisions: 4, + activeColor: const Color(0xFFAC5BF8), + onChanged: (value) { + setState(() { + _fontSize = value; + }); + // TODO: ํฐํŠธ ํฌ๊ธฐ ๋ณ€๊ฒฝ ์ ์šฉ + }, + ), + ), + const Text( + 'ํฌ๊ฒŒ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF999999), + ), + ), + ], + ), + ], + ), + ); + } +} + diff --git a/frontend/lib/screens/mypage/homework_status_page.dart b/frontend/lib/screens/mypage/homework_status_page.dart new file mode 100644 index 0000000..15d5131 --- /dev/null +++ b/frontend/lib/screens/mypage/homework_status_page.dart @@ -0,0 +1,475 @@ +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import '../../services/assessment_repository.dart'; +import '../../services/academy_service.dart'; +import '../../services/auth_service.dart'; +import '../../utils/academy_utils.dart'; +import '../../routes/app_routes.dart'; +import '../../widgets/back_button.dart'; +import '../../widgets/empty_state_message.dart'; + +enum HomeworkStatusViewState { + loading, + normal, // ์ˆ™์ œ ๋ชฉ๋ก ์ •์ƒ ํ‘œ์‹œ + noAcademy, // ํ•™์›์ด ํ•˜๋‚˜๋„ ์—†์Œ + error, // ๊ธฐํƒ€ ์—๋Ÿฌ +} + +/// ์ˆ™์ œ ํ˜„ํ™ฉ ํŽ˜์ด์ง€ +/// ํ• ๋‹น๋œ ์ˆ™์ œ ๋ชฉ๋ก๊ณผ ์ œ์ถœ ํ˜„ํ™ฉ์„ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€ +class HomeworkStatusPage extends StatefulWidget { + const HomeworkStatusPage({super.key}); + + @override + State createState() => _HomeworkStatusPageState(); +} + +class _HomeworkStatusPageState extends State { + final getIt = GetIt.instance; + + late final AssessmentRepository _assessmentRepository = + getIt(); + late final AcademyService _academyService = getIt(); + late final AuthService _authService = getIt(); + + HomeworkStatusViewState _viewState = HomeworkStatusViewState.loading; + String? _errorMessage; + List _homeworks = []; + + // Invariants: + // - when _viewState == HomeworkStatusViewState.error, _errorMessage != null (best-effort) + // - when _viewState == HomeworkStatusViewState.noAcademy, _homeworks is always empty + + @override + Widget build(BuildContext context) { + final pendingHomeworks = _homeworks.where((h) => !h.isCompleted).toList(); + final completedHomeworks = _homeworks.where((h) => h.isCompleted).toList(); + + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded( + child: _buildBody( + pendingHomeworks: pendingHomeworks, + completedHomeworks: completedHomeworks, + ), + ), + ], + ), + ), + ); + } + + Widget _buildBody({ + required List pendingHomeworks, + required List completedHomeworks, + }) { + if (_viewState == HomeworkStatusViewState.loading) { + return const Center(child: CircularProgressIndicator()); + } + + if (_viewState == HomeworkStatusViewState.error) { + return Padding( + padding: const EdgeInsets.all(20), + child: Center( + child: EmptyStateMessage( + icon: Icons.error_outline, + title: '์ˆ™์ œ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.', + description: _errorMessage, + primaryActionLabel: '๋‹ค์‹œ ์‹œ๋„', + onPrimaryAction: _loadAssessments, + ), + ), + ); + } + + if (_viewState == HomeworkStatusViewState.noAcademy) { + return const Center( + child: EmptyStateMessage.academy( + title: '๋“ฑ๋ก๋œ ํ•™์›์ด ์—†์–ด์š”.', + description: '๋งˆ์ดํŽ˜์ด์ง€์—์„œ ํ•™์›์„ ๋จผ์ € ๋“ฑ๋กํ•ด์ฃผ์„ธ์š”.', + ), + ); + } + + // ์—ฌ๊ธฐ๊นŒ์ง€ ์™”์œผ๋ฉด normal ์ƒํƒœ + if (_homeworks.isEmpty) { + return const Center( + child: EmptyStateMessage.homework( + title: '๋“ฑ๋ก๋œ ์ˆ™์ œ๊ฐ€ ์—†์–ด์š”.', + ), + ); + } + + return SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + + // ์š”์•ฝ ์นด๋“œ + _buildSummaryCard(pendingHomeworks.length), + + const SizedBox(height: 24), + + // ๋ฏธ์™„๋ฃŒ ์ˆ™์ œ + if (pendingHomeworks.isNotEmpty) ...[ + const Text( + '๋ฏธ์™„๋ฃŒ ์ˆ™์ œ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + ...pendingHomeworks.map((hw) => _buildHomeworkCard(hw)), + const SizedBox(height: 24), + ], + + // ์™„๋ฃŒ๋œ ์ˆ™์ œ + if (completedHomeworks.isNotEmpty) ...[ + const Text( + '์™„๋ฃŒ๋œ ์ˆ™์ œ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + ...completedHomeworks.map((hw) => _buildHomeworkCard(hw)), + ], + + const SizedBox(height: 20), + ], + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 17), + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x0D000000), + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + child: Row( + children: const [ + CustomBackButton(), + SizedBox(width: 20), + Text( + '์ˆ™์ œ ํ˜„ํ™ฉ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + ], + ), + ); + } + + Widget _buildSummaryCard(int pendingCount) { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF7C3AED)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + const Icon(Icons.assignment_outlined, size: 40, color: Colors.white), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '๋ฏธ์™„๋ฃŒ ์ˆ™์ œ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Colors.white, + ), + ), + const SizedBox(height: 4), + Text( + '$pendingCount๊ฐœ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 32, + color: Colors.white, + ), + ), + ], + ), + ), + ], + ), + ); + } + + Widget _buildHomeworkCard(HomeworkItem homework) { + final daysLeft = homework.dueDate.difference(DateTime.now()).inDays; + final isOverdue = daysLeft < 0; + final isDueSoon = daysLeft >= 0 && daysLeft <= 2; + + return GestureDetector( + onTap: () => _navigateToHomeDate(homework.dueDate), + child: Container( + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: homework.isCompleted ? const Color(0xFFF8F9FA) : Colors.white, + border: Border.all( + color: homework.isCompleted + ? const Color(0xFFE9ECEF) + : (isOverdue + ? const Color(0xFFF44336) + : (isDueSoon + ? const Color(0xFFFF9800) + : const Color(0xFFE9ECEF))), + ), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + homework.title, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: homework.isCompleted + ? const Color(0xFF999999) + : const Color(0xFF333333), + decoration: homework.isCompleted + ? TextDecoration.lineThrough + : null, + ), + ), + ), + if (homework.isCompleted) + const Icon( + Icons.check_circle, + color: Color(0xFF4CAF50), + size: 24, + ), + ], + ), + const SizedBox(height: 8), + Text( + homework.assignedBy, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF666666), + ), + ), + const SizedBox(height: 4), + Row( + children: [ + Icon( + Icons.schedule, + size: 14, + color: isOverdue + ? const Color(0xFFF44336) + : const Color(0xFF999999), + ), + const SizedBox(width: 4), + Text( + '๋งˆ๊ฐ: ${_formatDate(homework.dueDate)}', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: isOverdue + ? const Color(0xFFF44336) + : const Color(0xFF999999), + ), + ), + if (!homework.isCompleted && isDueSoon) ...[ + const SizedBox(width: 8), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 2, + ), + decoration: BoxDecoration( + color: const Color(0xFFFF9800), + borderRadius: BorderRadius.circular(8), + ), + child: const Text( + '๊ณง ๋งˆ๊ฐ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 10, + color: Colors.white, + ), + ), + ), + ], + ], + ), + ], + ), + ), + ); + } + + void _navigateToHomeDate(DateTime dueDate) { + final targetDate = DateTime(dueDate.year, dueDate.month, dueDate.day); + Navigator.pushNamedAndRemoveUntil( + context, + AppRoutes.mainNavigation, + (route) => false, + arguments: {'targetDate': _formatRouteDate(targetDate)}, + ); + } + + String _formatRouteDate(DateTime date) { + final mm = date.month.toString().padLeft(2, '0'); + final dd = date.day.toString().padLeft(2, '0'); + return '${date.year}-$mm-$dd'; + } + + String _formatDate(DateTime date) { + return '${date.year}.${date.month.toString().padLeft(2, '0')}.${date.day.toString().padLeft(2, '0')}'; + } + + @override + void initState() { + super.initState(); + _loadAssessments(); + } + + Future _loadAssessments() async { + setState(() { + _viewState = HomeworkStatusViewState.loading; + _errorMessage = null; + }); + + try { + final defaultAcademyCode = await _academyService.getDefaultAcademyCode(); + if (defaultAcademyCode == null) { + throw Exception('๋””ํดํŠธ ํ•™์›์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + String? userAcademyId = await getUserAcademyId( + academyService: _academyService, + academyCode: defaultAcademyCode, + ); + if (userAcademyId == null) { + final userId = await _authService.getUserId(); + if (userId != null) { + try { + final academies = await _academyService.getUserAcademies(userId); + if (academies.isNotEmpty) { + await _academyService.saveAcademiesToCache(academies); + userAcademyId = await getUserAcademyId( + academyService: _academyService, + academyCode: defaultAcademyCode, + registeredAcademies: academies + .where((academy) => academy.registerStatus == 'Y') + .toList(), + ); + } + } catch (e) { + print('[HomeworkStatusPage] ํ•™์› ๋ชฉ๋ก ๊ฐฑ์‹  ์‹คํŒจ: $e'); + } + } + } + if (userAcademyId == null) { + // ๋“ฑ๋ก๋œ ํ•™์›์ด ์ „ํ˜€ ์—†๋Š” ๊ฒฝ์šฐ + setState(() { + _viewState = HomeworkStatusViewState.noAcademy; + _homeworks = []; + }); + return; + } + + final now = DateTime.now(); + final monthStart = DateTime.utc(now.year, now.month, 1); + print( + '[HomeworkStatusPage] ์ˆ™์ œ ๋ฐ์ดํ„ฐ ์กฐํšŒ ์‹œ์ž‘ | ํ•™์› ์ฝ”๋“œ: $defaultAcademyCode, ํ•™์› ์‚ฌ์šฉ์ž ID: $userAcademyId, ๊ธฐ์ค€ ์›”: $monthStart', + ); + final data = await _assessmentRepository.getForMonth( + academyId: userAcademyId, + dateTime: monthStart, + ); + print('[HomeworkStatusPage] ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ ${data.length}๊ฐœ์˜ ๋‚ ์งœ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ '); + + final mapped = []; + data.forEach((dateString, assessments) { + final parsedDate = DateTime.tryParse(dateString); + final dueDate = parsedDate ?? DateTime.now(); + + for (final assessment in assessments) { + mapped.add( + HomeworkItem( + title: assessment.assessName, + dueDate: dueDate, + isCompleted: assessment.assessStatus.toUpperCase() == 'Y', + assignedBy: assessment.assessClass.isNotEmpty + ? assessment.assessClass + : '๋‹ด๋‹น ์„ ์ƒ๋‹˜ ๋ฏธ์ง€์ •', + ), + ); + } + }); + mapped.sort((a, b) => a.dueDate.compareTo(b.dueDate)); + + setState(() { + _homeworks = mapped; + _viewState = HomeworkStatusViewState.normal; + }); + } catch (e) { + print('[HomeworkStatusPage] ์ˆ™์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค: $e'); + setState(() { + _errorMessage = e.toString(); + _viewState = HomeworkStatusViewState.error; + }); + } + } +} + +class HomeworkItem { + final String title; + final DateTime dueDate; + final bool isCompleted; + final String assignedBy; + + HomeworkItem({ + required this.title, + required this.dueDate, + required this.isCompleted, + required this.assignedBy, + }); +} diff --git a/frontend/lib/screens/mypage/learning_statistics_page.dart b/frontend/lib/screens/mypage/learning_statistics_page.dart new file mode 100644 index 0000000..f616a47 --- /dev/null +++ b/frontend/lib/screens/mypage/learning_statistics_page.dart @@ -0,0 +1,281 @@ +import 'package:flutter/material.dart'; +import '../../widgets/back_button.dart'; + +/// ํ•™์Šต ํ†ต๊ณ„/ํ•™์Šต ๋ฆฌํฌํŠธ ํŽ˜์ด์ง€ +/// ์ƒ์„ธํ•œ ํ•™์Šต ๋ถ„์„, ๊ฐ•์ /์•ฝ์  ๋ถ„์„, ๊ณผ๋ชฉ๋ณ„ ํ†ต๊ณ„๋ฅผ ์ œ๊ณตํ•˜๋Š” ํŽ˜์ด์ง€ +class LearningStatisticsPage extends StatefulWidget { + const LearningStatisticsPage({super.key}); + + @override + State createState() => + _LearningStatisticsPageState(); +} + +class _LearningStatisticsPageState extends State { + String _selectedPeriod = '์ด๋ฒˆ ์ฃผ'; + + // TODO: ์„œ๋ฒ„์—์„œ ํ†ต๊ณ„ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ + final Map _subjectProgress = { + '์ˆ˜ํ•™': 75, + '์˜์–ด': 85, + '๊ณผํ•™': 60, + '๊ตญ์–ด': 70, + }; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + + // ๊ธฐ๊ฐ„ ์„ ํƒ + _buildPeriodSelector(), + + const SizedBox(height: 24), + + // ์ „์ฒด ํ•™์Šต ํ˜„ํ™ฉ ์นด๋“œ + _buildOverallStatusCard(), + + const SizedBox(height: 24), + + // ๊ณผ๋ชฉ๋ณ„ ํ†ต๊ณ„ + _buildSubjectStatistics(), + + const SizedBox(height: 24), + + // TODO: ๊ฐ•์ /์•ฝ์  ๋ถ„์„ + _buildStrengthWeaknessCard(), + + const SizedBox(height: 20), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 17), + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x0D000000), + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + child: Row( + children: const [ + CustomBackButton(), + SizedBox(width: 20), + Text( + 'ํ•™์Šต ํ†ต๊ณ„', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + ], + ), + ); + } + + Widget _buildPeriodSelector() { + final periods = ['์ด๋ฒˆ ์ฃผ', '์ด๋ฒˆ ๋‹ฌ', '์ „์ฒด']; + return Row( + children: periods.map((period) { + final isSelected = _selectedPeriod == period; + return Padding( + padding: const EdgeInsets.only(right: 8), + child: ChoiceChip( + label: Text(period), + selected: isSelected, + onSelected: (selected) { + setState(() { + _selectedPeriod = period; + }); + // TODO: ๊ธฐ๊ฐ„๋ณ„ ๋ฐ์ดํ„ฐ ์กฐํšŒ + }, + selectedColor: const Color(0xFFAC5BF8), + labelStyle: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: isSelected ? Colors.white : const Color(0xFF666666), + ), + ), + ); + }).toList(), + ); + } + + Widget _buildOverallStatusCard() { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF7C3AED)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildStatItem('ํ•™์Šต ์‹œ๊ฐ„', '15์‹œ๊ฐ„'), + _buildStatItem('ํ‘ผ ๋ฌธ์ œ', '127๊ฐœ'), + _buildStatItem('์ •๋‹ต๋ฅ ', '82%'), + ], + ), + ], + ), + ); + } + + Widget _buildStatItem(String label, String value) { + return Column( + children: [ + Text( + value, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 24, + color: Colors.white, + ), + ), + const SizedBox(height: 4), + Text( + label, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: Colors.white, + ), + ), + ], + ); + } + + Widget _buildSubjectStatistics() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '๊ณผ๋ชฉ๋ณ„ ์ง„ํ–‰๋ฅ ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + ..._subjectProgress.entries.map((entry) { + return Container( + margin: const EdgeInsets.only(bottom: 12), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + entry.key, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + Text( + '${entry.value}%', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Color(0xFFAC5BF8), + ), + ), + ], + ), + const SizedBox(height: 8), + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Container( + height: 8, + decoration: const BoxDecoration(color: Color(0xFFE9ECEF)), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: entry.value / 100, + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF7C3AED)], + ), + ), + ), + ), + ), + ), + ], + ), + ); + }), + ], + ); + } + + Widget _buildStrengthWeaknessCard() { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: const Center( + child: Text( + '๊ฐ•์ /์•ฝ์  ๋ถ„์„\n(์ถ”ํ›„ ๊ตฌํ˜„ ์˜ˆ์ •)', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } +} + diff --git a/frontend/lib/screens/mypage/mypage.dart b/frontend/lib/screens/mypage/mypage.dart new file mode 100644 index 0000000..0e3fa8d --- /dev/null +++ b/frontend/lib/screens/mypage/mypage.dart @@ -0,0 +1,324 @@ +import 'package:flutter/material.dart'; +import '../../widgets/app_header.dart'; +import '../../widgets/app_header_title.dart'; +import '../../widgets/app_header_menu_button.dart'; +import '../../services/user_service.dart'; +import '../../models/user.dart'; + +/// ๋งˆ์ดํŽ˜์ด์ง€ +/// ์‚ฌ์šฉ์ž ํ”„๋กœํ•„, ํ•™์Šต ํ˜„ํ™ฉ, ๊ฐ์ข… ์„ค์ • ๋ฉ”๋‰ด๋ฅผ ์ œ๊ณตํ•˜๋Š” ํŽ˜์ด์ง€ +/// +/// ๊ตฌ์„ฑ: +/// 1. ํ—ค๋”: ๋งˆ์ดํŽ˜์ด์ง€ ํƒ€์ดํ‹€ + ํ–„๋ฒ„๊ฑฐ ๋ฉ”๋‰ด +/// 2. ํ”„๋กœํ•„ ์„น์…˜: ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ + ์ด๋ฆ„ + ํŽธ์ง‘ ๋ฒ„ํŠผ +/// 3. ํ•™์Šต ํ˜„ํ™ฉ ์นด๋“œ (์ถ”ํ›„ ๊ตฌํ˜„) +/// 4. ์„ค์ • ๋ฉ”๋‰ด ๋ชฉ๋ก +class MyPage extends StatefulWidget { + const MyPage({super.key}); + + @override + State createState() => _MyPageState(); +} + +class _MyPageState extends State { + final UserService _userService = UserService(); + + // UserService์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ + String _userName = '๊ฒŒ์ŠคํŠธ'; + String? _profileImageUrl; + + @override + void initState() { + super.initState(); + _loadUserData(); + + // ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋ก (ํ”„๋กœํ•„ ์ˆ˜์ • ์‹œ ์ž๋™ ์—…๋ฐ์ดํŠธ) + _userService.addListener(_onUserChanged); + } + + @override + void dispose() { + // ๋ฆฌ์Šค๋„ˆ ์ œ๊ฑฐ + _userService.removeListener(_onUserChanged); + super.dispose(); + } + + /// UserService์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด ๋กœ๋“œ + /// 1. ์บ์‹œ์—์„œ ๋จผ์ € ๋กœ๋“œ (๋น ๋ฅธ UI ํ‘œ์‹œ) + /// 2. ์„œ๋ฒ„์—์„œ ์ตœ์‹  ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ + Future _loadUserData() async { + // 1. ์บ์‹œ์—์„œ ๋จผ์ € ๋กœ๋“œ + final cachedUser = _userService.getUser(); + if (cachedUser != null) { + setState(() { + _userName = cachedUser.name; + _profileImageUrl = cachedUser.profileImageUrl; + }); + } + + // 2. ์„œ๋ฒ„์—์„œ ์ตœ์‹  ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ + final fetchedUser = await _userService.fetchUserFromServer(); + if (!mounted) return; + + if (fetchedUser != null) { + setState(() { + _userName = fetchedUser.name; + _profileImageUrl = fetchedUser.profileImageUrl; + }); + } + } + + /// ์‚ฌ์šฉ์ž ์ •๋ณด ๋ณ€๊ฒฝ ๋ฆฌ์Šค๋„ˆ + void _onUserChanged(User? user) { + if (user != null && mounted) { + setState(() { + _userName = user.name; + _profileImageUrl = user.profileImageUrl; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + // ํ—ค๋” + _buildHeader(), + + // ๋ฉ”์ธ ์ฝ˜ํ…์ธ  + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + + // ํ”„๋กœํ•„ ์„น์…˜ + _buildProfileSection(), + + const SizedBox(height: 24), + + // TODO: ํ•™์Šต ํ˜„ํ™ฉ ์นด๋“œ ๊ตฌํ˜„ + _buildLearningStatusCard(), + + const SizedBox(height: 24), + + // ์„ค์ • ๋ฉ”๋‰ด ๋ชฉ๋ก + _buildSettingsMenu(), + + const SizedBox(height: 20), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return const AppHeader( + title: AppHeaderTitle('๋งˆ์ดํŽ˜์ด์ง€', textAlign: TextAlign.center), + trailing: AppHeaderMenuButton(), + ); + } + + /// ํ”„๋กœํ•„ ์„น์…˜ + Widget _buildProfileSection() { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + // ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ + Container( + width: 60, + height: 60, + decoration: const BoxDecoration( + color: Color(0xFFE9ECEF), + shape: BoxShape.circle, + ), + child: _profileImageUrl != null + ? ClipOval( + child: Image.network( + _profileImageUrl!, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Icon( + Icons.person, + size: 32, + color: Color(0xFF999999), + ); + }, + ), + ) + : const Icon(Icons.person, size: 32, color: Color(0xFF999999)), + ), + const SizedBox(width: 16), + + // ์ด๋ฆ„ + Expanded( + child: Text( + _userName, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + ), + + // ํŽธ์ง‘ ๋ฒ„ํŠผ + IconButton( + icon: const Icon(Icons.edit_outlined, size: 24), + color: const Color(0xFF666666), + onPressed: () { + // TODO: ํ”„๋กœํ•„ ํŽธ์ง‘ ํŽ˜์ด์ง€๋กœ ์ด๋™ + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('ํ”„๋กœํ•„ ํŽธ์ง‘ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์˜ˆ์ •'))); + }, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ), + ], + ), + ); + } + + /// ํ•™์Šต ํ˜„ํ™ฉ ์นด๋“œ + /// TODO: ์ถ”ํ›„ ๊ตฌํ˜„ ์˜ˆ์ • + /// - ์—ฐ์† ํ•™์Šต ์ผ์ˆ˜ + /// - ์ฃผ๊ฐ„/์›”๊ฐ„ ํ•™์Šต ํ†ต๊ณ„ + /// - ์ตœ๊ทผ ํ•™์Šต ๋ฌธ์ œ์ง‘ + /// - ์ „์ฒด ์ง„ํ–‰๋ฅ  + Widget _buildLearningStatusCard() { + return Container( + width: double.infinity, + height: 150, + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: const Center( + child: Text( + 'ํ•™์Šต ํ˜„ํ™ฉ\n(์ถ”ํ›„ ๊ตฌํ˜„ ์˜ˆ์ •)', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } + + /// ์„ค์ • ๋ฉ”๋‰ด ๋ชฉ๋ก + Widget _buildSettingsMenu() { + final menuItems = [ + _MenuItem( + icon: Icons.smartphone, + title: 'ํ™”๋ฉด', + route: '/mypage/display-settings', + ), + _MenuItem( + icon: Icons.assignment_outlined, + title: '์ˆ™์ œ ํ˜„ํ™ฉ', + route: '/mypage/homework-status', + ), + _MenuItem( + icon: Icons.bar_chart_outlined, + title: 'ํ•™์Šต ํ†ต๊ณ„/ํ•™์Šต ๋ฆฌํฌํŠธ', + route: '/mypage/learning-statistics', + ), + _MenuItem( + icon: Icons.person_outline, + title: '๊ณ„์ • ๊ด€๋ฆฌ', + route: '/mypage/account-management', + ), + _MenuItem( + icon: Icons.school_outlined, + title: 'ํ•™์› ๊ด€๋ฆฌ', + route: '/mypage/academy-management', + ), + _MenuItem( + icon: Icons.notifications_outlined, + title: '์•Œ๋ฆผ ์„ค์ •', + route: '/mypage/notification-settings', + ), + ]; + + return Column( + children: menuItems.map((item) => _buildMenuItem(item)).toList(), + ); + } + + /// ๊ฐœ๋ณ„ ๋ฉ”๋‰ด ์•„์ดํ…œ + Widget _buildMenuItem(_MenuItem item) { + return Container( + margin: const EdgeInsets.only(bottom: 12), + child: Material( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + child: InkWell( + onTap: () { + Navigator.pushNamed(context, item.route); + }, + borderRadius: BorderRadius.circular(12), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + decoration: BoxDecoration( + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Icon(item.icon, size: 24, color: const Color(0xFF666666)), + const SizedBox(width: 16), + Expanded( + child: Text( + item.title, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + ), + const Icon( + Icons.chevron_right, + size: 24, + color: Color(0xFF999999), + ), + ], + ), + ), + ), + ), + ); + } +} + +/// ๋ฉ”๋‰ด ์•„์ดํ…œ ๋ชจ๋ธ +class _MenuItem { + final IconData icon; + final String title; + final String route; + + _MenuItem({required this.icon, required this.title, required this.route}); +} diff --git a/frontend/lib/screens/mypage/notification_settings_page.dart b/frontend/lib/screens/mypage/notification_settings_page.dart new file mode 100644 index 0000000..6689d77 --- /dev/null +++ b/frontend/lib/screens/mypage/notification_settings_page.dart @@ -0,0 +1,306 @@ +import 'package:flutter/material.dart'; +import '../../widgets/back_button.dart'; + +/// ์•Œ๋ฆผ ์„ค์ • ํŽ˜์ด์ง€ +/// ํ‘ธ์‹œ ์•Œ๋ฆผ, ์ˆ™์ œ ๋งˆ๊ฐ ์•Œ๋ฆผ, ํ•™์Šต ๋ฆฌ๋งˆ์ธ๋” ๋“ฑ์„ ์„ค์ •ํ•˜๋Š” ํŽ˜์ด์ง€ +class NotificationSettingsPage extends StatefulWidget { + const NotificationSettingsPage({super.key}); + + @override + State createState() => + _NotificationSettingsPageState(); +} + +class _NotificationSettingsPageState extends State { + // TODO: ์„ค์ • ๊ฐ’๋“ค์„ SharedPreferences์— ์ €์žฅ + bool _pushNotification = true; + bool _homeworkDeadline = true; + bool _learningReminder = false; + bool _academyNotice = true; + bool _marketingNotification = false; + + String _reminderTime = '20:00'; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + + // ์ „์ฒด ์•Œ๋ฆผ + _buildSectionTitle('์ „์ฒด ์•Œ๋ฆผ'), + const SizedBox(height: 12), + _buildSwitchSetting( + title: 'ํ‘ธ์‹œ ์•Œ๋ฆผ', + subtitle: '๋ชจ๋“  ์•Œ๋ฆผ ์ˆ˜์‹  ์—ฌ๋ถ€', + value: _pushNotification, + onChanged: (value) { + setState(() { + _pushNotification = value; + if (!value) { + // ํ‘ธ์‹œ ์•Œ๋ฆผ ๋„๋ฉด ๋ชจ๋“  ์•Œ๋ฆผ ๋„๊ธฐ + _homeworkDeadline = false; + _learningReminder = false; + _academyNotice = false; + _marketingNotification = false; + } + }); + // TODO: ์•Œ๋ฆผ ์„ค์ • ์ €์žฅ + }, + ), + + const SizedBox(height: 24), + + // ํ•™์Šต ๊ด€๋ จ ์•Œ๋ฆผ + _buildSectionTitle('ํ•™์Šต ๊ด€๋ จ'), + const SizedBox(height: 12), + _buildSwitchSetting( + title: '์ˆ™์ œ ๋งˆ๊ฐ ์•Œ๋ฆผ', + subtitle: '์ˆ™์ œ ๋งˆ๊ฐ 1์ผ ์ „, ๋‹น์ผ์— ์•Œ๋ฆผ', + value: _homeworkDeadline, + onChanged: _pushNotification + ? (value) { + setState(() { + _homeworkDeadline = value; + }); + // TODO: ์•Œ๋ฆผ ์„ค์ • ์ €์žฅ + } + : null, + ), + const SizedBox(height: 12), + _buildSwitchSetting( + title: 'ํ•™์Šต ๋ฆฌ๋งˆ์ธ๋”', + subtitle: '๋งค์ผ ์ •ํ•ด์ง„ ์‹œ๊ฐ„์— ํ•™์Šต ์•Œ๋ฆผ', + value: _learningReminder, + onChanged: _pushNotification + ? (value) { + setState(() { + _learningReminder = value; + }); + // TODO: ์•Œ๋ฆผ ์„ค์ • ์ €์žฅ + } + : null, + ), + if (_learningReminder) ...[ + const SizedBox(height: 12), + _buildTimeSelector(), + ], + + const SizedBox(height: 24), + + // ํ•™์› ๊ด€๋ จ ์•Œ๋ฆผ + _buildSectionTitle('ํ•™์› ๊ด€๋ จ'), + const SizedBox(height: 12), + _buildSwitchSetting( + title: 'ํ•™์› ๊ณต์ง€์‚ฌํ•ญ', + subtitle: '๋“ฑ๋ก๋œ ํ•™์›์˜ ๊ณต์ง€์‚ฌํ•ญ ์•Œ๋ฆผ', + value: _academyNotice, + onChanged: _pushNotification + ? (value) { + setState(() { + _academyNotice = value; + }); + // TODO: ์•Œ๋ฆผ ์„ค์ • ์ €์žฅ + } + : null, + ), + + const SizedBox(height: 24), + + // ๊ธฐํƒ€ ์•Œ๋ฆผ + _buildSectionTitle('๊ธฐํƒ€'), + const SizedBox(height: 12), + _buildSwitchSetting( + title: '๋งˆ์ผ€ํŒ… ์•Œ๋ฆผ', + subtitle: '์ด๋ฒคํŠธ, ํ˜œํƒ ๋“ฑ์˜ ๋งˆ์ผ€ํŒ… ์ •๋ณด', + value: _marketingNotification, + onChanged: _pushNotification + ? (value) { + setState(() { + _marketingNotification = value; + }); + // TODO: ์•Œ๋ฆผ ์„ค์ • ์ €์žฅ + } + : null, + ), + + const SizedBox(height: 20), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 17), + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x0D000000), + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + child: Row( + children: const [ + CustomBackButton(), + SizedBox(width: 20), + Text( + '์•Œ๋ฆผ ์„ค์ •', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + ], + ), + ); + } + + Widget _buildSectionTitle(String title) { + return Text( + title, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ); + } + + Widget _buildSwitchSetting({ + required String title, + required String subtitle, + required bool value, + required ValueChanged? onChanged, + }) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: onChanged == null + ? const Color(0xFF999999) + : const Color(0xFF333333), + ), + ), + const SizedBox(height: 4), + Text( + subtitle, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF999999), + ), + ), + ], + ), + ), + Switch( + value: value, + onChanged: onChanged, + activeColor: const Color(0xFFAC5BF8), + ), + ], + ), + ); + } + + Widget _buildTimeSelector() { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + const Text( + '์•Œ๋ฆผ ์‹œ๊ฐ„', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + const Spacer(), + TextButton( + onPressed: () async { + final TimeOfDay? picked = await showTimePicker( + context: context, + initialTime: TimeOfDay( + hour: int.parse(_reminderTime.split(':')[0]), + minute: int.parse(_reminderTime.split(':')[1]), + ), + ); + if (picked != null) { + setState(() { + _reminderTime = + '${picked.hour.toString().padLeft(2, '0')}:${picked.minute.toString().padLeft(2, '0')}'; + }); + // TODO: ์•Œ๋ฆผ ์‹œ๊ฐ„ ์ €์žฅ + } + }, + child: Row( + children: [ + Text( + _reminderTime, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFFAC5BF8), + ), + ), + const SizedBox(width: 4), + const Icon( + Icons.access_time, + size: 20, + color: Color(0xFFAC5BF8), + ), + ], + ), + ), + ], + ), + ); + } +} + diff --git a/frontend/lib/screens/notification/notification_page.dart b/frontend/lib/screens/notification/notification_page.dart new file mode 100644 index 0000000..83f5d12 --- /dev/null +++ b/frontend/lib/screens/notification/notification_page.dart @@ -0,0 +1,495 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import '../../widgets/app_header.dart'; +import '../../widgets/app_header_title.dart'; +import '../../widgets/app_header_menu_button.dart'; +import '../../domain/notification/notification_entity.dart'; +import '../../domain/notification/notification_type.dart'; +import '../../data/notification/notification_local_data_source.dart'; +import '../../data/notification/notification_repository_impl.dart'; +import '../../application/notification/notification_notifier.dart'; +import '../../routes/app_routes.dart'; +import '../workbook/chapter_detail_page.dart' show QuestionStatus; + +/// ์•Œ๋ฆผ ํŽ˜์ด์ง€ +/// ํ•™์Šต ๊ด€๋ จ ์•Œ๋ฆผ, ์ˆ™์ œ ๋งˆ๊ฐ ์•Œ๋ฆผ, ํ•™์› ๊ณต์ง€์‚ฌํ•ญ ๋“ฑ์„ ํ‘œ์‹œํ•˜๋Š” ํŽ˜์ด์ง€ +/// +/// ๊ตฌ์„ฑ: +/// 1. ํ—ค๋”: ์•Œ๋ฆผ ํƒ€์ดํ‹€ + ์ „์ฒด ์ฝ์Œ ์ฒ˜๋ฆฌ ๋ฒ„ํŠผ +/// 2. ์•Œ๋ฆผ ๋ชฉ๋ก: ํƒ€์ž…๋ณ„ ์•„์ด์ฝ˜, ๋‚ด์šฉ, ์‹œ๊ฐ„, ์ฝ์Œ/์•ˆ์ฝ์Œ ์ƒํƒœ +class NotificationPage extends StatefulWidget { + const NotificationPage({super.key}); + + @override + State createState() => _NotificationPageState(); +} + +class _NotificationPageState extends State { + NotificationNotifier? _notificationNotifier; + + @override + void initState() { + super.initState(); + _initializeNotifier(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // ํŽ˜์ด์ง€๊ฐ€ ๋‹ค์‹œ ํ‘œ์‹œ๋  ๋•Œ๋งˆ๋‹ค ์•Œ๋ฆผ ๋ชฉ๋ก ์ƒˆ๋กœ๊ณ ์นจ + if (_notificationNotifier != null) { + _notificationNotifier!.load(); + } + } + + Future _initializeNotifier() async { + final prefs = await SharedPreferences.getInstance(); + final local = NotificationLocalDataSource(prefs); + final repository = NotificationRepositoryImpl(local); + final notifier = NotificationNotifier(repository); + await notifier.load(); + if (mounted) { + setState(() { + _notificationNotifier = notifier; + }); + } + } + + /// ์™ธ๋ถ€์—์„œ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•œ ์ƒˆ๋กœ๊ณ ์นจ ๋ฉ”์„œ๋“œ + /// MainNavigationPage์—์„œ ํƒญ ์ „ํ™˜ ์‹œ ํ˜ธ์ถœ + void refresh() { + _notificationNotifier?.load(); + } + + @override + void dispose() { + _notificationNotifier?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (_notificationNotifier == null) { + return const Scaffold( + backgroundColor: Colors.white, + body: SafeArea(child: Center(child: CircularProgressIndicator())), + ); + } + + final notifier = _notificationNotifier!; + + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: ValueListenableBuilder( + valueListenable: notifier.isLoading, + builder: (context, isLoading, _) { + if (isLoading && notifier.notifications.value.isEmpty) { + return const Center(child: CircularProgressIndicator()); + } + + return ValueListenableBuilder>( + valueListenable: notifier.notifications, + builder: (context, notifications, _) { + final unreadCount = notifier.unreadCount; + + return Column( + children: [ + // ํ—ค๋” + _buildHeader(unreadCount), + + // ์•Œ๋ฆผ ๋ชฉ๋ก + Expanded( + child: notifications.isEmpty + ? _buildEmptyState() + : ListView.builder( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + itemCount: notifications.length, + itemBuilder: (context, index) { + return _buildNotificationCard( + notifications[index], + index, + ); + }, + ), + ), + ], + ); + }, + ); + }, + ), + ), + ); + } + + Widget _buildHeader(int unreadCount) { + return AppHeader( + title: Row( + children: [ + const AppHeaderTitle('์•Œ๋ฆผ'), + if (unreadCount > 0) ...[ + const SizedBox(width: 8), // โœ… Rule 1: spacing์€ OK + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 2, + ), // โœ… Rule 5: trailing comma + decoration: BoxDecoration( + color: const Color(0xFFF44336), + borderRadius: BorderRadius.circular(10), + ), // โœ… Rule 5: trailing comma + child: Text( + unreadCount.toString(), + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 12, + color: Colors.white, + ), // โœ… Rule 5: trailing comma + ), // โœ… Rule 5: trailing comma + ), + ], + const Spacer(), + ], + ), // โœ… Rule 5: trailing comma + trailing: unreadCount > 0 + ? TextButton( + onPressed: _markAllAsRead, + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + minimumSize: Size.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), // โœ… Rule 5: trailing comma + child: const Text( + '๋ชจ๋‘ ์ฝ์Œ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Color(0xFFAC5BF8), + ), // โœ… Rule 5: trailing comma + ), // โœ… Rule 5: trailing comma + ) + : const AppHeaderMenuButton(), + ); + } + + Widget _buildNotificationCard(NotificationEntity notification, int index) { + return Dismissible( + key: Key('notification_${notification.id}'), + direction: DismissDirection.endToStart, + onDismissed: (direction) async { + if (_notificationNotifier != null) { + await _notificationNotifier!.delete(notification.id); + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('์•Œ๋ฆผ์ด ์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค'))); + } + } + }, + background: Container( + alignment: Alignment.centerRight, + padding: const EdgeInsets.only(right: 20), + decoration: BoxDecoration( + color: const Color(0xFFF44336), + borderRadius: BorderRadius.circular(12), + ), + child: const Icon(Icons.delete_outline, color: Colors.white, size: 24), + ), + child: Container( + margin: const EdgeInsets.only(bottom: 12), + child: Material( + color: notification.isRead ? Colors.white : const Color(0xFFF8F9FA), + borderRadius: BorderRadius.circular(12), + child: InkWell( + onTap: () { + _markAsRead(notification); + _handleNotificationTap(notification); + }, + borderRadius: BorderRadius.circular(12), + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all( + color: notification.isRead + ? const Color(0xFFE9ECEF) + : const Color(0xFFAC5BF8), + width: notification.isRead ? 1 : 2, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ์•Œ๋ฆผ ํƒ€์ž… ์•„์ด์ฝ˜ + _buildNotificationIcon(notification.type), + const SizedBox(width: 12), + + // ์•Œ๋ฆผ ๋‚ด์šฉ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + notification.title, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: notification.isRead + ? FontWeight.w600 + : FontWeight.w700, + fontSize: 16, + color: const Color(0xFF333333), + ), + ), + ), + if (!notification.isRead) + Container( + width: 8, + height: 8, + decoration: const BoxDecoration( + color: Color(0xFFAC5BF8), + shape: BoxShape.circle, + ), + ), + ], + ), + const SizedBox(height: 4), + Text( + notification.message, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + const SizedBox(height: 8), + Text( + _formatTime(notification.time), + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF999999), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + ), + ); + } + + Widget _buildNotificationIcon(NotificationType type) { + IconData icon; + Color color; + + switch (type) { + case NotificationType.homework: + icon = Icons.assignment_outlined; + color = const Color(0xFFFF9800); + break; + case NotificationType.learningReminder: + icon = Icons.schedule; + color = const Color(0xFFAC5BF8); + break; + case NotificationType.academyNotice: + icon = Icons.school_outlined; + color = const Color(0xFF2196F3); + break; + case NotificationType.grading: + icon = Icons.check_circle_outline; + color = const Color(0xFF4CAF50); + break; + case NotificationType.achievement: + icon = Icons.emoji_events_outlined; + color = const Color(0xFFFFC107); + break; + } + + return Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: color.withAlpha(26), + shape: BoxShape.circle, + ), + child: Icon(icon, color: color, size: 24), + ); + } + + Widget _buildEmptyState() { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.notifications_none, size: 64, color: Colors.grey[400]), + const SizedBox(height: 16), + const Text( + '์•Œ๋ฆผ์ด ์—†์Šต๋‹ˆ๋‹ค', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: Color(0xFF666666), + ), + ), + const SizedBox(height: 8), + Text( + '์ƒˆ๋กœ์šด ์•Œ๋ฆผ์ด ๋„์ฐฉํ•˜๋ฉด ์—ฌ๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Colors.grey[600], + ), + ), + ], + ), + ); + } + + Future _markAsRead(NotificationEntity notification) async { + if (!notification.isRead && _notificationNotifier != null) { + await _notificationNotifier!.markAsRead(notification.id); + } + } + + Future _markAllAsRead() async { + if (_notificationNotifier != null) { + await _notificationNotifier!.markAllAsRead(); + } + } + + String _formatTime(DateTime time) { + final now = DateTime.now(); + final difference = now.difference(time); + + if (difference.inMinutes < 1) { + return '๋ฐฉ๊ธˆ ์ „'; + } else if (difference.inMinutes < 60) { + return '${difference.inMinutes}๋ถ„ ์ „'; + } else if (difference.inHours < 24) { + return '${difference.inHours}์‹œ๊ฐ„ ์ „'; + } else if (difference.inDays < 7) { + return '${difference.inDays}์ผ ์ „'; + } else { + return '${time.year}.${time.month.toString().padLeft(2, '0')}.${time.day.toString().padLeft(2, '0')}'; + } + } + + void _handleNotificationTap(NotificationEntity notification) { + // ํ•ด์„ค ์ƒ์„ฑ ์™„๋ฃŒ ์•Œ๋ฆผ์ธ ๊ฒฝ์šฐ, ํ•ด๋‹น ๋ฌธ์ œ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ + if (notification.title == 'ํ•ด์„ค ์ƒ์„ฑ ์™„๋ฃŒ' && notification.data != null) { + final data = notification.data!; + + try { + int? _toInt(dynamic value) { + if (value is int) return value; + if (value is String) return int.tryParse(value); + return null; + } + + bool? _toBool(dynamic value) { + if (value is bool) return value; + if (value is String) { + final lower = value.toLowerCase(); + if (lower == 'true') return true; + if (lower == 'false') return false; + } + return null; + } + + // ํ•ด์„ค ์ƒ์„ฑ ์™„๋ฃŒ ์•Œ๋ฆผ payload ์˜ˆ์‹œ: + // { + // "student_response_id": 1764510387709, + // "user_id": 1, + // "chapter_id": 201, + // "academy_user_id": 20, + // "book_id": 1, + // "question_number": 1, + // "sub_question_number": 0, + // "is_correct": false, + // "score": 1 + // } + + final studentResponseId = _toInt(data['student_response_id']); + final academyUserId = _toInt(data['academy_user_id']); + final questionNumber = _toInt(data['question_number']); + // sub_question_number, book_id, score ๋“ฑ์€ ํ˜„์žฌ ํ™”๋ฉด ์ด๋™์—๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์ง€๋งŒ + // payload ๊ตฌ์กฐ ๊ฒ€์ฆ ๋ฐ ํ–ฅํ›„ ํ™•์žฅ์„ ์œ„ํ•ด ํ•œ ๋ฒˆ ์ฝ์–ด๋‘ก๋‹ˆ๋‹ค. + _toInt(data['sub_question_number']); + _toInt(data['book_id']); + _toInt(data['score']); + final chapterIdFromPayload = _toInt(data['chapter_id']); + final isCorrect = _toBool(data['is_correct']); + + if (studentResponseId == null || + academyUserId == null || + questionNumber == null || + isCorrect == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('๋ฌธ์ œ ์ •๋ณด๊ฐ€ ๋ถ€์กฑํ•˜์—ฌ ํ™”๋ฉด์œผ๋กœ ์ด๋™ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.')), + ); + return; + } + + // ์ •๋‹ต/์˜ค๋‹ต ์—ฌ๋ถ€๋ฅผ QuestionStatus๋กœ ๋งคํ•‘ + final status = isCorrect + ? QuestionStatus.correct + : QuestionStatus.incorrect; + + // ์•Œ๋ฆผ body์—์„œ ํด๋ž˜์Šค/๋ฌธ์ œ์ง‘ ์ด๋ฆ„ ์ถ”์ถœ (์˜ˆ: "[๊ณ ๊ธ‰์ˆ˜ํ•™๋ฐ˜] ์ˆ˜์—…์˜ [๊ธฐ์ดˆ์ˆ˜ํ•™๊ต์žฌ] 3๋ฒˆ ๋ฌธ์ œ ํ•ด์„ค ์ƒ์„ฑ ์™„๋ฃŒ") + final body = notification.message; + final matches = RegExp(r'\[(.*?)\]').allMatches(body).toList(); + final academyName = matches.isNotEmpty + ? matches[0].group(1) ?? 'ํ•™์›' + : 'ํ•™์›'; + final workbookName = matches.length > 1 + ? matches[1].group(1) ?? '๋ฌธ์ œ์ง‘' + : '๋ฌธ์ œ์ง‘'; + + // chapterId๋Š” payload์—์„œ ๋„˜์–ด์˜จ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋˜, + // ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ์—๋Š” 0์œผ๋กœ fallback ํ•ฉ๋‹ˆ๋‹ค. + final chapterId = chapterIdFromPayload ?? 0; + // chapterName์€ ํ—ค๋” ํ‘œ์‹œ์šฉ์œผ๋กœ๋งŒ ์‚ฌ์šฉ + final chapterName = '$academyName ์ˆ˜์—…'; + + Navigator.pushNamed( + context, + AppRoutes.questionDetail, + arguments: { + 'chapterId': chapterId, + 'academyUserId': academyUserId, + 'workbookName': workbookName, + 'chapterName': chapterName, + 'questionNumber': questionNumber, + 'status': status, + 'studentResponseId': studentResponseId, + }, + ); + return; + } catch (_) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('์•Œ๋ฆผ ๋ฐ์ดํ„ฐ ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์•„ ์ด๋™์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.')), + ); + return; + } + } + + // ๊ทธ ์™ธ ์•Œ๋ฆผ์€ ํ˜„์žฌ ๋ณ„๋„ ๋™์ž‘ ์—†์Œ (์ฝ์Œ ์ฒ˜๋ฆฌ๋งŒ ์ˆ˜ํ–‰) + } +} diff --git a/frontend/lib/screens/problem_solution_temp_page.dart b/frontend/lib/screens/problem_solution_temp_page.dart new file mode 100644 index 0000000..88fa40f --- /dev/null +++ b/frontend/lib/screens/problem_solution_temp_page.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; + +/// ์ž„์‹œ ๋ฌธ์ œ ํ’€์ด ํ™”๋ฉด +class ProblemSolutionTempPage extends StatelessWidget { + const ProblemSolutionTempPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + title: const Text( + '๋ฌธ์ œ ํ’€์ด', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + ), + ), + backgroundColor: Colors.white, + foregroundColor: const Color(0xFF333333), + elevation: 0, + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '1๋ฒˆ ๋ฌธ์ œ', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 22, + fontWeight: FontWeight.w700, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 16), + ClipRRect( + borderRadius: BorderRadius.circular(16), + child: Image.asset( + 'assets/images/temp/problem1.png', + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 24), + Container( + width: double.infinity, + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFF8F8FF), + borderRadius: BorderRadius.circular(16), + border: Border.all(color: const Color(0xFFE0E0F6)), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.05), + blurRadius: 10, + offset: const Offset(0, 4), + ), + ], + ), + child: const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'ํ’€์ด', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 18, + fontWeight: FontWeight.w700, + color: Color(0xFF6C63FF), + ), + ), + SizedBox(height: 12), + Text( + '์ง€๋ฌธ์—์„œ๋Š” ์šด๋™์ด ์ƒ์—…ํ™”๋˜๋ฉฐ ๋ˆยท์‹œ๊ฐ„์„ ๋งŽ์ด ์“ฐ๊ฒŒ ๋˜๊ณ , ๋งˆ๋ผํ†คยท๊ทนํ•œ ์Šคํฌ์ธ ๊นŒ์ง€ ํ•˜๋ฉด์„œ "์šด๋™์€ ๊ฑด๊ฐ•์— ์ข‹๋‹ค"๋Š” ์••๋ฐ• ๋•Œ๋ฌธ์— ์˜คํžˆ๋ ค ๋ถˆ์•ˆ๊ณผ ํ˜ผ๋ž€์˜ ์›์ธ์ด ๋˜์—ˆ๋‹ค๊ณ  ๋งํ•œ๋‹ค. ' + 'โ€˜be exercised aboutโ€™๋Š” โ€˜~๋•Œ๋ฌธ์— ๋ถˆ์•ˆํ•ดํ•˜๋‹ค, ์‹ ๊ฒฝ ์“ฐ๋‹คโ€™๋ผ๋Š” ๋œป์ด๋ฏ€๋กœ, ๊ฑด๊ฐ•์„ ์œ„ํ•ด ํ•˜๋Š” ์šด๋™์ด ์˜คํžˆ๋ ค ์ŠคํŠธ๋ ˆ์Šค๋ฅผ ์ค€๋‹ค๋Š” ์•„์ด๋Ÿฌ๋‹ˆ๋ฅผ ๋งํ•œ ๊ฒƒ์ด๋‹ค. ' + '๋”ฐ๋ผ์„œ ์šด๋™์ด ์›ฐ๋น™์„ ๋ช…๋ถ„์œผ๋กœ ์˜คํžˆ๋ ค ์ŠคํŠธ๋ ˆ์Šค๋ฅผ ์œ ๋ฐœํ•œ๋‹ค๋Š” โ‘ ์ด ์ •๋‹ต์ด๋‹ค.', + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + height: 1.6, + color: Color(0xFF444444), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/frontend/lib/screens/upload/upload_images_page.dart b/frontend/lib/screens/upload/upload_images_page.dart new file mode 100644 index 0000000..34f97a8 --- /dev/null +++ b/frontend/lib/screens/upload/upload_images_page.dart @@ -0,0 +1,701 @@ +import 'dart:collection'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import 'package:http/http.dart' as http; +import 'package:image_picker/image_picker.dart'; + +import '../../services/upload_batch_service.dart'; +import '../../services/upload_sse_service.dart'; +import '../../services/academy_service.dart'; +import '../../services/auth_service.dart'; +import '../../widgets/app_header.dart'; +import '../../widgets/app_header_title.dart'; +import '../../widgets/app_header_menu_button.dart'; +import '../../routes/app_routes.dart'; +import '../../utils/app_logger.dart'; + +enum ProblemType { + newProblem, // ์ƒˆ๋กœ ํ’€๊ธฐ + correctMistakes, // ์˜ค๋‹ต ์ˆ˜์ • +} + +enum UploadPageAcademyState { + checking, // ํ•™์› ์ •๋ณด ํ™•์ธ ์ค‘ + hasAcademy, + noAcademy, + error, // ํ•™์› ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ•จ +} + +class UploadImagesPage extends StatefulWidget { + const UploadImagesPage({super.key}); + + @override + State createState() => _UploadImagesPageState(); +} + +class _UploadImagesPageState extends State { + List _selectedImages = []; + ProblemType? _selectedType; + final ImagePicker _picker = ImagePicker(); + final getIt = GetIt.instance; + + late final UploadSseService _sseService = getIt(); + late final AcademyService _academyService = getIt(); + late final AuthService _authService = getIt(); + final Queue _pendingUploads = Queue(); + + bool _isSseConnecting = false; + bool _isUploading = false; + String? _uploadError; + String? _uploadSuccessMessage; + int? _uploadedCount; + int? _totalCount; + UploadPageAcademyState _academyState = UploadPageAcademyState.checking; + + /// ๋ฉ”์ธ ๋„ค๋น„๊ฒŒ์ด์…˜์—์„œ ํƒญ์„ ๋‹ค์‹œ ์„ ํƒํ–ˆ์„ ๋•Œ + /// ์—…๋กœ๋“œ ํŽ˜์ด์ง€ ์ƒํƒœ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ + void refresh() { + setState(() { + _selectedImages = []; + _selectedType = null; + _pendingUploads.clear(); + _isUploading = false; + _uploadError = null; + _uploadSuccessMessage = null; + _uploadedCount = null; + _totalCount = null; + _academyState = UploadPageAcademyState.checking; + }); + + // ํ•™์› ์ •๋ณด ๋‹ค์‹œ ํ™•์ธ + _checkAcademyState(); + } + + @override + void initState() { + super.initState(); + _checkAcademyState(); + _connectSse(); + } + + @override + void dispose() { + _sseService.dispose(); + super.dispose(); + } + + Future _connectSse() async { + setState(() { + _isSseConnecting = true; + }); + try { + await _sseService.connect(); + _sseService.uploadUrlStream.listen(_onUploadUrlReceived); + } catch (e) { + debugPrint('SSE connect error: $e'); + setState(() { + _uploadError = '์‹ค์‹œ๊ฐ„ ์—…๋กœ๋“œ ์ฑ„๋„ ์—ฐ๊ฒฐ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'; + }); + } finally { + if (mounted) { + setState(() { + _isSseConnecting = false; + }); + } + } + } + + Future _onUploadUrlReceived(String url) async { + if (_pendingUploads.isEmpty) { + debugPrint('Upload URL received but no pending images. url=$url'); + return; + } + + final file = _pendingUploads.removeFirst(); + try { + final bytes = await file.readAsBytes(); + final response = await http.put( + Uri.parse(url), + headers: { + // ์„œ๋ฒ„์—์„œ ๋ณ„๋„ Content-Type ์š”๊ตฌ ์‹œ ํ™•์žฅ์ž ๊ธฐ๋ฐ˜์œผ๋กœ ์กฐ์ • ๊ฐ€๋Šฅ + 'Content-Type': 'image/jpeg', + }, + body: bytes, + ); + + debugPrint('Uploaded ${file.path} โ†’ ${response.statusCode}'); + + if (response.statusCode < 200 || response.statusCode >= 300) { + throw Exception('์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์‹คํŒจ (${response.statusCode})'); + } + } catch (e) { + setState(() { + _uploadError = '์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: $e'; + }); + debugPrint('Upload error: $e'); + } finally { + if (_pendingUploads.isEmpty && mounted) { + setState(() { + _isUploading = false; + }); + } + } + } + + Future _pickImages() async { + final List images = await _picker.pickMultiImage(); + if (!mounted) return; + + setState(() { + _selectedImages = images; + }); + } + + /// ๋ฌธ์ œ ๋“ฑ๋ก ์„ฑ๊ณต ๋‹ค์ด์–ผ๋กœ๊ทธ ํ‘œ์‹œ + Future _showSuccessDialog() async { + if (!mounted) return; + + final timestamp = DateTime.now().toIso8601String(); + appLog('[UploadImagesPage][timecheck][$timestamp] ๋ฌธ์ œ ๋“ฑ๋ก ์™„๋ฃŒ ํŒ์—… ํ‘œ์‹œ'); + + await showDialog( + context: context, + barrierDismissible: false, // ๋ฐฐ๊ฒฝ ํƒญ์œผ๋กœ ๋‹ซ๊ธฐ ๋ฐฉ์ง€ + builder: (BuildContext dialogContext) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + title: const Text( + '๋ฌธ์ œ ๋“ฑ๋ก ์™„๋ฃŒ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + textAlign: TextAlign.center, + ), + content: const Text( + '๋ฌธ์ œ ๋“ฑ๋ก์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ฑ„์ ์ด ์™„๋ฃŒ๋˜๋ฉด ์•Œ๋ฆผ์œผ๋กœ ์•Œ๋ ค๋“œ๋ฆด๊ฒŒ์š”!', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF666666), + height: 1.5, + ), + textAlign: TextAlign.center, + ), + actions: [ + Center( + child: SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + Navigator.of(dialogContext).pop(); // ๋‹ค์ด์–ผ๋กœ๊ทธ ๋‹ซ๊ธฐ + Navigator.of(context).pushNamedAndRemoveUntil( + AppRoutes.mainNavigation, + (route) => false, // ๋ชจ๋“  ์ด์ „ ๋ผ์šฐํŠธ ์ œ๊ฑฐ + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFAC5BF8), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: const Text( + '๋„ค, ์•Œ๊ฒ ์–ด์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Colors.white, + ), + ), + ), + ), + ), + ], + ); + }, + ); + } + + Future _registerProblems() async { + if (_selectedImages.isEmpty) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”'))); + return; + } + + if (_selectedType == null) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('๋ฌธ์ œ ์œ ํ˜•์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”'))); + return; + } + + if (_academyState == UploadPageAcademyState.checking) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('ํ•™์› ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๋Š” ์ค‘์ž…๋‹ˆ๋‹ค. ์ž ์‹œ๋งŒ ๊ธฐ๋‹ค๋ ค์ฃผ์„ธ์š”.')), + ); + return; + } + + if (_academyState == UploadPageAcademyState.noAcademy) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('ํ•™์› ๋“ฑ๋ก์„ ๋จผ์ € ํ•ด์ฃผ์„ธ์š”.'))); + return; + } + + if (_isSseConnecting) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('์—…๋กœ๋“œ ์ฑ„๋„์„ ์ค€๋น„ ์ค‘์ž…๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.')), + ); + return; + } + + final timestamp = DateTime.now().toIso8601String(); + appLog( + '[UploadImagesPage][timecheck][$timestamp] ๋ฌธ์ œ ๋“ฑ๋ก ์š”์ฒญ ์‹œ์ž‘ - imageCount=${_selectedImages.length}, type=$_selectedType', + ); + + setState(() { + _uploadError = null; + _uploadSuccessMessage = null; + _uploadedCount = 0; + _totalCount = _selectedImages.length; + _isUploading = true; + }); + + try { + debugPrint( + '[UploadImagesPage] ๐Ÿš€ ์—…๋กœ๋“œ ์‹œ์ž‘: ${_selectedImages.length}๊ฐœ ์ด๋ฏธ์ง€', + ); + + // uploadImages ์™ธ๋ถ€ ํ•จ์ˆ˜ ์‚ฌ์šฉ (์ง„ํ–‰ ์ƒํ™ฉ ์ฝœ๋ฐฑ ํฌํ•จ) + final response = await uploadImages( + images: _selectedImages, + onProgress: (uploadedCount, totalCount) { + debugPrint( + '[UploadImagesPage] ๐Ÿ“ค ์—…๋กœ๋“œ ์ง„ํ–‰: $uploadedCount/$totalCount', + ); + if (mounted) { + setState(() { + _uploadedCount = uploadedCount; + _totalCount = totalCount; + }); + } + }, + ); + + appLog( + '[UploadImagesPage][timecheck] โœ… ์—…๋กœ๋“œ ์™„๋ฃŒ - studentResponseId=${response.studentResponseId}, total=${_selectedImages.length}', + ); + + debugPrint( + '[UploadImagesPage] โœ… ์—…๋กœ๋“œ ์™„๋ฃŒ: studentResponseId=${response.studentResponseId}', + ); + + if (mounted) { + setState(() { + _isUploading = false; + _uploadedCount = _selectedImages.length; + }); + + // ์„ฑ๊ณต ํŒ์—… ํ‘œ์‹œ + _showSuccessDialog(); + } + } on NoAcademyException catch (e) { + debugPrint('[UploadImagesPage] โŒ ์—…๋กœ๋“œ ์‹คํŒจ(ํ•™์› ์—†์Œ): $e'); + if (!mounted) return; + setState(() { + _isUploading = false; + _academyState = UploadPageAcademyState.noAcademy; + }); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(e.message))); + } catch (e) { + debugPrint('[UploadImagesPage] โŒ ์—…๋กœ๋“œ ์‹คํŒจ: $e'); + if (mounted) { + setState(() { + _isUploading = false; + _uploadError = e.toString(); + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('๋ฌธ์ œ ๋“ฑ๋ก ์š”์ฒญ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: $e'), + backgroundColor: Colors.red, + ), + ); + } + } + } + + Future _checkAcademyState() async { + setState(() { + _academyState = UploadPageAcademyState.checking; + }); + + try { + final userId = await _authService.getUserId(); + if (userId == null) { + if (!mounted) return; + setState(() { + _academyState = UploadPageAcademyState.error; + }); + return; + } + + final academies = await _academyService.getUserAcademies(userId); + final registered = academies + .where((a) => a.registerStatus == 'Y') + .toList(); + + if (!mounted) return; + setState(() { + _academyState = registered.isEmpty + ? UploadPageAcademyState.noAcademy + : UploadPageAcademyState.hasAcademy; + }); + } catch (e) { + debugPrint('[UploadImagesPage] ํ•™์› ์ƒํƒœ ์กฐํšŒ ์‹คํŒจ: $e'); + if (!mounted) return; + setState(() { + _academyState = UploadPageAcademyState.error; + }); + } + } + + @override + Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + final screenHeight = MediaQuery.of(context).size.height; + + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + _buildHeader(), + Expanded( + child: RefreshIndicator( + onRefresh: () async { + refresh(); + }, + child: SingleChildScrollView( + physics: + const AlwaysScrollableScrollPhysics(), // Pull-to-refresh๋ฅผ ์œ„ํ•ด ํ•ญ์ƒ ์Šคํฌ๋กค ๊ฐ€๋Šฅํ•˜๋„๋ก + child: Column( + children: [ + SizedBox(height: screenHeight * 0.015), + _buildImageGrid(screenWidth, screenHeight), + SizedBox(height: screenHeight * 0.02), + ], + ), + ), + ), + ), + _buildBottomButtons(screenWidth, screenHeight), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return const AppHeader( + title: AppHeaderTitle('์ด๋ฏธ์ง€ ์—…๋กœ๋“œ', textAlign: TextAlign.center), + trailing: AppHeaderMenuButton(), + ); + } + + Widget _buildImageGrid(double screenWidth, double screenHeight) { + if (_selectedImages.isEmpty) { + return Container( + width: screenWidth * 0.866, // 348/402 + height: screenHeight * 0.375, // 328/874 + margin: EdgeInsets.symmetric(horizontal: screenWidth * 0.067), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: const Color(0xFFE1E7ED)), + ), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (_academyState == UploadPageAcademyState.noAcademy) ...[ + const Text( + 'ํ•™์› ๋“ฑ๋ก์„ ๋จผ์ € ํ•ด์ฃผ์„ธ์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF7F818E), + ), + ), + ] else if (_academyState == UploadPageAcademyState.error) ...[ + const Text( + 'ํ•™์› ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์–ด์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF7F818E), + ), + ), + ] else if (_academyState == UploadPageAcademyState.checking) ...[ + const SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator(strokeWidth: 2), + ), + const SizedBox(height: 8), + const Text( + 'ํ•™์› ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๋Š” ์ค‘์ž…๋‹ˆ๋‹ค...', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF7F818E), + ), + ), + ] else ...[ + const Text( + '์ด๋ฏธ์ง€๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF7F818E), + ), + ), + ], + if (_uploadError != null) ...[ + const SizedBox(height: 8), + Text( + _uploadError!, + textAlign: TextAlign.center, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: Color(0xFFFF4258), + ), + ), + ], + if (_uploadSuccessMessage != null) ...[ + const SizedBox(height: 8), + Text( + _uploadSuccessMessage!, + textAlign: TextAlign.center, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: Color(0xFF4CAF50), + ), + ), + ], + if (_isUploading && _totalCount != null) ...[ + const SizedBox(height: 8), + Text( + '์—…๋กœ๋“œ ์ค‘: ${_uploadedCount ?? 0}/$_totalCount', + textAlign: TextAlign.center, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: Color(0xFFAC5BF8), + ), + ), + ], + ], + ), + ), + ); + } + + // 4x4 ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ + final gridWidth = screenWidth * 0.866; // 348/402 + final itemWidth = (gridWidth - 3 * 8) / 4; // 4๊ฐœ ์—ด, ๊ฐ„๊ฒฉ 8 + final itemHeight = itemWidth * 0.938; // 76/81 ๋น„์œจ + + return Container( + width: gridWidth, + margin: EdgeInsets.symmetric(horizontal: screenWidth * 0.067), + child: Wrap( + spacing: 8, + runSpacing: 8, + children: List.generate( + _selectedImages.length > 16 ? 16 : _selectedImages.length, + (index) => Container( + width: itemWidth, + height: itemHeight, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all(color: const Color(0xFFE1E7ED)), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(4), + child: Image.file( + File(_selectedImages[index].path), + fit: BoxFit.cover, + ), + ), + ), + ), + ), + ); + } + + Widget _buildBottomButtons(double screenWidth, double screenHeight) { + final buttonHeight = screenHeight * 0.045; // 39/874 + + return Container( + padding: EdgeInsets.symmetric( + horizontal: screenWidth * 0.072, + vertical: screenHeight * 0.015, + ), + child: Row( + children: [ + // ์ƒˆ๋กœ ํ’€๊ธฐ ๋ฒ„ํŠผ + Expanded( + child: GestureDetector( + onTap: () { + setState(() { + _selectedType = ProblemType.newProblem; + }); + }, + child: Container( + height: buttonHeight, + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all( + color: _selectedType == ProblemType.newProblem + ? const Color(0xFFAC5BF8) + : const Color(0xFFE1E7ED), + width: _selectedType == ProblemType.newProblem ? 2 : 1, + ), + borderRadius: BorderRadius.circular(5), + ), + child: const Center( + child: Text( + '์ƒˆ๋กœ ํ’€๊ธฐ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 14, + color: Color(0xFF585B69), + ), + ), + ), + ), + ), + ), + + SizedBox(width: screenWidth * 0.02), + + // ์ค‘์•™ ๋ฒ„ํŠผ (์ด๋ฏธ์ง€ ๊ฐ€์ ธ์˜ค๊ธฐ / ๋ฌธ์ œ ๋“ฑ๋ก) + Expanded( + flex: 2, + child: GestureDetector( + onTap: _selectedImages.isEmpty ? _pickImages : _registerProblems, + child: Container( + height: buttonHeight, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF636ACF)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(5), + ), + child: Center( + child: Text( + () { + if (_selectedImages.isEmpty) { + if (_academyState == UploadPageAcademyState.noAcademy) { + return 'ํ•™์› ๋“ฑ๋ก ํ•„์š”'; + } + if (_academyState == UploadPageAcademyState.checking) { + return 'ํ•™์› ์ •๋ณด ํ™•์ธ ์ค‘...'; + } + if (_academyState == UploadPageAcademyState.error) { + return '๋‹ค์‹œ ์‹œ๋„'; + } + return '์ด๋ฏธ์ง€ ๊ฐ€์ ธ์˜ค๊ธฐ'; + } + + if (_isUploading) { + if (_uploadedCount != null && _totalCount != null) { + return '์—…๋กœ๋“œ ์ค‘... ($_uploadedCount/$_totalCount)'; + } + return '์—…๋กœ๋“œ ์ค‘...'; + } + + return '๋ฌธ์ œ ๋“ฑ๋ก'; + }(), + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Color(0xFFF8F9FA), + ), + ), + ), + ), + ), + ), + + SizedBox(width: screenWidth * 0.02), + + // ์˜ค๋‹ต ์ˆ˜์ • ๋ฒ„ํŠผ + Expanded( + child: GestureDetector( + onTap: () { + setState(() { + _selectedType = ProblemType.correctMistakes; + }); + }, + child: Container( + height: buttonHeight, + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all( + color: _selectedType == ProblemType.correctMistakes + ? const Color(0xFFAC5BF8) + : const Color(0xFFE1E7ED), + width: _selectedType == ProblemType.correctMistakes ? 2 : 1, + ), + borderRadius: BorderRadius.circular(5), + ), + child: const Center( + child: Text( + '์˜ค๋‹ต ์ˆ˜์ •', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 14, + color: Color(0xFF585B69), + ), + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/frontend/lib/screens/workbook/API_RESPONSE_STRUCTURE.md b/frontend/lib/screens/workbook/API_RESPONSE_STRUCTURE.md new file mode 100644 index 0000000..6891722 --- /dev/null +++ b/frontend/lib/screens/workbook/API_RESPONSE_STRUCTURE.md @@ -0,0 +1,84 @@ +# WorkbookDetailPage API ์‘๋‹ต ๊ตฌ์กฐ + +## API ์—”๋“œํฌ์ธํŠธ + +**Method**: `GET` +**Endpoint**: `/grading/chapter/book/{book_id}/user/{academy_user_id}` +**Headers**: + +- `Content-Type: application/json` +- `Authorization: Bearer {token}` + +**Path Parameters**: + +- `book_id` (int): ๋ฌธ์ œ์ง‘ ID +- `academy_user_id` (int): ํ•™์› ์‚ฌ์šฉ์ž ID + +## ์‘๋‹ต ๊ตฌ์กฐ + +### ์‘๋‹ต ํ˜•์‹ + +```json +[ + { + "chapter_id": 1, + "book_id": 1, + "main_chapter_number": 1, + "sub_chapter_number": 0, + "chapter_name": "Gradi์˜ ์ดํ•ด", + "chapter_start_page": 0, + "chapter_end_page": 0, + "chapter_start_question": 0, + "chapter_end_question": 0, + "total_chapter_question": 20, + "student_answer_count": 0 + }, + ... +] +``` + +**์‘๋‹ต ํƒ€์ž…**: JSON ๋ฐฐ์—ด (`List`) + +### ์‘๋‹ต ํ•„๋“œ ์ƒ์„ธ + +| ํ•„๋“œ๋ช… (JSON) | ํƒ€์ž… | ํ•„์ˆ˜ ์—ฌ๋ถ€ | ๊ธฐ๋ณธ๊ฐ’ | ์„ค๋ช… | +| ------------------------ | ---------------- | --------- | ------ | ------------------------------------ | +| `chapter_id` | `int` | ํ•„์ˆ˜ | - | ์ฑ•ํ„ฐ ๊ณ ์œ  ID | +| `book_id` | `int` | ํ•„์ˆ˜ | - | ๋ฌธ์ œ์ง‘ ID | +| `main_chapter_number` | `int` | ์„ ํƒ | `0` | ๋Œ€๋‹จ์› ๋ฒˆํ˜ธ (์ •๋ ฌ ๊ธฐ์ค€) | +| `sub_chapter_number` | `int` | ์„ ํƒ | `0` | ์†Œ๋‹จ์› ๋ฒˆํ˜ธ (์ •๋ ฌ ๊ธฐ์ค€) | +| `chapter_name` | `string \| null` | ์„ ํƒ | `null` | ์ฑ•ํ„ฐ ์ด๋ฆ„ | +| `chapter_start_page` | `int` | ์„ ํƒ | `0` | ์ฑ•ํ„ฐ ์‹œ์ž‘ ํŽ˜์ด์ง€ | +| `chapter_end_page` | `int` | ์„ ํƒ | `0` | ์ฑ•ํ„ฐ ์ข…๋ฃŒ ํŽ˜์ด์ง€ | +| `chapter_start_question` | `int` | ์„ ํƒ | `0` | ์ฑ•ํ„ฐ ์‹œ์ž‘ ๋ฌธ์ œ ๋ฒˆํ˜ธ | +| `chapter_end_question` | `int` | ์„ ํƒ | `0` | ์ฑ•ํ„ฐ ์ข…๋ฃŒ ๋ฌธ์ œ ๋ฒˆํ˜ธ | +| `total_chapter_question` | `int` | ์„ ํƒ | `0` | ์ฑ•ํ„ฐ ์ „์ฒด ๋ฌธ์ œ ์ˆ˜ | +| `student_answer_count` | `int` | ์„ ํƒ | `0` | ํ•™์ƒ์ด ์ œ์ถœํ•œ ๋‹ต์•ˆ ์ˆ˜ (์™„๋ฃŒ ๋ฌธ์ œ ์ˆ˜) | + +## ์ •๋ ฌ ๊ทœ์น™ + +UseCase์—์„œ ์ž๋™์œผ๋กœ ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค: + +1. `main_chapter_number` ์˜ค๋ฆ„์ฐจ์ˆœ +2. `sub_chapter_number` ์˜ค๋ฆ„์ฐจ์ˆœ + +## ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜ + +API ์‘๋‹ต(`ChapterApiResponse`)์€ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ(`ChapterEntity`)๋กœ ๋ณ€ํ™˜๋˜๋ฉฐ, ์ถ”๊ฐ€๋กœ ๋‹ค์Œ ๊ณ„์‚ฐ๋œ ์†์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค: + +- `progress` (double): `student_answer_count / total_chapter_question` (0.0 ~ 1.0) +- `formattedName` (string): `"{chapterId}. {chapterName}"` ํ˜•์‹ (chapterId๋ฅผ ์ธ๋ฑ์Šค๋กœ ์‚ฌ์šฉ) +- `problemCountDisplay` (string): `"{studentAnswerCount} / {totalChapterQuestion}"` ํ˜•์‹ + +## ์—๋Ÿฌ ์ฒ˜๋ฆฌ + +- **401 Unauthorized**: ์ธ์ฆ ์‹คํŒจ (ํ† ํฐ ๋งŒ๋ฃŒ ๋˜๋Š” ์œ ํšจํ•˜์ง€ ์•Š์Œ) +- **200 OK**: ์„ฑ๊ณต (๋นˆ ๋ฐฐ์—ด์ผ ์ˆ˜ ์žˆ์Œ) +- **๊ธฐํƒ€ ์ƒํƒœ ์ฝ”๋“œ**: API ํ˜ธ์ถœ ์‹คํŒจ ์˜ˆ์™ธ ๋ฐœ์ƒ + +## ์ฐธ๊ณ  ํŒŒ์ผ + +- API ํ˜ธ์ถœ: `frontend/lib/data/chapter/chapter_api.dart` +- Repository: `frontend/lib/data/chapter/chapter_repository_impl.dart` +- UseCase: `frontend/lib/domain/chapter/get_chapters_for_book_use_case.dart` +- Entity: `frontend/lib/domain/chapter/chapter_entity.dart` diff --git a/frontend/lib/screens/workbook/chapter_detail_page.dart b/frontend/lib/screens/workbook/chapter_detail_page.dart new file mode 100644 index 0000000..e30ac5a --- /dev/null +++ b/frontend/lib/screens/workbook/chapter_detail_page.dart @@ -0,0 +1,391 @@ +import 'package:flutter/material.dart'; +import 'dart:developer' as developer; +import '../../widgets/back_button.dart'; +import '../../services/get_chapter_question_statuses_use_case.dart'; +import '../../services/models/question_status_model.dart'; + +/// ๋ฌธ์ œ ํ’€์ด ์ƒํƒœ (UI ์ „์šฉ enum, Domain์— ์—†์Œ) +enum QuestionStatus { + correct, // isCorrect == true + incorrect, // isCorrect == false + unsolved, // isCorrect == null +} + +/// ์ฑ•ํ„ฐ ์ƒ์„ธ ํŽ˜์ด์ง€ +/// WorkbookDetailPage์—์„œ ์ฑ•ํ„ฐ๋ฅผ ์„ ํƒํ•˜๋ฉด ํ‘œ์‹œ๋˜๋Š” ํŽ˜์ด์ง€ +/// +/// ๊ตฌ์„ฑ: +/// 1. ํ—ค๋”: ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ + ์ฑ•ํ„ฐ๋ช… +/// 2. ๋ฌธ์ œ ๋ชฉ๋ก: ๊ฐ ๋ฌธ์ œ์˜ ํ’€์ด ์ƒํƒœ๋ฅผ ์ƒ‰์ƒ์œผ๋กœ ํ‘œ์‹œ +/// - ์ดˆ๋ก์ƒ‰: ํ’€๊ณ  ๋งž์€ ๋ฌธ์ œ +/// - ๋นจ๊ฐ„์ƒ‰: ํ’€๊ณ  ํ‹€๋ฆฐ ๋ฌธ์ œ +/// - ํšŒ์ƒ‰: ํ’€์ง€ ์•Š์€ ๋ฌธ์ œ +class ChapterDetailPage extends StatefulWidget { + final int chapterId; + final int academyUserId; + final String workbookName; + final String chapterName; + final GetChapterQuestionStatusesUseCase getChapterQuestionStatusesUseCase; + + const ChapterDetailPage({ + super.key, + required this.chapterId, + required this.academyUserId, + required this.workbookName, + required this.chapterName, + required this.getChapterQuestionStatusesUseCase, + }); + + @override + State createState() => _ChapterDetailPageState(); +} + +class _ChapterDetailPageState extends State { + List _questionStatuses = []; + bool _isLoading = false; + String? _errorMessage; + + @override + void initState() { + super.initState(); + _loadQuestionStatuses(); + } + + Future _loadQuestionStatuses() async { + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + final statuses = await widget.getChapterQuestionStatusesUseCase.call( + chapterId: widget.chapterId, + academyUserId: widget.academyUserId, + ); + + if (!mounted) return; + + setState(() { + _questionStatuses = statuses; + _isLoading = false; + }); + } catch (e) { + developer.log('โŒ [ChapterDetailPage] ๋ฌธ์ œ ์ƒํƒœ ๋กœ๋“œ ์‹คํŒจ: $e'); + + if (!mounted) return; + + setState(() { + _errorMessage = '๋ฌธ์ œ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'; + _isLoading = false; + }); + } + } + + /// UI ์ •์ฑ…: isCorrect? -> QuestionStatus ๋ณ€ํ™˜ + QuestionStatus _getQuestionStatus(QuestionStatusModel model) { + final isCorrect = model.isCorrect; + + if (isCorrect == null) { + return QuestionStatus.unsolved; // UI์—์„œ ํŒ๋‹จ + } else if (isCorrect) { + return QuestionStatus.correct; + } else { + return QuestionStatus.incorrect; + } + } + + // ํ†ต๊ณ„ ๊ณ„์‚ฐ (UI ๋ ˆ์ด์–ด์—์„œ ์ฒ˜๋ฆฌ) + int _getCorrectCount() { + return _questionStatuses.where((model) => model.isCorrect == true).length; + } + + int _getIncorrectCount() { + return _questionStatuses.where((model) => model.isCorrect == false).length; + } + + int _getUnsolvedCount() { + return _questionStatuses.where((model) => model.isCorrect == null).length; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + // ํ—ค๋” + _buildHeader(), + + // ๋ฉ”์ธ ์ฝ˜ํ…์ธ  + Expanded(child: _buildContent()), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 17), + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x0D000000), + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + child: Row( + children: [ + const CustomBackButton(), + const SizedBox(width: 20), + Expanded( + child: Text( + widget.chapterName, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ); + } + + Widget _buildContent() { + // ๋กœ๋”ฉ ์ƒํƒœ + if (_isLoading) { + return const Center( + child: Padding( + padding: EdgeInsets.all(40.0), + child: CircularProgressIndicator(), + ), + ); + } + + // ์—๋Ÿฌ ์ƒํƒœ + if (_errorMessage != null) { + return Center( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.error_outline, + color: Color(0xFFFF6B6B), + size: 48, + ), + const SizedBox(height: 16), + Text( + _errorMessage!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFFF6B6B), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadQuestionStatuses, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFFF6B6B), + foregroundColor: Colors.white, + ), + child: const Text('๋‹ค์‹œ ์‹œ๋„'), + ), + ], + ), + ), + ); + } + + // ๋นˆ ์ƒํƒœ + if (_questionStatuses.isEmpty) { + return Center( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Text( + '๋“ฑ๋ก๋œ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } + + // ์ •์ƒ ์ƒํƒœ + return SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + + // ์ฑ•ํ„ฐ ์ •๋ณด + _buildChapterInfo(), + + const SizedBox(height: 24), + + // ๋ฌธ์ œ ๋ชฉ๋ก + _buildQuestionGrid(), + + const SizedBox(height: 20), + ], + ), + ); + } + + /// ์ฑ•ํ„ฐ ์ •๋ณด (์ง„ํ–‰ ์ƒํƒœ) + Widget _buildChapterInfo() { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + _buildStatusIndicator('๋งž์€ ๋ฌธ์ œ', Colors.green, _getCorrectCount()), + _buildStatusIndicator('ํ‹€๋ฆฐ ๋ฌธ์ œ', Colors.red, _getIncorrectCount()), + _buildStatusIndicator('์•ˆ ํ‘ผ ๋ฌธ์ œ', Colors.grey, _getUnsolvedCount()), + ], + ), + ); + } + + Widget _buildStatusIndicator(String label, Color color, int count) { + return Column( + children: [ + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: color.withAlpha(51), + shape: BoxShape.circle, + ), + child: Center( + child: Text( + count.toString(), + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: color, + ), + ), + ), + ), + const SizedBox(height: 8), + Text( + label, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: Color(0xFF666666), + ), + ), + ], + ); + } + + /// ๋ฌธ์ œ ๊ทธ๋ฆฌ๋“œ (4์—ด) + Widget _buildQuestionGrid() { + return GridView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + childAspectRatio: 1, + ), + itemCount: _questionStatuses.length, + itemBuilder: (context, index) { + final model = _questionStatuses[index]; + final status = _getQuestionStatus(model); + return _buildQuestionCard(model.questionNumber, status); + }, + ); + } + + /// ๊ฐœ๋ณ„ ๋ฌธ์ œ ์นด๋“œ + Widget _buildQuestionCard(int questionNumber, QuestionStatus status) { + Color backgroundColor; + Color textColor; + + switch (status) { + case QuestionStatus.correct: + backgroundColor = const Color(0xFF4CAF50); // ์ดˆ๋ก์ƒ‰ + textColor = Colors.white; + break; + case QuestionStatus.incorrect: + backgroundColor = const Color(0xFFF44336); // ๋นจ๊ฐ„์ƒ‰ + textColor = Colors.white; + break; + case QuestionStatus.unsolved: + backgroundColor = const Color(0xFFE9ECEF); // ํšŒ์ƒ‰ + textColor = const Color(0xFF666666); + break; + } + + return GestureDetector( + onTap: () { + // TODO: QuestionDetailPage๋กœ ์ด๋™ + Navigator.pushNamed( + context, + '/workbook/question-detail', + arguments: { + 'chapterId': widget.chapterId, + 'academyUserId': widget.academyUserId, + 'workbookName': widget.workbookName, + 'chapterName': widget.chapterName, + 'questionNumber': questionNumber, + 'status': status, + }, + ); + }, + child: Container( + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(13), + offset: const Offset(0, 2), + blurRadius: 4, + ), + ], + ), + child: Center( + child: Text( + questionNumber.toString(), + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: textColor, + ), + ), + ), + ), + ); + } +} diff --git a/frontend/lib/screens/workbook/models/class_data.dart b/frontend/lib/screens/workbook/models/class_data.dart new file mode 100644 index 0000000..a4adbab --- /dev/null +++ b/frontend/lib/screens/workbook/models/class_data.dart @@ -0,0 +1,17 @@ +import 'workbook_info.dart'; + +/// ํด๋ž˜์Šค ๋ฐ์ดํ„ฐ ๋ชจ๋ธ (UI์šฉ) +/// +/// ํด๋ž˜์Šค๋ณ„ ๋ฌธ์ œ์ง‘ ๋ชฉ๋ก์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•œ UI ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. +class ClassData { + final String className; + final String lastStudyDate; + final List workbooks; + + ClassData({ + required this.className, + required this.lastStudyDate, + required this.workbooks, + }); +} + diff --git a/frontend/lib/screens/workbook/models/workbook_data.dart b/frontend/lib/screens/workbook/models/workbook_data.dart new file mode 100644 index 0000000..eb5989e --- /dev/null +++ b/frontend/lib/screens/workbook/models/workbook_data.dart @@ -0,0 +1,23 @@ +/// ๋ฌธ์ œ์ง‘ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ (๋ฌธ์ œ์ง‘ ์ˆœ ํŽ˜์ด์ง€์šฉ, UI์šฉ) +/// +/// ๋ฌธ์ œ์ง‘ ์ˆœ ๋ทฐ์—์„œ ํ‘œ์‹œ๋˜๋Š” ๋ฌธ์ œ์ง‘ ์ •๋ณด์ž…๋‹ˆ๋‹ค. +class WorkbookData { + final String workbookName; + final String lastStudyDate; + final int progress; + final String thumbnailPath; + final String className; + final int? bookId; + final int academyUserId; + + WorkbookData({ + required this.workbookName, + required this.lastStudyDate, + required this.progress, + required this.thumbnailPath, + required this.className, + this.bookId, + required this.academyUserId, + }); +} + diff --git a/frontend/lib/screens/workbook/models/workbook_info.dart b/frontend/lib/screens/workbook/models/workbook_info.dart new file mode 100644 index 0000000..6527f3d --- /dev/null +++ b/frontend/lib/screens/workbook/models/workbook_info.dart @@ -0,0 +1,21 @@ +/// ๋ฌธ์ œ์ง‘ ์ •๋ณด ๋ชจ๋ธ (ํด๋ž˜์Šค ๋‚ด๋ถ€์šฉ, UI์šฉ) +/// +/// ํด๋ž˜์Šค ์นด๋“œ ๋‚ด๋ถ€์— ํ‘œ์‹œ๋˜๋Š” ๋ฌธ์ œ์ง‘ ์ •๋ณด์ž…๋‹ˆ๋‹ค. +class WorkbookInfo { + final String name; + final String lastStudyDate; + final int progress; + final String thumbnailPath; + final int? bookId; + final int academyUserId; + + WorkbookInfo({ + required this.name, + required this.lastStudyDate, + required this.progress, + required this.thumbnailPath, + this.bookId, + required this.academyUserId, + }); +} + diff --git a/frontend/lib/screens/workbook/question_detail_page.dart b/frontend/lib/screens/workbook/question_detail_page.dart new file mode 100644 index 0000000..1e2b585 --- /dev/null +++ b/frontend/lib/screens/workbook/question_detail_page.dart @@ -0,0 +1,723 @@ +import 'package:flutter/material.dart'; +import '../../widgets/back_button.dart'; +import 'chapter_detail_page.dart'; +import '../../domain/student_answer/student_answer_repository.dart'; +import '../../domain/student_answer/student_answer_query.dart'; +import '../../domain/section_image/get_section_image_use_case.dart'; +import '../../config/app_dependencies.dart'; +import '../../utils/app_logger.dart'; +import '../../domain/question/question_identifier.dart'; +import '../../domain/explanation/explanation_source.dart'; +import '../../application/explanation/question_explanation_controller.dart'; + +/// ๋ฌธ์ œ ์ƒ์„ธ ํŽ˜์ด์ง€ +/// ChapterDetailPage์—์„œ ๋ฌธ์ œ๋ฅผ ์„ ํƒํ•˜๋ฉด ํ‘œ์‹œ๋˜๋Š” ํŽ˜์ด์ง€ +/// +/// ๊ตฌ์„ฑ: +/// 1. ํ—ค๋”: ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ + ๋ฌธ์ œ ๋ฒˆํ˜ธ +/// 2. Section ์ด๋ฏธ์ง€: AI๊ฐ€ ์ธ์‹ํ•œ ๋ฌธ์ œ ์˜์—ญ ์ด๋ฏธ์ง€ (crop๋œ ์ด๋ฏธ์ง€) +/// 3. ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ: ํ•ด๋‹น ๋ฌธ์ œ์˜ ๊ณผ๊ฑฐ ์ฑ„์  ๊ธฐ๋ก +/// - ์ฑ„์  ์ผ์‹œ +/// - ์ฑ„์  ๊ฒฐ๊ณผ (์ •๋‹ต/์˜ค๋‹ต) +/// - ํ•™์ƒ ๋‹ต์•ˆ ์ด๋ฏธ์ง€ +class QuestionDetailPage extends StatefulWidget { + final int chapterId; + final int academyUserId; + final String workbookName; + final String chapterName; + final int questionNumber; + final QuestionStatus status; + final int? initialStudentResponseId; + final StudentAnswerRepository studentAnswerRepository; + final GetSectionImageUseCase getSectionImageUseCase; + final QuestionExplanationController explanationController; + + QuestionDetailPage({ + super.key, + required this.chapterId, + required this.academyUserId, + required this.workbookName, + required this.chapterName, + required this.questionNumber, + required this.status, + this.initialStudentResponseId, + StudentAnswerRepository? studentAnswerRepository, + GetSectionImageUseCase? getSectionImageUseCase, + required this.explanationController, + }) : studentAnswerRepository = + studentAnswerRepository ?? AppDependencies.studentAnswerRepository, + getSectionImageUseCase = + getSectionImageUseCase ?? AppDependencies.getSectionImageUseCase; + + @override + State createState() => _QuestionDetailPageState(); +} + +class _QuestionDetailPageState extends State { + ExplanationSource? _explanationSource; + bool _hasShownRequestSuccessPopup = false; + + /// Section ์ด๋ฏธ์ง€ URL + String? _sectionImageUrl; + bool _isLoadingImage = false; + String? _imageError; + + /// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ๋ชฉ๋ก + /// TODO: ์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ (๋‚˜์ค‘์— ๊ตฌํ˜„) + + final List _gradingHistory = []; + + @override + void initState() { + super.initState(); + _loadSectionImage(); + } + + /// Section ์ด๋ฏธ์ง€ ๋กœ๋“œ + /// + /// chapterId + academyUserId ๋˜๋Š” studentResponseId๋กœ ๋‹ต์•ˆ์„ ์กฐํšŒํ•˜์—ฌ + /// studentResponseId๋ฅผ ์ฐพ๊ณ , ๊ทธ๊ฒƒ์œผ๋กœ ์ด๋ฏธ์ง€๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. + Future _loadSectionImage() async { + setState(() { + _isLoadingImage = true; + _imageError = null; + }); + + try { + // 1. ๋‹ต์•ˆ ์กฐํšŒํ•˜์—ฌ studentResponseId ์ฐพ๊ธฐ + final query = widget.initialStudentResponseId != null + ? StudentAnswerQuery.byResponse( + studentResponseId: widget.initialStudentResponseId!, + ) + : StudentAnswerQuery.byChapter( + chapterId: widget.chapterId, + academyUserId: widget.academyUserId, + ); + + final answers = await widget.studentAnswerRepository.getStudentAnswers( + query, + ); + + // 2. ํ•ด๋‹น ๋ฌธ์ œ ๋ฒˆํ˜ธ์˜ ๋‹ต์•ˆ ์ฐพ๊ธฐ (subQuestionNumber๋Š” 0 ์šฐ์„ , ์—†์œผ๋ฉด ์ฒซ ๋ฒˆ์งธ) + final matchingAnswers = answers + .where((a) => a.questionNumber == widget.questionNumber) + .toList(); + + if (matchingAnswers.isEmpty) { + if (!mounted) return; + setState(() { + _isLoadingImage = false; + _imageError = '๋‹ต์•ˆ ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'; + }); + return; + } + + // subQuestionNumber๊ฐ€ 0์ธ ๋‹ต์•ˆ์„ ์šฐ์„  ์„ ํƒ, ์—†์œผ๋ฉด ์ฒซ ๋ฒˆ์งธ ๋‹ต์•ˆ + final answer = matchingAnswers.firstWhere( + (a) => a.subQuestionNumber == 0, + orElse: () => matchingAnswers.first, + ); + + // ExplanationSource ๊ตฌ์„ฑ (bookId๋Š” ํ˜„์žฌ ์ปจํ…์ŠคํŠธ์—์„œ ์•Œ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ 0์œผ๋กœ ๋‘ ) + final questionId = QuestionIdentifier( + bookId: 0, + chapterId: answer.chapterId ?? widget.chapterId, + page: answer.page, + questionNumber: answer.questionNumber, + subQuestionNumber: answer.subQuestionNumber, + ); + + _explanationSource = ExplanationSource( + studentResponseId: answer.studentResponseId, + academyUserId: widget.academyUserId, + question: questionId, + ); + + if (!mounted) return; + + // 3. ์ด๋ฏธ์ง€ ์กฐํšŒ + // ๋‹ต์•ˆ์˜ questionNumber์™€ subQuestionNumber๋ฅผ ์‚ฌ์šฉ + // (๋‹ต์•ˆ์ด ์‹ค์ œ๋กœ ์ €์žฅ๋œ ๋ฌธ์ œ ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•จ) + final imageQuestionNumber = answer.questionNumber; + final imageSubQuestionNumber = answer.subQuestionNumber; + + appLog( + '[question_detail_page] ์ด๋ฏธ์ง€ ์กฐํšŒ ์‹œ์ž‘ - questionNumber: $imageQuestionNumber, subQuestionNumber: $imageSubQuestionNumber, studentResponseId: ${answer.studentResponseId}', + ); + + final imageEntity = await widget.getSectionImageUseCase.call( + academyUserId: widget.academyUserId, + studentResponseId: answer.studentResponseId, + questionNumber: imageQuestionNumber, + subQuestionNumber: imageSubQuestionNumber, + ); + + // ํ•ด์„ค ๋กœ๋”ฉ (์—๋Ÿฌ๊ฐ€ ๋‚˜๋„ ์ด๋ฏธ์ง€ ๋กœ๋”ฉ์—๋Š” ์˜ํ–ฅ ์—†์Œ) + final source = _explanationSource; + if (source != null) { + // ํŽ˜์ด์ง€ ์ง„์ž… ์‹œ์—๋Š” ์ด๋ฏธ ์ƒ์„ฑ๋œ ํ•ด์„ค๋งŒ ์กฐํšŒํ•˜๊ณ , + // ํ•ด์„ค์ด ์—†์œผ๋ฉด ์•„๋ฌด ์ž‘์—…๋„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค (POST ๋ฏธ์ˆ˜ํ–‰). + await widget.explanationController.loadExisting(source); + } + + if (!mounted) return; + + setState(() { + _sectionImageUrl = imageEntity?.imageUrl; + _isLoadingImage = false; + if (imageEntity == null) { + _imageError = '์ด๋ฏธ์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'; + appLog('[question_detail_page] ์ด๋ฏธ์ง€ ์—”ํ‹ฐํ‹ฐ๊ฐ€ null์ž…๋‹ˆ๋‹ค.'); + } else { + appLog('[question_detail_page] ์ด๋ฏธ์ง€ URL ์„ค์ •๋จ: ${imageEntity.imageUrl}'); + } + }); + } catch (e) { + appLog('[question_detail_page] ์ด๋ฏธ์ง€ ๋กœ๋“œ ์‹คํŒจ: $e'); + + if (!mounted) return; + + setState(() { + _isLoadingImage = false; + _imageError = '์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + // ํ—ค๋” + _buildHeader(), + + // ๋ฉ”์ธ ์ฝ˜ํ…์ธ  + Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + + // Section ์ด๋ฏธ์ง€ (๋ฌธ์ œ ์˜์—ญ) + _buildSectionImage(), + + const SizedBox(height: 24), + + // ํ•ด์„ค ์„น์…˜ + _buildExplanationSection(), + + const SizedBox(height: 24), + + // ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ์„น์…˜ + _buildGradingHistorySection(), + + const SizedBox(height: 20), + ], + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 17), + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x0D000000), + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + child: Row( + children: [ + const CustomBackButton(), + const SizedBox(width: 20), + Expanded( + child: Row( + children: [ + Text( + '๋ฌธ์ œ ${widget.questionNumber}', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + ), + const SizedBox(width: 12), + _buildStatusBadge(), + ], + ), + ), + ], + ), + ); + } + + /// ๋ฌธ์ œ ์ƒํƒœ ๋ฐฐ์ง€ + Widget _buildStatusBadge() { + String text; + Color backgroundColor; + Color textColor; + + switch (widget.status) { + case QuestionStatus.correct: + text = '์ •๋‹ต'; + backgroundColor = const Color(0xFF4CAF50); + textColor = Colors.white; + break; + case QuestionStatus.incorrect: + text = '์˜ค๋‹ต'; + backgroundColor = const Color(0xFFF44336); + textColor = Colors.white; + break; + case QuestionStatus.unsolved: + text = '๋ฏธํ’€์ด'; + backgroundColor = const Color(0xFFE9ECEF); + textColor = const Color(0xFF666666); + break; + } + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(12), + ), + child: Text( + text, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 12, + color: textColor, + ), + ), + ); + } + + /// Section ์ด๋ฏธ์ง€ (AI๊ฐ€ ์ธ์‹ํ•œ ๋ฌธ์ œ ์˜์—ญ) + /// TODO: ์‹ค์ œ ์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์˜จ ์ด๋ฏธ์ง€ ํ‘œ์‹œ + Widget _buildSectionImage() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '๋ฌธ์ œ ์˜์—ญ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + Container( + width: double.infinity, + height: 200, + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: _buildImageContent(), + ), + ], + ); + } + + Widget _buildExplanationSection() { + return AnimatedBuilder( + animation: widget.explanationController, + builder: (context, _) { + final state = widget.explanationController.state; + + if (state.lastRequestPerformed && !_hasShownRequestSuccessPopup) { + _hasShownRequestSuccessPopup = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + showDialog( + context: context, + builder: (dialogContext) { + return AlertDialog( + title: const Text('ํ•ด์„ค ์š”์ฒญ ์™„๋ฃŒ'), + content: const Text( + '์ •์ƒ์ ์œผ๋กœ ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n' + 'ํ•ด์„ค์ด ์ค€๋น„๋˜๋ฉด ์•Œ๋ฆผ์œผ๋กœ ์•Œ๋ ค๋“œ๋ฆด๊ฒŒ์š”!', + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(dialogContext).pop(), + child: const Text('ํ™•์ธ'), + ), + ], + ); + }, + ); + }); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Text( + 'ํ•ด์„ค', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(width: 8), + TextButton( + onPressed: state.isLoading || _explanationSource == null + ? null + : () async { + final source = _explanationSource; + if (source != null) { + await widget.explanationController.requestAgain( + source, + ); + } + }, + child: state.isLoading + ? const SizedBox( + width: 16, + height: 16, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : Text( + state.explanation == null ? 'ํ•ด์„ค ์š”์ฒญ' : 'ํ•ด์„ค ๋‹ค์‹œ ์š”์ฒญ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 12, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFFE9ECEF)), + ), + child: _buildExplanationContent(state), + ), + ], + ); + }, + ); + } + + Widget _buildExplanationContent(QuestionExplanationState state) { + if (state.isLoading && state.explanation == null) { + return const Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator(strokeWidth: 2), + ), + ); + } + + if (state.errorMessage != null) { + return Text( + state.errorMessage!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFF44336), + ), + ); + } + + if (state.explanation == null) { + return const Text( + '์•„์ง ์ƒ์„ฑ๋œ ํ•ด์„ค์ด ์—†์Šต๋‹ˆ๋‹ค.\nํ•ด์„ค ์š”์ฒญ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ํ•ด์„ค์„ ์ƒ์„ฑํ•ด๋ณด์„ธ์š”.', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ); + } + + return Text( + state.explanation!.text, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 14, + color: Color(0xFF333333), + height: 1.5, + ), + ); + } + + Widget _buildImageContent() { + // ๋กœ๋”ฉ ์ค‘ + if (_isLoadingImage) { + return const Center(child: CircularProgressIndicator()); + } + + // ์—๋Ÿฌ ์ƒํƒœ + if (_imageError != null) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.image_not_supported, + size: 48, + color: Color(0xFFCCCCCC), + ), + const SizedBox(height: 8), + Text( + _imageError!, + textAlign: TextAlign.center, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ], + ), + ); + } + + // ์ด๋ฏธ์ง€ ํ‘œ์‹œ + if (_sectionImageUrl != null) { + return ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Image.network( + _sectionImageUrl!, + fit: BoxFit.contain, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress == null) return child; + return const Center(child: CircularProgressIndicator()); + }, + errorBuilder: (context, error, stackTrace) { + appLog('[question_detail_page] ์ด๋ฏธ์ง€ ๋กœ๋“œ ์—๋Ÿฌ: $error'); + appLog('[question_detail_page] ์ด๋ฏธ์ง€ URL: $_sectionImageUrl'); + appLog('[question_detail_page] StackTrace: $stackTrace'); + return _buildPlaceholder('์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'); + }, + ), + ); + } + + // ์ด๋ฏธ์ง€ ์—†์Œ + return _buildPlaceholder('์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + Widget _buildPlaceholder([String? message]) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.image_outlined, size: 48, color: Color(0xFFCCCCCC)), + const SizedBox(height: 8), + Text( + message ?? '์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.', + textAlign: TextAlign.center, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ], + ), + ); + } + + /// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ์„น์…˜ + Widget _buildGradingHistorySection() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + '์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + + _gradingHistory.isEmpty + ? _buildEmptyHistory() + : ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: _gradingHistory.length, + separatorBuilder: (context, index) => + const SizedBox(height: 12), + itemBuilder: (context, index) { + return _buildHistoryCard(_gradingHistory[index], index + 1); + }, + ), + ], + ); + } + + Widget _buildEmptyHistory() { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(24), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: const Center( + child: Text( + '์•„์ง ์ฑ„์  ๊ธฐ๋ก์ด ์—†์Šต๋‹ˆ๋‹ค', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } + + /// ๊ฐœ๋ณ„ ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ์นด๋“œ + Widget _buildHistoryCard(GradingHistory history, int attemptNumber) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(13), + offset: const Offset(0, 2), + blurRadius: 8, + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ํ—ค๋”: ์‹œ๋„ ๋ฒˆํ˜ธ + ๊ฒฐ๊ณผ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '$attemptNumber๋ฒˆ์งธ ์‹œ๋„', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 4, + ), + decoration: BoxDecoration( + color: history.isCorrect + ? const Color(0xFF4CAF50) + : const Color(0xFFF44336), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + history.isCorrect ? '์ •๋‹ต' : '์˜ค๋‹ต', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 12, + color: Colors.white, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + + // ์ฑ„์  ์ผ์‹œ + Text( + _formatDateTime(history.gradingDate), + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF999999), + ), + ), + const SizedBox(height: 12), + + // ํ”ผ๋“œ๋ฐฑ + if (history.feedback != null) + Text( + history.feedback!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + + // TODO: ํ•™์ƒ ๋‹ต์•ˆ ์ด๋ฏธ์ง€ ํ‘œ์‹œ + // if (history.studentAnswerImagePath != null) + // _buildStudentAnswerImage(history.studentAnswerImagePath!), + ], + ), + ); + } + + /// ๋‚ ์งœ ํฌ๋งทํŒ… + String _formatDateTime(DateTime dateTime) { + return '${dateTime.year}.${dateTime.month.toString().padLeft(2, '0')}.${dateTime.day.toString().padLeft(2, '0')} ' + '${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}'; + } +} + +/// ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ๋ชจ๋ธ +class GradingHistory { + final DateTime gradingDate; + final bool isCorrect; + final String? studentAnswerImagePath; + final String? feedback; + + GradingHistory({ + required this.gradingDate, + required this.isCorrect, + this.studentAnswerImagePath, + this.feedback, + }); +} diff --git a/frontend/lib/screens/workbook/workbook_detail_page.dart b/frontend/lib/screens/workbook/workbook_detail_page.dart new file mode 100644 index 0000000..dfaf385 --- /dev/null +++ b/frontend/lib/screens/workbook/workbook_detail_page.dart @@ -0,0 +1,369 @@ +import 'package:flutter/material.dart'; +import '../../widgets/back_button.dart'; +import '../../domain/chapter/chapter_entity.dart'; +import '../../domain/chapter/get_chapters_for_book_use_case.dart'; +import 'dart:developer' as developer; + +/// ๋ฌธ์ œ์ง‘ ์ƒ์„ธ ํŽ˜์ด์ง€ +/// WorkbookPage์—์„œ ๋ฌธ์ œ์ง‘์„ ์„ ํƒํ•˜๋ฉด ํ‘œ์‹œ๋˜๋Š” ํŽ˜์ด์ง€ +/// +/// ๊ตฌ์„ฑ: +/// 1. ํ—ค๋”: ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ + ๋ฌธ์ œ์ง‘ ์ด๋ฆ„ +/// 2. ๋ฌธ์ œ์ง‘ ํ’€์ด ํ˜„ํ™ฉ ์„น์…˜ (๊ณต๊ฐ„๋งŒ ํ™•๋ณด, ์ถ”ํ›„ ๊ตฌํ˜„) +/// 3. ์ฑ•ํ„ฐ ๋ชฉ๋ก: ๊ฐ ์ฑ•ํ„ฐ์˜ ์ด๋ฆ„๊ณผ "ํ‘ผ ๋ฌธ์ œ ์ˆ˜/์ „์ฒด ๋ฌธ์ œ ์ˆ˜" ํ‘œ์‹œ +class WorkbookDetailPage extends StatefulWidget { + final String workbookName; + final String? + thumbnailPath; // TODO(downy): workbook ์ธ๋„ค์ผ์„ ํ—ค๋” ์šฐ์ธก์— ํ‘œ์‹œ (Figma node-id=... ์ฐธ์กฐ) + final int bookId; + final int academyUserId; + final GetChaptersForBookUseCase getChaptersUseCase; + + const WorkbookDetailPage({ + super.key, + required this.workbookName, + this.thumbnailPath, + required this.bookId, + required this.academyUserId, + required this.getChaptersUseCase, + }); + + @override + State createState() => _WorkbookDetailPageState(); +} + +class _WorkbookDetailPageState extends State { + // ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ƒ์ˆ˜ํ™” (๋‚˜์ค‘์— AppStrings๋กœ ์ด๋™ ๊ฐ€๋Šฅ) + static const String _defaultChapterErrorMessage = '์ฑ•ํ„ฐ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'; + static const String _emptyChapterMessage = '๋“ฑ๋ก๋œ ์ฑ•ํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'; + + // ์ƒํƒœ ๊ด€๋ฆฌ + List _chapters = []; + bool _isLoading = false; + String? _errorMessage; + + @override + void initState() { + super.initState(); + _loadChapters(); + } + + /// ์ฑ•ํ„ฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + Future _loadChapters() async { + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + final chapters = await widget.getChaptersUseCase.call( + bookId: widget.bookId, + academyUserId: widget.academyUserId, + ); + + if (!mounted) return; + + setState(() { + _chapters = chapters; + _isLoading = false; + }); + } catch (e) { + developer.log('โŒ [WorkbookDetailPage] ์ฑ•ํ„ฐ ๋กœ๋“œ ์‹คํŒจ: $e'); + + if (!mounted) return; + + setState(() { + _errorMessage = _defaultChapterErrorMessage; + _isLoading = false; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + // ํ—ค๋” + _buildHeader(), + + // ๋ฉ”์ธ ์ฝ˜ํ…์ธ  + Expanded(child: _buildContent()), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return Container( + padding: const EdgeInsets.fromLTRB(20, 17, 20, 17), + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x0D000000), + blurRadius: 4, + offset: Offset(0, 2), + ), + ], + ), + child: Row( + children: [ + const CustomBackButton(), + const SizedBox(width: 20), + Expanded( + child: Text( + widget.workbookName, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ); + } + + /// ๋ฉ”์ธ ์ฝ˜ํ…์ธ  (์Šคํฌ๋กค ๊ตฌ์กฐ ๊ฐœ์„ ) + /// + /// CustomScrollView + SliverList๋กœ ํ†ตํ•ฉํ•˜์—ฌ ์„ฑ๋Šฅ ์ตœ์ ํ™” + Widget _buildContent() { + // ๋กœ๋”ฉ ์ƒํƒœ + if (_isLoading) { + return const Center( + child: Padding( + padding: EdgeInsets.all(40.0), + child: CircularProgressIndicator(), + ), + ); + } + + // ์—๋Ÿฌ ์ƒํƒœ + if (_errorMessage != null) { + return Center( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.error_outline, + color: Color(0xFFFF6B6B), + size: 48, + ), + const SizedBox(height: 16), + Text( + _errorMessage!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFFF6B6B), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: _loadChapters, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFFF6B6B), + foregroundColor: Colors.white, + ), + child: const Text('๋‹ค์‹œ ์‹œ๋„'), + ), + ], + ), + ), + ); + } + + // ๋นˆ ์ƒํƒœ + if (_chapters.isEmpty) { + return Center( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Text( + _emptyChapterMessage, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } + + // ์ •์ƒ ์ƒํƒœ: CustomScrollView๋กœ ํ†ตํ•ฉ + // padding์€ horizontal๋งŒ ์ ์šฉํ•˜๊ณ , ์„ธ๋กœ ์—ฌ๋ฐฑ์€ SliverToBoxAdapter๋กœ ๊ด€๋ฆฌ + return CustomScrollView( + slivers: [ + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 20), + sliver: SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == 0) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + _buildProgressSection(), + const SizedBox(height: 24), + const Text( + '์ฑ•ํ„ฐ ๋ชฉ๋ก', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 16), + ], + ); + } + // ์ฑ•ํ„ฐ ์นด๋“œ (index 1๋ถ€ํ„ฐ ์‹œ์ž‘) + final chapterIndex = index - 1; + final chapter = _chapters[chapterIndex]; + return Padding( + padding: EdgeInsets.only( + bottom: chapterIndex < _chapters.length - 1 ? 12 : 0, + ), + child: _buildChapterCard(chapter), + ); + }, + childCount: _chapters.length + 1, // ํƒ€์ดํ‹€ ์„น์…˜ + ์ฑ•ํ„ฐ ๊ฐœ์ˆ˜ + ), + ), + ), + const SliverToBoxAdapter(child: SizedBox(height: 20)), + ], + ); + } + + Widget _buildProgressSection() { + return Container( + width: double.infinity, + height: 120, + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + ), + child: const Center( + child: Text( + '๋ฌธ์ œ์ง‘ ํ’€์ด ํ˜„ํ™ฉ\n(์ถ”ํ›„ ๊ตฌํ˜„ ์˜ˆ์ •)', + textAlign: TextAlign.center, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFF999999), + ), + ), + ), + ); + } + + /// ๊ฐœ๋ณ„ ์ฑ•ํ„ฐ ์นด๋“œ + /// + /// workbook_page.dart์˜ progress bar ๋””์ž์ธ๊ณผ ๋™์ผํ•˜๊ฒŒ ๊ตฌํ˜„ + Widget _buildChapterCard(ChapterEntity chapter) { + return GestureDetector( + onTap: () { + // TODO: ChapterDetailPage๋กœ ์ด๋™ + Navigator.pushNamed( + context, + '/workbook/chapter-detail', + arguments: { + 'chapterId': chapter.chapterId, + 'academyUserId': widget.academyUserId, + 'workbookName': widget.workbookName, + 'chapterName': chapter.formattedName, + }, + ); + }, + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(13), + offset: const Offset(0, 2), + blurRadius: 8, + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ์ฑ•ํ„ฐ๋ช… + Text( + chapter.formattedName, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + const SizedBox(height: 12), + + // ์ง„ํ–‰ ์ƒํƒœ (workbook_page.dart์™€ ๋™์ผํ•œ ์Šคํƒ€์ผ) + Row( + children: [ + Expanded( + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Container( + height: 8, // workbook_page.dart์™€ ๋™์ผ + decoration: const BoxDecoration(color: Color(0xFFE9ECEF)), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: chapter.progress, + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF7C3AED)], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + ), + ), + ), + ), + ), + ), + const SizedBox(width: 12), + Text( + chapter + .problemCountDisplay, // "{studentAnswerCount} / {totalChapterQuestion}" + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Color(0xFF666666), + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/frontend/lib/screens/workbook/workbook_page.dart b/frontend/lib/screens/workbook/workbook_page.dart new file mode 100644 index 0000000..68c7e7d --- /dev/null +++ b/frontend/lib/screens/workbook/workbook_page.dart @@ -0,0 +1,641 @@ +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import '../../widgets/app_header.dart'; +import '../../widgets/app_header_title.dart'; +import '../../widgets/app_header_menu_button.dart'; +import '../../widgets/empty_state_message.dart'; +import '../../services/academy_service.dart'; +import '../../services/auth_service.dart'; +import '../../services/workbook_repository_impl.dart'; +import '../../data/mappers/workbook_mapper.dart'; +import 'models/class_data.dart'; +import 'models/workbook_info.dart'; +import 'models/workbook_data.dart'; +import 'dart:developer' as developer; + +enum WorkbookViewType { + byClass, // ํด๋ž˜์Šค ์ˆœ + byWorkbook, // ๋ฌธ์ œ์ง‘ ์ˆœ +} + +class WorkbookPage extends StatefulWidget { + const WorkbookPage({super.key}); + + @override + State createState() => _WorkbookPageState(); +} + +class _WorkbookPageState extends State { + WorkbookViewType _currentView = WorkbookViewType.byClass; + + final GetIt _getIt = GetIt.instance; + + // Services (DI์—์„œ ์ฃผ์ž…) + late final AuthService _authService; + late final AcademyService _academyService; + late final WorkbookRepositoryImpl _workbookRepository; + late final WorkbookMapper _workbookMapper; + + // Data + List _classData = []; + List _workbookData = []; + bool _isLoading = false; + String? _errorMessage; + bool _hasLoadedOnce = false; + bool _hasRefreshedOnReturn = false; + + @override + void initState() { + super.initState(); + _authService = _getIt(); + _academyService = _getIt(); + _workbookRepository = _getIt(); + _workbookMapper = _getIt(); + _loadWorkbooks(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ ๋Œ์•„์˜ฌ ๋•Œ ๊ฐ•์ œ ์ƒˆ๋กœ๊ณ ์นจ + if (!_hasRefreshedOnReturn) { + _hasRefreshedOnReturn = true; + _loadWorkbooks(forceRefresh: true); + } + } + + /// ์™ธ๋ถ€์—์„œ ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•œ ์ƒˆ๋กœ๊ณ ์นจ ๋ฉ”์„œ๋“œ + void refresh() { + developer.log('๐Ÿ”„ [WorkbookPage] refresh() called from external'); + _hasRefreshedOnReturn = false; + _loadWorkbooks(forceRefresh: true); + } + + /// ๋ฌธ์ œ์ง‘ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + Future _loadWorkbooks({bool forceRefresh = false}) async { + if (_hasLoadedOnce && !forceRefresh) { + return; // ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ ์‚ฌ์šฉ + } + + if (forceRefresh) { + _hasLoadedOnce = false; + } + + setState(() { + _isLoading = true; + _errorMessage = null; + }); + + try { + // 1. UserId๋กœ academyUserIds ์กฐํšŒ + final userId = await _authService.getUserId(); + if (userId == null) { + throw Exception('์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + final academies = await _academyService.getUserAcademies(userId); + final academyUserIds = academies + .where((a) => a.registerStatus == 'Y') + .map((a) => a.academy_user_id) + .whereType() + .toList(); + + if (academyUserIds.isEmpty) { + setState(() { + _classData = []; + _workbookData = []; + _isLoading = false; + }); + return; + } + + // 2. Repository ํ˜ธ์ถœ (className์€ Repository ๋‚ด๋ถ€์—์„œ ์ฒ˜๋ฆฌ) + final summariesMap = await _workbookRepository + .getWorkbookSummariesByAcademyUserIds(academyUserIds); + + // 3. Mapper๋กœ UI ๋ชจ๋ธ ๋ณ€ํ™˜ + final classData = _workbookMapper.convertToClassData(summariesMap); + final workbookData = _workbookMapper.convertToWorkbookData(summariesMap); + + // 4. UI ์—…๋ฐ์ดํŠธ + setState(() { + _classData = classData; + _workbookData = workbookData; + _isLoading = false; + _hasLoadedOnce = true; + }); + } catch (e) { + developer.log('โŒ [WorkbookPage] ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์‹คํŒจ: $e'); + setState(() { + _isLoading = false; + _errorMessage = e.toString().replaceAll('Exception: ', ''); + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + // ํ—ค๋” + _buildHeader(), + + // ๋ฉ”์ธ ์ฝ˜ํ…์ธ  (์Šคํฌ๋กค ๊ฐ€๋Šฅ + Pull-to-refresh) + Expanded( + child: RefreshIndicator( + onRefresh: () async { + await _loadWorkbooks(forceRefresh: true); + }, + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), // Pull-to-refresh๋ฅผ ์œ„ํ•ด ํ•ญ์ƒ ์Šคํฌ๋กค ๊ฐ€๋Šฅํ•˜๋„๋ก + padding: EdgeInsets.symmetric( + horizontal: MediaQuery.of(context).size.width * 0.05, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: MediaQuery.of(context).size.height * 0.032, + ), + + // ํ† ๊ธ€ ๋ฒ„ํŠผ + _buildToggle(), + + Container( + height: MediaQuery.of(context).size.height * 0.01, + ), + + // ๋ฉ”์ธ ์ฝ˜ํ…์ธ  + _isLoading + ? const Center( + child: Padding( + padding: EdgeInsets.all(40.0), + child: CircularProgressIndicator(), + ), + ) + : _errorMessage != null + ? _buildErrorState() + : _currentView == WorkbookViewType.byClass + ? _buildClassView() + : _buildWorkbookView(), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } + + Widget _buildHeader() { + return const AppHeader( + title: AppHeaderTitle('๋ฌธ์ œ์ง‘'), + trailing: AppHeaderMenuButton(), + ); + } + + Widget _buildErrorState() { + return Center( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon(Icons.error_outline, color: Color(0xFFFF6B6B), size: 48), + const SizedBox(height: 16), + Text( + _errorMessage ?? '์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: Color(0xFFFF6B6B), + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () => _loadWorkbooks(forceRefresh: true), + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFFF6B6B), + foregroundColor: Colors.white, + ), + child: const Text('๋‹ค์‹œ ์‹œ๋„'), + ), + ], + ), + ), + ); + } + + Widget _buildToggle() { + final screenWidth = MediaQuery.of(context).size.width; + // ํ† ๊ธ€ ํฌ๊ธฐ ๊ณ„์‚ฐ (Figma ๋น„์œจ: 28:17 ์œ ์ง€) + final toggleWidth = screenWidth * 0.07; + final toggleHeight = toggleWidth * (17 / 28); // ๋น„์œจ ์œ ์ง€ + final circleSize = toggleWidth * (13 / 28); // ๋น„์œจ ์œ ์ง€ + final circlePadding = toggleWidth * (2 / 28); // ๋น„์œจ ์œ ์ง€ + + return Row( + children: [ + // ํ† ๊ธ€ ์Šค์œ„์น˜ + GestureDetector( + onTap: () { + setState(() { + _currentView = _currentView == WorkbookViewType.byClass + ? WorkbookViewType.byWorkbook + : WorkbookViewType.byClass; + }); + }, + child: Container( + width: toggleWidth, + height: toggleHeight, + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF7C3AED)], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + borderRadius: BorderRadius.circular(12), + ), + child: AnimatedAlign( + duration: const Duration(milliseconds: 200), + alignment: _currentView == WorkbookViewType.byClass + ? Alignment.centerLeft + : Alignment.centerRight, + child: Container( + width: circleSize, + height: circleSize, + margin: EdgeInsets.all(circlePadding), + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + ), + ), + ), + ), + Container(width: screenWidth * 0.03), + // ํ† ๊ธ€ ๋ผ๋ฒจ + Text( + _currentView == WorkbookViewType.byClass ? '์ตœ๊ทผ ํด๋ž˜์Šค ์ˆœ' : '์ตœ๊ทผ ๋ฌธ์ œ์ง‘ ์ˆœ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + ], + ); + } + + Widget _buildClassView() { + if (_classData.isEmpty) { + final screenHeight = MediaQuery.of(context).size.height; + return SizedBox( + height: screenHeight * 0.6, + child: const Center( + child: EmptyStateMessage.classRoom( + title: '๋“ฑ๋ก๋œ ํด๋ž˜์Šค๊ฐ€ ์—†์–ด์š”.', + description: 'ํ•™์›์—์„œ ํด๋ž˜์Šค๋ฅผ ๋ฐฐ์ •ํ•ด์ฃผ๋ฉด ์ด๊ณณ์— ํ‘œ์‹œ๋ผ์š”.', + ), + ), + ); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: _classData.length, + separatorBuilder: (context, index) => + Container(height: MediaQuery.of(context).size.height * 0.02), + itemBuilder: (context, index) { + final classItem = _classData[index]; + return _buildClassCard(classItem); + }, + ), + ], + ); + } + + Widget _buildClassCard(ClassData classData) { + return Container( + padding: EdgeInsets.all(MediaQuery.of(context).size.width * 0.04), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(13), + offset: const Offset(0, 2), + blurRadius: 8, + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ํด๋ž˜์Šค๋ช… + Text( + classData.className, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + + Container(height: MediaQuery.of(context).size.height * 0.02), + + // ๋ฌธ์ œ์ง‘ ์ธ๋„ค์ผ๊ณผ ์ง„ํ–‰๋ฅ  ๋ฆฌ์ŠคํŠธ + classData.workbooks.isEmpty + ? const SizedBox.shrink() + : Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: List.generate(classData.workbooks.length, (index) { + final workbook = classData.workbooks[index]; + return Padding( + padding: EdgeInsets.only( + right: index < classData.workbooks.length - 1 + ? MediaQuery.of(context).size.width * 0.04 + : 0, + ), + child: _buildWorkbookProgress(workbook), + ); + }), + ), + ], + ), + ); + } + + Widget _buildWorkbookProgress(WorkbookInfo workbook) { + final screenWidth = MediaQuery.of(context).size.width; + final thumbnailWidth = screenWidth * 0.15; // ํ™”๋ฉด ๋„ˆ๋น„์˜ 15% + final thumbnailHeight = thumbnailWidth * 1.33; // 3:4 ๋น„์œจ ์œ ์ง€ + + return GestureDetector( + onTap: () { + if (workbook.bookId == null) { + // bookId๊ฐ€ ์—†์œผ๋ฉด ์ด๋™ํ•˜์ง€ ์•Š์Œ + return; + } + // WorkbookDetailPage๋กœ ์ด๋™ + Navigator.pushNamed( + context, + '/workbook/detail', + arguments: { + 'workbookName': workbook.name, + 'thumbnailPath': workbook.thumbnailPath, + 'bookId': workbook.bookId, + 'academyUserId': workbook.academyUserId, + }, + ); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ๋ฌธ์ œ์ง‘ ์ธ๋„ค์ผ + ClipRRect( + borderRadius: BorderRadius.circular(4), + child: Container( + width: thumbnailWidth, + height: thumbnailHeight, + color: const Color(0xFFE9ECEF), + child: _buildThumbnailImage(workbook.thumbnailPath), + ), + ), + Container(height: MediaQuery.of(context).size.height * 0.01), + // ์ง„ํ–‰๋ฅ  ๋ฐ” + SizedBox( + width: thumbnailWidth, + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Container( + height: 6, + decoration: const BoxDecoration(color: Color(0xFFE9ECEF)), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: workbook.progress / 100, + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF7C3AED)], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + ), + ), + ), + ), + ), + ), + ], + ), + ); + } + + Widget _buildWorkbookView() { + if (_workbookData.isEmpty) { + return const Center( + child: EmptyStateMessage.workbook( + title: 'ํ˜„์žฌ ๋“ฑ๋ก๋œ ๋ฌธ์ œ์ง‘์ด ์—†์–ด์š”.', + description: '์„ ์ƒ๋‹˜์ด ๋ฌธ์ œ์ง‘์„ ๋ฐฐ์ •ํ•˜๋ฉด ์ด๊ณณ์— ํ‘œ์‹œ๋ผ์š”.', + ), + ); + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListView.separated( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: _workbookData.length, + separatorBuilder: (context, index) => + Container(height: MediaQuery.of(context).size.height * 0.02), + itemBuilder: (context, index) { + return _buildWorkbookCard(_workbookData[index]); + }, + ), + ], + ); + } + + Widget _buildWorkbookCard(WorkbookData workbookData) { + return GestureDetector( + onTap: () { + if (workbookData.bookId == null) { + // bookId๊ฐ€ ์—†์œผ๋ฉด ์ด๋™ํ•˜์ง€ ์•Š์Œ + return; + } + // WorkbookDetailPage๋กœ ์ด๋™ + Navigator.pushNamed( + context, + '/workbook/detail', + arguments: { + 'workbookName': workbookData.workbookName, + 'thumbnailPath': workbookData.thumbnailPath, + 'bookId': workbookData.bookId, + 'academyUserId': workbookData.academyUserId, + }, + ); + }, + child: Container( + padding: EdgeInsets.all(MediaQuery.of(context).size.width * 0.04), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(13), + offset: const Offset(0, 2), + blurRadius: 8, + ), + ], + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ๋ฌธ์ œ์ง‘ ์ธ๋„ค์ผ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Container( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.18, + minWidth: 60, + maxHeight: MediaQuery.of(context).size.width * 0.23, + minHeight: 80, + ), + color: const Color(0xFFE74C3C), + child: _buildThumbnailImage(workbookData.thumbnailPath), + ), + ), + + Container(width: MediaQuery.of(context).size.width * 0.04), + + // ๋ฌธ์ œ์ง‘ ์ •๋ณด + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ๋ฌธ์ œ์ง‘๋ช… + Text( + workbookData.workbookName, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 16, + color: Color(0xFF333333), + ), + ), + + Container(height: MediaQuery.of(context).size.height * 0.01), + + // ํ•™์Šต ์ •๋ณด + Text( + '${workbookData.className}์—์„œ ์ง„ํ–‰ ์ค‘', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF666666), + ), + ), + + Container(height: MediaQuery.of(context).size.height * 0.005), + + // ๋งˆ์ง€๋ง‰ ํ•™์Šต์ผ + Text( + '๋งˆ์ง€๋ง‰ ํ•™์Šต ์ผ ${workbookData.lastStudyDate}', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 12, + color: Color(0xFF999999), + ), + ), + + Container(height: MediaQuery.of(context).size.height * 0.015), + + // ์ง„ํ–‰๋ฅ  + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Container( + height: 8, + decoration: const BoxDecoration( + color: Color(0xFFE9ECEF), + ), + child: FractionallySizedBox( + alignment: Alignment.centerLeft, + widthFactor: workbookData.progress / 100, + child: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [ + Color(0xFFAC5BF8), + Color(0xFF7C3AED), + ], + begin: Alignment.centerLeft, + end: Alignment.centerRight, + ), + ), + ), + ), + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ); + } + + /// ์ธ๋„ค์ผ ์ด๋ฏธ์ง€ ๋กœ๋“œ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ + /// + /// ๋„คํŠธ์›Œํฌ URL์ธ ๊ฒฝ์šฐ Image.network ์‚ฌ์šฉ, + /// asset ๊ฒฝ๋กœ์ธ ๊ฒฝ์šฐ Image.asset ์‚ฌ์šฉ + Widget _buildThumbnailImage(String thumbnailPath) { + if (thumbnailPath.startsWith('http')) { + return Image.network( + thumbnailPath, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Center( + child: Icon(Icons.book, color: Color(0xFF999999)), + ); + }, + ); + } else { + return Image.asset( + thumbnailPath, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Center( + child: Icon(Icons.book, color: Color(0xFF999999)), + ); + }, + ); + } + } +} diff --git a/frontend/lib/services/academy_service.dart b/frontend/lib/services/academy_service.dart new file mode 100644 index 0000000..6f77547 --- /dev/null +++ b/frontend/lib/services/academy_service.dart @@ -0,0 +1,835 @@ +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert'; +import 'auth_service.dart'; +import '../config/api_config.dart'; +import '../utils/app_logger.dart'; + +/// ํ•™์› ๊ด€๋ จ API ํ˜ธ์ถœ ๋ฐ ์บ์‹ฑ์„ ๋‹ด๋‹นํ•˜๋Š” ์„œ๋น„์Šค +/// +/// DI Container์—์„œ singleton์œผ๋กœ ๊ด€๋ฆฌ๋˜๋ฉฐ, +/// AuthService๋Š” ์ƒ์„ฑ์ž ์ฃผ์ž…์„ ํ†ตํ•ด ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. +class AcademyService { + final AuthService _authService; + + AcademyService({AuthService? authService}) + : _authService = authService ?? AuthService(); + + // SharedPreferences ํ‚ค + static const String _academiesCacheKey = 'user_academies_cache'; + static const String _defaultAcademyCodeKey = 'default_academy_code'; + + // ํด๋ž˜์Šค ์ •๋ณด ์บ์‹œ (๋ฉ”๋ชจ๋ฆฌ) + final Map _classCache = {}; + + /// ๋””ํดํŠธ ํ•™์› ๋ณ€๊ฒฝ ๊ฐ์ง€์šฉ ๋…ธํ‹ฐํŒŒ์ด์–ด + final ValueNotifier defaultAcademyVersion = ValueNotifier(0); + + /// ๊ทผ์ฒ˜ ํ•™์› ๋ฆฌ์ŠคํŠธ ์กฐํšŒ + Future> getNearbyAcademies({ + required double latitude, + required double longitude, + }) async { + try { + // JWT ํ† ํฐ ๊ฐ€์ ธ์˜ค๊ธฐ + final token = await _authService.getAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + // API ์—”๋“œํฌ์ธํŠธ ๊ตฌ์„ฑ (radius, page, size๋Š” ๋ฐฑ์—”๋“œ ๋””ํดํŠธ๊ฐ’ ์‚ฌ์šฉ) + // ์—๋ฎฌ๋ ˆ์ดํ„ฐ/์‹ค๊ธฐ๊ธฐ์—์„œ ์ „๋‹ฌ๋ฐ›์€ ํ˜„์žฌ ์œ„์น˜(lat, lng)๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ + final uri = Uri.parse( + '${ApiConfig.baseUrl}/academy/nearby?lat=$latitude&lng=$longitude', + ); + + // API ํ˜ธ์ถœ + final response = await http.get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final List data = json.decode(response.body); + return data.map((item) => AcademyResponse.fromJson(item)).toList(); + } else if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } else { + throw Exception('ํ•™์› ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: ${response.statusCode}'); + } + } catch (e) { + rethrow; + } + } + + /// ์‚ฌ์šฉ์ž ๋“ฑ๋ก ํ•™์› ๋ฆฌ์ŠคํŠธ ์กฐํšŒ + Future> getUserAcademies(String userId) async { + try { + final token = await _authService.getAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/academy/academy-users/$userId/academies', + ); + + final response = await http.get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + try { + final List data = json.decode(response.body); + return data.map((item) { + try { + return UserAcademyResponse.fromJson(item); + } catch (e) { + rethrow; + } + }).toList(); + } catch (e) { + throw Exception('ํ•™์› ์ •๋ณด ํŒŒ์‹ฑ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: $e'); + } + } else if (response.statusCode == 404) { + // 404๋Š” ๋นˆ ๋ฐฐ์—ด ๋ฐ˜ํ™˜ (ํ•™์›์ด ์—†๋Š” ๊ฒฝ์šฐ) + return []; + } else if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } else { + throw Exception('ํ•™์› ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: ${response.statusCode}'); + } + } catch (e) { + rethrow; + } + } + + /// ํ•™์› ๋“ฑ๋ก ์š”์ฒญ + /// + /// ์‘๋‹ต: status code๋งŒ ํ™•์ธ (200/201์ด๋ฉด ์„ฑ๊ณต) + /// ์‘๋‹ต body๋Š” ํŒŒ์‹ฑํ•˜์ง€ ์•Š์œผ๋ฉฐ, academyId, userId๋ฅผ ๋ฐ›์ง€ ์•Š์Œ + Future joinAcademyRequest({ + required String academy_id, + required int user_id, + }) async { + try { + final token = await _authService.getAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/academy/academy-users/join/request', + ); + + final requestBody = json.encode({ + 'academy': {'academy_code': academy_id}, + 'user_id': user_id, + // TODO: ์‹ค์ œ ํด๋ž˜์Šค ์—ฐ๋™ ์‹œ ์„œ๋ฒ„ ์Šคํ‚ค๋งˆ์— ๋งž๊ฒŒ ๊ฐ’ ๊ต์ฒด + // ํ˜„์žฌ๋Š” ํ•ญ์ƒ 0์„ ์ „๋‹ฌ (๋ฐฑ์—”๋“œ ๊ธฐ๋ณธ ๋ฐ˜/์ „์ฒด ๋ฐ˜ ๋“ฑ ์ฒ˜๋ฆฌ์šฉ) + 'class_id': 0, + }); + + final response = await http.post( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: requestBody, + ); + + if (response.statusCode == 200 || + response.statusCode == 201 || + response.statusCode == 202) { + // ์„ฑ๊ณต ์‘๋‹ต์ด๋ฏ€๋กœ ์•„๋ฌด๊ฒƒ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Œ (์‘๋‹ต body ํŒŒ์‹ฑ ๋ถˆํ•„์š”) + return; + } else if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } else { + // ์—๋Ÿฌ ์‘๋‹ต ์ฒ˜๋ฆฌ (์‘๋‹ต body๊ฐ€ JSON์ด ์•„๋‹ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ) + String errorMessage = 'ํ•™์› ๋“ฑ๋ก ์š”์ฒญ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: ${response.statusCode}'; + + // ์š”์ฒญ ๋ณธ๋ฌธ ์ •๋ณด๋ฅผ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€์— ํฌํ•จ + String requestInfo = '\n์ „์†ก๋œ ๋ฐ์ดํ„ฐ: $requestBody'; + + if (response.body.isNotEmpty) { + try { + final errorBody = json.decode(response.body); + final serverMessage = + errorBody['message'] ?? + errorBody['error'] ?? + errorBody['detail'] ?? + response.body; + errorMessage = '$errorMessage\n์„œ๋ฒ„ ์‘๋‹ต: $serverMessage$requestInfo'; + } catch (e) { + // JSON ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ์‘๋‹ต body๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ + errorMessage = '$errorMessage\n์„œ๋ฒ„ ์‘๋‹ต: ${response.body}$requestInfo'; + } + } else { + errorMessage = '$errorMessage$requestInfo'; + } + + throw Exception(errorMessage); + } + } catch (e) { + rethrow; + } + } + + /// ํ•™์› ํƒˆํ‡ด ์š”์ฒญ + Future leaveAcademy(int academyUserId) async { + try { + final token = await _authService.getAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/academy/academy-users/$academyUserId/leave', + ); + + final response = await http.delete( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200 || response.statusCode == 202) { + await _removeAcademyFromCache(academyUserId); + return; + } else if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } else { + final message = response.body.isNotEmpty ? response.body : '์‘๋‹ต ์—†์Œ'; + throw Exception('ํ•™์› ํƒˆํ‡ด ์š”์ฒญ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค: $message'); + } + } catch (e) { + rethrow; + } + } + + // TODO: ๋ฐฑ์—”๋“œ์—์„œ academyId๋กœ ํ•™์› ์ƒ์„ธ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” API๊ฐ€ ๊ตฌํ˜„ ์ค‘์ž…๋‹ˆ๋‹ค. + // ์™„๋ฃŒ ํ›„ frontend์—์„œ๋„ ๊ตฌํ˜„ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. + + /// ํ•™์› ๋ชฉ๋ก์„ SharedPreferences์— ์ €์žฅ (์‚ฌ์šฉ์ž๋ณ„) + Future saveAcademiesToCache(List academies) async { + try { + final prefs = await SharedPreferences.getInstance(); + final userId = await _authService.getUserId(); + if (userId == null) { + return; + } + final cacheKey = '${_academiesCacheKey}_$userId'; + final jsonData = json.encode( + academies.map((academy) => academy.toJson()).toList(), + ); + await prefs.setString(cacheKey, jsonData); + // ๊ตฌ ๋ฒ„์ „ ์บ์‹œ ์ œ๊ฑฐ + if (prefs.containsKey(_academiesCacheKey)) { + await prefs.remove(_academiesCacheKey); + } + } catch (e) { + // ์บ์‹œ ์ €์žฅ ์‹คํŒจ๋Š” ๋ฌด์‹œ + } + } + + /// SharedPreferences์—์„œ ํ•™์› ๋ชฉ๋ก ๋กœ๋“œ (์‚ฌ์šฉ์ž๋ณ„) + Future?> loadAcademiesFromCache() async { + try { + final prefs = await SharedPreferences.getInstance(); + final userId = await _authService.getUserId(); + if (userId == null) { + return null; + } + final cacheKey = '${_academiesCacheKey}_$userId'; + final cachedJson = prefs.getString(cacheKey); + if (cachedJson == null) { + // ๊ตฌ ๋ฒ„์ „ ์บ์‹œ ์ œ๊ฑฐ + if (prefs.containsKey(_academiesCacheKey)) { + await prefs.remove(_academiesCacheKey); + } + return null; + } + + final List data = json.decode(cachedJson); + return data.map((item) => UserAcademyResponse.fromJson(item)).toList(); + } catch (e) { + return null; + } + } + + /// ๋””ํดํŠธ ํ•™์› ์ฝ”๋“œ๋ฅผ SharedPreferences์— ์ €์žฅ + Future saveDefaultAcademyCode(String academyCode) async { + try { + final prefs = await SharedPreferences.getInstance(); + final currentCode = prefs.getString(_defaultAcademyCodeKey); + if (currentCode == academyCode) { + return; + } + + await prefs.setString(_defaultAcademyCodeKey, academyCode); + defaultAcademyVersion.value++; + } catch (e) { + // ์บ์‹œ ์ €์žฅ ์‹คํŒจ๋Š” ๋ฌด์‹œ + } + } + + /// SharedPreferences์—์„œ ๋””ํดํŠธ ํ•™์› ์ฝ”๋“œ ๋กœ๋“œ + Future getDefaultAcademyCode() async { + try { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString(_defaultAcademyCodeKey); + } catch (e) { + return null; + } + } + + /// ๋””ํดํŠธ ํ•™์› ์„ ํƒ ๋กœ์ง + /// + /// ์„ ํƒ ์šฐ์„ ์ˆœ์œ„: + /// 1. SharedPreferences์— ์ €์žฅ๋œ ๋งˆ์ง€๋ง‰ ์„ ํƒ ํ•™์› (registerStatus == 'Y'์ธ ๊ฒฝ์šฐ๋งŒ) + /// 2. registerStatus == 'Y'์ธ ์ฒซ ๋ฒˆ์งธ ํ•™์› + /// 3. ์—†์œผ๋ฉด null ๋ฐ˜ํ™˜ + String? selectDefaultAcademy(List academies) { + if (academies.isEmpty) { + return null; + } + + // ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์›๋งŒ ํ•„ํ„ฐ๋ง + final registeredAcademies = academies + .where((academy) => academy.registerStatus == 'Y') + .toList(); + + if (registeredAcademies.isEmpty) { + return null; + } + + // 1. SharedPreferences์—์„œ ๋งˆ์ง€๋ง‰ ์„ ํƒํ•œ ํ•™์› ์ฝ”๋“œ ํ™•์ธ + // (๋น„๋™๊ธฐ์ด๋ฏ€๋กœ ๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Future๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ) + // ๋Œ€์‹  academies ๋ฆฌ์ŠคํŠธ์—์„œ ์ง์ ‘ ํ™•์ธ + // ์ด ๋ฉ”์„œ๋“œ๋Š” ๋‚˜์ค‘์— getDefaultAcademyCode()์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋จ + + // 2. ๋“ฑ๋ก์™„๋ฃŒ๋œ ์ฒซ ๋ฒˆ์งธ ํ•™์› ๋ฐ˜ํ™˜ + final firstRegistered = registeredAcademies.first; + if (firstRegistered.academyCode != null) { + return firstRegistered.academyCode; + } + + return null; + } + + /// ๋งˆ์ง€๋ง‰ ์„ ํƒํ•œ ํ•™์› ์ฝ”๋“œ์™€ ํ˜„์žฌ ํ•™์› ๋ชฉ๋ก์„ ๋น„๊ตํ•˜์—ฌ ๋””ํดํŠธ ํ•™์› ์„ ํƒ + /// + /// ์ด ๋ฉ”์„œ๋“œ๋Š” ๋น„๋™๊ธฐ๋กœ SharedPreferences๋ฅผ ํ™•์ธํ•˜๊ณ , + /// ์ €์žฅ๋œ ํ•™์› ์ฝ”๋“œ๊ฐ€ ํ˜„์žฌ ๋ชฉ๋ก์— ์žˆ๊ณ  ๋“ฑ๋ก์™„๋ฃŒ ์ƒํƒœ์ธ์ง€ ํ™•์ธ + Future selectDefaultAcademyAsync( + List academies, + ) async { + if (academies.isEmpty) { + return null; + } + + // ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์›๋งŒ ํ•„ํ„ฐ๋ง + final registeredAcademies = academies + .where((academy) => academy.registerStatus == 'Y') + .toList(); + + if (registeredAcademies.isEmpty) { + return null; + } + + // 1. SharedPreferences์—์„œ ๋งˆ์ง€๋ง‰ ์„ ํƒํ•œ ํ•™์› ์ฝ”๋“œ ํ™•์ธ + final savedAcademyCode = await getDefaultAcademyCode(); + + if (savedAcademyCode != null) { + // ์ €์žฅ๋œ ํ•™์› ์ฝ”๋“œ๊ฐ€ ํ˜„์žฌ ๋ชฉ๋ก์— ์žˆ๊ณ  ๋“ฑ๋ก์™„๋ฃŒ ์ƒํƒœ์ธ์ง€ ํ™•์ธ + final savedAcademy = registeredAcademies.firstWhere( + (academy) => academy.academyCode == savedAcademyCode, + orElse: () => registeredAcademies.first, + ); + + if (savedAcademy.academyCode != null) { + return savedAcademy.academyCode; + } + } + + // 2. ์ €์žฅ๋œ ํ•™์›์ด ์—†๊ฑฐ๋‚˜ ์œ ํšจํ•˜์ง€ ์•Š์œผ๋ฉด ๋“ฑ๋ก์™„๋ฃŒ๋œ ์ฒซ ๋ฒˆ์งธ ํ•™์› ๋ฐ˜ํ™˜ + final firstRegistered = registeredAcademies.first; + if (firstRegistered.academyCode != null) { + return firstRegistered.academyCode; + } + + return null; + } + + /// ํ•™์› ์ฝ”๋“œ๋กœ ํ•™์› ์ •๋ณด ์กฐํšŒ (์บ์‹œ์—์„œ) + Future getAcademyByCode(String academyCode) async { + final academies = await loadAcademiesFromCache(); + if (academies == null) { + return null; + } + + try { + return academies.firstWhere( + (academy) => academy.academyCode == academyCode, + ); + } catch (e) { + return null; + } + } + + /// ํด๋ž˜์Šค ์ •๋ณด ์กฐํšŒ + /// + /// ์—ฌ๋Ÿฌ assigneeId๋ฅผ ๋ฐ›์•„์„œ academyUserId์™€ className ์Œ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + /// assigneeId์™€ academyUserId๋Š” ํ•ญ์ƒ ์ผ์น˜ํ•˜๋ฏ€๋กœ, academyUserId๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. + /// + /// [assigneeIds]: ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ์กฐํšŒํ•  assigneeId ๋ฆฌ์ŠคํŠธ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: Map ํ˜•ํƒœ + /// ์˜ˆ: {"10": "์กฐ์„ฑ์ œ ์„ ์ƒ๋‹˜ 3๋ฐ˜", "11": "์กฐ์„ฑ์ œ ์„ ์ƒ๋‹˜ 3๋ฐ˜", "12": "์˜ค์„ธ์ข… ์„ ์ƒ๋‹˜ 3๋ฐ˜"} + Future> getClassesByAssigneeIds( + List assigneeIds, + ) async { + if (assigneeIds.isEmpty) { + return {}; + } + + // 1. ์บ์‹œ์—์„œ ํ™•์ธ + final uncachedIds = assigneeIds + .where((id) => !_classCache.containsKey(id)) + .toList(); + + // 2. ์บ์‹œ์— ์—†๋Š” ID๋“ค๋งŒ API ํ˜ธ์ถœ + if (uncachedIds.isNotEmpty) { + try { + final token = await _authService.getAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = ApiConfig.getAcademyClassesUri(uncachedIds); + + final response = await http.get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final List data = json.decode(response.body); + + // academyUserId == assigneeId ์ด๋ฏ€๋กœ, academyUserId๋ฅผ ํ‚ค๋กœ ์‚ฌ์šฉ + for (var item in data) { + final academyUserId = item['academyUserId']?.toString() ?? ''; + final className = item['className']?.toString() ?? ''; + + if (academyUserId.isNotEmpty && className.isNotEmpty) { + _classCache[academyUserId] = className; + } + } + } else if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } else { + // API ์‹คํŒจ ์‹œ ๋นˆ ๋งต ๋ฐ˜ํ™˜ (์—๋Ÿฌ๋Š” throwํ•˜์ง€ ์•Š์Œ) + } + } catch (e) { + // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ์—๋„ ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋Š” ๋ฐ˜ํ™˜ + } + } + + // 3. ์บ์‹œ์—์„œ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ (์š”์ฒญํ•œ ๋ชจ๋“  ID์— ๋Œ€ํ•ด) + final result = Map.fromEntries( + assigneeIds.map((id) => MapEntry(id, _classCache[id] ?? '')), + ); + return result; + } + + /// ํด๋ž˜์Šค ์ •๋ณด ์บ์‹œ ์ดˆ๊ธฐํ™” + void clearClassCache() { + _classCache.clear(); + } + + /// ํ•™์› ์ฝ”๋“œ๋กœ ํ•™์› ์ •๋ณด ๋ฐ ์Šค์ผ€์ค„ ์กฐํšŒ + Future getAcademySchedule(String academyCode) async { + appLog('[academy:academy_service] API ํ˜ธ์ถœ ์‹œ์ž‘ - academyCode: $academyCode'); + + try { + // ensureValidAccessToken ์‚ฌ์šฉ (๋‹ค๋ฅธ ์„œ๋น„์Šค์™€ ์ผ๊ด€์„ฑ ์œ ์ง€) + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + appLog('[academy:academy_service] ์ธ์ฆ ํ† ํฐ ์—†์Œ'); + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/academy/academy-schedules/$academyCode', + ); + + appLog('[academy:academy_service] GET ์š”์ฒญ: $uri'); + + final response = await http.get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + appLog('[academy:academy_service] ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: ${response.statusCode}'); + appLog('[academy:academy_service] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}'); + + if (response.statusCode == 200) { + final Map data = json.decode(response.body); + appLog('[academy:academy_service] ์‘๋‹ต ํŒŒ์‹ฑ ์„ฑ๊ณต'); + appLog('[academy:academy_service] ํŒŒ์‹ฑ๋œ ๋ฐ์ดํ„ฐ: $data'); + + final result = AcademyScheduleResponse.fromJson(data); + appLog( + '[academy:academy_service] AcademyScheduleResponse ์ƒ์„ฑ ์™„๋ฃŒ - academyName: ${result.academy.academyName}, schedules ๊ฐœ์ˆ˜: ${result.schedules.length}', + ); + + return result; + } else if (response.statusCode == 401) { + appLog('[academy:academy_service] ์ธ์ฆ ์‹คํŒจ (401)'); + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } else if (response.statusCode == 404) { + appLog('[academy:academy_service] ํ•™์› ์ •๋ณด ์—†์Œ (404)'); + throw Exception('ํ•™์› ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } else { + // ๋กœ๊ทธ์—๋Š” ์ƒ์„ธ ์ •๋ณด, ์˜ˆ์™ธ์—๋Š” ์ผ๋ฐ˜ ๋ฉ”์‹œ์ง€ + appLog( + '[academy:academy_service] API ํ˜ธ์ถœ ์‹คํŒจ - status: ${response.statusCode}', + ); + throw Exception('ํ•™์› ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + } catch (e) { + appLog('[academy:academy_service] ์—๋Ÿฌ ๋ฐœ์ƒ: $e'); + rethrow; + } + } + + Future _removeAcademyFromCache(int academyUserId) async { + try { + final prefs = await SharedPreferences.getInstance(); + final userId = await _authService.getUserId(); + if (userId == null) return; + + final cacheKey = '${_academiesCacheKey}_$userId'; + final cachedJson = prefs.getString(cacheKey); + if (cachedJson == null) return; + + final List data = json.decode(cachedJson); + data.removeWhere((item) => item['academy_user_id'] == academyUserId); + await prefs.setString(cacheKey, json.encode(data)); + } catch (e) { + // ์บ์‹œ ์ œ๊ฑฐ ์‹คํŒจ๋Š” ๋ฌด์‹œ + } + } + + /// ํ•™์› ์ด๋ฏธ์ง€ ๋ฆฌ์ŠคํŠธ ์กฐํšŒ + /// + /// [academyCode]: ํ•™์› ์ฝ”๋“œ + /// ๋ฐ˜ํ™˜๊ฐ’: AcademyImageResponse (academy_code, academy_image_urls, main_image_url) + Future getAcademyImages(String academyCode) async { + try { + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = Uri.parse('${ApiConfig.baseUrl}/academy/images/$academyCode'); + + final response = await http.get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + if (response.statusCode == 200) { + final Map data = json.decode(response.body); + return AcademyImageResponse.fromJson(data); + } else if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } else if (response.statusCode == 404) { + throw Exception('ํ•™์› ์ด๋ฏธ์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } else { + throw Exception('ํ•™์› ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + } catch (e) { + rethrow; + } + } +} + +/// ํ•™์› ์‘๋‹ต ๋ชจ๋ธ +class AcademyResponse { + final String academyName; + final String academyRoadAddress; + final double distanceKm; + final String? academyCode; // ํ•™์› ์ฝ”๋“œ + + AcademyResponse({ + required this.academyName, + required this.academyRoadAddress, + required this.distanceKm, + this.academyCode, + }); + + factory AcademyResponse.fromJson(Map json) { + return AcademyResponse( + academyName: json['academyName'] ?? '', + academyRoadAddress: json['academyRoadAddress'] ?? '', + distanceKm: (json['distanceKM'] ?? json['distanceKm'] ?? 0.0).toDouble(), + academyCode: json['academyCode']?.toString(), + ); + } +} + +/// ์‚ฌ์šฉ์ž ๋“ฑ๋ก ํ•™์› ์‘๋‹ต ๋ชจ๋ธ +class UserAcademyResponse { + // ์ถ”๊ฐ€ ํ•„๋“œ๋“ค (snake_case) + final int? academy_user_id; + final int? academy_id; + final int? class_id; + final int? user_id; + final int? learner_id; + + // ๊ธฐ์กด ํ•„๋“œ๋“ค (camelCase๋กœ ์œ ์ง€ - UI์—์„œ ์‚ฌ์šฉ) + final String academyName; + final String academyRoadAddress; + final String registerStatus; // 'Y' ๋˜๋Š” 'P' + final String? academyCode; // ํ•™์› ์ฝ”๋“œ + + UserAcademyResponse({ + this.academy_user_id, + this.academy_id, + this.class_id, + this.user_id, + this.learner_id, + required this.academyName, + required this.academyRoadAddress, + required this.registerStatus, + this.academyCode, + }); + + factory UserAcademyResponse.fromJson(Map json) { + try { + // academy ๊ฐ์ฒด ์ถ”์ถœ (null ์•ˆ์ „) + final academy = json['academy'] as Map? ?? {}; + + final academyName = academy['academy_name']?.toString() ?? ''; + final academyCode = academy['academy_code']?.toString(); + final registerStatus = json['register_status']?.toString() ?? 'P'; + + return UserAcademyResponse( + // ์ถ”๊ฐ€ ํ•„๋“œ๋“ค (snake_case) + academy_user_id: json['academy_user_id'] as int?, + academy_id: json['academy_id'] as int?, + class_id: json['class_id'] as int?, + user_id: json['user_id'] as int?, + learner_id: json['learner_id'] as int?, + + // academy ๊ฐ์ฒด์—์„œ ์ถ”์ถœํ•œ ํ•„๋“œ๋“ค + academyName: academyName, + academyRoadAddress: academy['academy_road_address']?.toString() ?? '', + registerStatus: registerStatus, + academyCode: academyCode, + ); + } catch (e) { + rethrow; + } + } + + /// JSON์œผ๋กœ ๋ณ€ํ™˜ (SharedPreferences ์ €์žฅ์šฉ) + Map toJson() { + return { + 'academy_user_id': academy_user_id, + 'academy_id': academy_id, + 'class_id': class_id, + 'user_id': user_id, + 'learner_id': learner_id, + 'academyName': academyName, + 'academyRoadAddress': academyRoadAddress, + 'registerStatus': registerStatus, + 'academyCode': academyCode, + }; + } +} + +/// ํ•™์› ์Šค์ผ€์ค„ API ์‘๋‹ต ๋ชจ๋ธ +class AcademyScheduleResponse { + final AcademyInfo academy; + final List schedules; + + AcademyScheduleResponse({required this.academy, required this.schedules}); + + factory AcademyScheduleResponse.fromJson(Map json) { + return AcademyScheduleResponse( + academy: AcademyInfo.fromJson(json['academy'] as Map), + schedules: + (json['schedules'] as List?) + ?.map((item) => Schedule.fromJson(item as Map)) + .toList() ?? + [], + ); + } +} + +/// ํ•™์› ์ •๋ณด DTO (API ์‘๋‹ต ์ „์šฉ) +/// +/// ์ฃผ์˜: AcademyData์™€ ์ค‘๋ณต ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. +/// ๋‚˜์ค‘์— ๋„๋ฉ”์ธ ๋ชจ๋ธ ํ†ตํ•ฉ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. +class AcademyInfo { + final String academyName; + final String academyCode; + final String academyDescription; + final String academyPhone; + final String academyEmail; + final String academyWebsite; + final String academyRoadAddress; + final String academyDetailAddress; + final double academyLatitude; + final double academyLongitude; + + AcademyInfo({ + required this.academyName, + required this.academyCode, + required this.academyDescription, + required this.academyPhone, + required this.academyEmail, + required this.academyWebsite, + required this.academyRoadAddress, + required this.academyDetailAddress, + required this.academyLatitude, + required this.academyLongitude, + }); + + factory AcademyInfo.fromJson(Map json) { + return AcademyInfo( + academyName: json['academy_name'] as String? ?? '', + academyCode: json['academy_code'] as String? ?? '', + academyDescription: json['academy_description'] as String? ?? '', + academyPhone: json['academy_phone'] as String? ?? '', + academyEmail: json['academy_email'] as String? ?? '', + academyWebsite: json['academy_website'] as String? ?? '', + academyRoadAddress: json['academy_road_address'] as String? ?? '', + academyDetailAddress: json['academy_detail_address'] as String? ?? '', + academyLatitude: (json['academy_latitude'] as num?)?.toDouble() ?? 0.0, + academyLongitude: (json['academy_longitude'] as num?)?.toDouble() ?? 0.0, + ); + } +} + +/// ํ•™์› ์Šค์ผ€์ค„ ๋ชจ๋ธ +class Schedule { + final int id; + final String academyCode; + final int dayOfWeek; // 0=์ผ์š”์ผ, 1=์›”์š”์ผ, ..., 6=ํ† ์š”์ผ + final String startTime; // "HH:MM:SS" + final String endTime; // "HH:MM:SS" + + Schedule({ + required this.id, + required this.academyCode, + required this.dayOfWeek, + required this.startTime, + required this.endTime, + }); + + factory Schedule.fromJson(Map json) { + return Schedule( + id: json['id'] as int? ?? 0, + academyCode: json['academy_code'] as String? ?? '', + dayOfWeek: json['day_of_week'] as int? ?? 0, + startTime: json['start_time'] as String? ?? '', + endTime: json['end_time'] as String? ?? '', + ); + } + + /// dayOfWeek๋ฅผ ์š”์ผ ์ด๋ฆ„์œผ๋กœ ๋ณ€ํ™˜ + /// + /// ๋ฒ”์œ„ ์ฒดํฌ๋ฅผ ํ†ตํ•ด 0~6 ์™ธ ๊ฐ’์ด ๋“ค์–ด์™€๋„ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. + String get dayName { + const days = ['์ผ์š”์ผ', '์›”์š”์ผ', 'ํ™”์š”์ผ', '์ˆ˜์š”์ผ', '๋ชฉ์š”์ผ', '๊ธˆ์š”์ผ', 'ํ† ์š”์ผ']; + // ๋ฒ”์œ„ ์ฒดํฌ: 0~6 ์™ธ ๊ฐ’ ๋ฐฉ์–ด + if (dayOfWeek < 0 || dayOfWeek > 6) { + return '์•Œ ์ˆ˜ ์—†์Œ'; + } + return days[dayOfWeek]; + } + + /// ์‹œ๊ฐ„ ํฌ๋งทํŒ… (HH:MM:SS โ†’ HH:MM AM/PM) + /// + /// TODO: ๋‚˜์ค‘์— ์‹œ๊ฐ„ ๊ด€๋ จ ๋กœ์ง์ด ๋ณต์žกํ•ด์ง€๋ฉด DateTime/TimeOfDay๋กœ ํŒŒ์‹ฑ ๊ณ ๋ ค + /// TODO: ๊ตญ์ œํ™” ํ•„์š” ์‹œ intl ํŒจํ‚ค์ง€ DateFormat ์‚ฌ์šฉ ๊ณ ๋ ค + String get formattedStartTime { + return _formatTime(startTime); + } + + String get formattedEndTime { + return _formatTime(endTime); + } + + String _formatTime(String timeStr) { + if (timeStr.isEmpty) return ''; + try { + final parts = timeStr.split(':'); + if (parts.length >= 2) { + final hour = int.parse(parts[0]); + final minute = parts[1]; + if (hour == 0) { + return '12:$minute AM'; + } else if (hour < 12) { + return '$hour:$minute AM'; + } else if (hour == 12) { + return '12:$minute PM'; + } else { + return '${hour - 12}:$minute PM'; + } + } + } catch (e) { + // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ์›๋ณธ ๋ฐ˜ํ™˜ + } + return timeStr; + } +} + +/// ํ•™์› ์ด๋ฏธ์ง€ API ์‘๋‹ต ๋ชจ๋ธ +class AcademyImageResponse { + final String academyCode; + final List academyImageUrls; + final String? mainImageUrl; + + AcademyImageResponse({ + required this.academyCode, + required this.academyImageUrls, + this.mainImageUrl, + }); + + factory AcademyImageResponse.fromJson(Map json) { + return AcademyImageResponse( + academyCode: json['academy_code'] as String? ?? '', + academyImageUrls: + (json['academy_image_urls'] as List?) + ?.map((url) => url.toString()) + .toList() ?? + [], + mainImageUrl: json['main_image_url']?.toString(), + ); + } +} diff --git a/frontend/lib/services/assessment_api.dart b/frontend/lib/services/assessment_api.dart new file mode 100644 index 0000000..46bb2dd --- /dev/null +++ b/frontend/lib/services/assessment_api.dart @@ -0,0 +1,149 @@ +import 'dart:convert'; +import 'dart:developer' as developer; + +import 'package:http/http.dart' as http; + +import '../config/api_config.dart'; +import '../models/assessment.dart'; +import '../utils/app_logger.dart'; +import 'auth_service.dart'; + +/// ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜์—ฌ Assessment ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ „์šฉ API ๋ ˆ์ด์–ด. +class AssessmentApi { + AssessmentApi({ + required AuthService authService, + required http.Client httpClient, + }) : _authService = authService, + _httpClient = httpClient; + + final AuthService _authService; + final http.Client _httpClient; + + /// ์ง€์ •๋œ ํ•™์› ์‚ฌ์šฉ์ž์˜ ํŠน์ • ์›” ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. + /// + /// [monthStart]๋Š” ํ•ด๋‹น ์›”์˜ ์ฒซ์งธ ๋‚ (UTC)์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + Future>> fetchAssessmentsForMonth({ + required String userAcademyId, + required DateTime monthStart, + }) async { + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = ApiConfig.getAssessmentsAssigneeUri( + userAcademyId, + dateTime: monthStart, + ); + print( + '[AssessmentApi] GET $uri | academy: $userAcademyId, monthStart: $monthStart', + ); + + // appLog๋กœ API ํ˜ธ์ถœ ์ •๋ณด ๊ธฐ๋ก + appLog( + '[continuous_learning:assessment_api] API ํ˜ธ์ถœ ์‹œ์ž‘ - URL: $uri, userAcademyId: $userAcademyId, monthStart: $monthStart', + ); + + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + final previewLength = response.body.length > 200 + ? 200 + : response.body.length; + final previewBody = response.body.substring(0, previewLength); + print( + '[AssessmentApi] Response status: ${response.statusCode} | body preview: $previewBody', + ); + + // appLog๋กœ API ์‘๋‹ต ์ •๋ณด ๊ธฐ๋ก + appLog( + '[continuous_learning:assessment_api] API ์‘๋‹ต - status: ${response.statusCode}, body length: ${response.body.length}, preview: $previewBody', + ); + + if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + throw Exception('Assessment API ํ˜ธ์ถœ ์‹คํŒจ (status: ${response.statusCode})'); + } + + try { + final dynamic data = json.decode(response.body); + final Map> monthData = {}; + + if (data is List) { + for (final item in data) { + final assessment = Assessment.fromJson(item); + final deadlineDate = item['assessDeadline'] as String?; + if (deadlineDate == null) continue; + + final formattedDate = _normalizeDate(deadlineDate); + monthData.putIfAbsent(formattedDate, () => []).add(assessment); + } + } else if (data is Map) { + data.forEach((key, value) { + if (value is List) { + monthData[key.toString()] = value + .map((item) => Assessment.fromJson(item)) + .toList(); + } + }); + } else { + developer.log('โš ๏ธ [AssessmentApi] ์•Œ ์ˆ˜ ์—†๋Š” ์‘๋‹ต ํ˜•์‹: $data'); + } + + // appLog๋กœ ํŒŒ์‹ฑ๋œ ๋ฐ์ดํ„ฐ ์ •๋ณด ๊ธฐ๋ก + appLog( + '[continuous_learning:assessment_api] ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ ์™„๋ฃŒ - ๋‚ ์งœ๋ณ„ ๊ณผ์ œ ์ˆ˜: ${monthData.length}๊ฐœ ๋‚ ์งœ', + ); + monthData.forEach((date, assessments) { + appLog( + '[continuous_learning:assessment_api] - $date: ${assessments.length}๊ฐœ ๊ณผ์ œ', + ); + }); + + return monthData; + } catch (e) { + developer.log('โŒ [AssessmentApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + rethrow; + } + } + + /// ๋‹ค์–‘ํ•œ ๋‚ ์งœ ๋ฌธ์ž์—ด์„ YYYY-MM-DD ํ˜•์‹์œผ๋กœ ์ •๊ทœํ™”ํ•ฉ๋‹ˆ๋‹ค. + String _normalizeDate(String date) { + try { + if (date.length == 10 && date.contains('-') && !date.contains('T')) { + return date; + } + + if (date.contains('T')) { + final parsed = DateTime.parse(date); + return _formatDate(parsed); + } + + if (date.length == 8 && !date.contains('-') && !date.contains('/')) { + return '${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}'; + } + + if (date.contains('/')) { + return date.replaceAll('/', '-'); + } + + final parsed = DateTime.parse(date); + return _formatDate(parsed); + } catch (e) { + developer.log('โš ๏ธ [AssessmentApi] ๋‚ ์งœ ์ •๊ทœํ™” ์‹คํŒจ: $date, error: $e'); + return date; + } + } + + String _formatDate(DateTime date) { + return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; + } +} diff --git a/frontend/lib/services/assessment_local_store.dart b/frontend/lib/services/assessment_local_store.dart new file mode 100644 index 0000000..4f1e44b --- /dev/null +++ b/frontend/lib/services/assessment_local_store.dart @@ -0,0 +1,132 @@ +import 'dart:convert'; +import 'dart:developer' as developer; + +import 'package:shared_preferences/shared_preferences.dart'; + +import '../models/assessment.dart'; + +/// SharedPreferences ๊ธฐ๋ฐ˜ ๋กœ์ปฌ ์Šค๋ƒ…์ƒท ์ €์žฅ์†Œ. +class AssessmentLocalStore { + AssessmentLocalStore({SharedPreferences? preferences}) + : _prefs = preferences; + + SharedPreferences? _prefs; + + static const String _cacheVersionKey = 'assessment_cache_version'; + static const int _currentCacheVersion = 3; + + Future get _prefsInstance async { + _prefs ??= await SharedPreferences.getInstance(); + return _prefs!; + } + + Future _ensureVersion() async { + final prefs = await _prefsInstance; + final version = prefs.getInt(_cacheVersionKey) ?? 1; + if (version < _currentCacheVersion) { + await _clearAllWithPrefs(prefs); + await prefs.setInt(_cacheVersionKey, _currentCacheVersion); + developer.log( + '๐Ÿ”„ Assessment ์บ์‹œ ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ: $version -> $_currentCacheVersion', + ); + } + } + + String _monthKey(String academyId, int year, int month) { + final formattedMonth = month.toString().padLeft(2, '0'); + return 'assessments_${academyId}_${year}-$formattedMonth'; + } + + Future?> loadDay({ + required String academyId, + required String date, + }) async { + final parsed = DateTime.tryParse(date); + if (parsed == null) return null; + + final monthData = await loadMonth( + academyId: academyId, + year: parsed.year, + month: parsed.month, + ); + return monthData[date]; + } + + Future>> loadMonth({ + required String academyId, + required int year, + required int month, + }) async { + await _ensureVersion(); + final prefs = await _prefsInstance; + final cacheKey = _monthKey(academyId, year, month); + final cachedJson = prefs.getString(cacheKey); + + if (cachedJson == null) { + return {}; + } + + try { + final Map monthData = json.decode(cachedJson); + final result = >{}; + + monthData.forEach((date, assessmentsJson) { + try { + final assessments = (assessmentsJson as List) + .map((item) => Assessment.fromJson(item)) + .toList(); + result[date] = assessments; + } catch (e) { + developer.log('โš ๏ธ Assessment ์บ์‹œ ํŒŒ์‹ฑ ์‹คํŒจ ($date): $e'); + } + }); + + return result; + } catch (e) { + developer.log('โŒ Assessment ์บ์‹œ ๋กœ๋“œ ์‹คํŒจ: $e'); + return {}; + } + } + + Future saveMonth({ + required String academyId, + required int year, + required int month, + required Map> data, + }) async { + await _ensureVersion(); + final prefs = await _prefsInstance; + final cacheKey = _monthKey(academyId, year, month); + + final Map payload = {}; + data.forEach((date, assessments) { + payload[date] = assessments.map((a) => a.toJson()).toList(); + }); + + await prefs.setString(cacheKey, json.encode(payload)); + developer.log('โœ… Assessment ์บ์‹œ ์ €์žฅ: $cacheKey'); + } + + Future clearMonth({ + required String academyId, + required int year, + required int month, + }) async { + final prefs = await _prefsInstance; + await prefs.remove(_monthKey(academyId, year, month)); + } + + Future clearAll() async { + final prefs = await _prefsInstance; + await _clearAllWithPrefs(prefs); + await prefs.setInt(_cacheVersionKey, _currentCacheVersion); + } + + Future _clearAllWithPrefs(SharedPreferences prefs) async { + final keys = prefs.getKeys().where((key) => key.startsWith('assessments_')); + for (final key in keys) { + await prefs.remove(key); + } + } +} + diff --git a/frontend/lib/services/assessment_repository.dart b/frontend/lib/services/assessment_repository.dart new file mode 100644 index 0000000..25e70dc --- /dev/null +++ b/frontend/lib/services/assessment_repository.dart @@ -0,0 +1,253 @@ +import 'dart:async'; +import 'dart:developer' as developer; + +import '../models/assessment.dart'; +import 'academy_service.dart'; +import 'assessment_api.dart'; +import 'assessment_local_store.dart'; + +/// Assessment ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ ๋‹จ์ผ ์ง„์ž…์ . +/// +/// ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ โ†’ SharedPreferences โ†’ API ์ˆœ์„œ๋กœ ์ฝ๊ณ , +/// API ์„ฑ๊ณต ์‹œ SharedPreferences โ†’ ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์œผ๋กœ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค. +class AssessmentRepository { + AssessmentRepository({ + required AssessmentApi api, + required AssessmentLocalStore localStore, + required AcademyService academyService, + }) : _api = api, + _localStore = localStore, + _academyService = academyService; + + final AssessmentApi _api; + final AssessmentLocalStore _localStore; + final AcademyService _academyService; + + final Map> _memoryCache = {}; + + /// ๋‚ ์งœ ๋‹จ์œ„ ํ‚ค ์ƒ์„ฑ (academyId|YYYY-MM-DD) + String _cacheKey(String academyId, String date) => '$academyId|$date'; + + DateTime _monthStart(DateTime dateTime) => + DateTime.utc(dateTime.year, dateTime.month, 1); + + /// ์ฝ๊ธฐ: ๋ฉ”๋ชจ๋ฆฌ โ†’ ๋กœ์ปฌ โ†’ API + Future> getForDate({ + required String academyId, + required String date, + bool forceRefresh = false, + }) async { + final key = _cacheKey(academyId, date); + + if (!forceRefresh && _memoryCache.containsKey(key)) { + return _memoryCache[key]!; + } + + if (!forceRefresh) { + final cached = await _localStore.loadDay( + academyId: academyId, + date: date, + ); + if (cached != null) { + _memoryCache[key] = cached; + _refreshMonthFromServerInBackground( + academyId: academyId, + monthStart: _monthStart(DateTime.parse(date)), + ); + return cached; + } + } + + final monthData = await getForMonth( + academyId: academyId, + dateTime: DateTime.parse(date), + forceRefresh: forceRefresh, + ); + return monthData[date] ?? []; + } + + Future>> getForDates({ + required String academyId, + required List dates, + bool forceRefresh = false, + }) async { + final Map> result = {}; + final Map> datesByMonth = {}; + + for (final date in dates) { + final parsed = DateTime.parse(date); + final monthKey = + '${parsed.year}-${parsed.month.toString().padLeft(2, '0')}'; + datesByMonth.putIfAbsent(monthKey, () => []).add(date); + } + + for (final entry in datesByMonth.entries) { + final year = int.parse(entry.key.split('-')[0]); + final month = int.parse(entry.key.split('-')[1]); + final monthData = await getForMonth( + academyId: academyId, + dateTime: DateTime.utc(year, month, 1), + forceRefresh: forceRefresh, + ); + for (final date in entry.value) { + result[date] = monthData[date] ?? []; + } + } + + return result; + } + + Future>> getForMonth({ + required String academyId, + required DateTime dateTime, + bool forceRefresh = false, + }) async { + final monthStart = _monthStart(dateTime); + final year = monthStart.year; + final month = monthStart.month; + final prefix = '$academyId|${year}-${month.toString().padLeft(2, '0')}-'; + + if (!forceRefresh) { + final fromMemory = _getMonthFromMemoryCache(prefix); + if (fromMemory.isNotEmpty) { + await _updateClassNamesInMonthData(fromMemory); + return fromMemory; + } + } + + if (!forceRefresh) { + final fromLocal = await _localStore.loadMonth( + academyId: academyId, + year: year, + month: month, + ); + if (fromLocal.isNotEmpty) { + _saveMonthToMemoryCache(academyId, fromLocal); + await _updateClassNamesInMonthData(fromLocal); + _refreshMonthFromServerInBackground( + academyId: academyId, + monthStart: monthStart, + ); + return fromLocal; + } + } + + final fromServer = await _api.fetchAssessmentsForMonth( + userAcademyId: academyId, + monthStart: monthStart, + ); + + await _updateClassNamesInMonthData(fromServer); + await _saveMonthSnapshot( + academyId: academyId, + monthStart: monthStart, + data: fromServer, + ); + return fromServer; + } + + Future clearAll() async { + _memoryCache.clear(); + await _localStore.clearAll(); + developer.log('โœ… Assessment ์บ์‹œ ์ „์ฒด ์ดˆ๊ธฐํ™”'); + } + + void clearMemory() { + _memoryCache.clear(); + } + + Future _saveMonthSnapshot({ + required String academyId, + required DateTime monthStart, + required Map> data, + }) async { + _saveMonthToMemoryCache(academyId, data); + await _localStore.saveMonth( + academyId: academyId, + year: monthStart.year, + month: monthStart.month, + data: data, + ); + } + + void _saveMonthToMemoryCache( + String academyId, + Map> monthData, + ) { + monthData.forEach((date, assessments) { + _memoryCache[_cacheKey(academyId, date)] = assessments; + }); + } + + Map> _getMonthFromMemoryCache(String prefix) { + final result = >{}; + _memoryCache.forEach((key, value) { + if (key.startsWith(prefix)) { + final date = key.split('|')[1]; + result[date] = value; + } + }); + return result; + } + + void _refreshMonthFromServerInBackground({ + required String academyId, + required DateTime monthStart, + }) { + Future(() async { + try { + final fresh = await _api.fetchAssessmentsForMonth( + userAcademyId: academyId, + monthStart: monthStart, + ); + await _updateClassNamesInMonthData(fresh); + await _saveMonthSnapshot( + academyId: academyId, + monthStart: monthStart, + data: fresh, + ); + developer.log('๐Ÿ”„ Assessment ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ƒˆ๋กœ๊ณ ์นจ ์™„๋ฃŒ'); + } catch (e) { + developer.log('โš ๏ธ Assessment ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ƒˆ๋กœ๊ณ ์นจ ์‹คํŒจ: $e'); + } + }); + } + + Future _updateClassNamesInMonthData( + Map> monthData, + ) async { + final Set assigneeIds = {}; + monthData.forEach((_, assessments) { + for (final assessment in assessments) { + if (assessment.assessClass.isNotEmpty && + RegExp(r'^\d+$').hasMatch(assessment.assessClass)) { + assigneeIds.add(assessment.assessClass); + } + } + }); + + if (assigneeIds.isEmpty) { + return; + } + + try { + final classMap = await _academyService.getClassesByAssigneeIds( + assigneeIds.toList(), + ); + + monthData.forEach((date, assessments) { + for (var i = 0; i < assessments.length; i++) { + final assessment = assessments[i]; + if (RegExp(r'^\d+$').hasMatch(assessment.assessClass)) { + final className = classMap[assessment.assessClass]; + if (className != null && className.isNotEmpty) { + assessments[i] = assessment.copyWith(assessClass: className); + } + } + } + }); + } catch (e) { + developer.log('โš ๏ธ ํด๋ž˜์Šค ์ •๋ณด ์—…๋ฐ์ดํŠธ ์‹คํŒจ: $e'); + } + } +} diff --git a/frontend/lib/services/auth_service.dart b/frontend/lib/services/auth_service.dart new file mode 100644 index 0000000..b4e9a73 --- /dev/null +++ b/frontend/lib/services/auth_service.dart @@ -0,0 +1,451 @@ +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import '../config/api_config.dart'; + +/// ์ธ์ฆ ๋ฐ ํ† ํฐ ๊ด€๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ์„œ๋น„์Šค +/// +/// DI Container์—์„œ singleton์œผ๋กœ ๊ด€๋ฆฌ๋˜๋ฉฐ, +/// ๋” ์ด์ƒ ํŒŒ์ผ ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +class AuthService { + AuthService(); + + static const String _accessTokenKey = 'access_token'; + static const String _refreshTokenKey = 'refresh_token'; + static const String _userIdKey = 'user_id'; + static const String _autoLoginKey = 'auto_login'; + static const String _saveAccountIdKey = 'save_account_id'; + static const String _savedAccountIdKey = 'saved_account_id'; + + /// Refresh Token ์ €์žฅ + Future saveRefreshToken(String token) async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString(_refreshTokenKey, token); + developer.log('Refresh token saved successfully'); + } catch (e) { + developer.log('Failed to save refresh token: $e'); + } + } + + /// Access Token ๊ฐ€์ ธ์˜ค๊ธฐ + Future getAccessToken() async { + try { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString(_accessTokenKey); + } catch (e) { + developer.log('Failed to get access token: $e'); + return null; + } + } + + /// Refresh Token ๊ฐ€์ ธ์˜ค๊ธฐ + Future getRefreshToken() async { + try { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString(_refreshTokenKey); + } catch (e) { + developer.log('Failed to get refresh token: $e'); + return null; + } + } + + /// ๋กœ๊ทธ์ธ ์ƒํƒœ ํ™•์ธ + Future isLoggedIn() async { + final token = await getAccessToken(); + return token != null && token.isNotEmpty; + } + + /// JWT payload ๋””์ฝ”๋”ฉ + Map? _decodeJwtPayload(String token) { + try { + // JWT๋Š” header.payload.signature ํ˜•์‹ + final parts = token.split('.'); + if (parts.length != 3) { + developer.log('Invalid JWT token format'); + return null; + } + + // payload ๋ถ€๋ถ„ ๋””์ฝ”๋”ฉ + final payload = parts[1]; + + // Base64 URL ๋””์ฝ”๋”ฉ (ํŒจ๋”ฉ ์ถ”๊ฐ€) + String normalizedPayload = payload + .replaceAll('-', '+') + .replaceAll('_', '/'); + switch (normalizedPayload.length % 4) { + case 1: + normalizedPayload += '==='; + break; + case 2: + normalizedPayload += '=='; + break; + case 3: + normalizedPayload += '='; + break; + } + + final decodedBytes = base64Url.decode(normalizedPayload); + final decodedString = utf8.decode(decodedBytes); + return json.decode(decodedString) as Map; + } catch (e) { + developer.log('Error decoding JWT payload: $e'); + return null; + } + } + + /// JWT ํ† ํฐ ๋งŒ๋ฃŒ ํ™•์ธ + bool isTokenExpired(String token) { + try { + final payload = _decodeJwtPayload(token); + if (payload == null) return true; + + // exp (expiration) ํ•„๋“œ ํ™•์ธ + final exp = payload['exp'] as int?; + if (exp == null) { + developer.log('Token has no expiration field'); + return true; // exp๊ฐ€ ์—†์œผ๋ฉด ๋งŒ๋ฃŒ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ + } + + final expirationTime = DateTime.fromMillisecondsSinceEpoch(exp * 1000); + final isExpired = DateTime.now().isAfter(expirationTime); + + if (isExpired) { + developer.log('Token expired at: ${expirationTime.toIso8601String()}'); + } + + return isExpired; + } catch (e) { + developer.log('Error checking token expiration: $e'); + return true; // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ๋งŒ๋ฃŒ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ + } + } + + /// JWT ํ† ํฐ์ด ๊ณง ๋งŒ๋ฃŒ๋  ์˜ˆ์ •์ธ์ง€ ํ™•์ธ (์‚ฌ์ „ ๊ฐฑ์‹ ์šฉ) + /// [threshold]: ๋งŒ๋ฃŒ๋˜๊ธฐ ์ „ ์–ผ๋งˆ๋‚˜ ๋‚จ์•˜์„ ๋•Œ ๊ฐฑ์‹ ํ• ์ง€ (๊ธฐ๋ณธ๊ฐ’: 5๋ถ„) + bool isTokenExpiringSoon( + String token, { + Duration threshold = const Duration(minutes: 5), + }) { + try { + final payload = _decodeJwtPayload(token); + if (payload == null) return true; + + // exp (expiration) ํ•„๋“œ ํ™•์ธ + final exp = payload['exp'] as int?; + if (exp == null) { + developer.log('Token has no expiration field'); + return true; // exp๊ฐ€ ์—†์œผ๋ฉด ๊ณง ๋งŒ๋ฃŒ๋  ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ + } + + final expirationTime = DateTime.fromMillisecondsSinceEpoch(exp * 1000); + final now = DateTime.now(); + final timeUntilExpiry = expirationTime.difference(now); + + // ์ด๋ฏธ ๋งŒ๋ฃŒ๋˜์—ˆ๊ฑฐ๋‚˜, ์ž„๊ณ„๊ฐ’ ์ด๋‚ด๋กœ ๋‚จ์•˜์œผ๋ฉด true + final isExpiringSoon = + timeUntilExpiry.isNegative || timeUntilExpiry <= threshold; + + if (isExpiringSoon && !timeUntilExpiry.isNegative) { + developer.log( + 'Token expiring soon: ${timeUntilExpiry.inMinutes} minutes remaining (threshold: ${threshold.inMinutes} minutes)', + ); + } + + return isExpiringSoon; + } catch (e) { + developer.log('Error checking token expiration soon: $e'); + return true; // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ๊ณง ๋งŒ๋ฃŒ๋  ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ + } + } + + /// JWT ํ† ํฐ์—์„œ user_id ์ถ”์ถœ + String? _extractUserIdFromToken(String token) { + try { + final payloadMap = _decodeJwtPayload(token); + if (payloadMap == null) { + return null; + } + + // user_id ๋˜๋Š” userId ํ•„๋“œ ์ฐพ๊ธฐ + final userId = + payloadMap['user_id'] ?? + payloadMap['userId'] ?? + payloadMap['sub'] ?? + payloadMap['id']; + + if (userId != null) { + developer.log('User ID extracted from token: $userId'); + return userId.toString(); + } else { + developer.log('User ID not found in token payload: $payloadMap'); + return null; + } + } catch (e) { + developer.log('Error extracting user ID from token: $e'); + return null; + } + } + + /// Access Token ์ €์žฅ ๋ฐ user_id ์ถ”์ถœํ•˜์—ฌ ์ €์žฅ + Future saveAccessToken(String token) async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString(_accessTokenKey, token); + developer.log('Access token saved successfully'); + + // JWT์—์„œ user_id ์ถ”์ถœํ•˜์—ฌ ์ €์žฅ + final userId = _extractUserIdFromToken(token); + if (userId != null) { + await prefs.setString(_userIdKey, userId); + developer.log('User ID saved successfully: $userId'); + } else { + developer.log('Warning: Could not extract user ID from token'); + } + } catch (e) { + developer.log('Failed to save access token: $e'); + } + } + + /// User ID ๊ฐ€์ ธ์˜ค๊ธฐ + Future getUserId() async { + try { + final prefs = await SharedPreferences.getInstance(); + final userId = prefs.getString(_userIdKey); + + // SharedPreferences์— ์—†์œผ๋ฉด ํ† ํฐ์—์„œ ์ถ”์ถœ ์‹œ๋„ + if (userId == null) { + final token = await getAccessToken(); + if (token != null) { + final extractedUserId = _extractUserIdFromToken(token); + if (extractedUserId != null) { + await prefs.setString(_userIdKey, extractedUserId); + return extractedUserId; + } + } + } + + return userId; + } catch (e) { + developer.log('Failed to get user ID: $e'); + return null; + } + } + + /// Refresh Token์œผ๋กœ Access Token ๊ฐฑ์‹  + Future refreshAccessToken() async { + try { + final refreshToken = await getRefreshToken(); + if (refreshToken == null || refreshToken.isEmpty) { + developer.log('โŒ No refresh token found'); + return false; + } + + developer.log('๐Ÿ”„ Refreshing access token...'); + + // Refresh Token์œผ๋กœ ์ƒˆ Access Token ์š”์ฒญ + final response = await http + .post( + ApiConfig.getRefreshTokenUri(), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $refreshToken', + }, + ) + .timeout(const Duration(seconds: 10)); + + if (response.statusCode == 200) { + try { + final responseData = json.decode(response.body); + + // ์ƒˆ Access Token ์ €์žฅ + if (responseData['accessToken'] != null) { + final newAccessToken = responseData['accessToken'] as String; + await saveAccessToken(newAccessToken); + + // ์ƒˆ Refresh Token์ด ์žˆ์œผ๋ฉด ํ•จ๊ป˜ ์ €์žฅ + if (responseData['refreshToken'] != null) { + await saveRefreshToken(responseData['refreshToken'] as String); + } + + developer.log('โœ… Access token refreshed successfully'); + return true; + } else { + developer.log('โŒ Refresh response missing accessToken'); + return false; + } + } catch (e) { + developer.log('โŒ Error parsing refresh response: $e'); + return false; + } + } else if (response.statusCode == 401 || response.statusCode == 403) { + // Refresh Token๋„ ๋งŒ๋ฃŒ๋œ ๊ฒฝ์šฐ + developer.log( + 'โŒ Refresh token expired (${response.statusCode}) - ๋กœ๊ทธ์ธ ํ•„์š”', + ); + await clearTokens(); + return false; + } else { + developer.log('โŒ Failed to refresh token: ${response.statusCode}'); + developer.log(' Response: ${response.body}'); + return false; + } + } catch (e) { + developer.log('โŒ Error refreshing access token: $e'); + return false; + } + } + + /// Access Token์ด ์œ ํšจํ•œ์ง€ ํ™•์ธํ•˜๊ณ  ํ•„์š”์‹œ ๊ฐฑ์‹  (์‚ฌ์ „ ๊ฐฑ์‹  ๋ฐฉ์‹) + /// ๋งŒ๋ฃŒ๋˜๊ธฐ 5๋ถ„ ์ „์— ์ž๋™์œผ๋กœ ๊ฐฑ์‹  ์‹œ๋„ + /// ๋ฐ˜ํ™˜๊ฐ’: ์œ ํšจํ•œ Access Token (๊ฐฑ์‹  ์„ฑ๊ณต ๋˜๋Š” ์ด๋ฏธ ์œ ํšจํ•œ ๊ฒฝ์šฐ), null (๊ฐฑ์‹  ์‹คํŒจ) + Future ensureValidAccessToken() async { + var token = await getAccessToken(); + if (token == null) { + developer.log('โŒ No access token found'); + return null; + } + + // ํ† ํฐ์ด ๊ณง ๋งŒ๋ฃŒ๋  ์˜ˆ์ •์ด๋ฉด (๋งŒ๋ฃŒ 5๋ถ„ ์ „) ์‚ฌ์ „ ๊ฐฑ์‹  ์‹œ๋„ + if (isTokenExpiringSoon(token)) { + developer.log('โš ๏ธ Access token expiring soon, refreshing proactively...'); + final refreshed = await refreshAccessToken(); + + if (refreshed) { + return await getAccessToken(); + } else { + // ์‚ฌ์ „ ๊ฐฑ์‹  ์‹คํŒจ ์‹œ, ์ด๋ฏธ ๋งŒ๋ฃŒ๋œ ๊ฒฝ์šฐ์ธ์ง€ ํ™•์ธ + final newToken = await getAccessToken(); + if (newToken != null && !isTokenExpired(newToken)) { + // ๊ฐฑ์‹ ์€ ์‹คํŒจํ–ˆ์ง€๋งŒ ํ† ํฐ์ด ์•„์ง ์œ ํšจํ•œ ๊ฒฝ์šฐ + return newToken; + } + return null; + } + } + + // ํ† ํฐ์ด ์•„์ง ์œ ํšจํ•˜๋ฉด ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ + return token; + } + + /// ์ž๋™ ๋กœ๊ทธ์ธ ์„ค์ • ์ €์žฅ + Future setAutoLogin(bool enabled) async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool(_autoLoginKey, enabled); + developer.log('Auto login setting saved: $enabled'); + } catch (e) { + developer.log('Failed to save auto login setting: $e'); + } + } + + /// ์ž๋™ ๋กœ๊ทธ์ธ ์„ค์ • ์กฐํšŒ + Future isAutoLoginEnabled() async { + try { + final prefs = await SharedPreferences.getInstance(); + return prefs.getBool(_autoLoginKey) ?? false; + } catch (e) { + developer.log('Failed to get auto login setting: $e'); + return false; + } + } + + /// ์•„์ด๋”” ์ €์žฅ ์„ค์ • ์ €์žฅ + Future setSaveAccountId(bool enabled) async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool(_saveAccountIdKey, enabled); + developer.log('Save account ID setting saved: $enabled'); + } catch (e) { + developer.log('Failed to save account ID setting: $e'); + } + } + + /// ์•„์ด๋”” ์ €์žฅ ์„ค์ • ์กฐํšŒ + Future isSaveAccountIdEnabled() async { + try { + final prefs = await SharedPreferences.getInstance(); + return prefs.getBool(_saveAccountIdKey) ?? false; + } catch (e) { + developer.log('Failed to get save account ID setting: $e'); + return false; + } + } + + /// ์ €์žฅ๋œ ์•„์ด๋”” ์กฐํšŒ + Future getSavedAccountId() async { + try { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString(_savedAccountIdKey); + } catch (e) { + developer.log('Failed to get saved account ID: $e'); + return null; + } + } + + /// ์•„์ด๋”” ์ €์žฅ + Future saveAccountId(String accountId) async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString(_savedAccountIdKey, accountId); + developer.log('Account ID saved: $accountId'); + } catch (e) { + developer.log('Failed to save account ID: $e'); + } + } + + /// ์ €์žฅ๋œ ์•„์ด๋”” ์‚ญ์ œ + Future clearSavedAccountId() async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(_savedAccountIdKey); + developer.log('Saved account ID cleared'); + } catch (e) { + developer.log('Failed to clear saved account ID: $e'); + } + } + + /// ํ† ํฐ ์‚ญ์ œ (๋กœ๊ทธ์•„์›ƒ ์‹œ) + /// [clearAutoLogin]: ์ž๋™ ๋กœ๊ทธ์ธ ์„ค์ •๋„ ํ•จ๊ป˜ ์‚ญ์ œํ• ์ง€ ์—ฌ๋ถ€ (๊ธฐ๋ณธ๊ฐ’: true) + Future clearTokens({bool clearAutoLogin = true}) async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(_accessTokenKey); + await prefs.remove(_refreshTokenKey); + await prefs.remove(_userIdKey); + + if (clearAutoLogin) { + await prefs.remove(_autoLoginKey); + } + + developer.log('Tokens cleared successfully'); + } catch (e) { + developer.log('Failed to clear tokens: $e'); + } + } + + Future signOutFromServer() async { + try { + final token = await getAccessToken(); + if (token == null) { + developer.log('โš ๏ธ signOut skipped: no access token'); + return; + } + + final response = await http.post( + ApiConfig.getSignOutUri(), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + developer.log( + '[AuthService] sign-out response: ${response.statusCode} ${response.body}', + ); + } catch (e) { + developer.log('โš ๏ธ signOutFromServer failed: $e'); + } + } +} diff --git a/frontend/lib/services/continuous_learning_api.dart b/frontend/lib/services/continuous_learning_api.dart new file mode 100644 index 0000000..8f6aa4e --- /dev/null +++ b/frontend/lib/services/continuous_learning_api.dart @@ -0,0 +1,139 @@ +import 'dart:convert'; +import 'dart:developer' as developer; +import 'package:http/http.dart' as http; +import '../config/api_config.dart'; +import '../utils/app_logger.dart'; +import 'auth_service.dart'; + +/// Grading History Summary API ์‘๋‹ต DTO +class GradingHistorySummaryResponse { + final double totalScore; + final int daysSinceStartOfYear; + + GradingHistorySummaryResponse({ + required this.totalScore, + required this.daysSinceStartOfYear, + }); + + factory GradingHistorySummaryResponse.fromJson(Map json) { + return GradingHistorySummaryResponse( + totalScore: (json['total_score'] as num?)?.toDouble() ?? 0.0, + daysSinceStartOfYear: json['days_since_start_of_year'] as int? ?? 0, + ); + } +} + +/// Continuous Learning API ํ˜ธ์ถœ ์ „์šฉ ๋ ˆ์ด์–ด +class ContinuousLearningApi { + ContinuousLearningApi({ + required AuthService authService, + required http.Client httpClient, + }) : _authService = authService, + _httpClient = httpClient; + + final AuthService _authService; + final http.Client _httpClient; + + /// Grading History Summary ์กฐํšŒ + /// + /// [academyUserId]: ์กฐํšŒํ•  academyUserId + /// + /// ๋ฐ˜ํ™˜๊ฐ’: GradingHistorySummaryResponse + Future fetchGradingHistorySummary( + int academyUserId, + ) async { + appLog( + '[continuous_learning:continuous_learning_api] API ํ˜ธ์ถœ ์‹œ์ž‘ - academyUserId: $academyUserId', + ); + + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + appLog('[continuous_learning:continuous_learning_api] ์ธ์ฆ ํ† ํฐ ์—†์Œ'); + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/grading-histories/summary?academyUserId=$academyUserId', + ); + + appLog('[continuous_learning:continuous_learning_api] GET ์š”์ฒญ: $uri'); + developer.log('๐Ÿ“Š [ContinuousLearningApi] GET $uri'); + + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + appLog( + '[continuous_learning:continuous_learning_api] ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: ${response.statusCode}', + ); + appLog( + '[continuous_learning:continuous_learning_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}', + ); + developer.log('๐Ÿ“Š [ContinuousLearningApi] Response status: ${response.statusCode}'); + + if (response.statusCode == 401) { + appLog('[continuous_learning:continuous_learning_api] ์ธ์ฆ ์‹คํŒจ (401)'); + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + appLog( + '[continuous_learning:continuous_learning_api] API ํ˜ธ์ถœ ์‹คํŒจ - status: ${response.statusCode}', + ); + throw Exception( + 'Grading History Summary API ํ˜ธ์ถœ ์‹คํŒจ (status: ${response.statusCode})', + ); + } + + try { + final Map data = json.decode(response.body); + final result = GradingHistorySummaryResponse.fromJson(data); + appLog( + '[continuous_learning:continuous_learning_api] ์‘๋‹ต ํŒŒ์‹ฑ ์„ฑ๊ณต - totalScore: ${result.totalScore}, daysSinceStartOfYear: ${result.daysSinceStartOfYear}', + ); + return result; + } catch (e) { + appLog( + '[continuous_learning:continuous_learning_api] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e', + ); + appLog( + '[continuous_learning:continuous_learning_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}', + ); + developer.log('โŒ [ContinuousLearningApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + developer.log('โŒ [ContinuousLearningApi] Response body: ${response.body}'); + rethrow; + } + } + + /// ์—ฌ๋Ÿฌ academyUserId์— ๋Œ€ํ•œ Grading History Summary ์กฐํšŒ (๋ณ‘๋ ฌ) + /// + /// [academyUserIds]: ์กฐํšŒํ•  academyUserId ๋ฆฌ์ŠคํŠธ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ๊ฐ academyUserId๋ณ„ GradingHistorySummaryResponse ๋งต + Future> + fetchGradingHistorySummaries( + List academyUserIds, + ) async { + appLog( + '[continuous_learning:continuous_learning_api] ์—ฌ๋Ÿฌ academyUserId ์กฐํšŒ ์‹œ์ž‘ - academyUserIds: $academyUserIds', + ); + + // ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ + final results = await Future.wait( + academyUserIds.map((id) => fetchGradingHistorySummary(id)), + ); + + final resultMap = Map.fromIterables(academyUserIds, results); + appLog( + '[continuous_learning:continuous_learning_api] ์—ฌ๋Ÿฌ academyUserId ์กฐํšŒ ์™„๋ฃŒ - ๊ฒฐ๊ณผ ๊ฐœ์ˆ˜: ${resultMap.length}', + ); + + return resultMap; + } +} + diff --git a/frontend/lib/services/daily_learning_service.dart b/frontend/lib/services/daily_learning_service.dart new file mode 100644 index 0000000..644668f --- /dev/null +++ b/frontend/lib/services/daily_learning_service.dart @@ -0,0 +1,145 @@ +import 'workbook_api.dart'; +import 'academy_service.dart'; +import 'auth_service.dart'; +import '../utils/kst_date_factory.dart'; +import '../utils/app_logger.dart'; +import 'dart:developer' as developer; + +/// ์ผ์ผ ํ•™์Šต ๋ฐ์ดํ„ฐ ์กฐํšŒ ๊ฒฐ๊ณผ +class DailyLearningResult { + final List data; + final bool hasError; + final String? errorMessage; + + DailyLearningResult({ + required this.data, + this.hasError = false, + this.errorMessage, + }); + + /// ์„ฑ๊ณต ๊ฒฐ๊ณผ + factory DailyLearningResult.success(List data) { + return DailyLearningResult(data: data); + } + + /// ์—๋Ÿฌ ๊ฒฐ๊ณผ + factory DailyLearningResult.error(String message) { + return DailyLearningResult( + data: [], + hasError: true, + errorMessage: message, + ); + } + + /// ๋นˆ ๊ฒฐ๊ณผ (ํ•™์Šต ๊ธฐ๋ก ์—†์Œ) + factory DailyLearningResult.empty() { + return DailyLearningResult(data: []); + } + + /// ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ + bool get hasData => data.isNotEmpty && + data.any((response) => response.books.any((b) => b.bookId != null)); +} + +/// ์ผ์ผ ํ•™์Šต ๋ฐ์ดํ„ฐ ์กฐํšŒ ์„œ๋น„์Šค +/// +/// HomePage์™€ ContinuousLearningDetailPage์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง์„ ๋ถ„๋ฆฌ +class DailyLearningService { + DailyLearningService({ + required WorkbookApi workbookApi, + required AcademyService academyService, + required AuthService authService, + }) : _workbookApi = workbookApi, + _academyService = academyService, + _authService = authService; + + final WorkbookApi _workbookApi; + final AcademyService _academyService; + final AuthService _authService; + + /// ํŠน์ • ๋‚ ์งœ์˜ ํ•™์Šต ๋ฐ์ดํ„ฐ ์กฐํšŒ + /// + /// [date]: ์กฐํšŒํ•  ๋‚ ์งœ (์–ด๋–ค ํƒ€์ž„์กด์ด๋“  ์ƒ๊ด€์—†์Œ, KST๋กœ ๋ณ€ํ™˜๋จ) + /// + /// ๋ฐ˜ํ™˜๊ฐ’: DailyLearningResult (์„ฑ๊ณต/์—๋Ÿฌ/๋นˆ ์ƒํƒœ ๊ตฌ๋ถ„) + /// + /// ์ฃผ์˜: date๋Š” KST๋กœ ๋ณ€ํ™˜๋˜์–ด WorkbookApi์— ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. + /// WorkbookApi ๋‚ด๋ถ€์—์„œ๋Š” ์ถ”๊ฐ€ ๋ณ€ํ™˜์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + Future getDailyLearningData(DateTime date) async { + try { + // 1. ์‚ฌ์šฉ์ž ID ํ™•์ธ + final userId = await _authService.getUserId(); + if (userId == null) { + return DailyLearningResult.error('์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + // 2. ํ•™์› ๋ชฉ๋ก ์กฐํšŒ + final academies = await _academyService.getUserAcademies(userId); + final academyUserIds = academies + .where((a) => a.registerStatus == 'Y') + .map((a) => a.academy_user_id) + .whereType() + .toList(); + + if (academyUserIds.isEmpty) { + return DailyLearningResult.empty(); + } + + // 3. KST ๋‚ ์งœ๋กœ ๋ณ€ํ™˜ (ํ•œ ๋ฒˆ๋งŒ ์ˆ˜ํ–‰) + final kstDate = KstDateFactory.toKstDate(date); + + // 4. API ํ˜ธ์ถœ (kstDate๋Š” ์ด๋ฏธ KST๋กœ ๋ณ€ํ™˜๋œ ์ƒํƒœ) + final data = await _workbookApi.fetchWorkbooksByDateRange( + academyUserIds: academyUserIds, + startDate: kstDate, // ์ด๋ฏธ KST๋กœ ๋ณ€ํ™˜๋จ + endDate: kstDate, // ์ด๋ฏธ KST๋กœ ๋ณ€ํ™˜๋จ + ); + + // 5. ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ + return DailyLearningResult.success(data); + } on Exception catch (e) { + appLog('[daily_learning:daily_learning_service] ์กฐํšŒ ์‹คํŒจ: $e'); + developer.log('โŒ [DailyLearningService] ์กฐํšŒ ์‹คํŒจ: $e'); + return DailyLearningResult.error('ํ•™์Šต ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } catch (e) { + appLog('[daily_learning:daily_learning_service] ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜: $e'); + developer.log('โŒ [DailyLearningService] ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜: $e'); + return DailyLearningResult.error('์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + } + + /// ์˜ค๋Š˜์˜ ํ•™์Šต ๋ฐ์ดํ„ฐ ์กฐํšŒ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: DailyLearningResult (์„ฑ๊ณต/์—๋Ÿฌ/๋นˆ ์ƒํƒœ ๊ตฌ๋ถ„) + Future getTodayLearningData() async { + final todayKst = KstDateFactory.getTodayKst(); + return getDailyLearningData(todayKst); + } + + /// ํ•™์Šต ๋ฐ์ดํ„ฐ์—์„œ ๋ชจ๋“  ์ฑ… ๋ชฉ๋ก ์ถ”์ถœ + /// + /// [result]: DailyLearningResult + /// ๋ฐ˜ํ™˜๊ฐ’: BookData ๋ฆฌ์ŠคํŠธ (bookId๊ฐ€ null์ด ์•„๋‹Œ ๊ฒƒ๋งŒ) + static List extractBooks(DailyLearningResult result) { + if (!result.hasData) return []; + + final allBooks = []; + for (var response in result.data) { + allBooks.addAll(response.books.where((b) => b.bookId != null)); + } + return allBooks; + } + + /// ๊ฐ€์žฅ ๋งŽ์ด ํ•™์Šตํ•œ ์ฑ… ์„ ํƒ + /// + /// [books]: BookData ๋ฆฌ์ŠคํŠธ + /// ๋ฐ˜ํ™˜๊ฐ’: ๊ฐ€์žฅ ๋งŽ์ด ํ•™์Šตํ•œ ์ฑ… (totalSolvedPages ๊ธฐ์ค€), ์—†์œผ๋ฉด null + static BookData? selectMostLearnedBook(List books) { + if (books.isEmpty) return null; + + // totalSolvedPages๊ฐ€ ๊ฐ€์žฅ ๋งŽ์€ ์ฑ… ์„ ํƒ + books.sort((a, b) => b.totalSolvedPages.compareTo(a.totalSolvedPages)); + return books.first; + } +} + diff --git a/frontend/lib/services/explanation_api.dart b/frontend/lib/services/explanation_api.dart new file mode 100644 index 0000000..2df8560 --- /dev/null +++ b/frontend/lib/services/explanation_api.dart @@ -0,0 +1,215 @@ +import 'dart:convert'; + +import 'package:http/http.dart' as http; + +import '../config/api_config.dart'; +import '../utils/app_logger.dart'; + +/// ํ•ด์„ค ์ƒ์„ฑ/์กฐํšŒ์šฉ API ๋ž˜ํผ +class ExplanationApi { + final Future Function() _tokenProvider; + final http.Client _httpClient; + + ExplanationApi({ + required Future Function() tokenProvider, + required http.Client httpClient, + }) : _tokenProvider = tokenProvider, + _httpClient = httpClient; + + /// ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ + /// + /// POST /grading/student-answers/explanation + /// Body: + /// { + /// "student_response_id": ..., + /// "user_id": ..., + /// "academy_user_id": ..., + /// "academy_id": ..., + /// "page_number": ..., + /// "question_number": ..., + /// "answer": ... + /// } + Future> postExplanation({ + required int studentResponseId, + required int userId, + required int academyUserId, + required int academyId, + required int pageNumber, + required int questionNumber, + required String answer, + }) async { + final token = await _tokenProvider(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/student-answers/explanation', + ); + + final body = { + 'student_response_id': studentResponseId, + 'user_id': userId, + 'academy_user_id': academyUserId, + 'academy_id': academyId, + 'page_number': pageNumber, + 'question_number': questionNumber, + 'answer': answer, + }; + + appLog('[explanation] POST INPUT: $uri'); + appLog('[explanation] POST INPUT body: ${json.encode(body)}'); + + final response = await _httpClient + .post( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: json.encode(body), + ) + .timeout(const Duration(seconds: 15)); + + appLog('[explanation] POST OUTPUT status: ${response.statusCode}'); + + if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + appLog('[explanation] POST OUTPUT error body: ${response.body}'); + throw Exception('ํ•ด์„ค ์ƒ์„ฑ ์š”์ฒญ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. (status: ${response.statusCode})'); + } + + final decoded = json.decode(response.body) as Map; + appLog('[explanation] POST OUTPUT body: ${json.encode(decoded)}'); + return decoded; + } + + /// ํ•™์ƒ ๋‹ต์•ˆ ์ •๋ณด ์กฐํšŒ + /// + /// GET /grading/student-answers/find + /// ?studentResponseId={id} + /// &questionNumber={n} + /// &subQuestionNumber={n} + Future> findStudentAnswer({ + required int studentResponseId, + required int questionNumber, + required int subQuestionNumber, + }) async { + final token = await _tokenProvider(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/student-answers/find' + '?studentResponseId=$studentResponseId' + '&questionNumber=$questionNumber' + '&subQuestionNumber=$subQuestionNumber', + ); + + appLog('[explanation] GET (์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ) INPUT: $uri'); + appLog( + '[explanation] GET (์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ) INPUT params: studentResponseId=$studentResponseId, questionNumber=$questionNumber, subQuestionNumber=$subQuestionNumber', + ); + + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + appLog('[explanation] GET (์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ) OUTPUT status: ${response.statusCode}'); + + if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + appLog('[explanation] GET (์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ) OUTPUT error body: ${response.body}'); + throw Exception('ํ•™์ƒ ๋‹ต์•ˆ ์กฐํšŒ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. (status: ${response.statusCode})'); + } + + final decoded = json.decode(response.body) as Map; + appLog('[explanation] GET (์ •๋‹ต ๊ฐ€์ ธ์˜ค๊ธฐ) OUTPUT body: ${json.encode(decoded)}'); + return decoded; + } + + /// ํ•ด์„ค ์กฐํšŒ (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) + /// + /// GET /grading/student-answers/get-explanation + /// ?studentResponseId={id} + /// &academyUserId={id} + /// &questionNumber={n} + /// &subquestionNumber={n} + /// + /// 404์™€ 400 ์‘๋‹ต์€ ๋™์ผํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜์—ฌ null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + /// (ํ•ด์„ค์ด ์•„์ง ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ Redis์— ์—†์Œ์„ ์˜๋ฏธ) + Future?> getExplanation({ + required int studentResponseId, + required int academyUserId, + required int questionNumber, + required int subQuestionNumber, + }) async { + final token = await _tokenProvider(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/student-answers/get-explanation' + '?studentResponseId=$studentResponseId' + '&academyUserId=$academyUserId' + '&questionNumber=$questionNumber' + '&subQuestionNumber=$subQuestionNumber', + ); + + appLog('[explanation] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) INPUT: $uri'); + appLog( + '[explanation] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) INPUT params: studentResponseId=$studentResponseId, academyUserId=$academyUserId, questionNumber=$questionNumber, subQuestionNumber=$subQuestionNumber', + ); + + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + appLog( + '[explanation] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) OUTPUT status: ${response.statusCode}', + ); + + // 404์™€ 400์„ ๋™์ผํ•˜๊ฒŒ ์ฒ˜๋ฆฌ: ํ•ด์„ค์ด ์•„์ง ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ Redis์— ์—†์Œ + if (response.statusCode == 404 || response.statusCode == 400) { + appLog( + '[explanation] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) OUTPUT: ํ•ด์„ค์ด ์•„์ง ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ Redis์— ์—†์Œ (404/400)', + ); + appLog('[explanation] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) OUTPUT body: null'); + return null; + } + if (response.statusCode == 401) { + appLog('[explanation] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) OUTPUT error: ์ธ์ฆ ์‹คํŒจ'); + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + appLog( + '[explanation] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) OUTPUT error body: ${response.body}', + ); + throw Exception('ํ•ด์„ค ์กฐํšŒ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. (status: ${response.statusCode})'); + } + + final decoded = json.decode(response.body) as Map; + appLog( + '[explanation] GET (Redis์—์„œ LLM ํ•ด์„ค ๊ฐ€์ ธ์˜ค๊ธฐ) OUTPUT body: ${json.encode(decoded)}', + ); + return decoded; + } +} diff --git a/frontend/lib/services/explanation_repository_impl.dart b/frontend/lib/services/explanation_repository_impl.dart new file mode 100644 index 0000000..c4fe876 --- /dev/null +++ b/frontend/lib/services/explanation_repository_impl.dart @@ -0,0 +1,77 @@ +import '../domain/explanation/explanation_entity.dart'; +import '../domain/explanation/explanation_repository.dart'; +import '../domain/explanation/explanation_source.dart'; +import '../data/explanation/explanation_mapper.dart'; +import 'explanation_api.dart'; + +/// Explanation ๋„๋ฉ”์ธ Repository ๊ตฌํ˜„์ฒด +class ExplanationRepositoryImpl implements ExplanationRepository { + final ExplanationApi _api; + final ExplanationMapper _mapper; + + ExplanationRepositoryImpl({ + required ExplanationApi api, + required ExplanationMapper mapper, + }) : _api = api, + _mapper = mapper; + + @override + Future findStudentAnswer(ExplanationSource source) async { + final json = await _api.findStudentAnswer( + studentResponseId: source.studentResponseId, + questionNumber: source.question.questionNumber, + subQuestionNumber: source.question.subQuestionNumber, + ); + + return StudentAnswerInfo( + studentAnswerId: json['studentAnswerId'] as int, + studentResponseId: json['studentResponseId'] as int, + chapterId: json['chapterId'] as int, + page: json['page'] as int, + questionNumber: json['questionNumber'] as int, + subQuestionNumber: json['subQuestionNumber'] as int, + answer: json['answer'] as String, + sectionUrl: json['section_url'] as String?, + score: (json['score'] as num).toDouble(), + correct: json['correct'] as bool, + ); + } + + @override + Future getExplanation(ExplanationSource source) async { + final json = await _api.getExplanation( + studentResponseId: source.studentResponseId, + academyUserId: source.academyUserId, + questionNumber: source.question.questionNumber, + subQuestionNumber: source.question.subQuestionNumber, + ); + + if (json == null) { + return null; + } + + return _mapper.fromGetResponse(json); + } + + @override + Future requestExplanation( + ExplanationSource source, { + required int requestedByUserId, + required int academyId, + required String answer, + }) async { + final json = await _api.postExplanation( + studentResponseId: source.studentResponseId, + userId: requestedByUserId, + academyUserId: source.academyUserId, + academyId: academyId, + pageNumber: source.question.page, + questionNumber: source.question.questionNumber, + answer: answer, + ); + + return _mapper.fromPostResponse(json); + } +} + + diff --git a/frontend/lib/services/fcm_service.dart b/frontend/lib/services/fcm_service.dart new file mode 100644 index 0000000..643659c --- /dev/null +++ b/frontend/lib/services/fcm_service.dart @@ -0,0 +1,410 @@ +import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'dart:developer' as developer; +import 'package:flutter/foundation.dart'; +import 'dart:io'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'package:shared_preferences/shared_preferences.dart'; +import '../domain/notification/notification_entity.dart'; +import '../domain/notification/notification_repository.dart'; +import '../domain/notification/notification_type.dart'; +import '../data/notification/notification_local_data_source.dart'; +import '../data/notification/notification_repository_impl.dart'; +import '../utils/app_logger.dart'; + +/// FCM ๋ฐ ๋กœ์ปฌ ์•Œ๋ฆผ์„ ๊ด€๋ฆฌํ•˜๋Š” ์„œ๋น„์Šค +/// +/// - DI Container์—์„œ singleton์œผ๋กœ ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค. +/// - ํฌ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ ์ €์žฅ ์‹œ DI๋กœ ์ฃผ์ž…๋œ NotificationRepository๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. +/// - ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ ์ €์žฅ์€ Firebase ์ œ์•ฝ์ƒ ์—ฌ์ „ํžˆ ๋…๋ฆฝ์ ์ธ ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. +class FCMService { + final FirebaseMessaging _firebaseMessaging; + final FlutterLocalNotificationsPlugin _localNotifications; + final NotificationRepository _notificationRepository; + + FCMService({ + FirebaseMessaging? firebaseMessaging, + FlutterLocalNotificationsPlugin? localNotifications, + required NotificationRepository notificationRepository, + }) : _firebaseMessaging = firebaseMessaging ?? FirebaseMessaging.instance, + _localNotifications = + localNotifications ?? FlutterLocalNotificationsPlugin(), + _notificationRepository = notificationRepository; + + String? _fcmToken; + String? get fcmToken => _fcmToken; + + /// FCM ์ดˆ๊ธฐํ™” + Future initialize() async { + // ์•Œ๋ฆผ ๊ถŒํ•œ ์š”์ฒญ + NotificationSettings settings = await _firebaseMessaging.requestPermission( + alert: true, + badge: true, + sound: true, + provisional: false, + ); + + if (settings.authorizationStatus == AuthorizationStatus.authorized) { + developer.log('์‚ฌ์šฉ์ž๊ฐ€ ์•Œ๋ฆผ ๊ถŒํ•œ์„ ํ—ˆ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค'); + } else { + developer.log('์‚ฌ์šฉ์ž๊ฐ€ ์•Œ๋ฆผ ๊ถŒํ•œ์„ ๊ฑฐ๋ถ€ํ–ˆ์Šต๋‹ˆ๋‹ค'); + return; + } + + // iOS์—์„œ APNS ํ† ํฐ ์š”์ฒญ (FCM ํ† ํฐ์„ ๋ฐ›๊ธฐ ์ „์— ํ•„์š”) + if (Platform.isIOS) { + try { + developer.log('๐ŸŽ iOS: APNS ํ† ํฐ ์š”์ฒญ ์ค‘...'); + String? apnsToken = await _firebaseMessaging.getAPNSToken(); + if (apnsToken != null) { + developer.log('โœ… APNS ํ† ํฐ ์ˆ˜์‹  ์„ฑ๊ณต'); + debugPrint('โœ… APNS Token: $apnsToken'); + } else { + developer.log('โš ๏ธ APNS ํ† ํฐ์ด ์•„์ง ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค (์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์ผ ์ˆ˜ ์žˆ์Œ)'); + debugPrint('โš ๏ธ APNS ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ์‹ค์ œ ๊ธฐ๊ธฐ์—์„œ ํ…Œ์ŠคํŠธํ•˜๊ฑฐ๋‚˜ ๋‚˜์ค‘์— ๋‹ค์‹œ ์‹œ๋„ํ•˜์„ธ์š”.'); + // ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ๋Š” APNS ํ† ํฐ์„ ์–ป์„ ์ˆ˜ ์—†์ง€๋งŒ ๊ณ„์† ์ง„ํ–‰ + } + } catch (e) { + developer.log('โš ๏ธ APNS ํ† ํฐ ์š”์ฒญ ์ค‘ ์˜ค๋ฅ˜ (์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์ผ ์ˆ˜ ์žˆ์Œ): $e'); + debugPrint('โš ๏ธ APNS ํ† ํฐ ์˜ค๋ฅ˜ (์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ๋Š” ์ •์ƒ): $e'); + // ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ๋Š” APNS ํ† ํฐ์„ ์–ป์„ ์ˆ˜ ์—†์ง€๋งŒ ๊ณ„์† ์ง„ํ–‰ + } + } + + // FCM ํ† ํฐ ๊ฐ€์ ธ์˜ค๊ธฐ + developer.log('๐Ÿ”” FCM ํ† ํฐ ์š”์ฒญ ์‹œ์ž‘...'); + try { + _fcmToken = await _firebaseMessaging.getToken(); + + if (_fcmToken != null) { + developer.log('โœ… FCM ํ† ํฐ ์ƒ์„ฑ ์„ฑ๊ณต!'); + developer.log('๐Ÿ“ฑ FCM Token: $_fcmToken'); + developer.log('๐Ÿ“ ํ† ํฐ ๊ธธ์ด: ${_fcmToken!.length}์ž'); + debugPrint('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); + debugPrint('๐Ÿ”” FCM ํ† ํฐ ์ƒ์„ฑ ์™„๋ฃŒ'); + debugPrint('๐Ÿ“ฑ Token: $_fcmToken'); + debugPrint('๐Ÿ“ ๊ธธ์ด: ${_fcmToken!.length}์ž'); + debugPrint('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); + } else { + developer.log('โŒ FCM ํ† ํฐ ์ƒ์„ฑ ์‹คํŒจ: ํ† ํฐ์ด null์ž…๋‹ˆ๋‹ค'); + debugPrint('โŒ FCM ํ† ํฐ ์ƒ์„ฑ ์‹คํŒจ!'); + } + } catch (e) { + developer.log('โš ๏ธ FCM ํ† ํฐ ์š”์ฒญ ์‹คํŒจ: $e'); + debugPrint('โš ๏ธ FCM ํ† ํฐ ์š”์ฒญ ์‹คํŒจ: $e'); + if (Platform.isIOS) { + developer.log('๐Ÿ’ก iOS ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ๋Š” APNS ํ† ํฐ์ด ์—†์–ด FCM ํ† ํฐ์„ ๋ฐ›์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + developer.log('๐Ÿ’ก ์‹ค์ œ ๊ธฐ๊ธฐ์—์„œ ํ…Œ์ŠคํŠธํ•˜๊ฑฐ๋‚˜, APNS ์ธ์ฆ์„œ๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.'); + debugPrint('๐Ÿ’ก iOS ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์—์„œ๋Š” FCM ํ† ํฐ์„ ๋ฐ›์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + debugPrint('๐Ÿ’ก ์‹ค์ œ ๊ธฐ๊ธฐ์—์„œ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.'); + } + // ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์•ฑ์€ ๊ณ„์† ์‹คํ–‰ + } + + // ํ† ํฐ ๊ฐฑ์‹  ๋ฆฌ์Šค๋„ˆ + _firebaseMessaging.onTokenRefresh.listen((newToken) { + _fcmToken = newToken; + developer.log('๐Ÿ”„ FCM Token ๊ฐฑ์‹ ๋จ'); + developer.log('๐Ÿ“ฑ ์ƒˆ FCM Token: $newToken'); + developer.log('๐Ÿ“ ์ƒˆ ํ† ํฐ ๊ธธ์ด: ${newToken.length}์ž'); + debugPrint('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); + debugPrint('๐Ÿ”„ FCM ํ† ํฐ ๊ฐฑ์‹  ์™„๋ฃŒ'); + debugPrint('๐Ÿ“ฑ New Token: $newToken'); + debugPrint('๐Ÿ“ ๊ธธ์ด: ${newToken.length}์ž'); + debugPrint('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); + // ์„œ๋ฒ„์— ์ƒˆ ํ† ํฐ ์ „์†ก + _sendTokenToServer(newToken); + }); + + // ๋กœ์ปฌ ์•Œ๋ฆผ ์ดˆ๊ธฐํ™” + await _initializeLocalNotifications(); + + // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฉ”์‹œ์ง€ ํ•ธ๋“ค๋Ÿฌ ์„ค์ • + FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); + + // ํฌ๊ทธ๋ผ์šด๋“œ ๋ฉ”์‹œ์ง€ ํ•ธ๋“ค๋Ÿฌ + FirebaseMessaging.onMessage.listen(_handleForegroundMessage); + + // ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์•Œ๋ฆผ ํƒญ ํ•ธ๋“ค๋Ÿฌ + FirebaseMessaging.onMessageOpenedApp.listen(_handleNotificationTap); + + // ์•ฑ์ด ์ข…๋ฃŒ๋œ ์ƒํƒœ์—์„œ ์•Œ๋ฆผ์œผ๋กœ ์•ฑ ์‹คํ–‰๋œ ๊ฒฝ์šฐ + RemoteMessage? initialMessage = await _firebaseMessaging + .getInitialMessage(); + if (initialMessage != null) { + _handleNotificationTap(initialMessage); + } + + // ์„œ๋ฒ„์— ํ† ํฐ ์ „์†ก (์•ฑ ์ตœ์ดˆ ์‹คํ–‰ ์‹œ 1ํšŒ) + await syncTokenWithServer(); + } + + /// ํ˜„์žฌ ๋ณด์œ ํ•œ FCM ํ† ํฐ์„ ์„œ๋ฒ„์™€ ๋™๊ธฐํ™” + /// + /// - ํ† ํฐ์ด ์—†๋Š” ๊ฒฝ์šฐ ํ•œ ๋ฒˆ ๋” getToken์„ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. + /// - ํ† ํฐ์ด ์žˆ์œผ๋ฉด `_sendTokenToServer`๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. + Future syncTokenWithServer() async { + try { + // ํ† ํฐ์ด ์•„์ง ์—†๋Š” ๊ฒฝ์šฐ ํ•œ ๋ฒˆ ๋” ์‹œ๋„ + _fcmToken ??= await _firebaseMessaging.getToken(); + + if (_fcmToken == null) { + developer.log('โš ๏ธ syncTokenWithServer: FCM ํ† ํฐ์ด ์—†์–ด ์„œ๋ฒ„ ์ „์†ก์„ ๊ฑด๋„ˆ๋œ€'); + return; + } + + await _sendTokenToServer(_fcmToken!); + } catch (e) { + developer.log('โš ๏ธ syncTokenWithServer ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: $e'); + } + } + + /// ๋กœ์ปฌ ์•Œ๋ฆผ ์ดˆ๊ธฐํ™” + Future _initializeLocalNotifications() async { + const AndroidInitializationSettings androidSettings = + AndroidInitializationSettings('@mipmap/ic_launcher'); + + const DarwinInitializationSettings iosSettings = + DarwinInitializationSettings( + requestAlertPermission: true, + requestBadgePermission: true, + requestSoundPermission: true, + ); + + const InitializationSettings initSettings = InitializationSettings( + android: androidSettings, + iOS: iosSettings, + ); + + await _localNotifications.initialize( + initSettings, + onDidReceiveNotificationResponse: _onNotificationTapped, + ); + + // Android ์ฑ„๋„ ์ƒ์„ฑ + const AndroidNotificationChannel channel = AndroidNotificationChannel( + 'high_importance_channel', + 'High Importance Notifications', + description: 'This channel is used for important notifications.', + importance: Importance.high, + ); + + await _localNotifications + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin + >() + ?.createNotificationChannel(channel); + } + + /// ํฌ๊ทธ๋ผ์šด๋“œ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ + void _handleForegroundMessage(RemoteMessage message) async { + appLog( + '[notification:fcm_service] ํฌ๊ทธ๋ผ์šด๋“œ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹  - messageId: ${message.messageId}', + ); + appLog('[notification:fcm_service] ๋ฉ”์‹œ์ง€ data: ${json.encode(message.data)}'); + if (message.notification != null) { + appLog( + '[notification:fcm_service] notification.title: ${message.notification!.title}', + ); + appLog( + '[notification:fcm_service] notification.body: ${message.notification!.body}', + ); + } + appLog('[notification:fcm_service] sentTime: ${message.sentTime}'); + appLog( + '[notification:fcm_service] ์ „์ฒด ๋ฉ”์‹œ์ง€ JSON: ${json.encode({ + 'messageId': message.messageId, + 'data': message.data, + 'notification': message.notification != null ? {'title': message.notification!.title, 'body': message.notification!.body} : null, + 'sentTime': message.sentTime?.toIso8601String(), + })}', + ); + + developer.log('ํฌ๊ทธ๋ผ์šด๋“œ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹ : ${message.messageId}'); + + // ์•Œ๋ฆผ ํ‘œ์‹œ + _showLocalNotification(message); + + // ์•Œ๋ฆผ ์ €์žฅ + try { + final entity = NotificationEntity.fromRemoteMessage(message); + + if (entity.type == NotificationType.grading) { + final timestamp = DateTime.now().toIso8601String(); + appLog( + '[notification:fcm_service][timecheck][$timestamp] ์ฑ„์  ์™„๋ฃŒ ์•Œ๋ฆผ ์ˆ˜์‹ (ํฌ๊ทธ๋ผ์šด๋“œ) - id=${entity.id}, title=${entity.title}', + ); + } + + await _notificationRepository.saveNotification(entity); + developer.log('โœ… ํฌ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ ์ €์žฅ ์™„๋ฃŒ: ${entity.id}'); + } catch (e) { + developer.log('โŒ ํฌ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ ์ €์žฅ ์‹คํŒจ: $e'); + } + } + + /// ๋กœ์ปฌ ์•Œ๋ฆผ ํ‘œ์‹œ + Future _showLocalNotification(RemoteMessage message) async { + final notification = message.notification; + + if (notification != null) { + await _localNotifications.show( + notification.hashCode, + notification.title, + notification.body, + const NotificationDetails( + android: AndroidNotificationDetails( + 'high_importance_channel', + 'High Importance Notifications', + channelDescription: + 'This channel is used for important notifications.', + importance: Importance.high, + priority: Priority.high, + icon: '@mipmap/ic_launcher', + ), + iOS: DarwinNotificationDetails(), + ), + payload: message.data.toString(), + ); + } + } + + /// ์•Œ๋ฆผ ํƒญ ์ฒ˜๋ฆฌ + void _handleNotificationTap(RemoteMessage message) { + appLog( + '[notification:fcm_service] ์•Œ๋ฆผ ํƒญ๋จ - messageId: ${message.messageId}', + ); + appLog('[notification:fcm_service] ๋ฉ”์‹œ์ง€ data: ${json.encode(message.data)}'); + if (message.notification != null) { + appLog( + '[notification:fcm_service] notification.title: ${message.notification!.title}', + ); + appLog( + '[notification:fcm_service] notification.body: ${message.notification!.body}', + ); + } + appLog( + '[notification:fcm_service] ์ „์ฒด ๋ฉ”์‹œ์ง€ JSON: ${json.encode({ + 'messageId': message.messageId, + 'data': message.data, + 'notification': message.notification != null ? {'title': message.notification!.title, 'body': message.notification!.body} : null, + 'sentTime': message.sentTime?.toIso8601String(), + })}', + ); + + developer.log('์•Œ๋ฆผ ํƒญ๋จ: ${message.messageId}'); + + // TODO: ์•Œ๋ฆผ ํƒ€์ž…์— ๋”ฐ๋ผ ํŽ˜์ด์ง€ ์ด๋™ + final data = message.data; + if (data.containsKey('type')) { + // ์˜ˆ: Navigator.pushNamed(context, '/notification-detail'); + } + } + + /// ๋กœ์ปฌ ์•Œ๋ฆผ ํƒญ ์ฒ˜๋ฆฌ + void _onNotificationTapped(NotificationResponse response) { + developer.log('๋กœ์ปฌ ์•Œ๋ฆผ ํƒญ๋จ: ${response.payload}'); + // TODO: ์•Œ๋ฆผ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ + } + + /// ์„œ๋ฒ„์— FCM ํ† ํฐ ์ „์†ก + Future _sendTokenToServer(String token) async { + try { + // TODO: ์‹ค์ œ ์„œ๋ฒ„ API ์—”๋“œํฌ์ธํŠธ๋กœ ๋ณ€๊ฒฝ + const String serverUrl = 'https://your-backend-url.com/api/fcm/token'; + + final response = await http.post( + Uri.parse(serverUrl), + headers: {'Content-Type': 'application/json'}, + body: json.encode({ + 'fcm_token': token, + 'device_type': 'mobile', // Android ๋˜๋Š” iOS + 'user_id': 'current_user_id', // TODO: ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž ID + }), + ); + + if (response.statusCode == 200) { + developer.log('FCM ํ† ํฐ์ด ์„œ๋ฒ„์— ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค'); + } else { + developer.log('FCM ํ† ํฐ ์ „์†ก ์‹คํŒจ: ${response.statusCode}'); + } + } catch (e) { + developer.log('FCM ํ† ํฐ ์ „์†ก ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: $e'); + } + } + + /// ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ + Future markAsRead(String notificationId) async { + try { + // TODO: ์‹ค์ œ ์„œ๋ฒ„ API ์—”๋“œํฌ์ธํŠธ๋กœ ๋ณ€๊ฒฝ + final String serverUrl = + 'https://your-backend-url.com/api/notifications/$notificationId/read'; + + final response = await http.put( + Uri.parse(serverUrl), + headers: {'Content-Type': 'application/json'}, + ); + + if (response.statusCode == 200) { + developer.log('์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์™„๋ฃŒ'); + } + } catch (e) { + developer.log('์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: $e'); + } + } +} + +/// NotificationRepository ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜ (๋ฐฑ๊ทธ๋ผ์šด๋“œ์šฉ) +Future +_buildNotificationRepositoryForBackground() async { + final prefs = await SharedPreferences.getInstance(); + final local = NotificationLocalDataSource(prefs); + return NotificationRepositoryImpl(local); +} + +/// ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฉ”์‹œ์ง€ ํ•ธ๋“ค๋Ÿฌ (์ตœ์ƒ์œ„ ํ•จ์ˆ˜์—ฌ์•ผ ํ•จ) +@pragma('vm:entry-point') +Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { + // appLog๋Š” ์ตœ์ƒ์œ„ ํ•จ์ˆ˜์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ + appLog( + '[notification:fcm_service] ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹  - messageId: ${message.messageId}', + ); + appLog('[notification:fcm_service] ๋ฉ”์‹œ์ง€ data: ${json.encode(message.data)}'); + if (message.notification != null) { + appLog( + '[notification:fcm_service] notification.title: ${message.notification!.title}', + ); + appLog( + '[notification:fcm_service] notification.body: ${message.notification!.body}', + ); + } + appLog('[notification:fcm_service] sentTime: ${message.sentTime}'); + appLog( + '[notification:fcm_service] ์ „์ฒด ๋ฉ”์‹œ์ง€ JSON: ${json.encode({ + 'messageId': message.messageId, + 'data': message.data, + 'notification': message.notification != null ? {'title': message.notification!.title, 'body': message.notification!.body} : null, + 'sentTime': message.sentTime?.toIso8601String(), + })}', + ); + + developer.log('๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹ : ${message.messageId}'); + + try { + final repository = await _buildNotificationRepositoryForBackground(); + final entity = NotificationEntity.fromRemoteMessage(message); + + if (entity.type == NotificationType.grading) { + final timestamp = DateTime.now().toIso8601String(); + appLog( + '[notification:fcm_service][timecheck][$timestamp] ์ฑ„์  ์™„๋ฃŒ ์•Œ๋ฆผ ์ˆ˜์‹ (๋ฐฑ๊ทธ๋ผ์šด๋“œ) - id=${entity.id}, title=${entity.title}', + ); + } + + await repository.saveNotification(entity); + developer.log('โœ… ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ ์ €์žฅ ์™„๋ฃŒ: ${entity.id}'); + } catch (e) { + developer.log('โŒ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์•Œ๋ฆผ ์ €์žฅ ์‹คํŒจ: $e'); + } +} diff --git a/frontend/lib/services/get_chapter_question_statuses_use_case.dart b/frontend/lib/services/get_chapter_question_statuses_use_case.dart new file mode 100644 index 0000000..29d36c4 --- /dev/null +++ b/frontend/lib/services/get_chapter_question_statuses_use_case.dart @@ -0,0 +1,68 @@ +import '../domain/chapter/chapter_repository.dart'; +import '../domain/student_answer/student_answer_repository.dart'; +import '../domain/student_answer/student_answer_query.dart'; +import 'models/question_status_model.dart'; +import 'policies/answer_selection_policy.dart'; + +/// ์ฑ•ํ„ฐ์˜ ๋ฌธ์ œ๋ณ„ ํ’€์ด ์ƒํƒœ ์กฐํšŒ UseCase (Application Layer) +/// +/// **์ฑ…์ž„**: +/// - Domain Entity๋“ค์„ ์กฐํ•ฉํ•˜์—ฌ UI์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ +/// - ์ƒํƒœ ๊ณ„์‚ฐ ๋กœ์ง ํฌํ•จ +/// - ์ •์ฑ… ๋กœ์ง์€ ๋ณ„๋„ ๊ฐ์ฒด๋กœ ๋ถ„๋ฆฌ +class GetChapterQuestionStatusesUseCase { + final ChapterRepository _chapterRepository; + final StudentAnswerRepository _studentAnswerRepository; + final AnswerSelectionPolicy _selectionPolicy; + + GetChapterQuestionStatusesUseCase({ + required ChapterRepository chapterRepository, + required StudentAnswerRepository studentAnswerRepository, + AnswerSelectionPolicy? selectionPolicy, + }) : _chapterRepository = chapterRepository, + _studentAnswerRepository = studentAnswerRepository, + _selectionPolicy = selectionPolicy ?? AnswerSelectionPolicy(); + + /// ์ฑ•ํ„ฐ์˜ ๋ฌธ์ œ๋ณ„ ํ’€์ด ์ƒํƒœ ๋ฐ˜ํ™˜ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ๋ฌธ์ œ ๋ฒˆํ˜ธ ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌ๋œ ์ƒํƒœ ๋ฆฌ์ŠคํŠธ + Future> call({ + required int chapterId, + required int academyUserId, + }) async { + // 1. ์ฑ•ํ„ฐ ์ •๋ณด ์กฐํšŒ + final chapter = await _chapterRepository.getChapterById(chapterId); + + // 2. ํ•™์ƒ ๋‹ต์•ˆ ์กฐํšŒ (Query ๊ฐ์ฒด ์‚ฌ์šฉ) + final answers = await _studentAnswerRepository.getStudentAnswers( + StudentAnswerQuery.byChapter( + chapterId: chapterId, + academyUserId: academyUserId, + ), + ); + + // 3. question_number๋ณ„๋กœ Map ์ƒ์„ฑ (์ •์ฑ… ์ ์šฉ) + final answerMap = {}; + for (final answer in answers) { + final existing = answerMap[answer.questionNumber]; + answerMap[answer.questionNumber] = _selectionPolicy.selectAnswer( + existing, + answer.isCorrect, + ); + } + + // 4. ์ „์ฒด ๋ฌธ์ œ ๋ฒˆํ˜ธ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ (1๋ถ€ํ„ฐ totalChapterQuestion๊นŒ์ง€) + final result = []; + for (int questionNumber = 1; + questionNumber <= chapter.totalChapterQuestion; + questionNumber++) { + result.add(QuestionStatusModel( + questionNumber: questionNumber, + isCorrect: answerMap[questionNumber], // null์ผ ์ˆ˜ ์žˆ์Œ + )); + } + + return result; + } +} + diff --git a/frontend/lib/services/get_monthly_learning_status_use_case_impl.dart b/frontend/lib/services/get_monthly_learning_status_use_case_impl.dart new file mode 100644 index 0000000..39b6469 --- /dev/null +++ b/frontend/lib/services/get_monthly_learning_status_use_case_impl.dart @@ -0,0 +1,142 @@ +import '../domain/learning/get_monthly_learning_status_use_case.dart'; +import '../domain/learning/daily_learning_status.dart'; +import '../domain/learning/learning_completion_service.dart'; +import 'assessment_repository.dart'; +import '../domain/grading_history/grading_history_repository.dart'; +import '../domain/grading_history/grading_history_entity.dart'; + +/// GetMonthlyLearningStatusUseCase ๊ตฌํ˜„์ฒด +/// +/// Data Layer์—์„œ Domain Layer ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. +/// +/// ์ฃผ์˜์‚ฌํ•ญ: +/// - ์ด UseCase๋Š” "์›”๋ณ„ ํ•™์Šต ์ƒํƒœ ์กฐํšŒ"์— ์ง‘์ค‘ํ•ฉ๋‹ˆ๋‹ค. +/// - ์‚ฌ์šฉ์ž/ํ•™์› ์ปจํ…์ŠคํŠธ๋Š” ํ˜ธ์ถœํ•˜๋Š” ์ชฝ(UI Layer)์—์„œ ๊ฒฐ์ •ํ•˜์—ฌ +/// ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ(academyId, academyUserIds)๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค. +class GetMonthlyLearningStatusUseCaseImpl + implements GetMonthlyLearningStatusUseCase { + final AssessmentRepository _assessmentRepository; + final GradingHistoryRepository _gradingHistoryRepository; + final LearningCompletionService _completionService; + + GetMonthlyLearningStatusUseCaseImpl({ + required AssessmentRepository assessmentRepository, + required GradingHistoryRepository gradingHistoryRepository, + required LearningCompletionService completionService, + }) : _assessmentRepository = assessmentRepository, + _gradingHistoryRepository = gradingHistoryRepository, + _completionService = completionService; + + @override + Future> call(DateTime month) async { + // ์›”์˜ ์ฒซ ๋‚ ๋กœ ์ •๊ทœํ™” + final normalizedMonth = DateTime(month.year, month.month, 1); + final lastDay = DateTime(normalizedMonth.year, normalizedMonth.month + 1, 0) + .day; + + // ๋นˆ ์ƒํƒœ ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ (๋ฐ์ดํ„ฐ๊ฐ€ ์—†์–ด๋„ ๋ชจ๋“  ๋‚ ์งœ์— ๋Œ€ํ•ด ์ƒํƒœ ๋ฐ˜ํ™˜) + final statuses = []; + + for (int day = 1; day <= lastDay; day++) { + final date = DailyLearningStatus.normalizeDate( + DateTime(normalizedMonth.year, normalizedMonth.month, day), + ); + statuses.add(DailyLearningStatus( + date: date, + isCompleted: false, // ๊ธฐ๋ณธ๊ฐ’, ์•„๋ž˜์—์„œ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ํ›„ ์—…๋ฐ์ดํŠธ + )); + } + + return statuses; + } + + /// ์‚ฌ์šฉ์ž ํ•™์› ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฐ›์•„์„œ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๊ณ  ์™„๋ฃŒ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จ + /// + /// ์ด ๋ฉ”์„œ๋“œ๋Š” UI Layer์—์„œ ํ˜ธ์ถœํ•˜์—ฌ ์‚ฌ์šฉ์ž/ํ•™์› ์ •๋ณด๋ฅผ ์ „๋‹ฌ๋ฐ›์Šต๋‹ˆ๋‹ค. + /// UseCase ์ž์ฒด๋Š” ์‚ฌ์šฉ์ž ์ปจํ…์ŠคํŠธ๋ฅผ ๋ชจ๋ฅด์ง€๋งŒ, ์ด ํ—ฌํผ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด + /// ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๊ณ  ์™„๋ฃŒ ์—ฌ๋ถ€๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. + /// + /// [month]: ์กฐํšŒํ•  ์›” + /// [academyId]: Assessment ์กฐํšŒ์šฉ academyId (userAcademyId) + /// [academyUserIds]: GradingHistory ์กฐํšŒ์šฉ academyUserId ๋ฆฌ์ŠคํŠธ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ์™„๋ฃŒ ์—ฌ๋ถ€๊ฐ€ ์—…๋ฐ์ดํŠธ๋œ DailyLearningStatus ๋ฆฌ์ŠคํŠธ + Future> callWithContext({ + required DateTime month, + required String academyId, + required List academyUserIds, + }) async { + // 1. ํ•ด๋‹น ์›”์˜ Assessment ๋ฐ์ดํ„ฐ ๋กœ๋“œ + final assessmentsByDate = await _assessmentRepository.getForMonth( + academyId: academyId, + dateTime: month, + ); + + // 2. ํ•ด๋‹น ์›”์˜ GradingHistory ๋ฐ์ดํ„ฐ ๋กœ๋“œ + final gradingHistoriesByAcademyUserId = + await _gradingHistoryRepository + .getGradingHistoriesByAcademyUserIds(academyUserIds); + + // 3. GradingHistory๋ฅผ ๋‚ ์งœ๋ณ„๋กœ ๊ทธ๋ฃนํ™” (ํ•ด๋‹น ์›”์— ์†ํ•˜๋Š” ๊ฒƒ๋งŒ) + final gradingHistoriesByDate = >{}; + gradingHistoriesByAcademyUserId.forEach((academyUserId, histories) { + for (var history in histories) { + // ํ•ด๋‹น ์›”์— ์†ํ•˜๋Š”์ง€ ํ™•์ธ + if (history.gradingDate.year == month.year && + history.gradingDate.month == month.month) { + final dateStr = _formatDate(history.gradingDate); + gradingHistoriesByDate.putIfAbsent(dateStr, () => []).add(history); + } + } + }); + + // 4. ํ•ด๋‹น ์›”์˜ ๋ชจ๋“  ๋‚ ์งœ์— ๋Œ€ํ•ด DailyLearningStatus ์ƒ์„ฑ + final normalizedMonth = DateTime(month.year, month.month, 1); + final lastDay = DateTime(normalizedMonth.year, normalizedMonth.month + 1, 0) + .day; + + final statuses = []; + + for (int day = 1; day <= lastDay; day++) { + final date = DailyLearningStatus.normalizeDate( + DateTime(normalizedMonth.year, normalizedMonth.month, day), + ); + + // LearningCompletionService๋กœ ์™„๋ฃŒ ์—ฌ๋ถ€ ํŒ๋‹จ + final isCompleted = _completionService.isCompleted( + date: date, + assessmentsByDate: assessmentsByDate, + gradingHistoriesByDate: gradingHistoriesByDate, + ); + + statuses.add(DailyLearningStatus( + date: date, + isCompleted: isCompleted, + // Phase 3์—์„œ bookProgresses ์ถ”๊ฐ€ ์˜ˆ์ • + )); + } + + return statuses; + } + + @override + Future getStatusForDate(DateTime date) async { + final month = DateTime(date.year, date.month, 1); + final statuses = await call(month); + final normalizedDate = DailyLearningStatus.normalizeDate(date); + + try { + return statuses.firstWhere( + (status) => DailyLearningStatus.normalizeDate(status.date) == normalizedDate, + ); + } catch (e) { + return DailyLearningStatus(date: normalizedDate, isCompleted: false); + } + } + + /// ๋‚ ์งœ ํฌ๋งทํŒ… (YYYY-MM-DD) + String _formatDate(DateTime date) { + return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; + } +} + diff --git a/frontend/lib/services/grading_history_api.dart b/frontend/lib/services/grading_history_api.dart new file mode 100644 index 0000000..6a2e7c9 --- /dev/null +++ b/frontend/lib/services/grading_history_api.dart @@ -0,0 +1,155 @@ +import 'dart:convert'; +import 'dart:developer' as developer; +import 'package:http/http.dart' as http; +import '../config/api_config.dart'; +import '../utils/app_logger.dart'; +import 'auth_service.dart'; + +/// API ์‘๋‹ต DTO (์„œ๋ฒ„ ์‘๋‹ต ๊ตฌ์กฐ ๊ทธ๋Œ€๋กœ) +/// +/// API ์‘๋‹ต: flat array ํ˜•ํƒœ +/// [{student_response_id: ..., academy_user_id: 20, ...}, {student_response_id: ..., academy_user_id: 25, ...}] +class GradingHistoryApiResponse { + final int studentResponseId; // student_response_id + final int academyUserId; // academy_user_id + final int? assessId; // assess_id + final int? bookId; // book_id + final String? bookName; // book_name + final String? bookImageUrl; // book_image_url + final int responseStartPage; // response_start_page + final int responseEndPage; // response_end_page + final int unrecognizedResponseCount; // unrecognized_response_count + final String createdAt; // created_at (ISO 8601) + final String? updatedAt; // updated_at + + GradingHistoryApiResponse({ + required this.studentResponseId, + required this.academyUserId, + this.assessId, + this.bookId, + this.bookName, + this.bookImageUrl, + required this.responseStartPage, + required this.responseEndPage, + this.unrecognizedResponseCount = 0, + required this.createdAt, + this.updatedAt, + }); + + factory GradingHistoryApiResponse.fromJson(Map json) { + return GradingHistoryApiResponse( + studentResponseId: json['student_response_id'] as int? ?? 0, + academyUserId: json['academy_user_id'] as int? ?? 0, + assessId: json['assess_id'] as int?, + bookId: json['book_id'] as int?, + bookName: json['book_name'] as String?, + bookImageUrl: json['book_image_url'] as String?, + responseStartPage: json['response_start_page'] as int? ?? 0, + responseEndPage: json['response_end_page'] as int? ?? 0, + unrecognizedResponseCount: + json['unrecognized_response_count'] as int? ?? 0, + createdAt: json['created_at'] as String? ?? '', + updatedAt: json['updated_at'] as String?, + ); + } +} + +/// Grading History API ํ˜ธ์ถœ ์ „์šฉ ๋ ˆ์ด์–ด +class GradingHistoryApi { + GradingHistoryApi({ + required AuthService authService, + required http.Client httpClient, + }) : _authService = authService, + _httpClient = httpClient; + + final AuthService _authService; + final http.Client _httpClient; + + /// ์—ฌ๋Ÿฌ academyUserId์— ๋Œ€ํ•œ ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ์กฐํšŒ + /// + /// [academyUserIds]: ์กฐํšŒํ•  academyUserId ๋ฆฌ์ŠคํŠธ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: flat array ํ˜•ํƒœ์˜ GradingHistoryApiResponse ๋ฆฌ์ŠคํŠธ + /// API ์‘๋‹ต: [{...}, {...}] ํ˜•ํƒœ์˜ ๋ฐฐ์—ด + /// + /// ํ˜„์žฌ๋Š” ์ „์ฒด ๋กœ๋“œ ๋ฐฉ์‹์ด๋ฉฐ, ํ•„์š” ์‹œ ํŽ˜์ด์ง• API๋กœ ํ™•์žฅ ๊ฐ€๋Šฅ + Future> fetchGradingHistories( + List academyUserIds, + ) async { + // ๋น„์ฆˆ๋‹ˆ์Šค ํ๋ฆ„ ๋กœ๊ทธ: appLog ์‚ฌ์šฉ + appLog( + '[grading_history:grading_history_api] API ํ˜ธ์ถœ ์‹œ์ž‘ - academyUserIds: $academyUserIds', + ); + + // 1. ํ† ํฐ ํ™•์ธ + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + appLog('[grading_history:grading_history_api] ์ธ์ฆ ํ† ํฐ ์—†์Œ'); + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + // 2. academyUserIds๋ฅผ ์ฝค๋งˆ๋กœ ๊ตฌ๋ถ„ํ•œ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ + final idsParam = academyUserIds.join(','); + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/student-responses/histories?academyUserIds=$idsParam', + ); + + appLog('[grading_history:grading_history_api] GET ์š”์ฒญ: $uri'); + // ๋””๋ฒ„๊น… ๋””ํ…Œ์ผ ๋กœ๊ทธ: developer.log ์‚ฌ์šฉ + developer.log('๐Ÿ“š [GradingHistoryApi] GET $uri'); + + // 3. API ํ˜ธ์ถœ + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + appLog( + '[grading_history:grading_history_api] ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: ${response.statusCode}', + ); + appLog('[grading_history:grading_history_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}'); + developer.log( + '๐Ÿ“š [GradingHistoryApi] Response status: ${response.statusCode}', + ); + + // 4. ์—๋Ÿฌ ์ฒ˜๋ฆฌ + if (response.statusCode == 401) { + appLog('[grading_history:grading_history_api] ์ธ์ฆ ์‹คํŒจ (401)'); + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + appLog( + '[grading_history:grading_history_api] API ํ˜ธ์ถœ ์‹คํŒจ - status: ${response.statusCode}', + ); + throw Exception('์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ์กฐํšŒ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. (status: ${response.statusCode})'); + } + + // 5. JSON ํŒŒ์‹ฑ + try { + final List data = json.decode(response.body); + final result = data + .map( + (item) => GradingHistoryApiResponse.fromJson( + item as Map, + ), + ) + .toList(); + + appLog( + '[grading_history:grading_history_api] ์‘๋‹ต ํŒŒ์‹ฑ ์„ฑ๊ณต - ํ•ญ๋ชฉ ์ˆ˜: ${result.length}', + ); + return result; + } catch (e) { + appLog('[grading_history:grading_history_api] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + appLog('[grading_history:grading_history_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}'); + developer.log('โŒ [GradingHistoryApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + developer.log('โŒ [GradingHistoryApi] Response body: ${response.body}'); + rethrow; + } + } +} diff --git a/frontend/lib/services/grading_history_repository_impl.dart b/frontend/lib/services/grading_history_repository_impl.dart new file mode 100644 index 0000000..395bbdf --- /dev/null +++ b/frontend/lib/services/grading_history_repository_impl.dart @@ -0,0 +1,139 @@ +import 'dart:convert'; +import 'dart:developer' as developer; +import 'package:shared_preferences/shared_preferences.dart'; +import '../domain/grading_history/grading_history_entity.dart'; +import '../domain/grading_history/grading_history_repository.dart'; +import 'grading_history_api.dart'; +import '../data/mappers/grading_history_mapper.dart'; +import 'academy_service.dart'; + +/// Grading History Repository ๊ตฌํ˜„์ฒด +/// +/// API ํ˜ธ์ถœ, className ์กฐํšŒ, ์บ์‹ฑ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. +class GradingHistoryRepositoryImpl implements GradingHistoryRepository { + GradingHistoryRepositoryImpl({ + required GradingHistoryApi api, + required GradingHistoryMapper mapper, + required AcademyService academyService, + }) : _api = api, + _mapper = mapper, + _academyService = academyService; + + final GradingHistoryApi _api; + final GradingHistoryMapper _mapper; + final AcademyService _academyService; + + static const String _cacheKeyPrefix = 'grading_history_'; + + @override + Future>> + getGradingHistoriesByAcademyUserIds(List academyUserIds) async { + if (academyUserIds.isEmpty) { + return {}; + } + + try { + // 1. API ํ˜ธ์ถœ (flat array ๋ฐ˜ํ™˜) + final apiResponses = await _api.fetchGradingHistories(academyUserIds); + + // 2. className ์กฐํšŒ + final classNameMapStr = await _academyService.getClassesByAssigneeIds( + academyUserIds.map((id) => id.toString()).toList(), + ); + + // 3. String โ†’ int ํ‚ค ๋ณ€ํ™˜ + final classNameMap = {}; + for (final id in academyUserIds) { + final className = classNameMapStr[id.toString()]; + classNameMap[id] = (className != null && className.isNotEmpty) + ? className + : null; + } + + // 4. Mapper๋กœ ๋ณ€ํ™˜ + final entities = _mapper.convertApiResponsesToEntities( + apiResponses, + classNameMap, + ); + + // 5. academyUserId๋ณ„ ๊ทธ๋ฃนํ•‘ + // โš ๏ธ ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ์—†๋Š” academyUserId๋„ ๋นˆ ๋ฆฌ์ŠคํŠธ๋กœ ํฌํ•จ (์บ์‹ฑ์„ ์œ„ํ•ด) + final groupedMap = >{}; + + // ๋จผ์ € ๋ชจ๋“  academyUserId์— ๋Œ€ํ•ด ๋นˆ ๋ฆฌ์ŠคํŠธ ์ดˆ๊ธฐํ™” + for (final id in academyUserIds) { + groupedMap[id] = []; + } + + // ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ๋“ค์„ ๊ทธ๋ฃนํ•‘ + for (final entity in entities) { + groupedMap[entity.academyUserId]?.add(entity); + } + + // 6. ์บ์‹œ ์ €์žฅ (academyUserId๋ณ„๋กœ, ๋นˆ ๋ฆฌ์ŠคํŠธ๋„ ์ €์žฅ) + for (final entry in groupedMap.entries) { + await _cacheGradingHistories(entry.key, entry.value); + } + + return groupedMap; + } catch (e) { + developer.log('โŒ [GradingHistoryRepository] API ํ˜ธ์ถœ ์‹คํŒจ: $e'); + + // ์บ์‹œ์—์„œ ๋กœ๋“œ ์‹œ๋„ + final cachedMap = >{}; + for (final id in academyUserIds) { + final cached = await _getCachedGradingHistories(id); + if (cached != null) { + // ๋นˆ ๋ฆฌ์ŠคํŠธ๋„ ํฌํ•จ (ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋„ ์บ์‹œ์— ์ €์žฅ๋จ) + cachedMap[id] = cached; + } + } + + if (cachedMap.isNotEmpty) { + developer.log('โœ… [GradingHistoryRepository] ์บ์‹œ์—์„œ ๋กœ๋“œ ์„ฑ๊ณต'); + return cachedMap; + } + + rethrow; + } + } + + /// ์บ์‹œ ์ €์žฅ + Future _cacheGradingHistories( + int academyUserId, + List entities, + ) async { + try { + final prefs = await SharedPreferences.getInstance(); + final cacheKey = '$_cacheKeyPrefix$academyUserId'; + final jsonList = entities.map((e) => e.toCacheJson()).toList(); + await prefs.setString(cacheKey, jsonEncode(jsonList)); + } catch (e) { + developer.log('โš ๏ธ [GradingHistoryRepository] ์บ์‹œ ์ €์žฅ ์‹คํŒจ: $e'); + } + } + + /// ์บ์‹œ์—์„œ ๋กœ๋“œ + Future?> _getCachedGradingHistories( + int academyUserId, + ) async { + try { + final prefs = await SharedPreferences.getInstance(); + final cacheKey = '$_cacheKeyPrefix$academyUserId'; + final cachedJson = prefs.getString(cacheKey); + if (cachedJson == null) return null; + + final List jsonList = jsonDecode(cachedJson); + return jsonList + .map( + (json) => GradingHistoryEntity.fromCacheJson( + json as Map, + ), + ) + .toList(); + } catch (e) { + developer.log('โš ๏ธ [GradingHistoryRepository] ์บ์‹œ ๋กœ๋“œ ์‹คํŒจ: $e'); + return null; + } + } +} diff --git a/frontend/lib/services/grading_history_use_case.dart b/frontend/lib/services/grading_history_use_case.dart new file mode 100644 index 0000000..25cb164 --- /dev/null +++ b/frontend/lib/services/grading_history_use_case.dart @@ -0,0 +1,66 @@ +import '../domain/grading_history/grading_history_entity.dart'; +import 'grading_history_api.dart'; + +/// Grading History UseCase +/// +/// API ์‘๋‹ต์„ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. +class GradingHistoryUseCase { + /// API ์‘๋‹ต ๋ฆฌ์ŠคํŠธ๋ฅผ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜ + /// + /// [responses]: API ์‘๋‹ต ๋ฆฌ์ŠคํŠธ (flat array) + /// [classNameMap]: academyUserId โ†’ className ๋งคํ•‘ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋ฆฌ์ŠคํŠธ (์ •๋ ฌ ์—†์Œ, ์ˆœ์ˆ˜ ๋ณ€ํ™˜๋งŒ) + /// ์ •๋ ฌ์€ UI ๋ ˆ์ด์–ด์—์„œ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. + List convertApiResponsesToEntities( + List responses, + Map classNameMap, + ) { + return responses.map((response) { + // 1. createdAt ํŒŒ์‹ฑ (UTC โ†’ ๋กœ์ปฌ ๋ณ€ํ™˜, ๋ฐฉ์–ด ๋กœ์ง ํฌํ•จ) + final createdAt = _parseCreatedAt(response.createdAt); + + // 2. className ์ฃผ์ž… + final className = classNameMap[response.academyUserId]; + + // 3. ์—”ํ‹ฐํ‹ฐ ์ƒ์„ฑ + return GradingHistoryEntity( + studentResponseId: response.studentResponseId, + academyUserId: response.academyUserId, + bookId: response.bookId, + bookName: response.bookName, + bookCoverImageUrl: response.bookImageUrl, + startPage: response.responseStartPage, + endPage: response.responseEndPage, + className: className, + gradingDate: createdAt, + assessId: response.assessId, + unrecognizedResponseCount: response.unrecognizedResponseCount, + ); + }).toList(); + } + + /// createdAt ๋ฌธ์ž์—ด์„ DateTime์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ํŒŒ์‹ฑ + /// + /// ๋นˆ ๋ฌธ์ž์—ด์ด๊ฑฐ๋‚˜ ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๊ณผ๊ฑฐ ๊ณ ์ •๊ฐ’ ๋ฐ˜ํ™˜ (์ •๋ ฌ ์‹œ ๋’ค๋กœ ๊ฐ€๋„๋ก) + /// + /// ๊ทœ์น™: + /// - created_at์€ ์„œ๋ฒ„์—์„œ UTC ๊ธฐ์ค€ ISO ๋ฌธ์ž์—ด๋กœ ๋‚ด๋ ค์˜จ๋‹ค๋Š” ์ „์ œ ํ•˜์— toLocal() ์ ์šฉ + /// - ๋งŒ์•ฝ ์„œ๋ฒ„๊ฐ€ ์ด๋ฏธ KST๋กœ ๋‚ด๋ ค์ฃผ๋ฉด toLocal() ์ œ๊ฑฐ ํ•„์š” + /// - ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ DateTime(1970, 1, 1) ๋ฐ˜ํ™˜ (์ •๋ ฌ ์‹œ ๊ฐ€์žฅ ๋’ค๋กœ) + DateTime _parseCreatedAt(String value) { + if (value.isEmpty) { + // ๋นˆ ๋ฌธ์ž์—ด์ด๋ฉด ๊ณผ๊ฑฐ ๊ณ ์ •๊ฐ’ ๋ฐ˜ํ™˜ (์ •๋ ฌ ์‹œ ๋’ค๋กœ ๊ฐ€๋„๋ก) + return DateTime(1970, 1, 1); + } + + try { + // created_at์€ ์„œ๋ฒ„์—์„œ UTC ๊ธฐ์ค€ ISO ๋ฌธ์ž์—ด๋กœ ๋‚ด๋ ค์˜จ๋‹ค๋Š” ์ „์ œ ํ•˜์— toLocal() ์ ์šฉ + // ๋งŒ์•ฝ ์„œ๋ฒ„๊ฐ€ ์ด๋ฏธ KST๋กœ ๋‚ด๋ ค์ฃผ๋ฉด toLocal() ์ œ๊ฑฐ ํ•„์š” + return DateTime.parse(value).toLocal(); + } catch (_) { + // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๊ณผ๊ฑฐ ๊ณ ์ •๊ฐ’ ๋ฐ˜ํ™˜ (์ •๋ ฌ ์‹œ ๊ฐ€์žฅ ๋’ค๋กœ) + return DateTime(1970, 1, 1); + } + } +} diff --git a/frontend/lib/services/learning_completion_service_impl.dart b/frontend/lib/services/learning_completion_service_impl.dart new file mode 100644 index 0000000..7af6028 --- /dev/null +++ b/frontend/lib/services/learning_completion_service_impl.dart @@ -0,0 +1,119 @@ +import '../domain/learning/learning_completion_service.dart'; +import '../domain/learning/daily_learning_status.dart'; +import '../models/assessment.dart'; +import '../domain/grading_history/grading_history_entity.dart'; + +/// LearningCompletionService ๊ตฌํ˜„์ฒด +/// +/// ์ˆœ์ˆ˜ ํ•จ์ˆ˜ํ˜•์œผ๋กœ ์„ค๊ณ„๋˜์–ด ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +/// ๋ชจ๋“  ํŒ๋‹จ์€ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋งŒ์œผ๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. +class LearningCompletionServiceImpl implements LearningCompletionService { + const LearningCompletionServiceImpl(); + + @override + bool isCompleted({ + required DateTime date, + Map>? assessmentsByDate, + Map>? gradingHistoriesByDate, + }) { + final dateStr = _formatDate(date); + + // ์šฐ์„ ์ˆœ์œ„ 1: GradingHistory (์‹ค์ œ ์ฑ„์ /์ œ์ถœ ๊ธฐ๋ก) + // - ํ•ด๋‹น ๋‚ ์งœ์— gradingDate ๊ฐ€ 1๊ฐœ ์ด์ƒ ์žˆ์œผ๋ฉด "์˜ค๋Š˜์˜ ํ•™์Šต์ด ์กด์žฌ"ํ•˜๋ฏ€๋กœ ์™„๋ฃŒ๋กœ ํŒ๋‹จ + if (gradingHistoriesByDate != null) { + final histories = gradingHistoriesByDate[dateStr] ?? []; + if (histories.isNotEmpty) { + return true; + } + } + + // ์šฐ์„ ์ˆœ์œ„ 2: Assessment (์ˆ™์ œ ์™„๋ฃŒ ๊ธฐ๋ก) + // - ๊ณผ์ œ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด "๋ชจ๋“  ๊ณผ์ œ๊ฐ€ Y"์ผ ๋•Œ๋งŒ ์™„๋ฃŒ๋กœ ํŒ๋‹จ + // - ๊ณผ์ œ๊ฐ€ ์•„์˜ˆ ์—†์„ ๋•Œ๋Š” ์—ฌ๊ธฐ์„œ๋Š” ์™„๋ฃŒ๋กœ ๋ณด์ง€ ์•Š์Œ + if (assessmentsByDate != null) { + final assessments = assessmentsByDate[dateStr] ?? []; + if (assessments.isEmpty) { + return false; + } + return assessments.every((a) => a.assessStatus == 'Y'); + } + + // GradingHistory, Assessment ๋ชจ๋‘ ์—†๋Š” ๊ฒฝ์šฐ โ†’ ์™„๋ฃŒ ์•„๋‹˜ + return false; + } + + @override + Map getCompletionMap({ + required DateTime startDate, + required DateTime endDate, + Map>? assessmentsByDate, + Map>? gradingHistoriesByDate, + }) { + final map = {}; + var current = DailyLearningStatus.normalizeDate(startDate); + final normalizedEnd = DailyLearningStatus.normalizeDate(endDate); + + while (current.isBefore(normalizedEnd) || + current.isAtSameMomentAs(normalizedEnd)) { + map[current] = isCompleted( + date: current, + assessmentsByDate: assessmentsByDate, + gradingHistoriesByDate: gradingHistoriesByDate, + ); + current = current.add(const Duration(days: 1)); + } + + return map; + } + + @override + int getConsecutiveDays({ + required DateTime date, + Map>? assessmentsByDate, + Map>? gradingHistoriesByDate, + }) { + var current = DailyLearningStatus.normalizeDate(date); + int streak = 0; + + // ์˜ค๋Š˜๋ถ€ํ„ฐ ์—ญ์ˆœ์œผ๋กœ ๊ณ„์‚ฐ + while (isCompleted( + date: current, + assessmentsByDate: assessmentsByDate, + gradingHistoriesByDate: gradingHistoriesByDate, + )) { + streak++; + current = current.subtract(const Duration(days: 1)); + } + + return streak; + } + + @override + bool shouldShowConnector({ + required DateTime date, + required DateTime nextDate, + Map>? assessmentsByDate, + Map>? gradingHistoriesByDate, + }) { + final normalizedDate = DailyLearningStatus.normalizeDate(date); + final normalizedNext = DailyLearningStatus.normalizeDate(nextDate); + + return isCompleted( + date: normalizedDate, + assessmentsByDate: assessmentsByDate, + gradingHistoriesByDate: gradingHistoriesByDate, + ) && + isCompleted( + date: normalizedNext, + assessmentsByDate: assessmentsByDate, + gradingHistoriesByDate: gradingHistoriesByDate, + ) && + normalizedNext.month == normalizedDate.month && + normalizedNext.year == normalizedDate.year; + } + + /// ๋‚ ์งœ ํฌ๋งทํŒ… (YYYY-MM-DD) + String _formatDate(DateTime date) { + return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; + } +} diff --git a/frontend/lib/services/location_service.dart b/frontend/lib/services/location_service.dart new file mode 100644 index 0000000..1777081 --- /dev/null +++ b/frontend/lib/services/location_service.dart @@ -0,0 +1,58 @@ +import 'package:geolocator/geolocator.dart'; +import 'dart:developer' as developer; + +/// ์œ„์น˜ ๊ถŒํ•œ ๋ฐ ํ˜„์žฌ ์œ„์น˜ ์กฐํšŒ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ์„œ๋น„์Šค +/// +/// DI Container์—์„œ singleton์œผ๋กœ ๊ด€๋ฆฌ๋˜๋ฉฐ, +/// ์ด ํŒŒ์ผ์—์„œ๋Š” ๋ณ„๋„์˜ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +class LocationService { + LocationService(); + + /// ์œ„์น˜ ๊ถŒํ•œ ์š”์ฒญ ๋ฐ ํ˜„์žฌ ์œ„์น˜ ๊ฐ€์ ธ์˜ค๊ธฐ + Future getCurrentLocation() async { + try { + // ์œ„์น˜ ์„œ๋น„์Šค ํ™œ์„ฑํ™” ํ™•์ธ + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled) { + developer.log('Location services are disabled'); + return null; + } + + // ์œ„์น˜ ๊ถŒํ•œ ํ™•์ธ + LocationPermission permission = await Geolocator.checkPermission(); + if (permission == LocationPermission.denied) { + permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { + developer.log('Location permissions are denied'); + return null; + } + } + + if (permission == LocationPermission.deniedForever) { + developer.log( + 'Location permissions are permanently denied, we cannot request permissions.'); + return null; + } + + // ํ˜„์žฌ ์œ„์น˜ ๊ฐ€์ ธ์˜ค๊ธฐ + Position position = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.high, + ); + + developer.log( + 'Current location: ${position.latitude}, ${position.longitude}'); + return position; + } catch (e) { + developer.log('Error getting current location: $e'); + return null; + } + } + + /// ์œ„์น˜ ๊ถŒํ•œ ์ƒํƒœ ํ™•์ธ + Future hasLocationPermission() async { + LocationPermission permission = await Geolocator.checkPermission(); + return permission == LocationPermission.whileInUse || + permission == LocationPermission.always; + } +} + diff --git a/frontend/lib/services/models/question_status_model.dart b/frontend/lib/services/models/question_status_model.dart new file mode 100644 index 0000000..e26897d --- /dev/null +++ b/frontend/lib/services/models/question_status_model.dart @@ -0,0 +1,14 @@ +/// ๋ฌธ์ œ ํ’€์ด ์ƒํƒœ ๋ชจ๋ธ (Application Layer) +/// +/// Domain Entity๋ฅผ UI์— ๋งž๊ฒŒ ๋ณ€ํ™˜ํ•œ ๋ชจ๋ธ +/// UI๋Š” ์ด ๋ชจ๋ธ์„ ๋ฐ›์•„์„œ ์ž์œ ๋กญ๊ฒŒ ๋ Œ๋”๋ง +class QuestionStatusModel { + final int questionNumber; + final bool? isCorrect; // null = ์•ˆ ํ’€์Œ, true = ๋งž์Œ, false = ํ‹€๋ฆผ + + const QuestionStatusModel({ + required this.questionNumber, + required this.isCorrect, + }); +} + diff --git a/frontend/lib/services/policies/answer_selection_policy.dart b/frontend/lib/services/policies/answer_selection_policy.dart new file mode 100644 index 0000000..5a757a7 --- /dev/null +++ b/frontend/lib/services/policies/answer_selection_policy.dart @@ -0,0 +1,10 @@ +/// ์ค‘๋ณต ๋‹ต์•ˆ ์„ ํƒ ์ •์ฑ… +/// +/// ๊ฐ™์€ ๋ฌธ์ œ ๋ฒˆํ˜ธ์— ์—ฌ๋Ÿฌ ๋‹ต์•ˆ์ด ์žˆ์„ ๊ฒฝ์šฐ ์–ด๋–ค ๋‹ต์•ˆ์„ ์„ ํƒํ• ์ง€ ๊ฒฐ์ • +class AnswerSelectionPolicy { + /// ๊ธฐ์กด ๋‹ต์•ˆ์„ ์šฐ์„  ์‚ฌ์šฉ, ์—†์œผ๋ฉด ์ƒˆ ๋‹ต์•ˆ ์‚ฌ์šฉ + bool? selectAnswer(bool? existing, bool? next) { + return existing ?? next; + } +} + diff --git a/frontend/lib/services/section_image_api.dart b/frontend/lib/services/section_image_api.dart new file mode 100644 index 0000000..306ea91 --- /dev/null +++ b/frontend/lib/services/section_image_api.dart @@ -0,0 +1,147 @@ +import 'dart:convert'; +import 'dart:developer' as developer; +import 'package:http/http.dart' as http; +import '../config/api_config.dart'; +import '../utils/app_logger.dart'; +import 'auth_service.dart'; + +/// API ์‘๋‹ต DTO (์„œ๋ฒ„ ์‘๋‹ต ๊ตฌ์กฐ ๊ทธ๋Œ€๋กœ) +class SectionImageApiResponse { + final String url; // S3 base URL + final String key; // S3 object key + + SectionImageApiResponse({ + required this.url, + required this.key, + }); + + factory SectionImageApiResponse.fromJson(Map json) { + final url = json['url'] as String?; + final key = json['key'] as String?; + + if (url == null || url.isEmpty) { + throw FormatException( + '[SectionImageApiResponse.fromJson] url is null or empty', + json, + ); + } + if (key == null || key.isEmpty) { + throw FormatException( + '[SectionImageApiResponse.fromJson] key is null or empty', + json, + ); + } + + return SectionImageApiResponse( + url: url, + key: key, + ); + } +} + +/// Section ์ด๋ฏธ์ง€๊ฐ€ ์—†์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ (Data Layer ๋‚ด๋ถ€์šฉ) +/// +/// Repository์—์„œ null๋กœ ๋ณ€ํ™˜๋˜์–ด UI ๋ ˆ์ด์–ด๋กœ๋Š” ์ „ํŒŒ๋˜์ง€ ์•Š์Œ +class SectionImageNotFoundException implements Exception { + final String message; + SectionImageNotFoundException(this.message); + + @override + String toString() => message; +} + +/// Section ์ด๋ฏธ์ง€ API ํ˜ธ์ถœ ์ „์šฉ ๋ ˆ์ด์–ด +class SectionImageApi { + final AuthService _authService; + final http.Client _httpClient; + + SectionImageApi({ + required AuthService authService, + required http.Client httpClient, + }) : _authService = authService, + _httpClient = httpClient; + + /// Section ์ด๋ฏธ์ง€ URL ์กฐํšŒ + /// + /// API ์ŠคํŽ™: GET /storage/section?academyUserId={id}&studentResponseId={id}&questionNumber={num}&subQuestionNumber={num} + /// (๋ฐฑ์—”๋“œ์™€ ํ•ฉ์˜ ์™„๋ฃŒ) + Future fetchSectionImageUrl({ + required int academyUserId, + required int studentResponseId, + required int questionNumber, + required int subQuestionNumber, + }) async { + appLog( + '[section_image:section_image_api] API ํ˜ธ์ถœ ์‹œ์ž‘ - academyUserId: $academyUserId, studentResponseId: $studentResponseId, questionNumber: $questionNumber, subQuestionNumber: $subQuestionNumber', + ); + + // 1. ํ† ํฐ ํ™•์ธ + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + appLog('[section_image:section_image_api] ์ธ์ฆ ํ† ํฐ ์—†์Œ'); + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + // 2. URI ์ƒ์„ฑ + final uri = Uri.parse( + '${ApiConfig.baseUrl}/storage/section?academyUserId=$academyUserId&studentResponseId=$studentResponseId&questionNumber=$questionNumber&subQuestionNumber=$subQuestionNumber', + ); + + appLog('[section_image:section_image_api] GET ์š”์ฒญ: $uri'); + developer.log('๐Ÿ–ผ๏ธ [SectionImageApi] GET $uri'); + + // 3. API ํ˜ธ์ถœ + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + appLog( + '[section_image:section_image_api] ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: ${response.statusCode}', + ); + appLog( + '[section_image:section_image_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}', + ); + developer.log( + '๐Ÿ–ผ๏ธ [SectionImageApi] Response status: ${response.statusCode}', + ); + + // 4. ์—๋Ÿฌ ์ฒ˜๋ฆฌ + if (response.statusCode == 401) { + appLog('[section_image:section_image_api] ์ธ์ฆ ์‹คํŒจ (401)'); + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode == 404) { + appLog('[section_image:section_image_api] ์ด๋ฏธ์ง€ ์—†์Œ (404)'); + throw SectionImageNotFoundException('ํ•ด๋‹น ๋ฌธ์ œ์˜ ์ด๋ฏธ์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + if (response.statusCode != 200) { + appLog( + '[section_image:section_image_api] API ํ˜ธ์ถœ ์‹คํŒจ - status: ${response.statusCode}', + ); + throw Exception('์ด๋ฏธ์ง€ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'); + } + + // 5. JSON ํŒŒ์‹ฑ + try { + final Map data = json.decode(response.body); + final result = SectionImageApiResponse.fromJson(data); + + appLog('[section_image:section_image_api] ์‘๋‹ต ํŒŒ์‹ฑ ์„ฑ๊ณต'); + return result; + } catch (e) { + appLog('[section_image:section_image_api] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + appLog('[section_image:section_image_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}'); + developer.log('โŒ [SectionImageApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + developer.log('โŒ [SectionImageApi] Response body: ${response.body}'); + rethrow; + } + } +} + + diff --git a/frontend/lib/services/section_image_mapper.dart b/frontend/lib/services/section_image_mapper.dart new file mode 100644 index 0000000..f5087c5 --- /dev/null +++ b/frontend/lib/services/section_image_mapper.dart @@ -0,0 +1,19 @@ +import '../domain/section_image/section_image_entity.dart'; +import 'section_image_api.dart'; + +/// Section ์ด๋ฏธ์ง€ API ์‘๋‹ต์„ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” Mapper +/// +/// Data Layer ๋‚ด๋ถ€ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋กœ, DTO โ†’ Entity ๋ณ€ํ™˜๋งŒ ๋‹ด๋‹น +class SectionImageMapper { + /// API ์‘๋‹ต์„ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜ + SectionImageEntity fromApi(SectionImageApiResponse response) { + // API ์‘๋‹ต์˜ url์€ ์ด๋ฏธ ์™„์„ฑ๋œ signed URL์ด๋ฏ€๋กœ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ + // (url์— query parameter๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์–ด key์™€ ํ•ฉ์น˜๋ฉด ์•ˆ ๋จ) + final imageUrl = response.url; + return SectionImageEntity( + imageUrl: imageUrl, + ); + } +} + + diff --git a/frontend/lib/services/section_image_repository_impl.dart b/frontend/lib/services/section_image_repository_impl.dart new file mode 100644 index 0000000..37cf224 --- /dev/null +++ b/frontend/lib/services/section_image_repository_impl.dart @@ -0,0 +1,48 @@ +import 'dart:developer' as developer; +import '../domain/section_image/section_image_entity.dart'; +import '../domain/section_image/section_image_repository.dart'; +import 'section_image_api.dart'; +import 'section_image_mapper.dart'; + +/// Section ์ด๋ฏธ์ง€ Repository ๊ตฌํ˜„์ฒด +class SectionImageRepositoryImpl implements SectionImageRepository { + final SectionImageApi _api; + final SectionImageMapper _mapper; + + SectionImageRepositoryImpl({ + required SectionImageApi api, + required SectionImageMapper mapper, + }) : _api = api, + _mapper = mapper; + + @override + Future getSectionImageUrl({ + required int academyUserId, + required int studentResponseId, + required int questionNumber, + required int subQuestionNumber, + }) async { + try { + // 1. API ํ˜ธ์ถœ + final apiResponse = await _api.fetchSectionImageUrl( + academyUserId: academyUserId, + studentResponseId: studentResponseId, + questionNumber: questionNumber, + subQuestionNumber: subQuestionNumber, + ); + + // 2. Mapper๋กœ ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜ + return _mapper.fromApi(apiResponse); + } on SectionImageNotFoundException { + // 404 ์—๋Ÿฌ๋Š” "์ด๋ฏธ์ง€ ์—†์Œ"์œผ๋กœ ๊ฐ„์ฃผํ•˜์—ฌ null ๋ฐ˜ํ™˜ (์ •์ƒ ์ผ€์ด์Šค) + developer.log('โ„น๏ธ [SectionImageRepository] ์ด๋ฏธ์ง€ ์—†์Œ (404) - ์ •์ƒ ์ผ€์ด์Šค'); + return null; + } catch (e) { + // ๊ทธ ์™ธ ์—๋Ÿฌ๋Š” ์˜ˆ์™ธ๋กœ ์ „ํŒŒ + developer.log('โŒ [SectionImageRepository] API ํ˜ธ์ถœ ์‹คํŒจ: $e'); + rethrow; + } + } +} + + diff --git a/frontend/lib/services/student_answer_api.dart b/frontend/lib/services/student_answer_api.dart new file mode 100644 index 0000000..64d2ff6 --- /dev/null +++ b/frontend/lib/services/student_answer_api.dart @@ -0,0 +1,454 @@ +import 'dart:convert'; +import 'dart:developer' as developer; +import 'package:http/http.dart' as http; +import '../config/api_config.dart'; +import '../utils/app_logger.dart'; +import 'auth_service.dart'; + +/// API ์‘๋‹ต DTO (์„œ๋ฒ„ ์‘๋‹ต ๊ตฌ์กฐ ๊ทธ๋Œ€๋กœ) +class StudentAnswerApiResponse { + final int studentAnswerId; + final int studentResponseId; + final int? chapterId; + final int page; + final int questionNumber; + final int subQuestionNumber; + final String answer; // ๋ฌธ์ž์—ด + final String? sectionUrl; + final bool? isCorrect; // null = ๋‹ต์•ˆ ์—†์Œ, true = ๋งž์Œ, false = ํ‹€๋ฆผ + final double score; + + StudentAnswerApiResponse({ + required this.studentAnswerId, + required this.studentResponseId, + this.chapterId, + required this.page, + required this.questionNumber, + required this.subQuestionNumber, + required this.answer, + this.sectionUrl, + required this.isCorrect, + required this.score, + }); + + factory StudentAnswerApiResponse.fromJson(Map json) { + // ํ•„์ˆ˜ ํ•„๋“œ ๊ฒ€์ฆ (ID๋Š” 0์ด๋ฉด ์œ ํšจํ•˜์ง€ ์•Š์Œ) + final studentAnswerId = json['student_answer_id'] as int?; + final studentResponseId = json['student_response_id'] as int?; + + if (studentAnswerId == null || studentAnswerId == 0) { + throw FormatException( + '[StudentAnswerApiResponse.fromJson] student_answer_id is null or 0', + json, + ); + } + if (studentResponseId == null || studentResponseId == 0) { + throw FormatException( + '[StudentAnswerApiResponse.fromJson] student_response_id is null or 0', + json, + ); + } + + return StudentAnswerApiResponse( + studentAnswerId: studentAnswerId, + studentResponseId: studentResponseId, + chapterId: json['chapter_id'] as int?, + page: json['page'] as int? ?? 0, + questionNumber: json['question_number'] as int? ?? 0, + subQuestionNumber: json['sub_question_number'] as int? ?? 0, + answer: json['answer'] as String? ?? '', // null์ด๋ฉด ๋นˆ ๋ฌธ์ž์—ด + sectionUrl: json['section_url'] as String?, + isCorrect: json['is_correct'] as bool?, // null ํ—ˆ์šฉ + score: (json['score'] as num?)?.toDouble() ?? 0.0, + ); + } +} + +/// ๋‹จ์ผ ๋‹ต์•ˆ ์ˆ˜์ • ์‘๋‹ต DTO +class UpdatedStudentAnswerDto { + final int studentAnswerId; + final int studentResponseId; + final int? chapterId; + final int page; + final int questionNumber; + final int subQuestionNumber; + final String answer; + final String? sectionUrl; + final bool? correct; // null ํ—ˆ์šฉ + final double score; + + UpdatedStudentAnswerDto({ + required this.studentAnswerId, + required this.studentResponseId, + this.chapterId, + required this.page, + required this.questionNumber, + required this.subQuestionNumber, + required this.answer, + this.sectionUrl, + required this.correct, + required this.score, + }); + + factory UpdatedStudentAnswerDto.fromJson(Map json) { + // ์„œ๋ฒ„๊ฐ€ snake_case ๋˜๋Š” camelCase๋ฅผ ํ˜ผ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋‘˜ ๋‹ค ๋Œ€์‘ + final studentAnswerId = + json['studentAnswerId'] as int? ?? json['student_answer_id'] as int?; + final studentResponseId = json['studentResponseId'] as int? ?? + json['student_response_id'] as int?; + + if (studentAnswerId == null || studentAnswerId == 0) { + throw FormatException( + '[UpdatedStudentAnswerDto.fromJson] studentAnswerId is null or 0', + json, + ); + } + if (studentResponseId == null || studentResponseId == 0) { + throw FormatException( + '[UpdatedStudentAnswerDto.fromJson] studentResponseId is null or 0', + json, + ); + } + + final chapterId = + json['chapterId'] as int? ?? json['chapter_id'] as int?; + final page = json['page'] as int? ?? 0; + final questionNumber = + json['questionNumber'] as int? ?? json['question_number'] as int? ?? 0; + final subQuestionNumber = json['subQuestionNumber'] as int? ?? + json['sub_question_number'] as int? ?? + 0; + final answer = json['answer'] as String? ?? ''; + final sectionUrl = + json['sectionUrl'] as String? ?? json['section_url'] as String?; + final correct = + json['correct'] as bool? ?? json['is_correct'] as bool?; + final score = (json['score'] as num?)?.toDouble() ?? 0.0; + + return UpdatedStudentAnswerDto( + studentAnswerId: studentAnswerId, + studentResponseId: studentResponseId, + chapterId: chapterId, + page: page, + questionNumber: questionNumber, + subQuestionNumber: subQuestionNumber, + answer: answer, + sectionUrl: sectionUrl, + correct: correct, + score: score, + ); + } +} + +/// Student Answer API ํ˜ธ์ถœ ์ „์šฉ ๋ ˆ์ด์–ด +class StudentAnswerApi { + final AuthService _authService; + final http.Client _httpClient; + + StudentAnswerApi({ + required AuthService authService, + required http.Client httpClient, + }) : _authService = authService, + _httpClient = httpClient; + + /// studentResponseId๋กœ ํ•™์ƒ ๋‹ต์•ˆ ๋ชฉ๋ก ์กฐํšŒ + /// + /// API ์ŠคํŽ™: GET /grading/student-answers/response?student_response_id={id} + /// (๋ฐฑ์—”๋“œ์™€ ํ•ฉ์˜ ์™„๋ฃŒ) + Future> fetchStudentAnswers( + int studentResponseId, + ) async { + appLog( + '[student_answer:student_answer_api] API ํ˜ธ์ถœ ์‹œ์ž‘ - studentResponseId: $studentResponseId', + ); + + // 1. ํ† ํฐ ํ™•์ธ + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + appLog('[student_answer:student_answer_api] ์ธ์ฆ ํ† ํฐ ์—†์Œ'); + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + // 2. URI ์ƒ์„ฑ + // โ€ป ์„œ๋ฒ„ ์ŠคํŽ™ ๋ณ€๊ฒฝ: student_response_id -> studentResponseId + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/student-answers/response?studentResponseId=$studentResponseId', + ); + + appLog('[student_answer:student_answer_api] GET ์š”์ฒญ: $uri'); + developer.log('๐Ÿ“ [StudentAnswerApi] GET $uri'); + + // 3. API ํ˜ธ์ถœ + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + appLog( + '[student_answer:student_answer_api] ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: ${response.statusCode}', + ); + developer.log( + '๐Ÿ“ [StudentAnswerApi] Response status: ${response.statusCode}', + ); + + // 4. ์—๋Ÿฌ ์ฒ˜๋ฆฌ + if (response.statusCode == 401) { + appLog('[student_answer:student_answer_api] ์ธ์ฆ ์‹คํŒจ (401)'); + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + appLog( + '[student_answer:student_answer_api] API ํ˜ธ์ถœ ์‹คํŒจ - status: ${response.statusCode}', + ); + throw Exception('ํ•™์ƒ ๋‹ต์•ˆ ์กฐํšŒ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'); + } + + // 5. JSON ํŒŒ์‹ฑ + try { + final List data = json.decode(response.body); + final result = data + .map( + (item) => + StudentAnswerApiResponse.fromJson(item as Map), + ) + .toList(); + + appLog( + '[student_answer:student_answer_api] ์‘๋‹ต ํŒŒ์‹ฑ ์„ฑ๊ณต - ํ•ญ๋ชฉ ์ˆ˜: ${result.length}', + ); + appLog('[student_answer:student_answer_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}'); + return result; + } catch (e) { + appLog('[student_answer:student_answer_api] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + appLog('[student_answer:student_answer_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}'); + developer.log('โŒ [StudentAnswerApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + developer.log('โŒ [StudentAnswerApi] Response body: ${response.body}'); + rethrow; + } + } + + /// ์ˆ˜์ •๋œ ๋‹ต์•ˆ๋“ค์„ ์„œ๋ฒ„์— ์ €์žฅ + /// + /// API ์ŠคํŽ™: PATCH /grading/student-answers (์ถ”์ •, ๋ฐฑ์—”๋“œ ํ™•์ธ ํ•„์š”) + /// Payload: [{student_answer_id: 1, answer: "B"}, ...] + Future updateStudentAnswers(List> payload) async { + appLog( + '[student_answer:student_answer_api] ๋‹ต์•ˆ ์ˆ˜์ • API ํ˜ธ์ถœ ์‹œ์ž‘ - ์ˆ˜์ • ํ•ญ๋ชฉ ์ˆ˜: ${payload.length}', + ); + + // 1. ํ† ํฐ ํ™•์ธ + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + // 2. URI ์ƒ์„ฑ (๋ฐฑ์—”๋“œ ์ŠคํŽ™ ํ™•์ธ ํ•„์š”) + final uri = Uri.parse('${ApiConfig.baseUrl}/grading/student-answers'); + + appLog('[student_answer:student_answer_api] PATCH ์š”์ฒญ: $uri'); + developer.log('๐Ÿ“ [StudentAnswerApi] PATCH $uri'); + + // 3. API ํ˜ธ์ถœ + final response = await _httpClient + .patch( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: json.encode(payload), + ) + .timeout(const Duration(seconds: 10)); + + appLog( + '[student_answer:student_answer_api] ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: ${response.statusCode}', + ); + + // 4. ์—๋Ÿฌ ์ฒ˜๋ฆฌ + if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200 && response.statusCode != 204) { + throw Exception('๋‹ต์•ˆ ์ €์žฅ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'); + } + + appLog('[student_answer:student_answer_api] ๋‹ต์•ˆ ์ˆ˜์ • ์„ฑ๊ณต'); + } + + /// chapterId + academyUserId๋กœ ํ•™์ƒ ๋‹ต์•ˆ ์กฐํšŒ (grass API) + /// + /// **API ์ŠคํŽ™**: GET /grading/student-answers/grass?academyUserId={id}&chapterId={id} + /// + /// **์‘๋‹ต ๊ตฌ์กฐ**: + /// - is_correct๊ฐ€ null์ด๋ฉด ์•ˆ ํ‘ผ ๋ฌธ์ œ + /// - is_correct๊ฐ€ true๋ฉด ๋งž์€ ๋ฌธ์ œ + /// - is_correct๊ฐ€ false๋ฉด ํ‹€๋ฆฐ ๋ฌธ์ œ + Future> fetchStudentAnswersByChapterAndAcademy( + int chapterId, + int academyUserId, + ) async { + appLog( + '[student_answer:student_answer_api] Grass API ํ˜ธ์ถœ ์‹œ์ž‘ - chapterId: $chapterId, academyUserId: $academyUserId', + ); + + // 1. ํ† ํฐ ํ™•์ธ + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + appLog('[student_answer:student_answer_api] ์ธ์ฆ ํ† ํฐ ์—†์Œ'); + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + // 2. URI ์ƒ์„ฑ + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/student-answers/grass?academyUserId=$academyUserId&chapterId=$chapterId', + ); + + appLog('[student_answer:student_answer_api] GET ์š”์ฒญ: $uri'); + developer.log('๐Ÿ“ [StudentAnswerApi] GET $uri'); + + // 3. API ํ˜ธ์ถœ + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + appLog( + '[student_answer:student_answer_api] ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ: ${response.statusCode}', + ); + developer.log( + '๐Ÿ“ [StudentAnswerApi] Response status: ${response.statusCode}', + ); + + // 4. ์—๋Ÿฌ ์ฒ˜๋ฆฌ + if (response.statusCode == 401) { + appLog('[student_answer:student_answer_api] ์ธ์ฆ ์‹คํŒจ (401)'); + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + appLog( + '[student_answer:student_answer_api] API ํ˜ธ์ถœ ์‹คํŒจ - status: ${response.statusCode}', + ); + throw Exception('ํ•™์ƒ ๋‹ต์•ˆ ์กฐํšŒ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'); + } + + // 5. JSON ํŒŒ์‹ฑ + try { + final List data = json.decode(response.body); + final result = data + .map( + (item) => + StudentAnswerApiResponse.fromJson(item as Map), + ) + .toList(); + + appLog( + '[student_answer:student_answer_api] ์‘๋‹ต ํŒŒ์‹ฑ ์„ฑ๊ณต - ํ•ญ๋ชฉ ์ˆ˜: ${result.length}', + ); + appLog('[student_answer:student_answer_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}'); + return result; + } catch (e) { + appLog('[student_answer:student_answer_api] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + appLog('[student_answer:student_answer_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}'); + developer.log('โŒ [StudentAnswerApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + developer.log('โŒ [StudentAnswerApi] Response body: ${response.body}'); + rethrow; + } + } + + /// ๋‹จ์ผ ๋‹ต์•ˆ ์ˆ˜์ • API + /// + /// ์ŠคํŽ™: PUT /grading/student-answers/update + /// Body: + /// { + /// "student_answer_id": 1, + /// "chapter_id": 1, + /// "student_response_id": 1764406625968, + /// "question_number": 1, + /// "sub_question_number": 0, + /// "answer": "test" + /// } + Future updateSingleStudentAnswer({ + required int studentAnswerId, + required int studentResponseId, + required int questionNumber, + required int subQuestionNumber, + required String answer, + required int chapterId, + }) async { + appLog( + '[student_answer:student_answer_api] ๋‹จ์ผ ๋‹ต์•ˆ ์ˆ˜์ • API ํ˜ธ์ถœ ์‹œ์ž‘ - studentAnswerId: $studentAnswerId', + ); + + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/student-answers/update', + ); + + final body = { + 'student_answer_id': studentAnswerId, + 'chapter_id': chapterId, + 'student_response_id': studentResponseId, + 'question_number': questionNumber, + 'sub_question_number': subQuestionNumber, + 'answer': answer, + }; + + appLog('[student_answer:student_answer_api] PUT ์š”์ฒญ: $uri'); + appLog('[student_answer:student_answer_api] ์š”์ฒญ ๋ณธ๋ฌธ: ${json.encode(body)}'); + developer.log('๐Ÿ“ [StudentAnswerApi] PUT $uri'); + developer.log('๐Ÿ“ [StudentAnswerApi] Request body: ${json.encode(body)}'); + + final response = await _httpClient + .put( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: json.encode(body), + ) + .timeout(const Duration(seconds: 10)); + + appLog( + '[student_answer:student_answer_api] ๋‹จ์ผ ๋‹ต์•ˆ ์ˆ˜์ • ์‘๋‹ต ์ฝ”๋“œ: ${response.statusCode}', + ); + appLog( + '[student_answer:student_answer_api] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}', + ); + + if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode < 200 || response.statusCode >= 300) { + developer.log('โŒ [StudentAnswerApi] ์‘๋‹ต ๋ณธ๋ฌธ: ${response.body}'); + throw Exception('๋‹ต์•ˆ ์ˆ˜์ •์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.'); + } + + try { + final Map jsonBody = + json.decode(response.body) as Map; + final dto = UpdatedStudentAnswerDto.fromJson(jsonBody); + appLog('[student_answer:student_answer_api] ๋‹จ์ผ ๋‹ต์•ˆ ์ˆ˜์ • ์‘๋‹ต ํŒŒ์‹ฑ ์„ฑ๊ณต'); + return dto; + } catch (e) { + appLog('[student_answer:student_answer_api] ๋‹จ์ผ ๋‹ต์•ˆ ์ˆ˜์ • ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + developer.log('โŒ [StudentAnswerApi] updateSingleStudentAnswer parse error: $e'); + developer.log('โŒ [StudentAnswerApi] body: ${response.body}'); + rethrow; + } + } +} diff --git a/frontend/lib/services/student_answer_mapper.dart b/frontend/lib/services/student_answer_mapper.dart new file mode 100644 index 0000000..2ee889d --- /dev/null +++ b/frontend/lib/services/student_answer_mapper.dart @@ -0,0 +1,25 @@ +import '../domain/student_answer/student_answer_entity.dart'; +import 'student_answer_api.dart'; + +/// Student Answer API ์‘๋‹ต์„ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” Mapper +/// +/// Data Layer ๋‚ด๋ถ€ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋กœ, DTO โ†’ Entity ๋ณ€ํ™˜๋งŒ ๋‹ด๋‹น +class StudentAnswerMapper { + /// API ์‘๋‹ต ๋ฆฌ์ŠคํŠธ๋ฅผ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜ + List fromApi(List responses) { + return responses.map((response) { + return StudentAnswerEntity( + studentAnswerId: response.studentAnswerId, + studentResponseId: response.studentResponseId, + chapterId: response.chapterId, + page: response.page, + questionNumber: response.questionNumber, + subQuestionNumber: response.subQuestionNumber, + answer: response.answer, + sectionUrl: response.sectionUrl, + isCorrect: response.isCorrect, + score: response.score, + ); + }).toList(); + } +} diff --git a/frontend/lib/services/student_answer_repository_impl.dart b/frontend/lib/services/student_answer_repository_impl.dart new file mode 100644 index 0000000..1c40bb7 --- /dev/null +++ b/frontend/lib/services/student_answer_repository_impl.dart @@ -0,0 +1,81 @@ +import 'dart:developer' as developer; +import '../domain/student_answer/student_answer_entity.dart'; +import '../domain/student_answer/student_answer_repository.dart'; +import '../domain/student_answer/student_answer_update.dart'; +import '../domain/student_answer/student_answer_query.dart'; +import 'student_answer_api.dart'; +import 'student_answer_mapper.dart'; + +/// Student Answer Repository ๊ตฌํ˜„์ฒด +class StudentAnswerRepositoryImpl implements StudentAnswerRepository { + final StudentAnswerApi _api; + final StudentAnswerMapper _mapper; + + StudentAnswerRepositoryImpl({ + required StudentAnswerApi api, + required StudentAnswerMapper mapper, + }) : _api = api, + _mapper = mapper; + + @override + Future> getStudentAnswersByResponseId( + int studentResponseId, + ) async { + try { + // 1. API ํ˜ธ์ถœ + final apiResponses = await _api.fetchStudentAnswers(studentResponseId); + + // 2. Mapper๋กœ ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜ + return _mapper.fromApi(apiResponses); + } catch (e) { + developer.log('โŒ [StudentAnswerRepository] API ํ˜ธ์ถœ ์‹คํŒจ: $e'); + rethrow; + } + } + + @override + Future updateStudentAnswers(List updates) async { + try { + // StudentAnswerUpdate โ†’ Map ๋ณ€ํ™˜ (API ๋ ˆ์ด์–ด๋Š” ๋‚ฎ์€ ์ˆ˜์ค€์˜ ํƒ€์ž…๋งŒ ๋ฐ›์Œ) + final payload = updates.map((update) { + return { + 'student_answer_id': update.studentAnswerId, + 'answer': update.newAnswer, + }; + }).toList(); + + await _api.updateStudentAnswers(payload); + } catch (e) { + developer.log('โŒ [StudentAnswerRepository] ๋‹ต์•ˆ ์ˆ˜์ • ์‹คํŒจ: $e'); + rethrow; + } + } + + @override + Future> getStudentAnswers( + StudentAnswerQuery query, + ) async { + try { + List apiResponses; + + if (query is ChapterAndAcademyQuery) { + // Grass API ํ˜ธ์ถœ + apiResponses = await _api.fetchStudentAnswersByChapterAndAcademy( + query.chapterId, + query.academyUserId, + ); + } else if (query is ResponseIdQuery) { + // ๊ธฐ์กด Response API ํ˜ธ์ถœ + apiResponses = await _api.fetchStudentAnswers(query.studentResponseId); + } else { + throw ArgumentError('์ง€์›ํ•˜์ง€ ์•Š๋Š” Query ํƒ€์ž…์ž…๋‹ˆ๋‹ค.'); + } + + // Mapper๋กœ ์—”ํ‹ฐํ‹ฐ ๋ณ€ํ™˜ + return _mapper.fromApi(apiResponses); + } catch (e) { + developer.log('โŒ [StudentAnswerRepository] ๋‹ต์•ˆ ์กฐํšŒ ์‹คํŒจ: $e'); + rethrow; + } + } +} diff --git a/frontend/lib/services/upload_batch_service.dart b/frontend/lib/services/upload_batch_service.dart new file mode 100644 index 0000000..3fa0f4f --- /dev/null +++ b/frontend/lib/services/upload_batch_service.dart @@ -0,0 +1,425 @@ +import 'dart:convert'; + +import 'package:http/http.dart' as http; +import 'package:image_picker/image_picker.dart'; + +import '../config/api_config.dart'; +import '../utils/app_logger.dart'; +import 'auth_service.dart'; +import 'academy_service.dart'; + +class NoAcademyException implements Exception { + final String message; + NoAcademyException([ + this.message = '๋“ฑ๋ก๋œ ํ•™์›์ด ์—†์Šต๋‹ˆ๋‹ค. ํ•™์›์„ ๋จผ์ € ๋“ฑ๋กํ•ด์ฃผ์„ธ์š”.', + ]); + + @override + String toString() => message; +} + +class UploadContext { + final int academyUserId; + final int userId; + final int? classId; // TODO: class_id๋Š” null์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ถ”ํ›„ ๊ตฌํ˜„ ์‹œ ํ™•์ธ ํ•„์š” + final int academyId; + + const UploadContext({ + required this.academyUserId, + required this.userId, + this.classId, // nullable์ด๋ฏ€๋กœ required ์ œ๊ฑฐ + required this.academyId, + }); +} + +/// Presigned URL ๋ฐฐ์น˜ ์‘๋‹ต ๋ชจ๋ธ +class PresignedBatchResponse { + final int studentResponseId; + final List presignedUrls; + final String message; + + PresignedBatchResponse({ + required this.studentResponseId, + required this.presignedUrls, + required this.message, + }); + + factory PresignedBatchResponse.fromJson(Map json) { + return PresignedBatchResponse( + studentResponseId: json['studentResponseId'] as int, + presignedUrls: (json['presignedUrls'] as List) + .map((url) => url as String) + .toList(), + message: json['message'] as String? ?? 'success', + ); + } +} + +class UploadBatchService { + final AuthService _authService; + final AcademyService _academyService; + + UploadBatchService({AuthService? authService, AcademyService? academyService}) + : _authService = authService ?? AuthService(), + _academyService = academyService ?? AcademyService(); + + /// ํ˜„์žฌ ๋””ํดํŠธ ํ•™์› ๊ธฐ์ค€ UploadContext ์ƒ์„ฑ + Future buildContext() async { + final userIdStr = await _authService.getUserId(); + if (userIdStr == null) { + throw Exception('์‚ฌ์šฉ์ž ID๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + final academyCode = await _academyService.getDefaultAcademyCode(); + if (academyCode == null) { + throw NoAcademyException(); + } + + appLog('[UploadBatchService] ๋””ํดํŠธ ํ•™์› ์ฝ”๋“œ: $academyCode'); + + // ์บ์‹œ์—์„œ ํ•™์› ์ •๋ณด ์กฐํšŒ ์‹œ๋„ + var academy = await _academyService.getAcademyByCode(academyCode); + appLog('[UploadBatchService] ์บ์‹œ ์กฐํšŒ ๊ฒฐ๊ณผ: ${academy != null ? "์„ฑ๊ณต" : "์‹คํŒจ"}'); + + // ์บ์‹œ์— ์—†์œผ๋ฉด API์—์„œ ๊ฐ€์ ธ์™€์„œ ์บ์‹œ์— ์ €์žฅ + if (academy == null) { + appLog('[UploadBatchService] ์บ์‹œ์— ํ•™์› ์ •๋ณด๊ฐ€ ์—†์Œ. API์—์„œ ๊ฐ€์ ธ์˜ค๋Š” ์ค‘...'); + try { + final academies = await _academyService.getUserAcademies(userIdStr); + appLog('[UploadBatchService] API์—์„œ ${academies.length}๊ฐœ์˜ ํ•™์›์„ ๊ฐ€์ ธ์˜ด'); + + if (academies.isEmpty) { + throw NoAcademyException(); + } + + // ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์›๋งŒ ํ•„ํ„ฐ๋ง + final registeredAcademies = academies + .where((a) => a.registerStatus == 'Y') + .toList(); + + appLog('[UploadBatchService] ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์›: ${registeredAcademies.length}๊ฐœ'); + + if (registeredAcademies.isEmpty) { + throw NoAcademyException(); + } + + // ํ•™์› ์ฝ”๋“œ ๋ชฉ๋ก ๋กœ๊น… + final academyCodes = registeredAcademies + .map((a) => a.academyCode ?? 'null') + .toList(); + appLog('[UploadBatchService] ๋“ฑ๋ก์™„๋ฃŒ๋œ ํ•™์› ์ฝ”๋“œ ๋ชฉ๋ก: $academyCodes'); + appLog('[UploadBatchService] ์ฐพ๋Š” ํ•™์› ์ฝ”๋“œ: $academyCode'); + + // ํ•ด๋‹น academyCode๊ฐ€ ์žˆ๋Š”์ง€ ์ง์ ‘ ํ™•์ธ + final matchingAcademies = registeredAcademies + .where((a) => a.academyCode == academyCode) + .toList(); + + UserAcademyResponse foundAcademy; + if (matchingAcademies.isNotEmpty) { + foundAcademy = matchingAcademies.first; + appLog('[UploadBatchService] โœ… ๋””ํดํŠธ ํ•™์› ์ฝ”๋“œ($academyCode)๋ฅผ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.'); + } else { + foundAcademy = registeredAcademies.first; + appLog( + '[UploadBatchService] โš ๏ธ ๋””ํดํŠธ ํ•™์› ์ฝ”๋“œ($academyCode)๊ฐ€ ์—†์–ด์„œ ์ฒซ ๋ฒˆ์งธ ํ•™์›(${foundAcademy.academyCode})์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.', + ); + } + + await _academyService.saveAcademiesToCache(academies); + + // ์ฐพ์€ ํ•™์› ์‚ฌ์šฉ + academy = foundAcademy; + appLog('[UploadBatchService] ํ•™์› ์ •๋ณด ์„ค์ • ์™„๋ฃŒ: ${academy.academyName}'); + } catch (e) { + appLog('[UploadBatchService] โŒ ํ•™์› ๋ชฉ๋ก ๊ฐฑ์‹  ์‹คํŒจ: $e'); + rethrow; // ์—๋Ÿฌ๋ฅผ ๋‹ค์‹œ ๋˜์ ธ์„œ ์ƒ์œ„์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก + } + } + + // academy๋Š” ์ด ์‹œ์ ์—์„œ ํ•ญ์ƒ non-null์ด์–ด์•ผ ํ•จ + // (์บ์‹œ์—์„œ ์ฐพ์•˜๊ฑฐ๋‚˜, API์—์„œ ๊ฐ€์ ธ์™”๊ฑฐ๋‚˜, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๊ฒƒ) + // ํ•˜์ง€๋งŒ ๋ฐฉ์–ด์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์œ„ํ•ด null ์ฒดํฌ ์œ ์ง€ + // ignore: dead_code, unnecessary_null_comparison + if (academy == null) { + throw NoAcademyException(); + } + + final finalAcademy = academy; + appLog('[UploadBatchService] ์ตœ์ข… ํ•™์› ์ •๋ณด:'); + appLog(' - academyName: ${finalAcademy.academyName}'); + appLog(' - academyCode: ${finalAcademy.academyCode}'); + appLog(' - registerStatus: ${finalAcademy.registerStatus}'); + // TODO: class_id๋Š” null์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ถ”ํ›„ ๊ตฌํ˜„ ์‹œ ํ™•์ธ ํ•„์š” + if (finalAcademy.academy_user_id == null || + finalAcademy.academy_id == null || + finalAcademy.user_id == null) { + appLog('[UploadBatchService] โŒ ํ•™์› ์‘๋‹ต์— ํ•„์š”ํ•œ ID๊ฐ€ ์—†์Œ:'); + appLog(' - academy_user_id: ${finalAcademy.academy_user_id}'); + appLog(' - class_id: ${finalAcademy.class_id}'); + appLog(' - academy_id: ${finalAcademy.academy_id}'); + appLog(' - user_id: ${finalAcademy.user_id}'); + throw Exception('ํ•™์› ์‘๋‹ต์— ํ•„์š”ํ•œ ID๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ํ•™์› ์ •๋ณด๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•ด์ฃผ์„ธ์š”.'); + } + + appLog('[UploadBatchService] โœ… UploadContext ์ƒ์„ฑ ์™„๋ฃŒ:'); + appLog(' - academyUserId: ${finalAcademy.academy_user_id}'); + appLog(' - userId: ${finalAcademy.user_id}'); + appLog(' - classId: ${finalAcademy.class_id}'); + appLog(' - academyId: ${finalAcademy.academy_id}'); + + return UploadContext( + academyUserId: finalAcademy.academy_user_id!, + userId: finalAcademy.user_id!, + classId: finalAcademy.class_id, // nullable์ด๋ฏ€๋กœ null ์ฒดํฌ ์—ฐ์‚ฐ์ž ์ œ๊ฑฐ + academyId: finalAcademy.academy_id!, + ); + } + + /// /upload-url/batch ํ˜ธ์ถœํ•˜์—ฌ presigned URL ๋ชฉ๋ก ๋ฐ›๊ธฐ + Future requestPresignedUrls({ + required UploadContext context, + required List images, + }) async { + if (images.isEmpty) { + throw Exception('์—…๋กœ๋“œํ•  ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ์—…๋กœ๋“œ URL ๋ฐฐ์น˜๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + final uri = ApiConfig.getUploadUrlBatchUri(); + + final body = images.map((image) { + final segments = image.path.split('/'); + final fileName = segments.isNotEmpty ? segments.last : 'image.png'; + return { + 'academy_user_id': context.academyUserId, + 'user_id': context.userId, + 'class_id': context.classId, + 'academy_id': context.academyId, + 'file_name': fileName, + 'url': null, + }; + }).toList(); + + appLog('[UploadBatchService] POST $uri'); + appLog('[UploadBatchService] body: $body'); + + final response = await http.post( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + body: json.encode(body), + ); + + appLog( + '[UploadBatchService] status=${response.statusCode}, body=${response.body}', + ); + + if (response.statusCode < 200 || response.statusCode >= 300) { + throw Exception('Upload URL batch ์š”์ฒญ ์‹คํŒจ: ${response.statusCode}'); + } + + try { + final jsonResponse = json.decode(response.body) as Map; + final presignedResponse = PresignedBatchResponse.fromJson(jsonResponse); + appLog( + '[UploadBatchService] โœ… Presigned URLs ๋ฐ›์Œ: ${presignedResponse.presignedUrls.length}๊ฐœ', + ); + return presignedResponse; + } catch (e) { + appLog('[UploadBatchService] โŒ ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + throw Exception('Presigned URL ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + } + } + + /// ํŒŒ์ผ ํ™•์žฅ์ž๋กœ Content-Type ๊ฒฐ์ • + String _getContentType(String fileName) { + final extension = fileName.split('.').last.toLowerCase(); + switch (extension) { + case 'jpg': + case 'jpeg': + return 'image/jpeg'; + case 'png': + return 'image/png'; + case 'gif': + return 'image/gif'; + case 'webp': + return 'image/webp'; + default: + return 'image/jpeg'; // ๊ธฐ๋ณธ๊ฐ’ + } + } + + /// Presigned URL๋กœ ๋‹จ์ผ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ + Future uploadToPresignedUrl({ + required XFile file, + required String presignedUrl, + String? contentType, + }) async { + try { + // ํŒŒ์ผ๋ช…์—์„œ Content-Type ๊ฒฐ์ • + final fileName = file.path.split('/').last; + final finalContentType = contentType ?? _getContentType(fileName); + + appLog( + '[UploadBatchService] S3 ์—…๋กœ๋“œ ์‹œ์ž‘: $fileName (Content-Type: $finalContentType)', + ); + + // ํŒŒ์ผ ๋ฐ”์ดํŠธ ์ฝ๊ธฐ + final bytes = await file.readAsBytes(); + appLog('[UploadBatchService] ํŒŒ์ผ ํฌ๊ธฐ: ${bytes.length} bytes'); + + // Presigned URL๋กœ PUT ์š”์ฒญ + final response = await http.put( + Uri.parse(presignedUrl), + headers: {'Content-Type': finalContentType}, + body: bytes, + ); + + appLog('[UploadBatchService] S3 ์—…๋กœ๋“œ ์‘๋‹ต: status=${response.statusCode}'); + + if (response.statusCode < 200 || response.statusCode >= 300) { + throw Exception( + 'S3 ์—…๋กœ๋“œ ์‹คํŒจ: HTTP ${response.statusCode} ${response.reasonPhrase}', + ); + } + + appLog('[UploadBatchService] โœ… S3 ์—…๋กœ๋“œ ์„ฑ๊ณต: $fileName'); + } catch (e) { + appLog('[UploadBatchService] โŒ S3 ์—…๋กœ๋“œ ์‹คํŒจ: $e'); + rethrow; + } + } + + /// ๊ธฐ์กด ๋ฉ”์„œ๋“œ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•œ ๋ž˜ํผ (deprecated) + @Deprecated('uploadImages๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”') + Future requestBatch({ + required UploadContext context, + required List images, + }) async { + await requestPresignedUrls(context: context, images: images); + } +} + +/// ํŒŒ์ผ ํ™•์žฅ์ž๋กœ Content-Type ๊ฒฐ์ • (์™ธ๋ถ€ ํ•จ์ˆ˜) +String getContentTypeFromFileName(String fileName) { + final extension = fileName.split('.').last.toLowerCase(); + switch (extension) { + case 'jpg': + case 'jpeg': + return 'image/jpeg'; + case 'png': + return 'image/png'; + case 'gif': + return 'image/gif'; + case 'webp': + return 'image/webp'; + default: + return 'image/jpeg'; // ๊ธฐ๋ณธ๊ฐ’ + } +} + +/// Presigned URL๋กœ ๋‹จ์ผ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ (์™ธ๋ถ€ ํ•จ์ˆ˜) +Future uploadToPresignedUrl({ + required XFile file, + required String presignedUrl, + String? contentType, +}) async { + try { + // ํŒŒ์ผ๋ช…์—์„œ Content-Type ๊ฒฐ์ • + final fileName = file.path.split('/').last; + final finalContentType = + contentType ?? getContentTypeFromFileName(fileName); + + appLog( + '[UploadBatchService] S3 ์—…๋กœ๋“œ ์‹œ์ž‘: $fileName (Content-Type: $finalContentType)', + ); + + // ํŒŒ์ผ ๋ฐ”์ดํŠธ ์ฝ๊ธฐ + final bytes = await file.readAsBytes(); + appLog('[UploadBatchService] ํŒŒ์ผ ํฌ๊ธฐ: ${bytes.length} bytes'); + + // Presigned URL๋กœ PUT ์š”์ฒญ + final response = await http.put( + Uri.parse(presignedUrl), + headers: {'Content-Type': finalContentType}, + body: bytes, + ); + + appLog('[UploadBatchService] S3 ์—…๋กœ๋“œ ์‘๋‹ต: status=${response.statusCode}'); + + if (response.statusCode < 200 || response.statusCode >= 300) { + throw Exception( + 'S3 ์—…๋กœ๋“œ ์‹คํŒจ: HTTP ${response.statusCode} ${response.reasonPhrase}', + ); + } + + appLog('[UploadBatchService] โœ… S3 ์—…๋กœ๋“œ ์„ฑ๊ณต: $fileName'); + } catch (e) { + appLog('[UploadBatchService] โŒ S3 ์—…๋กœ๋“œ ์‹คํŒจ: $e'); + rethrow; + } +} + +/// ์ „์ฒด ์—…๋กœ๋“œ ํ๋ฆ„: Presigned URL ์š”์ฒญ โ†’ S3 ์—…๋กœ๋“œ (์™ธ๋ถ€ ํ•จ์ˆ˜) +/// +/// ๋‹ค๋ฅธ ์ฝ”๋“œ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์™ธ๋ถ€ ํ•จ์ˆ˜๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. +/// UploadBatchService ์ธ์Šคํ„ด์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. +/// +/// [onProgress] ์ฝœ๋ฐฑ์€ ๊ฐ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์™„๋ฃŒ ์‹œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค. +/// (uploadedCount, totalCount) ํ˜•ํƒœ๋กœ ์ง„ํ–‰ ์ƒํ™ฉ์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. +Future uploadImages({ + required List images, + UploadBatchService? uploadService, + void Function(int uploadedCount, int totalCount)? onProgress, +}) async { + if (images.isEmpty) { + throw Exception('์—…๋กœ๋“œํ•  ์ด๋ฏธ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + // UploadBatchService ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ (์—†์œผ๋ฉด ๊ธฐ๋ณธ ์ธ์Šคํ„ด์Šค ์‚ฌ์šฉ) + final service = uploadService ?? UploadBatchService(); + + appLog('[UploadBatchService] ๐Ÿš€ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์‹œ์ž‘: ${images.length}๊ฐœ'); + + // 1. UploadContext ์ƒ์„ฑ + final context = await service.buildContext(); + appLog('[UploadBatchService] โœ… UploadContext ์ƒ์„ฑ ์™„๋ฃŒ'); + + // 2. Presigned URL ๋ฐฐ์น˜ ์š”์ฒญ + final presignedResponse = await service.requestPresignedUrls( + context: context, + images: images, + ); + + if (presignedResponse.presignedUrls.length != images.length) { + throw Exception( + 'Presigned URL ๊ฐœ์ˆ˜ ๋ถˆ์ผ์น˜: ์ด๋ฏธ์ง€ ${images.length}๊ฐœ, URL ${presignedResponse.presignedUrls.length}๊ฐœ', + ); + } + + // 3. ๊ฐ Presigned URL๋กœ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ + appLog('[UploadBatchService] ๐Ÿ“ค S3 ์—…๋กœ๋“œ ์‹œ์ž‘...'); + for (int i = 0; i < images.length; i++) { + final file = images[i]; + final presignedUrl = presignedResponse.presignedUrls[i]; + + appLog( + '[UploadBatchService] ์—…๋กœ๋“œ ์ค‘: ${i + 1}/${images.length} - ${file.path.split('/').last}', + ); + + await uploadToPresignedUrl(file: file, presignedUrl: presignedUrl); + + // ์ง„ํ–‰ ์ƒํ™ฉ ์ฝœ๋ฐฑ ํ˜ธ์ถœ + onProgress?.call(i + 1, images.length); + } + + appLog('[UploadBatchService] โœ… ๋ชจ๋“  ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์™„๋ฃŒ!'); + return presignedResponse; +} diff --git a/frontend/lib/services/upload_sse_service.dart b/frontend/lib/services/upload_sse_service.dart new file mode 100644 index 0000000..d34dd41 --- /dev/null +++ b/frontend/lib/services/upload_sse_service.dart @@ -0,0 +1,105 @@ +import 'dart:async'; +import 'dart:developer' as developer; + +import 'package:launchdarkly_event_source_client/launchdarkly_event_source_client.dart'; + +import '../config/api_config.dart'; +import 'auth_service.dart'; + +/// ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ์šฉ SSE ์ŠคํŠธ๋ฆผ ์„œ๋น„์Šค +/// +/// - ์—ฐ๊ฒฐ: GET /storage/storage/upload-stream +/// - ์ด๋ฒคํŠธ: +/// - event: "upload-url" โ†’ data: presigned URL 1๊ฐœ +/// - event: "ping" โ†’ keep-alive +class UploadSseService { + final AuthService _authService; + + UploadSseService({AuthService? authService}) + : _authService = authService ?? AuthService(); + + SSEClient? _sseClient; + StreamSubscription? _subscription; + final StreamController _uploadUrlController = + StreamController.broadcast(); + + Stream get uploadUrlStream => _uploadUrlController.stream; + + bool get isConnected => _sseClient != null; + + /// SSE ๊ตฌ๋… ์‹œ์ž‘ + Future connect() async { + if (_sseClient != null) { + return; + } + + try { + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. SSE ์—ฐ๊ฒฐ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + final uri = ApiConfig.getUploadStreamUri(); + developer.log('[UploadSseService] Connecting to $uri'); + + // launchdarkly_event_source_client๋Š” eventTypes๋ฅผ Set์œผ๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค + _sseClient = SSEClient( + uri, + {'upload-url', 'ping'}, // ์ˆ˜์‹ ํ•  ์ด๋ฒคํŠธ ํƒ€์ž…๋“ค + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ); + + developer.log('[UploadSseService] SSE connected'); + + _subscription = _sseClient!.stream.listen( + (Event event) { + if (event is MessageEvent) { + final eventType = event.type; + final data = event.data; + + developer.log('[UploadSseService] event=$eventType, data=$data'); + + if (eventType == 'upload-url' && data.isNotEmpty) { + _uploadUrlController.add(data); + } else if (eventType == 'ping') { + // keep-alive + developer.log('[UploadSseService] ping'); + } + } else if (event is OpenEvent) { + developer.log('[UploadSseService] Connection opened'); + } + }, + onError: (error) { + developer.log('[UploadSseService] Stream error: $error'); + }, + onDone: () { + developer.log('[UploadSseService] Stream closed'); + }, + ); + } catch (e) { + developer.log('[UploadSseService] SSE connect error: $e'); + rethrow; + } + } + + /// ๊ตฌ๋… ์ข…๋ฃŒ + void disconnect() { + try { + _subscription?.cancel(); + _subscription = null; + _sseClient?.close(); + _sseClient = null; + developer.log('[UploadSseService] SSE disconnected'); + } catch (e) { + developer.log('[UploadSseService] SSE disconnect error: $e'); + } + } + + void dispose() { + disconnect(); + _uploadUrlController.close(); + } +} diff --git a/frontend/lib/services/user_service.dart b/frontend/lib/services/user_service.dart new file mode 100644 index 0000000..f47ed32 --- /dev/null +++ b/frontend/lib/services/user_service.dart @@ -0,0 +1,214 @@ +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'dart:developer' as developer; +import '../models/user.dart'; +import '../config/api_config.dart'; +import 'auth_service.dart'; + +/// ์‚ฌ์šฉ์ž ์ •๋ณด ๊ด€๋ฆฌ ์„œ๋น„์Šค +/// +/// ์ฃผ์š” ๊ธฐ๋Šฅ: +/// 1. ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ (/me API) +/// 2. SharedPreferences์— ์บ์‹ฑ +/// 3. ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ๋กœ ๋น ๋ฅธ ์ ‘๊ทผ +/// 4. ์ƒํƒœ ๋ณ€๊ฒฝ ์•Œ๋ฆผ (listeners) +class UserService { + final AuthService _authService; + + UserService({AuthService? authService}) + : _authService = authService ?? AuthService(); + + static const String _userDataKey = 'user_data'; + + // ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ (๋น ๋ฅธ ์ ‘๊ทผ) + User? _cachedUser; + + // ์ƒํƒœ ๋ณ€๊ฒฝ ๋ฆฌ์Šค๋„ˆ + final List _listeners = []; + + /// ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋ก + void addListener(Function(User?) listener) { + _listeners.add(listener); + } + + /// ๋ฆฌ์Šค๋„ˆ ์ œ๊ฑฐ + void removeListener(Function(User?) listener) { + _listeners.remove(listener); + } + + /// ๋ฆฌ์Šค๋„ˆ๋“ค์—๊ฒŒ ์•Œ๋ฆผ + void _notifyListeners() { + for (var listener in _listeners) { + listener(_cachedUser); + } + } + + /// ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ (์บ์‹œ์—์„œ) + User? getUser() { + return _cachedUser; + } + + /// ์‚ฌ์šฉ์ž ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ (ํŽธ์˜ ๋ฉ”์„œ๋“œ) + String? getUserName() { + return _cachedUser?.name; + } + + /// ์‚ฌ์šฉ์ž ID ๊ฐ€์ ธ์˜ค๊ธฐ (ํŽธ์˜ ๋ฉ”์„œ๋“œ) + int? getUserId() { + return _cachedUser?.userId; + } + + /// ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL ๊ฐ€์ ธ์˜ค๊ธฐ (ํŽธ์˜ ๋ฉ”์„œ๋“œ) + String? getProfileImageUrl() { + return _cachedUser?.profileImageUrl; + } + + /// ๋กœ์ปฌ์— ์ €์žฅ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด ๋กœ๋“œ (์•ฑ ์‹œ์ž‘ ์‹œ) + Future loadUserFromCache() async { + try { + final prefs = await SharedPreferences.getInstance(); + final userDataString = prefs.getString(_userDataKey); + + if (userDataString != null) { + final userJson = json.decode(userDataString) as Map; + _cachedUser = User.fromJson(userJson); + developer.log('โœ… User loaded from cache: ${_cachedUser?.name}'); + _notifyListeners(); + return _cachedUser; + } + developer.log('โ„น๏ธ No cached user data found'); + return null; + } catch (e) { + developer.log('โŒ Failed to load user from cache: $e'); + return null; + } + } + + /// ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ (API ํ˜ธ์ถœ) + /// ํ† ํฐ ๋งŒ๋ฃŒ ์‹œ ์ž๋™์œผ๋กœ ๊ฐฑ์‹  ์‹œ๋„ + Future fetchUserFromServer() async { + try { + // ์œ ํšจํ•œ Access Token ํ™•์ธ ๋ฐ ํ•„์š”์‹œ ๊ฐฑ์‹  + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + developer.log('โŒ No valid access token available'); + return null; + } + + developer.log('๐ŸŒ Fetching user info from server...'); + + // API ํ˜ธ์ถœ + var response = await http + .get( + ApiConfig.getMeUri(), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + // 401 ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ํ† ํฐ ๊ฐฑ์‹  ํ›„ ์žฌ์‹œ๋„ + if (response.statusCode == 401) { + developer.log('โš ๏ธ Unauthorized (401): Attempting token refresh...'); + + final refreshed = await _authService.refreshAccessToken(); + if (refreshed) { + // ๊ฐฑ์‹ ๋œ ํ† ํฐ์œผ๋กœ ์žฌ์‹œ๋„ + final newToken = await _authService.getAccessToken(); + if (newToken != null) { + developer.log('๐Ÿ”„ Retrying request with refreshed token...'); + response = await http + .get( + ApiConfig.getMeUri(), + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $newToken', + }, + ) + .timeout(const Duration(seconds: 10)); + } else { + developer.log('โŒ Failed to get refreshed token'); + return null; + } + } else { + developer.log('โŒ Token refresh failed - ๋กœ๊ทธ์ธ ํ•„์š”'); + return null; + } + } + + if (response.statusCode == 200) { + final responseData = json.decode(utf8.decode(response.bodyBytes)); + _cachedUser = User.fromJson(responseData); + + // SharedPreferences์— ์ €์žฅ + await _saveUserToCache(_cachedUser!); + + developer.log('โœ… User fetched from server: ${_cachedUser?.name}'); + _notifyListeners(); + return _cachedUser; + } else { + developer.log('โŒ Failed to fetch user: ${response.statusCode}'); + developer.log(' Response: ${response.body}'); + return null; + } + } catch (e) { + developer.log('โŒ Error fetching user from server: $e'); + return null; + } + } + + /// ์‚ฌ์šฉ์ž ์ •๋ณด ์ €์žฅ (๋‚ด๋ถ€์šฉ) + Future _saveUserToCache(User user) async { + try { + final prefs = await SharedPreferences.getInstance(); + final userDataString = json.encode(user.toJson()); + await prefs.setString(_userDataKey, userDataString); + developer.log('โœ… User saved to cache'); + } catch (e) { + developer.log('โŒ Failed to save user to cache: $e'); + } + } + + /// ์‚ฌ์šฉ์ž ์ •๋ณด ์ดˆ๊ธฐํ™” (์•ฑ ์‹œ์ž‘ ์‹œ ๋˜๋Š” ๋กœ๊ทธ์ธ ์งํ›„ ํ˜ธ์ถœ) + /// + /// ์ „๋žต: + /// 1. ์บ์‹œ์—์„œ ๋จผ์ € ๋กœ๋“œ (๋น ๋ฅธ UI ํ‘œ์‹œ) + /// 2. ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์„œ๋ฒ„ ๋™๊ธฐํ™” (์ตœ์‹  ๋ฐ์ดํ„ฐ) + Future initialize() async { + developer.log('๐Ÿ”„ Initializing UserService...'); + + // 1. ์บ์‹œ์—์„œ ๋จผ์ € ๋กœ๋“œ (๋น ๋ฅธ UI ํ‘œ์‹œ) + final cachedUser = await loadUserFromCache(); + + // 2. ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์„œ๋ฒ„ ๋™๊ธฐํ™” (์ตœ์‹  ๋ฐ์ดํ„ฐ) + fetchUserFromServer().catchError((e) { + developer.log('โš ๏ธ Background sync failed: $e'); + // ์บ์‹œ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ + return null; + }); + + return cachedUser; + } + + /// ์‚ฌ์šฉ์ž ์ •๋ณด ๊ฐ•์ œ ์ƒˆ๋กœ๊ณ ์นจ + /// (ํ”„๋กœํ•„ ์ˆ˜์ • ํ›„ ๋“ฑ) + Future refresh() async { + developer.log('๐Ÿ”„ Refreshing user data...'); + return await fetchUserFromServer(); + } + + /// ์‚ฌ์šฉ์ž ์ •๋ณด ์‚ญ์ œ (๋กœ๊ทธ์•„์›ƒ ์‹œ) + Future clearUser() async { + try { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove(_userDataKey); + _cachedUser = null; + developer.log('โœ… User data cleared'); + _notifyListeners(); + } catch (e) { + developer.log('โŒ Failed to clear user data: $e'); + } + } +} diff --git a/frontend/lib/services/workbook_api.dart b/frontend/lib/services/workbook_api.dart new file mode 100644 index 0000000..3ada0b3 --- /dev/null +++ b/frontend/lib/services/workbook_api.dart @@ -0,0 +1,321 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:developer' as developer; +import 'package:http/http.dart' as http; +import '../config/api_config.dart'; +import 'auth_service.dart'; +import '../utils/api_date_formatter.dart'; +import '../utils/app_logger.dart'; + +/// โš ๏ธ Dart ๋ฌธ๋ฒ•์ƒ ํด๋ž˜์Šค๋Š” ํŒŒ์ผ ์ตœ์ƒ์œ„์— ์„ ์–ธ +/// WorkbookApiResponse์™€ BookData๋ฅผ ํŒŒ์ผ ์ตœ์ƒ์œ„๋กœ ์ด๋™ + +/// API ์‘๋‹ต DTO (์„œ๋ฒ„ ์‘๋‹ต ๊ตฌ์กฐ ๊ทธ๋Œ€๋กœ) +/// +/// API ์‘๋‹ต์€ ๋ฐฐ์—ด ํ˜•ํƒœ: [{academyUserId: 20, books: [...]}, {academyUserId: 25, books: [...]}] +class WorkbookApiResponse { + final int academyUserId; + final List books; + + WorkbookApiResponse({required this.academyUserId, required this.books}); + + factory WorkbookApiResponse.fromJson(Map json) { + return WorkbookApiResponse( + academyUserId: json['academyUserId'] as int? ?? 0, + books: + (json['books'] as List?) + ?.map((item) => BookData.fromJson(item)) + .toList() ?? + [], + ); + } +} + +/// Book ๋ฐ์ดํ„ฐ DTO +/// +/// API ์‘๋‹ต์˜ books ๋ฐฐ์—ด ๋‚ด๋ถ€ ๊ฐ์ฒด ๊ตฌ์กฐ +class BookData { + final int? bookId; // book_id + final String? bookName; // book_name + final int bookPage; // book_page + final String? bookSemester; // book_semester + final String? bookImageUrl; // book_image_url + final int totalSolvedPages; // total_solved_pages + final String? latestUpdatedAt; // latest_updated_at + + BookData({ + this.bookId, + this.bookName, + required this.bookPage, + this.bookSemester, + this.bookImageUrl, + required this.totalSolvedPages, + this.latestUpdatedAt, + }); + + factory BookData.fromJson(Map json) { + return BookData( + bookId: json['book_id'] as int?, + bookName: json['book_name'] as String?, + bookPage: json['book_page'] as int? ?? 0, + bookSemester: json['book_semester'] as String?, + bookImageUrl: json['book_image_url'] as String?, + totalSolvedPages: json['total_solved_pages'] as int? ?? 0, + latestUpdatedAt: json['latest_updated_at'] as String?, + ); + } +} + +/// Workbook API ํ˜ธ์ถœ ์ „์šฉ ๋ ˆ์ด์–ด +class WorkbookApi { + WorkbookApi({ + required AuthService authService, + required http.Client httpClient, + }) : _authService = authService, + _httpClient = httpClient; + + final AuthService _authService; + final http.Client _httpClient; + + /// ์—ฌ๋Ÿฌ academyUserId์— ๋Œ€ํ•œ ๋ฌธ์ œ์ง‘ ์กฐํšŒ (ํ•œ ๋ฒˆ์—) + /// + /// ์—ฌ๋Ÿฌ academyUserId๋ฅผ ์ฝค๋งˆ๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ํ•œ ๋ฒˆ์— ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. + /// ์˜ˆ: academyUserId=20,25 + /// + /// [academyUserIds]: ์กฐํšŒํ•  academyUserId ๋ฆฌ์ŠคํŠธ + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ๊ฐ academyUserId๋ณ„ WorkbookApiResponse ๋ฆฌ์ŠคํŠธ + Future> fetchWorkbooks( + List academyUserIds, + ) async { + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + // academyUserIds๋ฅผ ์ฝค๋งˆ๋กœ ๊ตฌ๋ถ„ํ•œ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ + final idsParam = academyUserIds.join(','); + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/student-responses/workbook?academyUserIds=$idsParam', + ); + + developer.log('๐Ÿ“š [WorkbookApi] GET $uri'); + + final response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 10)); + + developer.log('๐Ÿ“š [WorkbookApi] Response status: ${response.statusCode}'); + + if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode != 200) { + throw Exception('Workbook API ํ˜ธ์ถœ ์‹คํŒจ (status: ${response.statusCode})'); + } + + try { + final List data = json.decode(response.body); + + // API ์‘๋‹ต์€ ๋ฐฐ์—ด: [{academyUserId: 20, books: [...]}, {academyUserId: 25, books: [...]}] + final result = data + .map( + (item) => + WorkbookApiResponse.fromJson(item as Map), + ) + .toList(); + + return result; + } catch (e) { + developer.log('โŒ [WorkbookApi] ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + developer.log('โŒ [WorkbookApi] Response body: ${response.body}'); + rethrow; + } + } + + /// ๋‚ ์งœ ๋ฒ”์œ„๋กœ ๋ฌธ์ œ์ง‘ ํ•™์Šต ํ˜„ํ™ฉ ์กฐํšŒ + /// + /// **์ค‘์š”: ๋‚ ์งœ ๋ฐ ํƒ€์ž„์กด ๊ทœ์•ฝ** + /// - startDate์™€ endDate๋Š” KST(UTC+9) ๊ธฐ์ค€์œผ๋กœ ํ•ด์„๋ฉ๋‹ˆ๋‹ค. + /// - ์ž…๋ ฅ DateTime์€ ๋ฐ˜๋“œ์‹œ UTC ๊ธฐ๋ฐ˜์ด์–ด์•ผ ํ•˜๋ฉฐ, ์ด๋ฏธ KST๋กœ ๋ณ€ํ™˜๋œ ์ƒํƒœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. + /// - API ์š”์ฒญ ์‹œ ISO8601 ๋ฌธ์ž์—ด์— timezone ์ •๋ณด(+09:00)๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. + /// - ์„œ๋ฒ„๋Š” ์ด timezone ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ KST ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. + /// + /// **์˜ˆ์‹œ:** + /// - startDate: DateTime.utc(2025, 11, 1) (KST ๊ธฐ์ค€ 2025-11-01์„ ์˜๋ฏธ) + /// - ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ: "2025-11-01T00:00:00+09:00" + /// - ์„œ๋ฒ„๋Š” KST ๊ธฐ์ค€ 2025-11-01 00:00:00 ~ 23:59:59 ๋ฒ”์œ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. + /// + /// [academyUserIds]: ์กฐํšŒํ•  academyUserId ๋ฆฌ์ŠคํŠธ (๋น„์–ด์žˆ์œผ๋ฉด ์•ˆ๋จ) + /// [startDate]: ์‹œ์ž‘ ๋‚ ์งœ (KST ๊ธฐ์ค€, UTC ๊ธฐ๋ฐ˜ DateTime, ์‹œ๊ฐ„ ์ •๋ณด ๋ฌด์‹œ) + /// [endDate]: ์ข…๋ฃŒ ๋‚ ์งœ (KST ๊ธฐ์ค€, UTC ๊ธฐ๋ฐ˜ DateTime, ์‹œ๊ฐ„ ์ •๋ณด ๋ฌด์‹œ) + /// + /// ๋ฐ˜ํ™˜๊ฐ’: ๊ฐ academyUserId๋ณ„ WorkbookApiResponse ๋ฆฌ์ŠคํŠธ + /// + /// ์˜ˆ์™ธ: + /// - ArgumentError: startDate > endDate ๋˜๋Š” academyUserIds๊ฐ€ ๋น„์–ด์žˆ์„ ๋•Œ + /// - Exception: API ํ˜ธ์ถœ ์‹คํŒจ ์‹œ + Future> fetchWorkbooksByDateRange({ + required List academyUserIds, + required DateTime startDate, + required DateTime endDate, + }) async { + // Validation + if (academyUserIds.isEmpty) { + throw ArgumentError('academyUserIds๋Š” ๋น„์–ด์žˆ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + + // ๋‚ ์งœ ๋น„๊ต (์‹œ๊ฐ„ ์ •๋ณด ๋ฌด์‹œ) + final startDateOnly = DateTime.utc(startDate.year, startDate.month, startDate.day); + final endDateOnly = DateTime.utc(endDate.year, endDate.month, endDate.day); + + if (startDateOnly.isAfter(endDateOnly)) { + throw ArgumentError('startDate๋Š” endDate๋ณด๋‹ค ์ด์ „์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.'); + } + + final token = await _authService.ensureValidAccessToken(); + if (token == null) { + throw Exception('์ธ์ฆ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.'); + } + + // KST ๊ธฐ์ค€ ISO8601 ๋ฌธ์ž์—ด ์ƒ์„ฑ (timezone ํฌํ•จ) + // ์ค‘์š”: startDate์™€ endDate๋Š” ์ด๋ฏธ KST๋กœ ๋ณ€ํ™˜๋œ ์ƒํƒœ์ด๋ฏ€๋กœ + // ApiDateFormatter๊ฐ€ UTC ๊ธฐ๋ฐ˜์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + final startIso = ApiDateFormatter.formatDayStart(startDateOnly); + final endIso = ApiDateFormatter.formatDayEnd(endDateOnly); + + // academyUserIds๋ฅผ ์ฝค๋งˆ๋กœ ๊ตฌ๋ถ„ํ•œ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ + final idsParam = academyUserIds.join(','); + + // URI ์ƒ์„ฑ + final uri = Uri.parse( + '${ApiConfig.baseUrl}/grading/student-responses/workbook/range' + '?academyUserIds=$idsParam' + '&startDate=${Uri.encodeComponent(startIso)}' + '&endDate=${Uri.encodeComponent(endIso)}', + ); + + developer.log('๐Ÿ“š [WorkbookApi] GET $uri'); + developer.log('๐Ÿ“š [WorkbookApi] startDate: $startIso, endDate: $endIso'); + appLog('[workbook:workbook_api] API ํ˜ธ์ถœ ์‹œ์ž‘'); + appLog('[workbook:workbook_api] GET ์š”์ฒญ: $uri'); + appLog('[workbook:workbook_api] academyUserIds: $idsParam'); + appLog('[workbook:workbook_api] startDate: $startIso'); + appLog('[workbook:workbook_api] endDate: $endIso'); + + http.Response? response; + String? responseBody; + + try { + response = await _httpClient + .get( + uri, + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer $token', + }, + ) + .timeout(const Duration(seconds: 15)); + + developer.log('๐Ÿ“š [WorkbookApi] Response status: ${response.statusCode}'); + + // ์ƒํƒœ ์ฝ”๋“œ๋ณ„ ์ฒ˜๋ฆฌ + if (response.statusCode == 401) { + throw Exception('์ธ์ฆ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode == 400) { + throw Exception('์ž˜๋ชป๋œ ์š”์ฒญ์ž…๋‹ˆ๋‹ค. ๋‚ ์งœ ๋ฒ”์œ„๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”.'); + } + if (response.statusCode == 404) { + throw Exception('์š”์ฒญํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + } + if (response.statusCode == 204) { + return []; + } + if (response.statusCode != 200) { + throw Exception('Workbook API ํ˜ธ์ถœ ์‹คํŒจ (status: ${response.statusCode})'); + } + + // JSON ํŒŒ์‹ฑ + responseBody = response.body; + if (responseBody.isEmpty) { + return []; + } + + final dynamic decoded = json.decode(responseBody); + + if (decoded is! List) { + developer.log('โŒ [WorkbookApi] ์‘๋‹ต์ด ๋ฐฐ์—ด์ด ์•„๋‹™๋‹ˆ๋‹ค: ${decoded.runtimeType}'); + throw Exception('์„œ๋ฒ„ ์‘๋‹ต ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.'); + } + + final List data = decoded; + + // ์‘๋‹ต ๊ตฌ์กฐ ๋กœ๊ทธ ์ถœ๋ ฅ + appLog('[workbook:workbook_api] ์‘๋‹ต ๊ตฌ์กฐ:'); + appLog('[workbook:workbook_api] ์‘๋‹ต ํ•ญ๋ชฉ ์ˆ˜: ${data.length}'); + for (var i = 0; i < data.length; i++) { + final item = data[i]; + if (item is Map) { + appLog('[workbook:workbook_api] [ํ•ญ๋ชฉ ${i + 1}]'); + appLog('[workbook:workbook_api] - academyUserId: ${item['academyUserId']}'); + if (item['books'] != null && item['books'] is List) { + final books = item['books'] as List; + appLog('[workbook:workbook_api] - books ๊ฐœ์ˆ˜: ${books.length}'); + for (var j = 0; j < books.length; j++) { + final book = books[j]; + if (book is Map) { + appLog('[workbook:workbook_api] [์ฑ… ${j + 1}]'); + appLog('[workbook:workbook_api] - book_id: ${book['book_id']}'); + appLog('[workbook:workbook_api] - book_name: ${book['book_name']}'); + appLog('[workbook:workbook_api] - book_page: ${book['book_page']}'); + appLog('[workbook:workbook_api] - book_semester: ${book['book_semester']}'); + appLog('[workbook:workbook_api] - book_image_url: ${book['book_image_url']}'); + appLog('[workbook:workbook_api] - total_solved_pages: ${book['total_solved_pages']}'); + appLog('[workbook:workbook_api] - latest_updated_at: ${book['latest_updated_at']}'); + } + } + } else { + appLog('[workbook:workbook_api] - books: null ๋˜๋Š” ๋ฐฐ์—ด์ด ์•„๋‹˜'); + } + } + } + + final result = data + .map( + (item) { + if (item is! Map) { + throw Exception('์‘๋‹ต ํ•ญ๋ชฉ์ด ์˜ฌ๋ฐ”๋ฅธ ํ˜•์‹์ด ์•„๋‹™๋‹ˆ๋‹ค.'); + } + return WorkbookApiResponse.fromJson(item); + }, + ) + .toList(); + + developer.log('๐Ÿ“š [WorkbookApi] ํŒŒ์‹ฑ ์„ฑ๊ณต: ${result.length}๊ฐœ ํ•ญ๋ชฉ'); + appLog('[workbook:workbook_api] ํŒŒ์‹ฑ ์„ฑ๊ณต: ${result.length}๊ฐœ ํ•ญ๋ชฉ'); + return result; + } on TimeoutException { + developer.log('โŒ [WorkbookApi] ์š”์ฒญ ์‹œ๊ฐ„ ์ดˆ๊ณผ'); + throw Exception('์š”์ฒญ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”.'); + } on FormatException catch (e) { + developer.log('โŒ [WorkbookApi] JSON ํŒŒ์‹ฑ ์‹คํŒจ: $e'); + if (responseBody != null) { + developer.log('โŒ [WorkbookApi] Response body: $responseBody'); + } + throw Exception('์„œ๋ฒ„ ์‘๋‹ต์„ ํŒŒ์‹ฑํ•˜๋Š”๋ฐ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } catch (e) { + if (e is Exception) { + rethrow; + } + developer.log('โŒ [WorkbookApi] ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜: $e'); + throw Exception('์•Œ ์ˆ˜ ์—†๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.'); + } + } +} diff --git a/frontend/lib/services/workbook_repository_impl.dart b/frontend/lib/services/workbook_repository_impl.dart new file mode 100644 index 0000000..a611938 --- /dev/null +++ b/frontend/lib/services/workbook_repository_impl.dart @@ -0,0 +1,141 @@ +import 'dart:developer' as developer; +import 'package:shared_preferences/shared_preferences.dart'; +import 'dart:convert'; +import '../domain/workbook/workbook_repository.dart'; +import '../domain/workbook/workbook_summary_entity.dart'; +import 'workbook_api.dart'; +import '../data/mappers/workbook_mapper.dart'; +import 'academy_service.dart'; + +/// Workbook Repository ๊ตฌํ˜„์ฒด +/// +/// API ํ˜ธ์ถœ, className ์กฐํšŒ, ์บ์‹ฑ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. +class WorkbookRepositoryImpl implements WorkbookRepository { + WorkbookRepositoryImpl({ + required WorkbookApi api, + required WorkbookMapper mapper, + required AcademyService academyService, + }) : _api = api, + _mapper = mapper, + _academyService = academyService; + + final WorkbookApi _api; + final WorkbookMapper _mapper; + final AcademyService _academyService; + + static const String _cacheKeyPrefix = 'workbook_summaries_'; + + @override + Future>> + getWorkbookSummariesByAcademyUserIds(List academyUserIds) async { + if (academyUserIds.isEmpty) { + return {}; + } + + try { + // 1. Workbook API ํ˜ธ์ถœ + final apiResponses = await _api.fetchWorkbooks(academyUserIds); + + // 2. className ์กฐํšŒ (AcademyService ์‚ฌ์šฉ) + // โš ๏ธ ์ฃผ์˜: academyUserId์™€ assigneeId๋Š” 1:1 ๊ด€๊ณ„์ž…๋‹ˆ๋‹ค. + final classNameMapStr = await _academyService.getClassesByAssigneeIds( + academyUserIds.map((id) => id.toString()).toList(), + ); + + // 3. String โ†’ int ํ‚ค ๋ณ€ํ™˜ + final classNameMap = {}; + for (final id in academyUserIds) { + final className = classNameMapStr[id.toString()]; + // ๋นˆ ๋ฌธ์ž์—ด๋„ null๋กœ ์ฒ˜๋ฆฌ + classNameMap[id] = (className != null && className.isNotEmpty) + ? className + : null; + } + + // 4. Mapper๋กœ ๋ณ€ํ™˜ (์‹ค์ œ classNameMap ์ „๋‹ฌ) + final summariesMap = await _mapper.convertApiResponsesToSummaries( + apiResponses, + classNameMap, + ); + + // 5. ์บ์‹œ ์ €์žฅ + for (final entry in summariesMap.entries) { + await cacheWorkbookSummaries(entry.key, entry.value); + } + + return summariesMap; + } catch (e) { + developer.log('โŒ [WorkbookRepository] API ํ˜ธ์ถœ ์‹คํŒจ: $e'); + + // ์บ์‹œ์—์„œ ๋กœ๋“œ ์‹œ๋„ + final cachedMap = >{}; + for (final id in academyUserIds) { + final cached = await getCachedWorkbookSummaries(id); + if (cached != null && cached.isNotEmpty) { + cachedMap[id] = cached; + } + } + + if (cachedMap.isNotEmpty) { + developer.log('โœ… [WorkbookRepository] ์บ์‹œ์—์„œ ๋กœ๋“œ ์„ฑ๊ณต'); + return cachedMap; + } + + rethrow; + } + } + + @override + Future?> getCachedWorkbookSummaries( + int academyUserId, + ) async { + try { + final prefs = await SharedPreferences.getInstance(); + final cacheKey = '$_cacheKeyPrefix$academyUserId'; + final cachedJson = prefs.getString(cacheKey); + + if (cachedJson == null) { + return null; + } + + final List data = json.decode(cachedJson); + final result = data + .map((item) => WorkbookSummaryEntity.fromJson(item)) + .toList(); + return result; + } catch (e) { + developer.log('โš ๏ธ [WorkbookRepository] ์บ์‹œ ๋กœ๋“œ ์‹คํŒจ: $e'); + return null; + } + } + + @override + Future cacheWorkbookSummaries( + int academyUserId, + List summaries, + ) async { + try { + final prefs = await SharedPreferences.getInstance(); + final cacheKey = '$_cacheKeyPrefix$academyUserId'; + final jsonData = json.encode(summaries.map((s) => s.toJson()).toList()); + await prefs.setString(cacheKey, jsonData); + developer.log('โœ… [WorkbookRepository] ์บ์‹œ ์ €์žฅ ์™„๋ฃŒ: $academyUserId'); + } catch (e) { + developer.log('โš ๏ธ [WorkbookRepository] ์บ์‹œ ์ €์žฅ ์‹คํŒจ: $e'); + } + } + + @override + Future clearCache() async { + try { + final prefs = await SharedPreferences.getInstance(); + final keys = prefs.getKeys().where((k) => k.startsWith(_cacheKeyPrefix)); + for (final key in keys) { + await prefs.remove(key); + } + developer.log('โœ… [WorkbookRepository] ์บ์‹œ ์ดˆ๊ธฐํ™” ์™„๋ฃŒ'); + } catch (e) { + developer.log('โš ๏ธ [WorkbookRepository] ์บ์‹œ ์ดˆ๊ธฐํ™” ์‹คํŒจ: $e'); + } + } +} diff --git a/frontend/lib/services/workbook_use_case.dart b/frontend/lib/services/workbook_use_case.dart new file mode 100644 index 0000000..9401fff --- /dev/null +++ b/frontend/lib/services/workbook_use_case.dart @@ -0,0 +1,173 @@ +import '../domain/workbook/workbook_summary_entity.dart'; +import '../services/workbook_api.dart'; +import '../screens/workbook/models/class_data.dart'; +import '../screens/workbook/models/workbook_info.dart'; +import '../screens/workbook/models/workbook_data.dart'; + +/// Workbook ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ UseCase +/// +/// API ์‘๋‹ต์„ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ , UI ๋ชจ๋ธ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. +/// className์€ ์ด๋ฏธ Repository์—์„œ ์กฐํšŒ๋˜์–ด ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. +class WorkbookUseCase { + /// API ์‘๋‹ต์„ WorkbookSummaryEntity๋กœ ๋ณ€ํ™˜ + /// + /// [apiResponses]: API ์‘๋‹ต ๋ฆฌ์ŠคํŠธ (์—ฌ๋Ÿฌ academyUserId) + /// [classNameMap]: academyUserId โ†’ className ๋งคํ•‘ (Repository์—์„œ ์กฐํšŒ๋จ) + Future>> convertApiResponsesToSummaries( + List apiResponses, + Map classNameMap, + ) async { + final summariesMap = >{}; + + for (final apiResponse in apiResponses) { + final summaries = []; + final className = classNameMap[apiResponse.academyUserId]; + + for (final bookData in apiResponse.books) { + // latest_updated_at ํŒŒ์‹ฑ + DateTime? lastStudyDate; + if (bookData.latestUpdatedAt != null && bookData.latestUpdatedAt!.isNotEmpty) { + try { + lastStudyDate = DateTime.parse(bookData.latestUpdatedAt!).toLocal(); + } catch (e) { + // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ null ์œ ์ง€ + } + } + + // WorkbookSummaryEntity ์ƒ์„ฑ + final summary = WorkbookSummaryEntity( + bookId: bookData.bookId, + bookName: bookData.bookName ?? '์•Œ ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ์ง‘', + coverImageUrl: bookData.bookImageUrl, + totalPages: bookData.bookPage, // book_page ์‚ฌ์šฉ + totalSolvedPages: bookData.totalSolvedPages, + lastStudyDate: lastStudyDate, + academyUserId: apiResponse.academyUserId, + className: className, + bookSemester: bookData.bookSemester, + ); + + summaries.add(summary); + } + + summariesMap[apiResponse.academyUserId] = summaries; + } + + return summariesMap; + } + + /// WorkbookSummaryEntity ๋ฆฌ์ŠคํŠธ๋ฅผ ClassData๋กœ ๋ณ€ํ™˜ + /// + /// DateTime ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ ํ›„ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + List convertToClassData( + Map> summariesByAcademyUserId, + ) { + final classDataList = []; + + summariesByAcademyUserId.forEach((academyUserId, summaries) { + if (summaries.isEmpty) return; + + final className = summaries.first.className ?? '์•Œ ์ˆ˜ ์—†๋Š” ํด๋ž˜์Šค'; + + // DateTime ๊ธฐ์ค€์œผ๋กœ ์ตœ์‹  ๋‚ ์งœ ์ฐพ๊ธฐ + final lastStudyDate = _getLatestDateTime(summaries); + + // WorkbookInfo ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ + final workbooks = summaries.map((summary) { + return WorkbookInfo( + name: summary.bookName, + lastStudyDate: summary.formattedLastStudyDate, + progress: summary.progress, + thumbnailPath: summary.thumbnailPath, + bookId: summary.bookId, + academyUserId: summary.academyUserId, + ); + }).toList(); + + classDataList.add(ClassData( + className: className, + lastStudyDate: _formatDateTime(lastStudyDate), + workbooks: workbooks, + )); + }); + + // DateTime ๊ธฐ์ค€ ์ •๋ ฌ ํ›„ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ + classDataList.sort((a, b) { + final dateA = _parseFormattedDate(a.lastStudyDate); + final dateB = _parseFormattedDate(b.lastStudyDate); + return dateB.compareTo(dateA); // ์ตœ์‹ ์ˆœ + }); + + return classDataList; + } + + /// WorkbookSummaryEntity ๋ฆฌ์ŠคํŠธ๋ฅผ WorkbookData๋กœ ๋ณ€ํ™˜ + /// + /// DateTime ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ ํ›„ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + List convertToWorkbookData( + Map> summariesByAcademyUserId, + ) { + final workbookDataList = []; + + summariesByAcademyUserId.forEach((academyUserId, summaries) { + for (final summary in summaries) { + workbookDataList.add(WorkbookData( + workbookName: summary.bookName, + lastStudyDate: summary.formattedLastStudyDate, + progress: summary.progress, + thumbnailPath: summary.thumbnailPath, + className: summary.className ?? '์•Œ ์ˆ˜ ์—†๋Š” ํด๋ž˜์Šค', + bookId: summary.bookId, + academyUserId: summary.academyUserId, + )); + } + }); + + // DateTime ๊ธฐ์ค€ ์ •๋ ฌ ํ›„ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ + workbookDataList.sort((a, b) { + final dateA = _parseFormattedDate(a.lastStudyDate); + final dateB = _parseFormattedDate(b.lastStudyDate); + return dateB.compareTo(dateA); // ์ตœ์‹ ์ˆœ + }); + + return workbookDataList; + } + + /// summaries์—์„œ ๊ฐ€์žฅ ์ตœ๊ทผ DateTime ์ฐพ๊ธฐ + DateTime? _getLatestDateTime(List summaries) { + DateTime? latest; + for (final summary in summaries) { + if (summary.lastStudyDate != null) { + if (latest == null || summary.lastStudyDate!.isAfter(latest)) { + latest = summary.lastStudyDate; + } + } + } + return latest; + } + + /// DateTime์„ YYYY.MM.DD ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ + String _formatDateTime(DateTime? dateTime) { + if (dateTime == null) return ''; + return '${dateTime.year}.${dateTime.month.toString().padLeft(2, '0')}.${dateTime.day.toString().padLeft(2, '0')}'; + } + + /// YYYY.MM.DD ํ˜•์‹ ๋ฌธ์ž์—ด์„ DateTime์œผ๋กœ ํŒŒ์‹ฑ + DateTime _parseFormattedDate(String dateStr) { + if (dateStr.isEmpty) return DateTime(1970, 1, 1); // ๊ธฐ๋ณธ๊ฐ’ + try { + final parts = dateStr.split('.'); + if (parts.length == 3) { + return DateTime( + int.parse(parts[0]), + int.parse(parts[1]), + int.parse(parts[2]), + ); + } + } catch (e) { + // ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๊ธฐ๋ณธ๊ฐ’ + } + return DateTime(1970, 1, 1); + } +} + diff --git a/frontend/lib/theme/app_theme.dart b/frontend/lib/theme/app_theme.dart new file mode 100644 index 0000000..4416c86 --- /dev/null +++ b/frontend/lib/theme/app_theme.dart @@ -0,0 +1,180 @@ +import 'package:flutter/material.dart'; + +class AppTheme { + // Colors from Figma design system + static const Color primaryColor = Color(0xFFAC5BF8); + static const Color secondaryColor = Color(0xFF636ACF); + static const Color backgroundColor = Color(0xFFF3F3F3); + static const Color textPrimary = Color(0xFF5C5C5C); + static const Color textSecondary = Color(0xFFA0A0A0); + static const Color accentColor = Color(0xFF666EDE); + static const Color errorColor = Color(0xFFFF4258); + static const Color whiteColor = Color(0xFFFFFFFF); + + // Gradient colors + static const LinearGradient primaryGradient = LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [primaryColor, secondaryColor], + stops: [0.0, 1.0], + transform: GradientRotation(144 * 3.14159 / 180), // 144 degrees + ); + + static ThemeData get lightTheme { + return ThemeData( + useMaterial3: true, + fontFamily: 'Pretendard', + colorScheme: ColorScheme.fromSeed( + seedColor: primaryColor, + brightness: Brightness.light, + primary: primaryColor, + secondary: secondaryColor, + surface: whiteColor, + error: errorColor, + onPrimary: whiteColor, + onSecondary: whiteColor, + onSurface: textPrimary, + onError: whiteColor, + ), + + // Text themes + textTheme: const TextTheme( + displayLarge: TextStyle( + fontFamily: 'AppleSDGothicNeoH00', + fontWeight: FontWeight.w400, + fontSize: 88.98, + letterSpacing: -0.06, + color: textPrimary, + ), + headlineLarge: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 24, + color: textPrimary, + ), + headlineMedium: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 20, + color: textPrimary, + ), + titleLarge: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: textPrimary, + ), + titleMedium: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + color: textPrimary, + ), + bodyLarge: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 16, + color: textPrimary, + ), + bodyMedium: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 15, + color: textPrimary, + ), + bodySmall: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 14, + color: textSecondary, + ), + labelLarge: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 15, + color: textPrimary, + ), + ), + + // Input decoration theme + inputDecorationTheme: InputDecorationTheme( + filled: true, + fillColor: backgroundColor, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide.none, + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide.none, + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide(color: accentColor, width: 2), + ), + errorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide(color: errorColor, width: 2), + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: const BorderSide(color: errorColor, width: 2), + ), + hintStyle: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 15, + color: textSecondary, + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 18, + vertical: 16, + ), + ), + + // Elevated button theme + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + backgroundColor: primaryColor, + foregroundColor: whiteColor, + minimumSize: const Size(342, 50), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), + textStyle: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 16, + ), + ), + ), + + // Text button theme + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: accentColor, + textStyle: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 16, + ), + ), + ), + + // App bar theme + appBarTheme: const AppBarTheme( + backgroundColor: whiteColor, + foregroundColor: textPrimary, + elevation: 0, + centerTitle: true, + titleTextStyle: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 20, + color: textPrimary, + ), + ), + + // Scaffold theme + scaffoldBackgroundColor: whiteColor, + ); + } +} diff --git a/frontend/lib/utils/academy_utils.dart b/frontend/lib/utils/academy_utils.dart new file mode 100644 index 0000000..89849f6 --- /dev/null +++ b/frontend/lib/utils/academy_utils.dart @@ -0,0 +1,40 @@ +import 'dart:developer' as developer; + +import '../services/academy_service.dart'; + +/// ๊ณตํ†ต ํ•™์› ์œ ํ‹ธ ํ•จ์ˆ˜ ๋ชจ์Œ +Future getUserAcademyId({ + required AcademyService academyService, + List? registeredAcademies, + String? academyCode, +}) async { + final code = academyCode ?? await academyService.getDefaultAcademyCode(); + if (code == null) { + developer.log('โš ๏ธ [AcademyUtils] ๊ธฐ๋ณธ ํ•™์› ์ฝ”๋“œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); + return null; + } + + UserAcademyResponse? academy; + + final cachedList = registeredAcademies; + if (cachedList != null && cachedList.isNotEmpty) { + try { + academy = cachedList.firstWhere((a) => a.academyCode == code); + } catch (_) { + // ignore and fallback to cache lookup + } + } + + academy ??= await academyService.getAcademyByCode(code); + + if (academy == null) { + developer.log('โš ๏ธ [AcademyUtils] ํ•™์› ์ •๋ณด๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. code: $code'); + return null; + } + + final userAcademyId = academy.academy_user_id?.toString(); + developer.log( + 'โœ… [AcademyUtils] userAcademyId=$userAcademyId (academyCode: $code)', + ); + return userAcademyId; +} diff --git a/frontend/lib/utils/api_date_formatter.dart b/frontend/lib/utils/api_date_formatter.dart new file mode 100644 index 0000000..644df48 --- /dev/null +++ b/frontend/lib/utils/api_date_formatter.dart @@ -0,0 +1,27 @@ +import 'kst_date_factory.dart'; +import 'iso8601_formatter.dart'; + +/// API ์š”์ฒญ์šฉ ๋‚ ์งœ ํฌ๋งทํ„ฐ +/// +/// KST ๋‚ ์งœ๋ฅผ API ์š”์ฒญ์— ์ ํ•ฉํ•œ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. +/// ๋‚ด๋ถ€์ ์œผ๋กœ KstDateFactory์™€ Iso8601Formatter๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. +class ApiDateFormatter { + /// KST ๋‚ ์งœ์˜ ์‹œ์ž‘ ์‹œ๊ฐ„์„ API ์š”์ฒญ์šฉ ISO8601 ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ + /// + /// [kstDate]: KST ๊ธฐ์ค€ ๋‚ ์งœ (UTC ๊ธฐ๋ฐ˜ DateTime) + /// ๋ฐ˜ํ™˜๊ฐ’: ISO8601 ๋ฌธ์ž์—ด with timezone (์˜ˆ: "2025-11-01T00:00:00+09:00") + static String formatDayStart(DateTime kstDate) { + final utcStart = KstDateFactory.getDayStartUtc(kstDate); + return Iso8601Formatter.toKstIso8601(utcStart); + } + + /// KST ๋‚ ์งœ์˜ ์ข…๋ฃŒ ์‹œ๊ฐ„์„ API ์š”์ฒญ์šฉ ISO8601 ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ + /// + /// [kstDate]: KST ๊ธฐ์ค€ ๋‚ ์งœ (UTC ๊ธฐ๋ฐ˜ DateTime) + /// ๋ฐ˜ํ™˜๊ฐ’: ISO8601 ๋ฌธ์ž์—ด with timezone (์˜ˆ: "2025-11-01T23:59:59+09:00") + static String formatDayEnd(DateTime kstDate) { + final utcEnd = KstDateFactory.getDayEndUtc(kstDate); + return Iso8601Formatter.toKstIso8601(utcEnd); + } +} + diff --git a/frontend/lib/utils/app_logger.dart b/frontend/lib/utils/app_logger.dart new file mode 100644 index 0000000..239fb2f --- /dev/null +++ b/frontend/lib/utils/app_logger.dart @@ -0,0 +1,8 @@ +import 'package:flutter/foundation.dart'; // kDebugMode +import 'package:flutter/material.dart'; // debugPrint + +void appLog(String message) { + if (!kDebugMode) return; // ๋””๋ฒ„๊ทธ ๋ชจ๋“œ๊ฐ€ ์•„๋‹ˆ๋ฉด ๋ฐ”๋กœ ์ข…๋ฃŒ + + debugPrint('[APP] $message'); +} diff --git a/frontend/lib/utils/iso8601_formatter.dart b/frontend/lib/utils/iso8601_formatter.dart new file mode 100644 index 0000000..25324bc --- /dev/null +++ b/frontend/lib/utils/iso8601_formatter.dart @@ -0,0 +1,57 @@ +/// ISO8601 ๋ฌธ์ž์—ด ํฌ๋งทํ„ฐ +/// +/// UTC ๊ธฐ๋ฐ˜ DateTime์„ ISO8601 ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค. +/// API ์š”์ฒญ ์‹œ KST ํƒ€์ž„์กด ์ •๋ณด๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. +class Iso8601Formatter { + /// UTC DateTime์„ KST ํƒ€์ž„์กด์ด ํฌํ•จ๋œ ISO8601 ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ + /// + /// [utcDateTime]: UTC ๊ธฐ๋ฐ˜ DateTime + /// ๋ฐ˜ํ™˜๊ฐ’: ISO8601 ๋ฌธ์ž์—ด with timezone (์˜ˆ: "2025-11-01T00:00:00+09:00") + /// + /// ์ฃผ์˜: ์ž…๋ ฅ DateTime์€ ๋ฐ˜๋“œ์‹œ UTC ๊ธฐ๋ฐ˜์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + static String toKstIso8601(DateTime utcDateTime) { + // UTC DateTime์„ KST๋กœ ๋ณ€ํ™˜ (UTC + 9์‹œ๊ฐ„) + final kstDateTime = utcDateTime.add(const Duration(hours: 9)); + + // ISO8601 ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ (KST ํƒ€์ž„์กด ๋ช…์‹œ) + return _formatWithTimezone( + kstDateTime.year, + kstDateTime.month, + kstDateTime.day, + kstDateTime.hour, + kstDateTime.minute, + kstDateTime.second, + hoursOffset: 9, // KST = UTC+9 + ); + } + + /// ISO8601 ํ˜•์‹ ๋ฌธ์ž์—ด ์ƒ์„ฑ (ํƒ€์ž„์กด ํฌํ•จ) + /// + /// [year, month, day, hour, minute, second]: ๋‚ ์งœ/์‹œ๊ฐ„ ๊ตฌ์„ฑ ์š”์†Œ + /// [hoursOffset]: UTC๋กœ๋ถ€ํ„ฐ์˜ ์‹œ๊ฐ„ ์˜คํ”„์…‹ (KST๋Š” +9) + /// ๋ฐ˜ํ™˜๊ฐ’: ISO8601 ๋ฌธ์ž์—ด (์˜ˆ: "2025-11-01T00:00:00+09:00") + static String _formatWithTimezone( + int year, + int month, + int day, + int hour, + int minute, + int second, { + required int hoursOffset, + }) { + final sign = hoursOffset >= 0 ? '+' : '-'; + final absOffset = hoursOffset.abs(); + final hours = absOffset.toString().padLeft(2, '0'); + final minutes = '00'; // KST๋Š” ์ •ํ™•ํžˆ 9์‹œ๊ฐ„ ์˜คํ”„์…‹ + + final yearStr = year.toString().padLeft(4, '0'); + final monthStr = month.toString().padLeft(2, '0'); + final dayStr = day.toString().padLeft(2, '0'); + final hourStr = hour.toString().padLeft(2, '0'); + final minuteStr = minute.toString().padLeft(2, '0'); + final secondStr = second.toString().padLeft(2, '0'); + + return '$yearStr-$monthStr-${dayStr}T$hourStr:$minuteStr:$secondStr$sign$hours:$minutes'; + } +} + diff --git a/frontend/lib/utils/kst_date_factory.dart b/frontend/lib/utils/kst_date_factory.dart new file mode 100644 index 0000000..95bebc6 --- /dev/null +++ b/frontend/lib/utils/kst_date_factory.dart @@ -0,0 +1,79 @@ +/// KST ๋‚ ์งœ ์ƒ์„ฑ ํŒฉํ† ๋ฆฌ +/// +/// ๊ธฐ๊ธฐ ํƒ€์ž„์กด๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ํ•ญ์ƒ KST(UTC+9) ๊ธฐ์ค€ ๋‚ ์งœ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. +/// ๋ชจ๋“  DateTime์€ UTC ๊ธฐ๋ฐ˜์œผ๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ํƒ€์ž„์กด ์™œ๊ณก์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. +class KstDateFactory { + /// ํ˜„์žฌ ์‹œ๊ฐ์„ KST ๊ธฐ์ค€ ๋‚ ์งœ๋กœ ๋ณ€ํ™˜ + /// + /// ๊ธฐ๊ธฐ๊ฐ€ ์–ด๋А ํƒ€์ž„์กด์— ์žˆ๋“  ํ•ญ์ƒ KST ๊ธฐ์ค€์˜ "์˜ค๋Š˜" ๋‚ ์งœ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + /// ๋ฐ˜ํ™˜๊ฐ’: UTC ๊ธฐ๋ฐ˜ DateTime (๋‚ ์งœ๋งŒ ์˜๋ฏธ, ์‹œ๊ฐ„์€ 00:00:00 UTC) + /// + /// ์˜ˆ: ๋ฏธ๊ตญ LA์—์„œ ์‹คํ–‰ํ•ด๋„ KST ๊ธฐ์ค€ ์˜ค๋Š˜์ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. + static DateTime getTodayKst() { + // 1. UTC ์‹œ๊ฐ์„ ๊ฐ€์ ธ์˜ด + final nowUtc = DateTime.now().toUtc(); + + // 2. KST๋กœ ๋ณ€ํ™˜ (UTC + 9์‹œ๊ฐ„) + final nowKst = nowUtc.add(const Duration(hours: 9)); + + // 3. UTC ๊ธฐ๋ฐ˜์œผ๋กœ ๋‚ ์งœ๋งŒ ์ถ”์ถœ (์‹œ๊ฐ„ ์ •๋ณด ์ œ๊ฑฐ) + // ์ค‘์š”: UTC๋กœ ์ƒ์„ฑํ•˜์—ฌ ํƒ€์ž„์กด ์™œ๊ณก ๋ฐฉ์ง€ + return DateTime.utc(nowKst.year, nowKst.month, nowKst.day); + } + + /// ์ฃผ์–ด์ง„ ๋‚ ์งœ๋ฅผ KST ๊ธฐ์ค€ ๋‚ ์งœ๋กœ ๋ณ€ํ™˜ + /// + /// [date]: ๋ณ€ํ™˜ํ•  ๋‚ ์งœ (์–ด๋–ค ํƒ€์ž„์กด์ด๋“  ์ƒ๊ด€์—†์Œ) + /// ๋ฐ˜ํ™˜๊ฐ’: UTC ๊ธฐ๋ฐ˜ DateTime (๋‚ ์งœ๋งŒ ์˜๋ฏธ, ์‹œ๊ฐ„์€ 00:00:00 UTC) + /// + /// ์˜ˆ: DateTime(2025, 11, 1) (๋กœ์ปฌ) โ†’ DateTime.utc(2025, 11, 1) (KST ๊ธฐ์ค€) + static DateTime toKstDate(DateTime date) { + // 1. UTC๋กœ ๋ณ€ํ™˜ + final utc = date.toUtc(); + + // 2. KST๋กœ ๋ณ€ํ™˜ (UTC + 9์‹œ๊ฐ„) + final kst = utc.add(const Duration(hours: 9)); + + // 3. UTC ๊ธฐ๋ฐ˜์œผ๋กœ ๋‚ ์งœ๋งŒ ์ถ”์ถœ + return DateTime.utc(kst.year, kst.month, kst.day); + } + + /// KST ๋‚ ์งœ์˜ ์‹œ์ž‘ ์‹œ๊ฐ„(00:00:00)์„ UTC DateTime์œผ๋กœ ์ƒ์„ฑ + /// + /// [kstDate]: KST ๊ธฐ์ค€ ๋‚ ์งœ (UTC ๊ธฐ๋ฐ˜ DateTime) + /// ๋ฐ˜ํ™˜๊ฐ’: UTC ๊ธฐ๋ฐ˜ DateTime (ํ•ด๋‹น ๋‚ ์งœ์˜ 00:00:00 KST๋ฅผ UTC๋กœ ๋ณ€ํ™˜ํ•œ ๊ฐ’) + /// + /// ์˜ˆ: 2025-11-01 KST โ†’ 2025-10-31 15:00:00 UTC + static DateTime getDayStartUtc(DateTime kstDate) { + // KST 00:00:00 = UTC 15:00:00 (์ „๋‚ ) + // ๋”ฐ๋ผ์„œ KST ๋‚ ์งœ์—์„œ ํ•˜๋ฃจ๋ฅผ ๋นผ๊ณ  15์‹œ๋กœ ์„ค์ • + final previousDay = kstDate.subtract(const Duration(days: 1)); + return DateTime.utc( + previousDay.year, + previousDay.month, + previousDay.day, + 15, // KST 00:00 = UTC 15:00 (์ „๋‚ ) + 0, + 0, + ); + } + + /// KST ๋‚ ์งœ์˜ ์ข…๋ฃŒ ์‹œ๊ฐ„(23:59:59)์„ UTC DateTime์œผ๋กœ ์ƒ์„ฑ + /// + /// [kstDate]: KST ๊ธฐ์ค€ ๋‚ ์งœ (UTC ๊ธฐ๋ฐ˜ DateTime) + /// ๋ฐ˜ํ™˜๊ฐ’: UTC ๊ธฐ๋ฐ˜ DateTime (ํ•ด๋‹น ๋‚ ์งœ์˜ 23:59:59 KST๋ฅผ UTC๋กœ ๋ณ€ํ™˜ํ•œ ๊ฐ’) + /// + /// ์˜ˆ: 2025-11-01 KST โ†’ 2025-11-01 14:59:59 UTC + static DateTime getDayEndUtc(DateTime kstDate) { + // KST 23:59:59 = UTC 14:59:59 (๋‹น์ผ) + return DateTime.utc( + kstDate.year, + kstDate.month, + kstDate.day, + 14, // KST 23:59 = UTC 14:59 (๋‹น์ผ) + 59, + 59, + ); + } +} + diff --git a/frontend/lib/widgets/app_header.dart b/frontend/lib/widgets/app_header.dart new file mode 100644 index 0000000..1350dc1 --- /dev/null +++ b/frontend/lib/widgets/app_header.dart @@ -0,0 +1,97 @@ +import 'package:flutter/material.dart'; + +/// ์•ฑ์˜ ํ‘œ์ค€ ํ—ค๋” ์œ„์ ฏ +/// +/// Error Collector ๊ทœ์น™ ์ค€์ˆ˜: +/// - Rule 1: MediaQuery๋กœ ์ƒ๋Œ€ ํฌ๊ธฐ ์‚ฌ์šฉ +/// - Rule 4: super.key constructor +/// - Rule 10: ๊ณ ์ • ํฌ๊ธฐ ํšŒํ”ผ +/// - Rule 14: ์ผ๊ด€๋œ ๋ ˆ์ด์•„์›ƒ ํŒจํ„ด +/// +/// ์‚ฌ์šฉ ์˜ˆ์‹œ: +/// ```dart +/// AppHeader( +/// title: const AppHeaderTitle('๋ฌธ์ œ์ง‘'), +/// trailing: const AppHeaderMenuButton(), +/// ) +/// ``` +class AppHeader extends StatelessWidget { + /// ์™ผ์ชฝ ์˜์—ญ ์œ„์ ฏ (์„ ํƒ์ ) + /// null์ด๋ฉด ๊ท ํ˜•์„ ์œ„ํ•œ ๊ณต๊ฐ„์ด ์ž๋™์œผ๋กœ ์ถ”๊ฐ€๋จ + final Widget? leading; + + /// ์ค‘์•™ ํƒ€์ดํ‹€ ์œ„์ ฏ (ํ•„์ˆ˜) + final Widget title; + + /// ์˜ค๋ฅธ์ชฝ ์•ก์…˜ ์œ„์ ฏ (์„ ํƒ์ ) + final Widget? trailing; + + /// ํƒ€์ดํ‹€ ์ •๋ ฌ ๋ฐฉ์‹ (๊ธฐ๋ณธ๊ฐ’: ์ค‘์•™ ์ •๋ ฌ) + /// - left: ์™ผ์ชฝ ์ •๋ ฌ + /// - center: ์ค‘์•™ ์ •๋ ฌ + final String titleAlignment; + + const AppHeader({ + super.key, // โœ… Rule 4: super.key + this.leading, + required this.title, + this.trailing, + this.titleAlignment = 'center', + }); + + @override + Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + final screenHeight = MediaQuery.of(context).size.height; + + // โœ… Rule 1: ์ƒ๋Œ€ ํฌ๊ธฐ ์‚ฌ์šฉ + final horizontalPadding = screenWidth * 0.05; + final topPadding = screenHeight * 0.021; + final bottomPadding = screenHeight * 0.012; + + // โœ… Rule 1: ๊ท ํ˜•์„ ์œ„ํ•œ ๊ณต๊ฐ„๋„ ์ƒ๋Œ€ ํฌ๊ธฐ + final balanceSpace = screenWidth * 0.06; // 24px โ‰ˆ 6% of 402px + + return Container( + padding: EdgeInsets.fromLTRB( + horizontalPadding, + topPadding, + horizontalPadding, + bottomPadding, + ), // โœ… Rule 5: trailing comma + decoration: const BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x1A000000), + offset: Offset(0, 4), + blurRadius: 4, + ), + ], + ), // โœ… Rule 5: trailing comma + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // Leading (์™ผ์ชฝ) + if (leading != null) + leading! + else if (titleAlignment == 'left') + SizedBox(width: balanceSpace) // โœ… Rule 1: ์ƒ๋Œ€ ํฌ๊ธฐ (์™ผ์ชฝ ์ •๋ ฌ ์‹œ) + else + SizedBox(width: balanceSpace), // โœ… Rule 1: ์ƒ๋Œ€ ํฌ๊ธฐ (์ค‘์•™ ์ •๋ ฌ ์‹œ) + // Title (์ค‘์•™ or ์™ผ์ชฝ) + Expanded( + child: titleAlignment == 'left' + ? Align(alignment: Alignment.centerLeft, child: title) + : Center(child: title), // โœ… Rule 5: trailing comma + ), // โœ… Rule 5: trailing comma + // Trailing (์˜ค๋ฅธ์ชฝ) + if (trailing != null) + trailing! + else + SizedBox(width: balanceSpace), // โœ… Rule 1: ์ƒ๋Œ€ ํฌ๊ธฐ + ], + ), // โœ… Rule 5: trailing comma + ); + } +} diff --git a/frontend/lib/widgets/app_header_menu_button.dart b/frontend/lib/widgets/app_header_menu_button.dart new file mode 100644 index 0000000..dc830ef --- /dev/null +++ b/frontend/lib/widgets/app_header_menu_button.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import '../../screens/grading_history/grading_history_page.dart'; + +/// ํ—ค๋” ์ฑ„์  ํžˆ์Šคํ† ๋ฆฌ ๋ฒ„ํŠผ ์œ„์ ฏ +class AppHeaderMenuButton extends StatelessWidget { + final VoidCallback? onPressed; + + const AppHeaderMenuButton({ + super.key, // โœ… Rule 4 + this.onPressed, + }); + + @override + Widget build(BuildContext context) { + return IconButton( + icon: const Icon( + Icons.history, + color: Color(0xFF333333), + ), // โœ… Rule 5: trailing comma + onPressed: + onPressed ?? + () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const GradingHistoryPage(), + ), + ); + }, + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ); + } +} diff --git a/frontend/lib/widgets/app_header_title.dart b/frontend/lib/widgets/app_header_title.dart new file mode 100644 index 0000000..d6e7261 --- /dev/null +++ b/frontend/lib/widgets/app_header_title.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +/// ํ—ค๋” ํƒ€์ดํ‹€ ํ‘œ์ค€ ์œ„์ ฏ +/// +/// ์ผ๊ด€๋œ ํ…์ŠคํŠธ ์Šคํƒ€์ผ์„ ์ œ๊ณต +class AppHeaderTitle extends StatelessWidget { + final String text; + final TextAlign? textAlign; + + const AppHeaderTitle( + this.text, { + super.key, // โœ… Rule 4 + this.textAlign, + }); + + @override + Widget build(BuildContext context) { + return Text( + text, + textAlign: textAlign, // ์™ผ์ชฝ/์ค‘์•™ ์ •๋ ฌ ์ œ์–ด + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 20, + color: Color(0xFF333333), + ), // โœ… Rule 5: trailing comma + ); + } +} diff --git a/frontend/lib/widgets/app_logo.dart b/frontend/lib/widgets/app_logo.dart new file mode 100644 index 0000000..e002790 --- /dev/null +++ b/frontend/lib/widgets/app_logo.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class AppLogo extends StatelessWidget { + final double? width; + final double? height; + final double widthFactor; // ํ™”๋ฉด ๋„ˆ๋น„ ๋Œ€๋น„ ๋กœ๊ณ  ๋„ˆ๋น„ ๋น„์œจ + + const AppLogo({super.key, this.width, this.height, this.widthFactor = 0.7}); + + @override + Widget build(BuildContext context) { + final double screenWidth = MediaQuery.of(context).size.width; + final double targetWidth = width ?? (screenWidth * widthFactor); + + return Container( + width: targetWidth, + height: height, + constraints: BoxConstraints( + maxWidth: screenWidth * 0.9, // ํ™”๋ฉด ๋„ˆ๋น„์˜ 90%๋ฅผ ๋„˜์ง€ ์•Š์Œ + minWidth: 200, // ์ตœ์†Œ ๋„ˆ๋น„ ๋ณด์žฅ + maxHeight: height ?? 200, // ์ตœ๋Œ€ ๋†’์ด ์ œํ•œ + ), + child: FittedBox( + fit: BoxFit.contain, // ์ฃผ์–ด์ง„ ํญ ์•ˆ์—์„œ ์ž๋™ ์Šค์ผ€์ผ + child: ShaderMask( + shaderCallback: (bounds) => const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFFAC5BF8), // rgba(172, 91, 248, 1) + Color(0xFF636ACF), // rgba(99, 106, 207, 1) + ], + stops: [0.09, 0.92], + transform: GradientRotation(2.67), // 153 degrees in radians + ).createShader(bounds), + child: const Text( + 'GRADI', + style: TextStyle( + fontFamily: 'AppleSDGothicNeoH00', + fontSize: 96, // ๊ธฐ์ค€ ํฐํŠธ ํฌ๊ธฐ (FittedBox๊ฐ€ ์Šค์ผ€์ผ ์กฐ์ •) + fontWeight: FontWeight.w400, + height: 1.491, + letterSpacing: -0.06, + color: Colors.white, // This will be masked by the gradient + ), + ), + ), + ), + ); + } +} diff --git a/frontend/lib/widgets/back_button.dart b/frontend/lib/widgets/back_button.dart new file mode 100644 index 0000000..b452af5 --- /dev/null +++ b/frontend/lib/widgets/back_button.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class CustomBackButton extends StatelessWidget { + final VoidCallback? onPressed; + final double? width; + final double? height; + + const CustomBackButton({super.key, this.onPressed, this.width, this.height}); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: width ?? 38, + height: height ?? 38, + child: IconButton( + onPressed: onPressed ?? () => Navigator.of(context).pop(), + icon: CustomPaint( + size: const Size(9.5, 19), + painter: BackArrowPainter(), + ), + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ), + ); + } +} + +class BackArrowPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = const Color(0xFF5C5C5C) + ..style = PaintingStyle.stroke + ..strokeWidth = 3.17; + + final path = Path(); + // Draw left arrow + path.moveTo(size.width * 0.8, 0); + path.lineTo(0, size.height * 0.5); + path.lineTo(size.width * 0.8, size.height); + + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} diff --git a/frontend/lib/widgets/bottom_navigation_widget.dart b/frontend/lib/widgets/bottom_navigation_widget.dart new file mode 100644 index 0000000..7f35359 --- /dev/null +++ b/frontend/lib/widgets/bottom_navigation_widget.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class BottomNavigationWidget extends StatelessWidget { + final int currentIndex; + final Function(int) onTabChanged; + + const BottomNavigationWidget({ + super.key, + required this.currentIndex, + required this.onTabChanged, + }); + + void _handleTabChange(int index) { + if (index == currentIndex) return; // ํ˜„์žฌ ํƒญ์ด๋ฉด ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Œ + onTabChanged(index); + } + + @override + Widget build(BuildContext context) { + return Container( + height: 70, + decoration: const BoxDecoration( + color: Colors.white, + border: Border(top: BorderSide(color: Color(0xFFE9ECEF))), + ), + child: Row( + children: [ + _buildNavItem('Home', 'ํ™ˆ', 0), + _buildNavItem('Textbook', '๋ฌธ์ œ์ง‘', 1), + _buildNavItem('Upload_image', '์ด๋ฏธ์ง€์—…๋กœ๋“œ', 2), + _buildNavItem('Academy', 'ํ•™์›', 3), + _buildNavItem('Mypage', '๋งˆ์ดํŽ˜์ด์ง€', 4), + _buildNavItem('Alarm', '์•Œ๋žŒ', 5), + ], + ), + ); + } + + Widget _buildNavItem(String iconName, String label, int index) { + final isActive = currentIndex == index; + final iconPath = isActive + ? 'assets/images/icons/${iconName}_selected.svg' + : 'assets/images/icons/${iconName}_unselected.svg'; + + return Expanded( + child: GestureDetector( + onTap: () => _handleTabChange(index), + child: Container( + color: Colors.transparent, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // SVG ์•„์ด์ฝ˜ + SvgPicture.asset(iconPath, width: 24, height: 24), + const SizedBox(height: 4), + // ํ…์ŠคํŠธ + Text( + label, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: isActive ? FontWeight.w600 : FontWeight.w500, + fontSize: 10, + color: isActive + ? const Color(0xFFAC5BF8) + : const Color(0xFFADADAD), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/frontend/lib/widgets/continuous_learning_widget.dart b/frontend/lib/widgets/continuous_learning_widget.dart new file mode 100644 index 0000000..9df3ca4 --- /dev/null +++ b/frontend/lib/widgets/continuous_learning_widget.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; + +class ContinuousLearningWidget extends StatelessWidget { + final int consecutiveDays; + final List weeklyProgress; + + const ContinuousLearningWidget({ + super.key, + required this.consecutiveDays, + required this.weeklyProgress, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '$consecutiveDays์ผ ์—ฐ์†์œผ๋กœ ํ•™์Šตํ•˜๊ณ  ์žˆ์–ด์š”', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + color: Color(0xFF333333), + ), + ), + + const SizedBox(height: 8), + + Container( + padding: const EdgeInsets.symmetric(horizontal: 19, vertical: 15), + decoration: BoxDecoration( + color: const Color(0xFFF8F9FA), + border: Border.all(color: const Color(0xFFE9ECEF)), + borderRadius: BorderRadius.circular(10), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildDayCard('์›”', weeklyProgress[0]), + _buildDayCard('ํ™”', weeklyProgress[1]), + _buildDayCard('์ˆ˜', weeklyProgress[2]), + _buildDayCard('๋ชฉ', weeklyProgress[3]), + _buildDayCard('๊ธˆ', weeklyProgress[4]), + _buildDayCard('ํ† ', weeklyProgress[5]), + _buildDayCard('์ผ', weeklyProgress[6]), + ], + ), + ), + ], + ); + } + + Widget _buildDayCard(String day, bool isActive) { + return Column( + children: [ + Container( + width: 36, + height: 34, + decoration: BoxDecoration( + gradient: isActive + ? const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF636ACF)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ) + : null, + color: isActive ? null : Colors.grey[200], + borderRadius: BorderRadius.circular(8), + boxShadow: isActive + ? [ + BoxShadow( + color: const Color(0xFFAC5BF8).withValues(alpha: 0.3), + blurRadius: 4, + offset: const Offset(0, 0), + ), + ] + : null, + ), + child: Center( + child: Text( + day, + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 12, + color: isActive ? Colors.white : const Color(0xFF666666), + ), + ), + ), + ), + ], + ); + } +} diff --git a/frontend/lib/widgets/continuous_learning_widget_v2.dart b/frontend/lib/widgets/continuous_learning_widget_v2.dart new file mode 100644 index 0000000..aeebb97 --- /dev/null +++ b/frontend/lib/widgets/continuous_learning_widget_v2.dart @@ -0,0 +1,930 @@ +import 'package:flutter/material.dart'; +import '../models/assessment.dart'; +import '../domain/learning/daily_learning_status.dart'; +import '../domain/learning/get_monthly_learning_status_use_case.dart'; +import '../constants/learning_widget_spacing.dart'; + +/// ์—ฐ์†ํ•™์Šต ์œ„์ ฏ V2 - ๊ฐœ์„ ๋œ UI/UX +/// +/// ์ฃผ์š” ๊ธฐ๋Šฅ: +/// 1. ์›”๋ณ„ ๋‚ ์งœ ์Šคํฌ๋กค (ํ•œ ๋‹ฌ ๋‹จ์œ„) +/// 2. ์„ ํƒ๋œ ๋‚ ์งœ ํ‘œ์‹œ +/// 3. ํ•™์Šต ์™„๋ฃŒ ์ƒํƒœ ํ‘œ์‹œ (๊ทธ๋ผ๋ฐ์ด์…˜ ๋ฐ•์Šค) +/// 4. ์ˆ™์ œ ๋งˆ๊ฐ์ผ ํ‘œ์‹œ (์ฑ… ์•„์ด์ฝ˜) +/// 5. ์—ฐ์† ํ•™์Šต์ผ ์—ฐ๊ฒฐ์„  ํ‘œ์‹œ +/// +/// ๋ฐ์ดํ„ฐ ์†Œ์Šค ์šฐ์„ ์ˆœ์œ„: +/// 1. dailyStatusMap (์ƒˆ ๊ตฌ์กฐ, ๊ถŒ์žฅ) +/// 2. monthlyStatusUseCase (์ƒˆ ๊ตฌ์กฐ, ๊ถŒ์žฅ) +/// 3. dateAssessments (ํ•˜์œ„ ํ˜ธํ™˜์„ฑ, ์ถ”ํ›„ ์ œ๊ฑฐ ์˜ˆ์ •) +/// 4. completedDates (ํ•˜์œ„ ํ˜ธํ™˜์„ฑ, ์ถ”ํ›„ ์ œ๊ฑฐ ์˜ˆ์ •) +/// +/// ํžŒํŠธ ๋ฐ•์Šค ์ •๋ ฌ ๊ธฐ์ค€: +/// - ํžŒํŠธ ๋ฐ•์Šค๋Š” DateItem์˜ 1:1 ๋ฐ•์Šค(AspectRatio) ๊ธฐ์ค€ ์ค‘์•™์— ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค. +/// - DateItem์˜ ํ…์ŠคํŠธ ์˜์—ญ์€ ํžŒํŠธ ์ •๋ ฌ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +/// - Stack ๋†’์ด๋Š” itemWidth(cardWidth)๋กœ ์„ค์ •๋˜์–ด ๋ฐ•์Šค ๋†’์ด์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค. +class ContinuousLearningWidgetV2 extends StatefulWidget { + final int consecutiveDays; + final Set homeworkDeadlines; + final Function(DateTime)? onDateSelected; + final DateTime? selectedDate; + + // ์ƒˆ ๊ตฌ์กฐ (๊ถŒ์žฅ) + final Map? dailyStatusMap; + final GetMonthlyLearningStatusUseCase? monthlyStatusUseCase; + + // ํ•˜์œ„ ํ˜ธํ™˜์„ฑ (์ถ”ํ›„ ์ œ๊ฑฐ ์˜ˆ์ •) + @Deprecated('Use dailyStatusMap or monthlyStatusUseCase instead') + final Set completedDates; + @Deprecated('Use dailyStatusMap or monthlyStatusUseCase instead') + final Map>? dateAssessments; + + const ContinuousLearningWidgetV2({ + super.key, + required this.consecutiveDays, + this.homeworkDeadlines = const {}, + this.onDateSelected, + this.selectedDate, + // ์ƒˆ ๊ตฌ์กฐ + this.dailyStatusMap, + this.monthlyStatusUseCase, + // ํ•˜์œ„ ํ˜ธํ™˜์„ฑ + @Deprecated('Use dailyStatusMap or monthlyStatusUseCase instead') + this.completedDates = const {}, + @Deprecated('Use dailyStatusMap or monthlyStatusUseCase instead') + this.dateAssessments, + }); + + @override + State createState() => + _ContinuousLearningWidgetV2State(); +} + +class _ContinuousLearningWidgetV2State + extends State { + late DateTime _selectedDate; + final ScrollController _dateScrollController = ScrollController(); + + // ํ˜„์žฌ ํ‘œ์‹œ ์ค‘์ธ ์›”/๋…„๋„ + late DateTime _currentMonth; // ํ˜„์žฌ ํ‘œ์‹œ ์ค‘์ธ ์›”์˜ ์ฒซ ๋‚  (์˜ˆ: 2025-11-01) + + // ์›” ์ „ํ™˜ ์ค‘๋ณต ๋ฐฉ์ง€ + bool _isChangingMonth = false; + + // ๋งˆ์ง€๋ง‰ ์›” ๋ณ€๊ฒฝ ์‹œ๊ฐ„ (2์ดˆ ์ฟจ๋‹ค์šด์šฉ) + DateTime? _lastMonthChangeTime; + + // ํžŒํŠธ ํ‘œ์‹œ ๊ด€๋ จ + bool _showNextMonthHint = false; // ๋‹ค์Œ ๋‹ฌ ํžŒํŠธ ํ‘œ์‹œ ์—ฌ๋ถ€ + bool _showPrevMonthHint = false; // ์ด์ „ ๋‹ฌ ํžŒํŠธ ํ‘œ์‹œ ์—ฌ๋ถ€ + + // ์•„์ดํ…œ ๋„ˆ๋น„ (ํ•œ ๊ณณ์—์„œ ์ •์˜) + double? _itemWidth; + + // ํ˜„์žฌ ์›”์˜ ์ƒํƒœ ์บ์‹œ (UseCase ์‚ฌ์šฉ ์‹œ) + Map? _currentMonthStatuses; + + /// ์•„์ดํ…œ ๋„ˆ๋น„ getter (์ €์žฅ๋œ ๊ฐ’ ๋ฐ˜ํ™˜) + /// + /// itemWidth๋Š” didChangeDependencies์—์„œ ๊ณ„์‚ฐ๋˜๋ฉฐ, + /// ์ด getter๋Š” ์ €์žฅ๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. + /// null์ธ ๊ฒฝ์šฐ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. + double get itemWidth { + assert( + _itemWidth != null, + 'itemWidth must be initialized in didChangeDependencies', + ); + return _itemWidth!; + } + + // ์›” ์ „ํ™˜ ํŠธ๋ฆฌ๊ฑฐ ๊ด€๋ จ ์ƒ์ˆ˜ + // ์˜ค๋ฒ„์Šคํฌ๋กค ์ž„๊ณ„๊ฐ’: ์Šคํฌ๋กค์ด ๋์„ ๋„˜์–ด์„œ ์ผ์ • ๊ฑฐ๋ฆฌ ์ด์ƒ ์˜ค๋ฒ„์Šคํฌ๋กคํ–ˆ์„ ๋•Œ๋งŒ ์ „ํ™˜ + static const double _monthChangeOverScrollThreshold = + 0.3; // ์•„์ดํ…œ 0.3๊ฐœ ๋„ˆ๋น„ ์ด์ƒ ์˜ค๋ฒ„์Šคํฌ๋กค (๋” ์œ ์—ฐํ•˜๊ฒŒ) + + // ๊ฒฝ๊ณ„ ์›” ์ œํ•œ (์ถ”ํ›„ ๋น„์ฆˆ๋‹ˆ์Šค ๋ฃฐ์— ๋”ฐ๋ผ ์ฃผ์ž… ๊ฐ€๋Šฅ) + DateTime? _minMonth; + DateTime? _maxMonth; + + @override + void initState() { + super.initState(); + _selectedDate = widget.selectedDate ?? DateTime.now(); + // ํ˜„์žฌ ์›”์˜ ์ฒซ ๋‚ ๋กœ ์ดˆ๊ธฐํ™” + _currentMonth = DateTime(_selectedDate.year, _selectedDate.month, 1); + + // ๋‹ค์Œ ๋‹ฌ ์ด๋™ ์ œํ•œ: ํ˜„์žฌ ๋‹ฌ๋กœ๋ถ€ํ„ฐ ๋‹ค์Œ ๋‹ฌ๊นŒ์ง€๋งŒ ์ด๋™ ๊ฐ€๋Šฅ + // ์˜ˆ: 11์›”์ด๋ฉด 12์›”๊นŒ์ง€๋งŒ ์ด๋™ ๊ฐ€๋Šฅ, 13์›”์€ ๋ถˆ๊ฐ€ + _maxMonth = DateTime(_selectedDate.year, _selectedDate.month + 1, 1); + // ์ด์ „ ๋‹ฌ ์ด๋™์€ ์ œํ•œ ์—†์Œ (_minMonth๋Š” null๋กœ ์œ ์ง€) + + // UseCase๊ฐ€ ์žˆ์œผ๋ฉด ํ˜„์žฌ ์›” ๋ฐ์ดํ„ฐ ๋กœ๋“œ + if (widget.monthlyStatusUseCase != null) { + _loadMonthlyStatuses(); + } + + // ์˜ค๋Š˜ ๋‚ ์งœ๊ฐ€ ์˜ค๋ฅธ์ชฝ ๋์— ์˜ค๋„๋ก ์Šคํฌ๋กค ์œ„์น˜ ์„ค์ • + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + _scrollToDateInCurrentMonth(_selectedDate, jump: true); + } + }); + } + + /// UseCase๋กœ ํ˜„์žฌ ์›”์˜ ํ•™์Šต ์ƒํƒœ ๋กœ๋“œ + /// + /// ๋™๊ธฐํ™” ์‹œ์ : + /// - initState: ์œ„์ ฏ ์ดˆ๊ธฐํ™” ์‹œ ํ˜„์žฌ ์›” ๋ฐ์ดํ„ฐ ๋กœ๋“œ + /// - didChangeDependencies: ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ ๋Œ์•„์˜ฌ ๋•Œ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋กœ ๋™๊ธฐํ™” + /// - didUpdateWidget: monthlyStatusUseCase ๋ณ€๊ฒฝ ์‹œ ์ƒˆ๋กœ ๋กœ๋“œ + /// - _changeMonth: ์›” ๋ณ€๊ฒฝ ์‹œ ์ƒˆ ์›”์˜ ๋ฐ์ดํ„ฐ ๋กœ๋“œ + Future _loadMonthlyStatuses() async { + if (widget.monthlyStatusUseCase == null) return; + + try { + final statuses = await widget.monthlyStatusUseCase!.call(_currentMonth); + if (mounted) { + setState(() { + _currentMonthStatuses = { + for (var status in statuses) + DailyLearningStatus.normalizeDate(status.date): status, + }; + }); + } + } catch (e) { + // ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ๋นˆ ์ƒํƒœ ์œ ์ง€ + } + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // ์•„์ดํ…œ ๋„ˆ๋น„๋ฅผ ํ•œ ๊ณณ์—์„œ ์ •์˜ (์บ์‹ฑ) + // itemWidth์™€ cardWidth๋ฅผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด screenWidth / 7 ์‚ฌ์šฉ + if (_itemWidth == null) { + final screenWidth = MediaQuery.of(context).size.width; + _itemWidth = screenWidth / 7; + } + + // ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ ๋Œ์•„์˜ฌ ๋•Œ ํ˜„์žฌ ์›”์˜ ํ•™์Šต ์ƒํƒœ๋ฅผ ์ตœ์‹  ์ •๋ณด๋กœ ๋™๊ธฐํ™” + // (์˜ˆ: ์ˆ™์ œ ์™„๋ฃŒ ์ƒํƒœ ๋ณ€๊ฒฝ ๋“ฑ) + if (widget.monthlyStatusUseCase != null) { + _loadMonthlyStatuses(); + } + } + + @override + void didUpdateWidget(covariant ContinuousLearningWidgetV2 oldWidget) { + super.didUpdateWidget(oldWidget); + + // monthlyStatusUseCase๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ๊ฑฐ๋‚˜ ์ถ”๊ฐ€๋˜์—ˆ์„ ๋•Œ ์ƒํƒœ ๋กœ๋“œ + if (widget.monthlyStatusUseCase != null && + (oldWidget.monthlyStatusUseCase == null || + oldWidget.monthlyStatusUseCase != widget.monthlyStatusUseCase)) { + _loadMonthlyStatuses(); + } + + // dailyStatusMap์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ๋Š” ์ž๋™์œผ๋กœ ๋ฐ˜์˜๋จ (widget.dailyStatusMap ์‚ฌ์šฉ) + + final newSelected = widget.selectedDate ?? DateTime.now(); + if (!_isSameDay(newSelected, _selectedDate)) { + setState(() { + _selectedDate = newSelected; + }); + // ์™ธ๋ถ€์—์„œ selectedDate ๋ณ€๊ฒฝ ์‹œ: _setMonthAndScroll ์‚ฌ์šฉ (์›”+์Šคํฌ๋กค ๋ชจ๋‘ ์ฑ…์ž„) + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + _setMonthAndScroll(newSelected); + } + }); + } + } + + /// ์›” ๋ณ€๊ฒฝ + ์Šคํฌ๋กค์„ ํ•จ๊ป˜ ์ฒ˜๋ฆฌํ•˜๋Š” ์ƒ์œ„ ๋ฉ”์„œ๋“œ + /// + /// ์ฑ…์ž„: ์›” ๋ณ€๊ฒฝ๊ณผ ์Šคํฌ๋กค์„ ์ˆœ์„œ๋Œ€๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ณต์žก๋„ ๊ฐ์†Œ + void _setMonthAndScroll(DateTime targetDate) { + final targetMonth = DateTime(targetDate.year, targetDate.month, 1); + + // ์›”์ด ๋‹ค๋ฅด๋ฉด ๋จผ์ € ๋ณ€๊ฒฝ + if (_currentMonth.year != targetMonth.year || + _currentMonth.month != targetMonth.month) { + // targetDate๋ฅผ selectedDate๋กœ ์ „๋‹ฌํ•˜์—ฌ ํ•ด๋‹น ๋‚ ์งœ๋กœ ์ด๋™ + _changeMonth(targetMonth, selectedDate: targetDate); + // _changeMonth ๋‚ด๋ถ€์—์„œ ์ด๋ฏธ ์Šคํฌ๋กค ์ฒ˜๋ฆฌ๋จ + return; + } + + // ๊ฐ™์€ ์›”์ด๋ฉด ์Šคํฌ๋กค๋งŒ + _scrollToDateInCurrentMonth(targetDate, jump: false); + } + + /// ํ˜„์žฌ ์›” ๋‚ด์—์„œ ๋‚ ์งœ๋กœ ์Šคํฌ๋กค (์ฑ…์ž„: ์Šคํฌ๋กค ์œ„์น˜๋งŒ ์กฐ์ •) + void _scrollToDateInCurrentMonth(DateTime date, {bool jump = false}) { + // ์„ ํƒ๋œ ๋‚ ์งœ๊ฐ€ ํ˜„์žฌ ํ‘œ์‹œ ์ค‘์ธ ์›”์— ์†ํ•˜๋Š”์ง€ ํ™•์ธ + if (date.year != _currentMonth.year || date.month != _currentMonth.month) { + // ๋‹ค๋ฅธ ์›”์ด๋ฉด ์›”์„ ๋จผ์ € ๋ณ€๊ฒฝ (์ƒ์œ„ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ) + _setMonthAndScroll(date); + return; + } + + if (!_dateScrollController.hasClients) return; + + final targetIndex = date.day - 1; // 1์ผ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋ฏ€๋กœ -1 + final offset = targetIndex * itemWidth; // getter ์‚ฌ์šฉ + + if (jump) { + _dateScrollController.jumpTo(offset); + } else { + _dateScrollController.animateTo( + offset, + duration: const Duration(milliseconds: 250), + curve: Curves.easeOut, + ); + } + } + + /// ๋‹ค์Œ ๋‹ฌ๋กœ ์ด๋™ + void _navigateToNextMonth() { + // 2์ดˆ ์ฟจ๋‹ค์šด ์ฒดํฌ + final now = DateTime.now(); + if (_lastMonthChangeTime != null) { + final timeSinceLastChange = now.difference(_lastMonthChangeTime!); + if (timeSinceLastChange.inSeconds < 4) { + return; // 4์ดˆ๊ฐ€ ์ง€๋‚˜์ง€ ์•Š์•˜์œผ๋ฉด ์ด๋™ ๋ถˆ๊ฐ€ + } + } + + final nextMonth = DateTime(_currentMonth.year, _currentMonth.month + 1, 1); + + // ๊ฒฝ๊ณ„ ์ฒดํฌ + if (_maxMonth != null && nextMonth.isAfter(_maxMonth!)) { + return; + } + + // ๋‹ค์Œ ๋‹ฌ ์ฒซ ๋‚ ๋กœ ์ด๋™ + final targetDate = DateTime(nextMonth.year, nextMonth.month, 1); + + _lastMonthChangeTime = now; + _changeMonth(nextMonth, selectedDate: targetDate); + } + + /// ์ด์ „ ๋‹ฌ๋กœ ์ด๋™ + void _navigateToPreviousMonth() { + // 2์ดˆ ์ฟจ๋‹ค์šด ์ฒดํฌ + final now = DateTime.now(); + if (_lastMonthChangeTime != null) { + final timeSinceLastChange = now.difference(_lastMonthChangeTime!); + if (timeSinceLastChange.inSeconds < 4) { + return; // 4์ดˆ๊ฐ€ ์ง€๋‚˜์ง€ ์•Š์•˜์œผ๋ฉด ์ด๋™ ๋ถˆ๊ฐ€ + } + } + + // ์ด์ „ ๋‹ฌ์˜ ๋งˆ์ง€๋ง‰ ๋‚  ๊ณ„์‚ฐ + // DateTime(year, month, 0)์€ ์ด์ „ ๋‹ฌ์˜ ๋งˆ์ง€๋ง‰ ๋‚ ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค + // ์˜ˆ: DateTime(2025, 11, 0) โ†’ 2025๋…„ 10์›” 31์ผ + final prevMonthLastDay = DateTime( + _currentMonth.year, + _currentMonth.month, + 0, + ); + final prevMonthFirstDay = DateTime( + prevMonthLastDay.year, + prevMonthLastDay.month, + 1, + ); + + // ๊ฒฝ๊ณ„ ์ฒดํฌ (์ฒซ ๋‚  ๊ธฐ์ค€์œผ๋กœ ์ฒดํฌ) + if (_minMonth != null && prevMonthFirstDay.isBefore(_minMonth!)) { + return; + } + + // ์ด์ „ ๋‹ฌ์˜ ๋งˆ์ง€๋ง‰ ๋‚ ๋กœ ์ด๋™ + _lastMonthChangeTime = now; + _changeMonth(prevMonthFirstDay, selectedDate: prevMonthLastDay); + } + + /// ์›” ๋ณ€๊ฒฝ (์ฑ…์ž„: ์›” ์ƒํƒœ๋งŒ ๋ณ€๊ฒฝ) + /// + /// [newMonth]: ์ƒˆ ์›”์˜ ์ฒซ ๋‚  + /// [selectedDate]: ์„ ํƒํ•  ๋‚ ์งœ (null์ด๋ฉด ํ˜„์žฌ ์ผ์ž๋ฅผ ์ƒˆ ์›”๋กœ ๋ณ€ํ™˜) + void _changeMonth(DateTime newMonth, {DateTime? selectedDate}) { + // ๊ฐ™์€ ์›”์ด๋ฉด ๋ฌด์‹œ + if (_currentMonth.year == newMonth.year && + _currentMonth.month == newMonth.month) { + return; + } + + if (_isChangingMonth) return; + + _isChangingMonth = true; + + setState(() { + _currentMonth = newMonth; + // ์„ ํƒ๋œ ๋‚ ์งœ ์„ค์ • + if (selectedDate != null) { + // ๋ช…์‹œ์ ์œผ๋กœ ์ „๋‹ฌ๋œ ๋‚ ์งœ ์‚ฌ์šฉ + _selectedDate = selectedDate; + } else { + // selectedDate๊ฐ€ ์—†์œผ๋ฉด ํ˜„์žฌ ์„ ํƒ๋œ ๋‚ ์งœ์˜ ์ผ์ž๋ฅผ ์ƒˆ ์›”๋กœ ๋ณ€ํ™˜ ์‹œ๋„ + final currentDay = _selectedDate.day; + final newMonthLastDay = DateTime( + newMonth.year, + newMonth.month + 1, + 0, + ).day; + final targetDay = currentDay <= newMonthLastDay + ? currentDay + : newMonthLastDay; + _selectedDate = DateTime(newMonth.year, newMonth.month, targetDay); + } + }); + + // ์ƒˆ ์›”์˜ ํ•™์Šต ์ƒํƒœ ๋กœ๋“œ + if (widget.monthlyStatusUseCase != null) { + _loadMonthlyStatuses(); + } + + // ์Šคํฌ๋กค ์œ„์น˜ ์กฐ์ •: _currentMonth์™€ _selectedDate๊ฐ€ ์ด๋ฏธ ๋™๊ธฐํ™”๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์ง์ ‘ ์Šคํฌ๋กค + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) { + _isChangingMonth = false; + return; + } + + if (!_dateScrollController.hasClients) { + _isChangingMonth = false; + return; + } + + // _currentMonth์™€ _selectedDate๊ฐ€ ์ด๋ฏธ ๋™๊ธฐํ™”๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์ง์ ‘ ์Šคํฌ๋กค + // ์• ๋‹ˆ๋ฉ”์ด์…˜ ์—†์ด ์ฆ‰์‹œ ์ด๋™ (jumpTo)ํ•˜์—ฌ ๋ฌดํ•œ ๋ฃจํ”„ ๋ฐฉ์ง€ + final targetIndex = _selectedDate.day - 1; + final offset = targetIndex * itemWidth; + _dateScrollController + .animateTo( + offset, + duration: const Duration(milliseconds: 250), + curve: Curves.easeOut, + ) + .then((_) { + if (mounted) { + _isChangingMonth = false; + } + }); + }); + } + + /// ์Šคํฌ๋กค ์œ„์น˜ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ํžŒํŠธ ํ‘œ์‹œ ์—ฌ๋ถ€ ๊ฒฐ์ • + void _updateHintVisibility() { + if (!_dateScrollController.hasClients || _isChangingMonth) { + return; + } + + final position = _dateScrollController.position; + final pixels = position.pixels; + final max = position.maxScrollExtent; + final width = itemWidth; + + // ํžŒํŠธ ํ‘œ์‹œ ์ž„๊ณ„๊ฐ’: ์Šคํฌ๋กค์ด ๋์— ๊ฑฐ์˜ ๋„๋‹ฌํ–ˆ์„ ๋•Œ๋งŒ ํ‘œ์‹œ + // ์˜ค๋ฒ„์Šคํฌ๋กค(์Œ์ˆ˜ ๋˜๋Š” max ์ดˆ๊ณผ) ์ƒํƒœ์—์„œ๋งŒ ํžŒํŠธ ํ‘œ์‹œ + final hintThreshold = width * 0.2; // 0.2๊ฐœ ์•„์ดํ…œ ๋„ˆ๋น„ (๋” ์œ ์—ฐํ•˜๊ฒŒ) + + // ๋‹ค์Œ ๋‹ฌ ํžŒํŠธ ํ‘œ์‹œ ์กฐ๊ฑด: ์˜ค๋ฅธ์ชฝ ๋์„ ๋„˜์–ด์„œ ์˜ค๋ฒ„์Šคํฌ๋กค ์ƒํƒœ + final nextMonth = DateTime(_currentMonth.year, _currentMonth.month + 1, 1); + final canMoveToNext = + _maxMonth == null || + nextMonth.isBefore(_maxMonth!) || + nextMonth.isAtSameMomentAs(_maxMonth!); + // max๋ฅผ ๋„˜์–ด์„œ ์˜ค๋ฒ„์Šคํฌ๋กคํ–ˆ์„ ๋•Œ๋งŒ ํžŒํŠธ ํ‘œ์‹œ + final shouldShowNextHint = pixels > max + hintThreshold && canMoveToNext; + + // ์ด์ „ ๋‹ฌ ํžŒํŠธ ํ‘œ์‹œ ์กฐ๊ฑด: ์™ผ์ชฝ ๋์„ ๋„˜์–ด์„œ ์˜ค๋ฒ„์Šคํฌ๋กค ์ƒํƒœ + final prevMonth = DateTime(_currentMonth.year, _currentMonth.month - 1, 1); + final canMoveToPrev = + _minMonth == null || + prevMonth.isAfter(_minMonth!) || + prevMonth.isAtSameMomentAs(_minMonth!); + // 0์„ ๋„˜์–ด์„œ ์˜ค๋ฒ„์Šคํฌ๋กคํ–ˆ์„ ๋•Œ๋งŒ ํžŒํŠธ ํ‘œ์‹œ + final shouldShowPrevHint = pixels < -hintThreshold && canMoveToPrev; + + if (mounted) { + setState(() { + _showNextMonthHint = shouldShowNextHint; + _showPrevMonthHint = shouldShowPrevHint; + }); + } + } + + /// ScrollNotification ์ฒ˜๋ฆฌ + /// + /// ScrollUpdateNotification: ํžŒํŠธ ํ‘œ์‹œ ์—…๋ฐ์ดํŠธ + /// ScrollEndNotification: ์›” ์ „ํ™˜ ํŒ๋‹จ + bool _handleScrollNotification(ScrollNotification notification) { + // ์Šคํฌ๋กค ์—…๋ฐ์ดํŠธ ์‹œ ํžŒํŠธ ํ‘œ์‹œ ์—…๋ฐ์ดํŠธ + if (notification is ScrollUpdateNotification) { + _updateHintVisibility(); + return false; // ๊ณ„์† ์ „ํŒŒ + } + + // ์Šคํฌ๋กค์ด ๋๋‚œ ์‹œ์ ์—๋งŒ ์›” ์ „ํ™˜ ์ฒ˜๋ฆฌ + if (notification is! ScrollEndNotification) { + return false; // ๊ณ„์† ์ „ํŒŒ + } + + // ํžŒํŠธ ์ˆจ๊ธฐ๊ธฐ + if (mounted) { + setState(() { + _showNextMonthHint = false; + _showPrevMonthHint = false; + }); + } + + if (!mounted || _isChangingMonth) { + return false; + } + + if (!_dateScrollController.hasClients) { + return false; + } + + final position = _dateScrollController.position; + final pixels = position.pixels; + final max = position.maxScrollExtent; + final width = itemWidth; // getter ์‚ฌ์šฉ + + // ์˜ค๋ฅธ์ชฝ ๋ ๊ทผ์ฒ˜์—์„œ ์˜ค๋ฒ„์Šคํฌ๋กคํ–ˆ์„ ๋•Œ โ†’ ๋‹ค์Œ ๋‹ฌ + // max๋ฅผ ๋„˜์–ด์„œ ์˜ค๋ฒ„์Šคํฌ๋กคํ–ˆ๊ฑฐ๋‚˜, max ๊ทผ์ฒ˜์—์„œ ์Šคํฌ๋กค์ด ๋๋‚ฌ์„ ๋•Œ ์ „ํ™˜ + final nextMonthThreshold = width * _monthChangeOverScrollThreshold; + if (pixels > max - nextMonthThreshold || pixels > max) { + _navigateToNextMonth(); + return true; // ์ด๋ฒคํŠธ ์†Œ๋น„ + } + + // ์™ผ์ชฝ ๋ ๊ทผ์ฒ˜์—์„œ ์˜ค๋ฒ„์Šคํฌ๋กคํ–ˆ์„ ๋•Œ โ†’ ์ด์ „ ๋‹ฌ + // 0์„ ๋„˜์–ด์„œ ์˜ค๋ฒ„์Šคํฌ๋กคํ–ˆ๊ฑฐ๋‚˜, 0 ๊ทผ์ฒ˜์—์„œ ์Šคํฌ๋กค์ด ๋๋‚ฌ์„ ๋•Œ ์ „ํ™˜ + final prevMonthThreshold = width * _monthChangeOverScrollThreshold; + if (pixels < prevMonthThreshold || pixels < 0) { + _navigateToPreviousMonth(); + return true; // ์ด๋ฒคํŠธ ์†Œ๋น„ + } + + return false; // ๊ณ„์† ์ „ํŒŒ + } + + @override + void dispose() { + _dateScrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final screenHeight = MediaQuery.of(context).size.height; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // ์—ฐ์† ํ•™์Šต ์ผ์ˆ˜ ํ‘œ์‹œ + ์ƒ์„ธ ํŽ˜์ด์ง€ ์ด๋™ ๋ฒ„ํŠผ + GestureDetector( + onTap: () { + Navigator.pushNamed(context, '/continuous-learning-detail'); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + RichText( + text: TextSpan( + children: [ + TextSpan( + text: '${widget.consecutiveDays}์ผ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w700, + fontSize: 18, + color: Color(0xFFAC5BF8), + ), + ), + const TextSpan( + text: ' ์—ฐ์†์œผ๋กœ ํ•™์Šตํ•˜๊ณ  ์žˆ์–ด์š”', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 18, + color: Color(0xFF333333), + ), + ), + ], + ), + ), + Icon( + Icons.chevron_right, + color: Colors.grey[600], + size: MediaQuery.of(context).size.width * 0.06, + ), + ], + ), + ), + SizedBox(height: screenHeight * 0.0092), // 8px โ†’ 0.92% + // ๋‚ ์งœ ์Šคํฌ๋กค ์˜์—ญ (ListView ๊ฐ€๋กœ ์Šคํฌ๋กค) - ํ•œ ๋‹ฌ ๋‹จ์œ„ + // Stack ๋†’์ด = DateItem ์ „์ฒด ๋†’์ด (๋‚ ์งœ ํ…์ŠคํŠธ + ๊ฐ„๊ฒฉ + ๋ฐ•์Šค) + // ๋‚ ์งœ ํ…์ŠคํŠธ: fontSize 11 * height 1.1 โ‰ˆ 12px, SizedBox: 3px + // ํžŒํŠธ๋Š” DateItem์˜ 1:1 ๋ฐ•์Šค ๊ธฐ์ค€ ์ค‘์•™์— ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค. + SizedBox( + height: itemWidth + 15, // ๋ฐ•์Šค ๋†’์ด + ๋‚ ์งœ ํ…์ŠคํŠธ ๋†’์ด(์•ฝ 12px) + ๊ฐ„๊ฒฉ(3px) + child: Stack( + children: [ + NotificationListener( + onNotification: _handleScrollNotification, + child: ListView.builder( + controller: _dateScrollController, + scrollDirection: Axis.horizontal, + physics: const BouncingScrollPhysics(), + padding: EdgeInsets.symmetric( + horizontal: LearningWidgetSpacing.getOuterPadding(context), + ), + itemExtent: itemWidth, // ์นด๋“œ ๋„ˆ๋น„ (getter ์‚ฌ์šฉ) + itemCount: DateTime( + _currentMonth.year, + _currentMonth.month + 1, + 0, + ).day, + itemBuilder: (context, index) { + // _currentMonth๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‚ ์งœ ์ƒ์„ฑ + final date = DateTime( + _currentMonth.year, + _currentMonth.month, + index + 1, + ); + + final isSelected = _isSameDay(date, _selectedDate); + final isCompleted = _isDateCompleted(date); + final hasHomework = _hasHomeworkDeadline(date); + + // ๋‹ค์Œ ๋‚ ์งœ์˜ ์™„๋ฃŒ ์—ฌ๋ถ€ ํ™•์ธ (์—ฐ๊ฒฐ์„  ํ‘œ์‹œ์šฉ) + final nextDate = date.add(const Duration(days: 1)); + final isNextCompleted = _isDateCompleted(nextDate); + // ๋‹ค์Œ ๋‚ ์ด ํ˜„์žฌ ์›”์— ์†ํ•  ๋•Œ๋งŒ ์—ฐ๊ฒฐ์„  ํ‘œ์‹œ + final showConnector = + isCompleted && + isNextCompleted && + nextDate.month == date.month && + nextDate.year == date.year; + + return _buildDateItem( + date: date, + isSelected: isSelected, + isCompleted: isCompleted, + hasHomework: hasHomework, + showConnector: showConnector, + ); + }, + ), + ), + // ํžŒํŠธ ํ‘œ์‹œ (์˜ค๋ฒ„๋ ˆ์ด) + // ํžŒํŠธ๋Š” DateItem์˜ 1:1 ๋ฐ•์Šค ๊ธฐ์ค€ ์ค‘์•™์— ์ •๋ ฌ๋ฉ๋‹ˆ๋‹ค. + // ๋ฐ•์Šค๋Š” Stack ๋‚ด์—์„œ ์•„๋ž˜์ชฝ์— ์œ„์น˜ํ•˜๋ฏ€๋กœ, top offset์„ ์กฐ์ •ํ•˜์—ฌ ๋ฐ•์Šค ์ค‘์•™์— ๋งž์ถฅ๋‹ˆ๋‹ค. + if (_showNextMonthHint) + Positioned( + right: LearningWidgetSpacing.getOuterPadding( + context, + ), // ListView padding๊ณผ ๋™์ผ + top: 15, // ๋‚ ์งœ ํ…์ŠคํŠธ + ๊ฐ„๊ฒฉ ๋†’์ด๋งŒํผ offset + child: SizedBox( + height: itemWidth, // ๋ฐ•์Šค ๋†’์ด์™€ ๋™์ผ + child: Center( + child: _buildMonthHint('๋” ๋“œ๋ž˜๊ทธํ•ด์„œ\n๋‹ค์Œ ๋‹ฌ๋กœ', true), + ), + ), + ), + if (_showPrevMonthHint) + Positioned( + left: LearningWidgetSpacing.getOuterPadding( + context, + ), // ListView padding๊ณผ ๋™์ผ + top: 15, // ๋‚ ์งœ ํ…์ŠคํŠธ + ๊ฐ„๊ฒฉ ๋†’์ด๋งŒํผ offset + child: SizedBox( + height: itemWidth, // ๋ฐ•์Šค ๋†’์ด์™€ ๋™์ผ + child: Center( + child: _buildMonthHint('๋” ๋“œ๋ž˜๊ทธํ•ด์„œ\n์ด์ „ ๋‹ฌ๋กœ', false), + ), + ), + ), + ], + ), + ), + ], + ); + } + + /// ๋‚ ์งœ ์•„์ดํ…œ UI + Widget _buildDateItem({ + required DateTime date, + required bool isSelected, + required bool isCompleted, + required bool hasHomework, + required bool showConnector, + }) { + // cardWidth๋Š” itemWidth์™€ ๋™์ผํ•˜๊ฒŒ ์„ค์ • (ํ†ต์ผ) + final cardWidth = itemWidth; + + // ๋ฐ•์Šค ๋ฐฐ๊ฒฝ (ํ•™์Šต ์™„๋ฃŒ ์—ฌ๋ถ€์— ๋”ฐ๋ผ) + // ๋กœ๊ณ  ๊ทธ๋ผ๋ฐ์ด์…˜: linear-gradient(121.67deg, #AC5BF8 19.64%, #636ACF 77.54%) + final boxDecoration = isCompleted + ? BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + // 121.67deg โ‰ˆ 2.12 ๋ผ๋””์•ˆ + // CSS: linear-gradient(121.67deg, #AC5BF8 19.64%, #636ACF 77.54%) + colors: [ + Color(0xFFAC5BF8), // 19.64% + Color(0xFF636ACF), // 77.54% + ], + stops: [0.1964, 0.7754], + ), + borderRadius: BorderRadius.circular(10), + boxShadow: [ + BoxShadow( + color: const Color(0xFFAC5BF8).withOpacity(0.4), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ) + : BoxDecoration( + color: const Color(0xFFE1E7ED), // ํšŒ์ƒ‰ + borderRadius: BorderRadius.circular(10), + ); + + // ๋‚ ์งœ ํ…์ŠคํŠธ ์ƒ‰์ƒ + final dateColor = isSelected ? Colors.white : const Color(0xFF666666); + + // ์ฑ… ์•„์ด์ฝ˜ ์ƒ‰์ƒ + final bookIconColor = isCompleted ? Colors.white : const Color(0xFF7C3AED); + + return GestureDetector( + onTap: () { + // ๋‚ ์งœ ํƒญ ์‹œ: ๊ฐ™์€ ๋‹ฌ๋งŒ ๋ฐ”๋€๋‹ค โ†’ ์›”์€ ๋ฐ”๊พธ์ง€ ์•Š๊ณ , ๋‹จ์ˆœํžˆ ์„ ํƒ๋งŒ ๋ณ€๊ฒฝ + setState(() { + _selectedDate = date; + }); + if (widget.onDateSelected != null) { + widget.onDateSelected!(date); + } + // ์Šคํฌ๋กค ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ œ๊ฑฐ: ๋‚ ์งœ ์„ ํƒ ์‹œ ์ž๋™ ์Šคํฌ๋กคํ•˜์ง€ ์•Š์Œ + }, + child: SizedBox( + width: cardWidth, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: LearningWidgetSpacing.getInnerPadding(context), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // ๋‚ ์งœ (์›”/์ผ) - ์„ ํƒ๋œ ๋‚ ์€ ๊ทธ๋ผ๋ฐ์ด์…˜ ๋ฐฐ๊ฒฝ + Container( + padding: const EdgeInsets.symmetric(horizontal: 2, vertical: 0), + decoration: isSelected + ? BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFFAC5BF8), Color(0xFF636ACF)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(4), + boxShadow: [ + BoxShadow( + color: const Color(0xFFAC5BF8).withOpacity(0.3), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ) + : BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + '${date.month}/${date.day}', + style: TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 11, + color: dateColor, + height: 1.1, // ์ค„ ๊ฐ„๊ฒฉ ์ค„์ž„ + ), + ), + ), + const SizedBox(height: 3), + // ๋ฐ•์Šค์™€ ์—ฐ๊ฒฐ์„ ์„ Stack์œผ๋กœ ๊ตฌ์„ฑ + Stack( + clipBehavior: Clip.none, + children: [ + // ๋ฐ•์Šค (์ฑ… ์•„์ด์ฝ˜ ๋˜๋Š” ์ฒดํฌ ์•„์ด์ฝ˜ ๋˜๋Š” ๋‘˜ ๋‹ค ๋˜๋Š” ๋นˆ ๊ณต๊ฐ„) - 1:1 ๋น„์œจ ๊ฐ•์ œ + AspectRatio( + aspectRatio: 1.0, + child: Container( + decoration: boxDecoration, + child: _buildBoxContent( + hasHomework: hasHomework, + isCompleted: isCompleted, + bookIconColor: bookIconColor, + cardHeight: cardWidth, + ), + ), + ), + // ์—ฐ๊ฒฐ์„  (๋‹ค์Œ ๋‚ ์งœ์™€ ์—ฐ๊ฒฐ) + if (showConnector) + Positioned( + right: -LearningWidgetSpacing.getConnectorWidth(context), + top: + (cardWidth - + LearningWidgetSpacing.getConnectorWidth( + context, + )) / + 2, + child: Container( + width: LearningWidgetSpacing.getConnectorWidth(context), + height: LearningWidgetSpacing.getConnectorWidth( + context, + ), + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [Color(0xFFAC5BF8), Color(0xFF636ACF)], + stops: [0.1964, 0.7754], + ), + borderRadius: BorderRadius.circular(2), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ); + } + + /// ๋ฐ•์Šค ๋‚ด๋ถ€ ์ฝ˜ํ…์ธ  (์ฑ… ์•„์ด์ฝ˜, ์ฒดํฌ ์•„์ด์ฝ˜, ๋‘˜ ๋‹ค, ๋˜๋Š” ๋นˆ ๊ณต๊ฐ„) + Widget? _buildBoxContent({ + required bool hasHomework, + required bool isCompleted, + required Color bookIconColor, + required double cardHeight, + }) { + // ๋‘˜ ๋‹ค ์žˆ๋Š” ๊ฒฝ์šฐ: ์ฑ… ์•„์ด์ฝ˜๊ณผ ์ฒดํฌ ์•„์ด์ฝ˜์„ ํ•จ๊ป˜ ํ‘œ์‹œ + if (hasHomework && isCompleted) { + return Stack( + children: [ + // ์ฑ… ์•„์ด์ฝ˜ (์ค‘์•™) + Center( + child: Icon( + Icons.menu_book, + color: bookIconColor, + size: cardHeight * 0.4, + ), + ), + // ์ฒดํฌ ์•„์ด์ฝ˜ (์˜ค๋ฅธ์ชฝ ์ƒ๋‹จ) + Positioned( + top: cardHeight * 0.1, + right: cardHeight * 0.1, + child: Icon( + Icons.check_circle, + color: Colors.white, + size: cardHeight * 0.25, + ), + ), + ], + ); + } + // ์ฑ… ์•„์ด์ฝ˜๋งŒ + else if (hasHomework) { + return Center( + child: Icon( + Icons.menu_book, + color: bookIconColor, + size: cardHeight * 0.5, + ), + ); + } + // ์ฒดํฌ ์•„์ด์ฝ˜๋งŒ (ํ•™์Šต ์™„๋ฃŒ) + else if (isCompleted) { + return Center( + child: Icon(Icons.check, color: Colors.white, size: cardHeight * 0.5), + ); + } + // ๋‘˜ ๋‹ค ์—†์Œ + return null; + } + + // ํ—ฌํผ ๋ฉ”์„œ๋“œ๋“ค + + bool _isSameDay(DateTime date1, DateTime date2) { + return date1.year == date2.year && + date1.month == date2.month && + date1.day == date2.day; + } + + bool _isDateCompleted(DateTime date) { + final normalizedDate = DailyLearningStatus.normalizeDate(date); + + // ์šฐ์„ ์ˆœ์œ„ 1: dailyStatusMap ์‚ฌ์šฉ (์ƒˆ ๊ตฌ์กฐ) + if (widget.dailyStatusMap != null) { + return widget.dailyStatusMap![normalizedDate]?.isCompleted ?? false; + } + + // ์šฐ์„ ์ˆœ์œ„ 2: _currentMonthStatuses ์‚ฌ์šฉ (UseCase ๊ฒฐ๊ณผ) + if (_currentMonthStatuses != null) { + return _currentMonthStatuses![normalizedDate]?.isCompleted ?? false; + } + + // ์šฐ์„ ์ˆœ์œ„ 3: ๊ธฐ์กด dateAssessments ์‚ฌ์šฉ (ํ•˜์œ„ ํ˜ธํ™˜์„ฑ, ์ถ”ํ›„ ์ œ๊ฑฐ ์˜ˆ์ •) + if (widget.dateAssessments != null) { + final dateStr = _formatDate(date); + final assessments = widget.dateAssessments![dateStr] ?? []; + // ๊ณผ์ œ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ์„ ๋•Œ, "๋ชจ๋“  ๊ณผ์ œ๊ฐ€ Y"์ธ ๋‚ ๋งŒ ์™„๋ฃŒ๋กœ ๊ฐ„์ฃผ + if (assessments.isEmpty) { + return false; + } + return assessments.every((a) => a.assessStatus == 'Y'); + } + + // ์šฐ์„ ์ˆœ์œ„ 4: ๊ธฐ์กด completedDates ์‚ฌ์šฉ (ํ•˜์œ„ ํ˜ธํ™˜์„ฑ, ์ถ”ํ›„ ์ œ๊ฑฐ ์˜ˆ์ •) + final dateStr = _formatDate(date); + return widget.completedDates.contains(dateStr); + } + + /// ์›” ์ „ํ™˜ ํžŒํŠธ ์œ„์ ฏ ์ƒ์„ฑ + Widget _buildMonthHint(String text, bool isRight) { + return IgnorePointer( + child: AnimatedOpacity( + opacity: isRight + ? (_showNextMonthHint ? 1.0 : 0.0) + : (_showPrevMonthHint ? 1.0 : 0.0), + duration: const Duration(milliseconds: 200), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: LearningWidgetSpacing.hintOuterHorizontalPadding, + vertical: LearningWidgetSpacing.hintOuterVerticalPadding, + ), + child: Container( + padding: EdgeInsets.symmetric( + horizontal: LearningWidgetSpacing.getHintInnerHorizontalPadding( + context, + ), + vertical: LearningWidgetSpacing.getHintInnerVerticalPadding( + context, + ), + ), + decoration: BoxDecoration( + color: const Color(0xFFAC5BF8).withOpacity(0.9), + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: const Color(0xFFAC5BF8).withOpacity(0.3), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Text( + text, + textAlign: TextAlign.center, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 12, + color: Colors.white, + height: 1.3, + ), + ), + ), + ), + ), + ); + } + + bool _hasHomeworkDeadline(DateTime date) { + final dateStr = _formatDate(date); + + // Assessment ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ์„ ์šฐ์„  ์‚ฌ์šฉ + if (widget.dateAssessments != null) { + final assessments = widget.dateAssessments![dateStr] ?? []; + return assessments.isNotEmpty; + } + + // ์—†์œผ๋ฉด ๊ธฐ์กด homeworkDeadlines ์‚ฌ์šฉ (ํ•˜์œ„ ํ˜ธํ™˜์„ฑ) + return widget.homeworkDeadlines.contains(dateStr); + } + + /// ๋‚ ์งœ ํฌ๋งทํŒ… (YYYY-MM-DD) + String _formatDate(DateTime date) { + return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; + } +} diff --git a/frontend/lib/widgets/empty_state_message.dart b/frontend/lib/widgets/empty_state_message.dart new file mode 100644 index 0000000..80ae9f7 --- /dev/null +++ b/frontend/lib/widgets/empty_state_message.dart @@ -0,0 +1,147 @@ +import 'package:flutter/material.dart'; + +/// ๊ณตํ†ต Empty State ์œ„์ ฏ +/// +/// - ์•„์ด์ฝ˜, ์ œ๋ชฉ, ์„ค๋ช…, ๊ธฐ๋ณธ ์•ก์…˜ ๋ฒ„ํŠผ์„ ์ผ๊ด€๋œ ์Šคํƒ€์ผ๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. +/// - ๋ ˆ์ด์•„์›ƒ ๋ฐฐ์น˜๋Š” ๋ถ€๋ชจ์—์„œ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: Center, SingleChildScrollView ๋“ฑ). +class EmptyStateMessage extends StatelessWidget { + final IconData icon; + final String title; + final String? description; + final MainAxisAlignment mainAxisAlignment; + final String? primaryActionLabel; + final VoidCallback? onPrimaryAction; + + const EmptyStateMessage({ + super.key, + required this.icon, + required this.title, + this.description, + this.mainAxisAlignment = MainAxisAlignment.center, + this.primaryActionLabel, + this.onPrimaryAction, + }); + + /// ์ˆ™์ œ ๋„๋ฉ”์ธ์šฉ ํ”„๋ฆฌ์…‹ + const EmptyStateMessage.homework({ + super.key, + String? title, + String? description, + String? primaryActionLabel, + VoidCallback? onPrimaryAction, + }) : icon = Icons.assignment_outlined, + title = title ?? '๋“ฑ๋ก๋œ ์ˆ™์ œ๊ฐ€ ์—†์–ด์š”.', + description = description, + primaryActionLabel = primaryActionLabel, + onPrimaryAction = onPrimaryAction, + mainAxisAlignment = MainAxisAlignment.center; + + /// ๋ฌธ์ œ์ง‘ ๋„๋ฉ”์ธ์šฉ ํ”„๋ฆฌ์…‹ + const EmptyStateMessage.workbook({ + super.key, + String? title, + String? description, + String? primaryActionLabel, + VoidCallback? onPrimaryAction, + }) : icon = Icons.book_outlined, + title = title ?? 'ํ˜„์žฌ ๋“ฑ๋ก๋œ ๋ฌธ์ œ์ง‘์ด ์—†์–ด์š”.', + description = description, + primaryActionLabel = primaryActionLabel, + onPrimaryAction = onPrimaryAction, + mainAxisAlignment = MainAxisAlignment.center; + + /// ํ•™์› ๋„๋ฉ”์ธ์šฉ ํ”„๋ฆฌ์…‹ + const EmptyStateMessage.academy({ + super.key, + String? title, + String? description, + String? primaryActionLabel, + VoidCallback? onPrimaryAction, + }) : icon = Icons.school_outlined, + title = title ?? '๋“ฑ๋ก๋œ ํ•™์›์ด ์—†์–ด์š”.', + description = description, + primaryActionLabel = primaryActionLabel, + onPrimaryAction = onPrimaryAction, + mainAxisAlignment = MainAxisAlignment.center; + + /// ํด๋ž˜์Šค/๋ฐ˜ ๋„๋ฉ”์ธ์šฉ ํ”„๋ฆฌ์…‹ + const EmptyStateMessage.classRoom({ + super.key, + String? title, + String? description, + String? primaryActionLabel, + VoidCallback? onPrimaryAction, + }) : icon = Icons.group_outlined, + title = title ?? '๋“ฑ๋ก๋œ ํด๋ž˜์Šค๊ฐ€ ์—†์–ด์š”.', + description = description, + primaryActionLabel = primaryActionLabel, + onPrimaryAction = onPrimaryAction, + mainAxisAlignment = MainAxisAlignment.center; + + @override + Widget build(BuildContext context) { + final children = [ + Icon( + icon, + size: 64, + color: const Color(0xFF999999), + ), + const SizedBox(height: 16), + Text( + title, + textAlign: TextAlign.center, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w500, + fontSize: 16, + color: Color(0xFF666666), + ), + ), + ]; + + if (description != null && description!.isNotEmpty) { + children.addAll([ + const SizedBox(height: 8), + Text( + description!, + textAlign: TextAlign.center, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w400, + fontSize: 13, + color: Color(0xFF999999), + ), + ), + ]); + } + + if (primaryActionLabel != null && onPrimaryAction != null) { + children.addAll([ + const SizedBox(height: 24), + SizedBox( + width: 160, + child: ElevatedButton( + onPressed: onPrimaryAction, + child: Text( + primaryActionLabel!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontWeight: FontWeight.w600, + fontSize: 14, + ), + ), + ), + ), + ]); + } + + return Column( + mainAxisAlignment: mainAxisAlignment, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } +} + + diff --git a/frontend/lib/widgets/error_input_field.dart b/frontend/lib/widgets/error_input_field.dart new file mode 100644 index 0000000..bad69cf --- /dev/null +++ b/frontend/lib/widgets/error_input_field.dart @@ -0,0 +1,119 @@ +import 'package:flutter/material.dart'; + +class ErrorInputField extends StatelessWidget { + final String label; + final String placeholder; + final TextEditingController? controller; + final bool obscureText; + final TextInputType? keyboardType; + final ValueChanged? onChanged; + final String? errorText; + final bool hasError; + final double? width; + final double? height; + + const ErrorInputField({ + super.key, + required this.label, + required this.placeholder, + this.controller, + this.obscureText = false, + this.keyboardType, + this.onChanged, + this.errorText, + this.hasError = false, + this.width, + this.height, + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: width ?? 342, + height: height ?? (hasError ? 102 : 76), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Label + Text( + label, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w600, + height: 1.193, + color: Color(0xFF5C5C5C), + ), + ), + + const SizedBox(height: 8), + + // Input Field + Container( + width: 342, + height: 50, + decoration: BoxDecoration( + color: Colors.white, + border: hasError + ? Border.all( + color: const Color( + 0xFFAC5BF8, + ), // Gradient color for error border + width: 2, + ) + : null, + borderRadius: BorderRadius.circular(5), + ), + child: TextField( + controller: controller, + obscureText: obscureText, + keyboardType: keyboardType, + onChanged: onChanged, + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: hasError + ? const Color(0xFFFF4258) + : const Color(0xFFA0A0A0), + ), + decoration: InputDecoration( + hintText: placeholder, + hintStyle: TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: hasError + ? const Color(0xFFFF4258) + : const Color(0xFFA0A0A0), + ), + border: InputBorder.none, + contentPadding: const EdgeInsets.symmetric( + horizontal: 18, + vertical: 16, + ), + ), + ), + ), + + // Error Text + if (hasError && errorText != null) ...[ + const SizedBox(height: 8), + Text( + errorText!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: Color(0xFFAC5BF8), // Gradient color for error text + ), + ), + ], + ], + ), + ); + } +} diff --git a/frontend/lib/widgets/input_field.dart b/frontend/lib/widgets/input_field.dart new file mode 100644 index 0000000..c874908 --- /dev/null +++ b/frontend/lib/widgets/input_field.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; + +class InputField extends StatelessWidget { + final String placeholder; + final TextEditingController? controller; + final bool obscureText; + final TextInputType? keyboardType; + final ValueChanged? onChanged; + final double? width; + final double? height; + final bool isError; + + const InputField({ + super.key, + required this.placeholder, + this.controller, + this.obscureText = false, + this.keyboardType, + this.onChanged, + this.width, + this.height, + this.isError = false, + }); + + @override + Widget build(BuildContext context) { + return Container( + width: width ?? 342, + height: height ?? 50, + decoration: BoxDecoration( + color: const Color(0xFFF3F3F3), + borderRadius: BorderRadius.circular(5), + border: isError + ? Border.all(color: const Color(0xFFFF4258), width: 1) + : null, + ), + child: TextField( + controller: controller, + obscureText: obscureText, + keyboardType: keyboardType, + onChanged: onChanged, + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: isError ? const Color(0xFFFF4258) : const Color(0xFFA0A0A0), + ), + decoration: InputDecoration( + hintText: placeholder, + hintStyle: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: Color(0xFFA0A0A0), + ), + border: InputBorder.none, + contentPadding: const EdgeInsets.symmetric( + horizontal: 18, + vertical: 16, + ), + ), + ), + ); + } +} diff --git a/frontend/lib/widgets/labeled_input_field.dart b/frontend/lib/widgets/labeled_input_field.dart new file mode 100644 index 0000000..33754c0 --- /dev/null +++ b/frontend/lib/widgets/labeled_input_field.dart @@ -0,0 +1,112 @@ +import 'package:flutter/material.dart'; + +class LabeledInputField extends StatelessWidget { + final String label; + final String placeholder; + final TextEditingController? controller; + final bool obscureText; + final TextInputType? keyboardType; + final ValueChanged? onChanged; + final double? width; + final double? height; + final bool isError; + final String? errorMessage; + + const LabeledInputField({ + super.key, + required this.label, + required this.placeholder, + this.controller, + this.obscureText = false, + this.keyboardType, + this.onChanged, + this.width, + this.height, + this.isError = false, + this.errorMessage, + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: width ?? 342, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + // Label + Text( + label, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w600, + height: 1.193, + color: Color(0xFF5C5C5C), + ), + ), + + const SizedBox(height: 8), + + // Input Field + Container( + width: 342, + height: 50, + decoration: BoxDecoration( + color: const Color(0xFFF3F3F3), + borderRadius: BorderRadius.circular(5), + border: isError + ? Border.all(color: const Color(0xFFFF4258), width: 1) + : null, + ), + child: TextField( + controller: controller, + obscureText: obscureText, + keyboardType: keyboardType, + onChanged: onChanged, + style: TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: isError + ? const Color(0xFFFF4258) + : const Color(0xFFA0A0A0), + ), + decoration: InputDecoration( + hintText: placeholder, + hintStyle: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 15, + fontWeight: FontWeight.w500, + height: 1.193, + color: Color(0xFFA0A0A0), + ), + border: InputBorder.none, + contentPadding: const EdgeInsets.symmetric( + horizontal: 18, + vertical: 16, + ), + ), + ), + ), + + // Error Message + if (isError && errorMessage != null) ...[ + const SizedBox(height: 8), + Text( + errorMessage!, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 12, + fontWeight: FontWeight.w500, + height: 1.33, + color: Color(0xFFFF4258), + ), + ), + ], + ], + ), + ); + } +} diff --git a/frontend/lib/widgets/links_section.dart b/frontend/lib/widgets/links_section.dart new file mode 100644 index 0000000..c4276d5 --- /dev/null +++ b/frontend/lib/widgets/links_section.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; + +class LinksSection extends StatelessWidget { + final VoidCallback? onSignUp; + final VoidCallback? onFindID; + final VoidCallback? onFindPW; + + const LinksSection({super.key, this.onSignUp, this.onFindID, this.onFindPW}); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: 244, + height: 17, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // ํšŒ์›๊ฐ€์ž… + GestureDetector( + onTap: onSignUp, + child: Text( + 'ํšŒ์›๊ฐ€์ž…', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w600, + height: 1.193, + color: Color(0xFF666EDE), + ), + ), + ), + + // ๊ตฌ๋ถ„์„  1 + SizedBox( + width: 1, + height: 14, + child: Container(color: const Color(0xFFCBCBCB)), + ), + + // ์•„์ด๋”” ์ฐพ๊ธฐ + GestureDetector( + onTap: onFindID, + child: Text( + '์•„์ด๋”” ์ฐพ๊ธฐ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w500, + height: 1.193, + color: Color(0xFFA0A0A0), + ), + ), + ), + + // ๊ตฌ๋ถ„์„  2 + SizedBox( + width: 1, + height: 14, + child: Container(color: const Color(0xFFCBCBCB)), + ), + + // ๋น„๋ฐ€๋ฒˆํ˜ธ ์ฐพ๊ธฐ + GestureDetector( + onTap: onFindPW, + child: Text( + '๋น„๋ฐ€๋ฒˆํ˜ธ ์ฐพ๊ธฐ', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w500, + height: 1.193, + color: Color(0xFFA0A0A0), + ), + ), + ), + ], + ), + ); + } +} diff --git a/frontend/lib/widgets/login_button.dart b/frontend/lib/widgets/login_button.dart new file mode 100644 index 0000000..b6642c4 --- /dev/null +++ b/frontend/lib/widgets/login_button.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; + +class LoginButton extends StatelessWidget { + final String text; + final VoidCallback? onPressed; + final double? width; + final double? height; + + const LoginButton({ + super.key, + required this.text, + this.onPressed, + this.width, + this.height, + }); + + @override + Widget build(BuildContext context) { + return Container( + width: width ?? 342, + height: height ?? 50, + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFFAC5BF8), // rgba(172, 91, 248, 1) + Color(0xFF636ACF), // rgba(99, 106, 207, 1) + ], + stops: [0.0, 1.0], + transform: GradientRotation(2.51), // 144 degrees in radians + ), + borderRadius: BorderRadius.circular(5), + ), + child: ElevatedButton( + onPressed: onPressed, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), + ), + child: Text( + text, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 16, + fontWeight: FontWeight.w600, + height: 1.193, + color: Colors.white, + ), + ), + ), + ); + } +} diff --git a/frontend/lib/widgets/next_button.dart b/frontend/lib/widgets/next_button.dart new file mode 100644 index 0000000..aae26e3 --- /dev/null +++ b/frontend/lib/widgets/next_button.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; + +class NextButton extends StatelessWidget { + final String text; + final VoidCallback? onPressed; + final double? width; + final double? height; + + const NextButton({ + super.key, + this.text = '๋‹ค์Œ', + this.onPressed, + this.width, + this.height, + }); + + @override + Widget build(BuildContext context) { + return Container( + width: width ?? 342, + height: height ?? 50, + decoration: BoxDecoration( + gradient: const LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + Color(0xFFAC5BF8), // rgba(172, 91, 248, 1) + Color(0xFF636ACF), // rgba(99, 106, 207, 1) + ], + stops: [0.0, 1.0], + transform: GradientRotation(2.51), // 144 degrees in radians + ), + borderRadius: BorderRadius.circular(5), + ), + child: ElevatedButton( + onPressed: onPressed, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), + ), + child: Text( + text, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 16, + fontWeight: FontWeight.w600, + height: 1.193, + color: Colors.white, + ), + ), + ), + ); + } +} diff --git a/frontend/lib/widgets/page_title.dart b/frontend/lib/widgets/page_title.dart new file mode 100644 index 0000000..afee855 --- /dev/null +++ b/frontend/lib/widgets/page_title.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +class PageTitle extends StatelessWidget { + final String text; + final double? width; + final double? height; + final TextAlign? textAlign; + + const PageTitle({ + super.key, + required this.text, + this.width, + this.height, + this.textAlign, + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: width, + child: Text( + text, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 20, + fontWeight: FontWeight.w600, + height: 1.193, + color: Color(0xFF5C5C5C), + ), + textAlign: textAlign ?? TextAlign.center, + overflow: TextOverflow.visible, + ), + ); + } +} diff --git a/frontend/lib/widgets/sns_button.dart b/frontend/lib/widgets/sns_button.dart new file mode 100644 index 0000000..e8821f1 --- /dev/null +++ b/frontend/lib/widgets/sns_button.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +enum SNSProvider { kakao, google } + +class SNSButton extends StatelessWidget { + final SNSProvider provider; + final VoidCallback? onPressed; + final double? width; + final double? height; + + const SNSButton({ + super.key, + required this.provider, + this.onPressed, + this.width, + this.height, + }); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPressed, + child: SizedBox( + width: width ?? 50, + height: height ?? 50, + child: _buildIcon(), + ), + ); + } + + Widget _buildIcon() { + switch (provider) { + case SNSProvider.kakao: + return Image.asset( + 'assets/images/social_login/Button_Kakao.png', + width: width ?? 50, + height: height ?? 50, + fit: BoxFit.contain, + ); + case SNSProvider.google: + return Image.asset( + 'assets/images/social_login/Button_Google.png', + width: width ?? 50, + height: height ?? 50, + fit: BoxFit.contain, + ); + } + } +} diff --git a/frontend/lib/widgets/sns_divider.dart b/frontend/lib/widgets/sns_divider.dart new file mode 100644 index 0000000..5a14f39 --- /dev/null +++ b/frontend/lib/widgets/sns_divider.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; + +class SNSDivider extends StatelessWidget { + final String text; + final double? width; + final double? height; + + const SNSDivider({ + super.key, + this.text = 'SNS ๊ฐ„ํŽธ ๋กœ๊ทธ์ธ', + this.width, + this.height, + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: width ?? 339, + height: height ?? 17, + child: Row( + children: [ + // Left line + Expanded( + child: SizedBox( + height: 1, + child: Container(color: const Color(0xFFCBCBCB)), + ), + ), + + // Text + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Text( + text, + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 14, + fontWeight: FontWeight.w500, + height: 1.193, + color: Color(0xFFA0A0A0), + ), + ), + ), + + // Right line + Expanded( + child: SizedBox( + height: 1, + child: Container(color: const Color(0xFFCBCBCB)), + ), + ), + ], + ), + ); + } +} diff --git a/frontend/lib/widgets/user_id_card.dart b/frontend/lib/widgets/user_id_card.dart new file mode 100644 index 0000000..6909151 --- /dev/null +++ b/frontend/lib/widgets/user_id_card.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class UserIDCard extends StatelessWidget { + final String userName; + final String userId; + final double? width; + + const UserIDCard({ + super.key, + required this.userName, + required this.userId, + this.width, + }); + + @override + Widget build(BuildContext context) { + return Container( + constraints: BoxConstraints(maxWidth: width ?? double.infinity), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '$userName๋‹˜์˜ ์•„์ด๋””๋Š”', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 24, + fontWeight: FontWeight.w600, + color: Color(0xFF5C5C5C), + height: 1.193, + ), + ), + Text( + '$userId์ž…๋‹ˆ๋‹ค.', + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 24, + fontWeight: FontWeight.w600, + color: Color(0xFF5C5C5C), + height: 1.193, + ), + ), + ], + ), + ); + } +} diff --git a/frontend/lib/widgets/verification_code_input.dart b/frontend/lib/widgets/verification_code_input.dart new file mode 100644 index 0000000..cf68408 --- /dev/null +++ b/frontend/lib/widgets/verification_code_input.dart @@ -0,0 +1,110 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class VerificationCodeInput extends StatefulWidget { + final int length; + final ValueChanged? onChanged; + final double? width; + final double? height; + + const VerificationCodeInput({ + super.key, + this.length = 4, + this.onChanged, + this.width, + this.height, + }); + + @override + State createState() => _VerificationCodeInputState(); +} + +class _VerificationCodeInputState extends State { + final List _controllers = []; + final List _focusNodes = []; + String _code = ''; + + @override + void initState() { + super.initState(); + for (int i = 0; i < widget.length; i++) { + _controllers.add(TextEditingController()); + _focusNodes.add(FocusNode()); + } + } + + @override + void dispose() { + for (var controller in _controllers) { + controller.dispose(); + } + for (var focusNode in _focusNodes) { + focusNode.dispose(); + } + super.dispose(); + } + + void _onTextChanged(String value, int index) { + if (value.length == 1) { + // Move to next field + if (index < widget.length - 1) { + _focusNodes[index + 1].requestFocus(); + } + } else if (value.isEmpty) { + // Move to previous field + if (index > 0) { + _focusNodes[index - 1].requestFocus(); + } + } + + // Update code + _code = _controllers.map((controller) => controller.text).join(); + widget.onChanged?.call(_code); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + width: widget.width ?? 248, + height: widget.height ?? 50, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.generate(widget.length, (index) { + return Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: _controllers[index].text.isNotEmpty + ? Colors.white + : const Color(0xFFF3F3F3), + border: _controllers[index].text.isNotEmpty + ? Border.all(color: const Color(0xFF666EDE), width: 2) + : null, + borderRadius: BorderRadius.circular(5), + ), + child: TextField( + controller: _controllers[index], + focusNode: _focusNodes[index], + textAlign: TextAlign.center, + maxLength: 1, + keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], + style: const TextStyle( + fontFamily: 'Pretendard', + fontSize: 20, + fontWeight: FontWeight.w600, + color: Color(0xFF5C5C5C), + ), + decoration: const InputDecoration( + counterText: '', + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + ), + onChanged: (value) => _onTextChanged(value, index), + ), + ); + }), + ), + ); + } +} diff --git a/frontend/linux/.gitignore b/frontend/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/frontend/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/frontend/linux/CMakeLists.txt b/frontend/linux/CMakeLists.txt new file mode 100644 index 0000000..36b1acd --- /dev/null +++ b/frontend/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "gradi_frontend") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.gradi.gradi_frontend") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/frontend/linux/flutter/CMakeLists.txt b/frontend/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/frontend/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/frontend/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux b/frontend/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux new file mode 120000 index 0000000..10ab563 --- /dev/null +++ b/frontend/linux/flutter/ephemeral/.plugin_symlinks/file_selector_linux @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/file_selector_linux-0.9.3+2/ \ No newline at end of file diff --git a/frontend/linux/flutter/ephemeral/.plugin_symlinks/flutter_local_notifications_linux b/frontend/linux/flutter/ephemeral/.plugin_symlinks/flutter_local_notifications_linux new file mode 120000 index 0000000..57b79f9 --- /dev/null +++ b/frontend/linux/flutter/ephemeral/.plugin_symlinks/flutter_local_notifications_linux @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/flutter_local_notifications_linux-5.0.0/ \ No newline at end of file diff --git a/frontend/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux b/frontend/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux new file mode 120000 index 0000000..a1287b1 --- /dev/null +++ b/frontend/linux/flutter/ephemeral/.plugin_symlinks/image_picker_linux @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/image_picker_linux-0.2.2/ \ No newline at end of file diff --git a/frontend/linux/flutter/generated_plugin_registrant.cc b/frontend/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..64a0ece --- /dev/null +++ b/frontend/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); +} diff --git a/frontend/linux/flutter/generated_plugin_registrant.h b/frontend/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/frontend/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/frontend/linux/flutter/generated_plugins.cmake b/frontend/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..2db3c22 --- /dev/null +++ b/frontend/linux/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/frontend/linux/runner/CMakeLists.txt b/frontend/linux/runner/CMakeLists.txt new file mode 100644 index 0000000..e97dabc --- /dev/null +++ b/frontend/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/frontend/linux/runner/main.cc b/frontend/linux/runner/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/frontend/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/frontend/linux/runner/my_application.cc b/frontend/linux/runner/my_application.cc new file mode 100644 index 0000000..c62301d --- /dev/null +++ b/frontend/linux/runner/my_application.cc @@ -0,0 +1,144 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Called when first Flutter frame received. +static void first_frame_cb(MyApplication* self, FlView *view) +{ + gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "gradi_frontend"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "gradi_frontend"); + } + + gtk_window_set_default_size(window, 1280, 720); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + GdkRGBA background_color; + // Background defaults to black, override it here if necessary, e.g. #00000000 for transparent. + gdk_rgba_parse(&background_color, "#000000"); + fl_view_set_background_color(view, &background_color); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + // Show the window when Flutter renders. + // Requires the view to be realized so we can start rendering. + g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); + gtk_widget_realize(GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/frontend/linux/runner/my_application.h b/frontend/linux/runner/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/frontend/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/frontend/macos/.gitignore b/frontend/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/frontend/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/frontend/macos/Flutter/Flutter-Debug.xcconfig b/frontend/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..4b81f9b --- /dev/null +++ b/frontend/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/frontend/macos/Flutter/Flutter-Release.xcconfig b/frontend/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..5caa9d1 --- /dev/null +++ b/frontend/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/frontend/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..004132f --- /dev/null +++ b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,22 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import file_selector_macos +import firebase_core +import firebase_messaging +import flutter_local_notifications +import geolocator_apple +import shared_preferences_foundation + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) + FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) + GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) +} diff --git a/frontend/macos/Flutter/ephemeral/.app_filename b/frontend/macos/Flutter/ephemeral/.app_filename new file mode 100644 index 0000000..2534930 --- /dev/null +++ b/frontend/macos/Flutter/ephemeral/.app_filename @@ -0,0 +1 @@ +gradi_frontend.app diff --git a/frontend/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/frontend/macos/Flutter/ephemeral/Flutter-Generated.xcconfig new file mode 100644 index 0000000..7004660 --- /dev/null +++ b/frontend/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -0,0 +1,11 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=/Users/downy/flutter +FLUTTER_APPLICATION_PATH=/Users/downy/Documents/Gradi_25Fall/frontend +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/frontend/macos/Flutter/ephemeral/FlutterInputs.xcfilelist b/frontend/macos/Flutter/ephemeral/FlutterInputs.xcfilelist new file mode 100644 index 0000000..ecc14b1 --- /dev/null +++ b/frontend/macos/Flutter/ephemeral/FlutterInputs.xcfilelist @@ -0,0 +1,892 @@ +/Users/downy/.pub-cache/hosted/pub.dev/async-2.13.0/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/characters.dart +/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters.dart +/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/characters_impl.dart +/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/extensions.dart +/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/breaks.dart +/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/constants.dart +/Users/downy/.pub-cache/hosted/pub.dev/characters-1.4.0/lib/src/grapheme_clusters/table.dart +/Users/downy/.pub-cache/hosted/pub.dev/clock-1.1.2/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/collection.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/algorithms.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/boollist.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/canonicalized_map.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterable.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_iterator.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_list.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/combined_wrappers/combined_map.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/comparators.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/empty_unmodifiable_set.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_map.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/equality_set.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/functions.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_extensions.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/iterable_zip.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/list_extensions.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/priority_queue.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/queue_list.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/union_set_controller.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/unmodifiable_wrappers.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/utils.dart +/Users/downy/.pub-cache/hosted/pub.dev/collection-1.19.1/lib/src/wrappers.dart +/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/cupertino_icons-1.0.8/assets/CupertinoIcons.ttf +/Users/downy/.pub-cache/hosted/pub.dev/fake_async-1.3.3/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/flutter_lints-5.0.0/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/http.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/abortable.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_client.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_request.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/base_response.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/boundary_characters.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/byte_stream.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/client.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/exception.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_client.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/io_streamed_response.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_file_io.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/multipart_request.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/request.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/response.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_request.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/streamed_response.dart +/Users/downy/.pub-cache/hosted/pub.dev/http-1.5.0/lib/src/utils.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/http_parser.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/authentication_challenge.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/case_insensitive_map.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/charcodes.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/decoder.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/chunked_coding/encoder.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/http_date.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/media_type.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/scan.dart +/Users/downy/.pub-cache/hosted/pub.dev/http_parser-4.1.2/lib/src/utils.dart +/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker-11.0.2/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_flutter_testing-3.0.10/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/leak_tracker_testing-3.0.2/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/lints-5.1.1/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/matcher-0.12.17/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/blend/blend.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/contrast/contrast.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dislike/dislike_analyzer.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_color.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/dynamic_scheme.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/material_dynamic_colors.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/contrast_curve.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/src/tone_delta_pair.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/dynamiccolor/variant.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/cam16.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/hct.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/src/hct_solver.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/hct/viewing_conditions.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/material_color_utilities.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/core_palette.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/palettes/tonal_palette.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_celebi.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_map.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wsmeans.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/quantizer_wu.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/quantize/src/point_provider_lab.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_content.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_expressive.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fidelity.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_fruit_salad.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_monochrome.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_neutral.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_rainbow.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_tonal_spot.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/scheme/scheme_vibrant.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/score/score.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/temperature/temperature_cache.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/color_utils.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/math_utils.dart +/Users/downy/.pub-cache/hosted/pub.dev/material_color_utilities-0.11.1/lib/utils/string_utils.dart +/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta.dart +/Users/downy/.pub-cache/hosted/pub.dev/meta-1.16.0/lib/meta_meta.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/path.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/characters.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/context.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/internal_style.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/parsed_path.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_exception.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_map.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/path_set.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/posix.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/url.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/style/windows.dart +/Users/downy/.pub-cache/hosted/pub.dev/path-1.9.1/lib/src/utils.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/source_span.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/charcode.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/colors.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/file.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/highlighter.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/location_mixin.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_exception.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_mixin.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/span_with_context.dart +/Users/downy/.pub-cache/hosted/pub.dev/source_span-1.10.1/lib/src/utils.dart +/Users/downy/.pub-cache/hosted/pub.dev/stack_trace-1.12.1/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/stream_channel-2.1.4/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/charcode.dart +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/eager_span_scanner.dart +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/exception.dart +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/line_scanner.dart +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/relative_span_scanner.dart +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/span_scanner.dart +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/string_scanner.dart +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/src/utils.dart +/Users/downy/.pub-cache/hosted/pub.dev/string_scanner-1.4.1/lib/string_scanner.dart +/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/ascii_glyph_set.dart +/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/glyph_set.dart +/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/top_level.dart +/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/src/generated/unicode_glyph_set.dart +/Users/downy/.pub-cache/hosted/pub.dev/term_glyph-1.2.2/lib/term_glyph.dart +/Users/downy/.pub-cache/hosted/pub.dev/test_api-0.7.6/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_buffer.dart +/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/src/typed_queue.dart +/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_buffers.dart +/Users/downy/.pub-cache/hosted/pub.dev/typed_data-1.4.0/lib/typed_data.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb2.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/aabb3.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/colors.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/constants.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/error_helpers.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/frustum.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/intersection_result.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix2.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix3.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/matrix4.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/noise.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/obb3.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/opengl.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/plane.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quad.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/quaternion.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/ray.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/sphere.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/triangle.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/utilities.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector2.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector3.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/src/vector_math_64/vector4.dart +/Users/downy/.pub-cache/hosted/pub.dev/vector_math-2.2.0/lib/vector_math_64.dart +/Users/downy/.pub-cache/hosted/pub.dev/vm_service-15.0.2/LICENSE +/Users/downy/.pub-cache/hosted/pub.dev/web-1.1.1/LICENSE +/Users/downy/Documents/Gradi_25Fall/frontend/lib/main.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/routes/app_routes.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_error_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_result_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_id_verification_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_error_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_reset_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/find_password_verification_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/login_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/password_reset_success_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/reset_password_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/screens/signup_page.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/theme/app_theme.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/app_logo.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/back_button.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/input_field.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/labeled_input_field.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/links_section.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/login_button.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/next_button.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/page_title.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_button.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/sns_divider.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/user_id_card.dart +/Users/downy/Documents/Gradi_25Fall/frontend/lib/widgets/verification_code_input.dart +/Users/downy/Documents/Gradi_25Fall/frontend/pubspec.yaml +/Users/downy/flutter/bin/cache/artifacts/material_fonts/MaterialIcons-Regular.otf +/Users/downy/flutter/bin/cache/engine.stamp +/Users/downy/flutter/bin/cache/pkg/sky_engine/LICENSE +/Users/downy/flutter/packages/flutter/LICENSE +/Users/downy/flutter/packages/flutter/lib/animation.dart +/Users/downy/flutter/packages/flutter/lib/cupertino.dart +/Users/downy/flutter/packages/flutter/lib/foundation.dart +/Users/downy/flutter/packages/flutter/lib/gestures.dart +/Users/downy/flutter/packages/flutter/lib/material.dart +/Users/downy/flutter/packages/flutter/lib/painting.dart +/Users/downy/flutter/packages/flutter/lib/physics.dart +/Users/downy/flutter/packages/flutter/lib/rendering.dart +/Users/downy/flutter/packages/flutter/lib/scheduler.dart +/Users/downy/flutter/packages/flutter/lib/semantics.dart +/Users/downy/flutter/packages/flutter/lib/services.dart +/Users/downy/flutter/packages/flutter/lib/src/animation/animation.dart +/Users/downy/flutter/packages/flutter/lib/src/animation/animation_controller.dart +/Users/downy/flutter/packages/flutter/lib/src/animation/animation_style.dart +/Users/downy/flutter/packages/flutter/lib/src/animation/animations.dart +/Users/downy/flutter/packages/flutter/lib/src/animation/curves.dart +/Users/downy/flutter/packages/flutter/lib/src/animation/listener_helpers.dart +/Users/downy/flutter/packages/flutter/lib/src/animation/tween.dart +/Users/downy/flutter/packages/flutter/lib/src/animation/tween_sequence.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/activity_indicator.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/app.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/button.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/checkbox.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/colors.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/constants.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/context_menu_action.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/date_picker.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/dialog.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/expansion_tile.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_row.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/form_section.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/icon_theme_data.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/icons.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/interface_level.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_section.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/list_tile.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/localizations.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/magnifier.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/nav_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/page_scaffold.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/picker.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/radio.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/refresh.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/route.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/scrollbar.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/search_field.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/segmented_control.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/sheet.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/slider.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/switch.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_scaffold.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/tab_view.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_field.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_form_field_row.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/text_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/theme.dart +/Users/downy/flutter/packages/flutter/lib/src/cupertino/thumb_painter.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/_bitfield_io.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/_capabilities_io.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/_isolates_io.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/_platform_io.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/_timeline_io.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/annotations.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/assertions.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/basic_types.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/binding.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/bitfield.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/capabilities.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/change_notifier.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/collections.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/consolidate_response.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/constants.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/diagnostics.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/isolates.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/key.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/licenses.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/memory_allocations.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/node.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/object.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/observer_list.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/persistent_hash_map.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/platform.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/print.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/serialization.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/service_extensions.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/stack_frame.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/synchronous_future.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/timeline.dart +/Users/downy/flutter/packages/flutter/lib/src/foundation/unicode.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/arena.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/binding.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/constants.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/converter.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/drag.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/drag_details.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/eager.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/events.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/force_press.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_details.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/gesture_settings.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/hit_test.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/long_press.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/lsq_solver.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/monodrag.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/multidrag.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/multitap.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_router.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/pointer_signal_resolver.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/recognizer.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/resampler.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/scale.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/tap.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/tap_and_drag.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/team.dart +/Users/downy/flutter/packages/flutter/lib/src/gestures/velocity_tracker.dart +/Users/downy/flutter/packages/flutter/lib/src/material/about.dart +/Users/downy/flutter/packages/flutter/lib/src/material/action_buttons.dart +/Users/downy/flutter/packages/flutter/lib/src/material/action_chip.dart +/Users/downy/flutter/packages/flutter/lib/src/material/action_icons_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/adaptive_text_selection_toolbar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/animated_icons_data.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/add_event.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/arrow_menu.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/close_menu.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/ellipsis_search.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/event_add.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/home_menu.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/list_view.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_arrow.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_close.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/menu_home.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/pause_play.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/play_pause.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/search_ellipsis.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/animated_icons/data/view_list.g.dart +/Users/downy/flutter/packages/flutter/lib/src/material/app.dart +/Users/downy/flutter/packages/flutter/lib/src/material/app_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/app_bar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/arc.dart +/Users/downy/flutter/packages/flutter/lib/src/material/autocomplete.dart +/Users/downy/flutter/packages/flutter/lib/src/material/back_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/badge.dart +/Users/downy/flutter/packages/flutter/lib/src/material/badge_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/banner.dart +/Users/downy/flutter/packages/flutter/lib/src/material/banner_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/bottom_app_bar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet.dart +/Users/downy/flutter/packages/flutter/lib/src/material/bottom_sheet_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/button_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/button_bar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/button_style.dart +/Users/downy/flutter/packages/flutter/lib/src/material/button_style_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/button_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/calendar_date_picker.dart +/Users/downy/flutter/packages/flutter/lib/src/material/card.dart +/Users/downy/flutter/packages/flutter/lib/src/material/card_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/carousel.dart +/Users/downy/flutter/packages/flutter/lib/src/material/carousel_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/checkbox.dart +/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_list_tile.dart +/Users/downy/flutter/packages/flutter/lib/src/material/checkbox_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/chip.dart +/Users/downy/flutter/packages/flutter/lib/src/material/chip_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/choice_chip.dart +/Users/downy/flutter/packages/flutter/lib/src/material/circle_avatar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/color_scheme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/colors.dart +/Users/downy/flutter/packages/flutter/lib/src/material/constants.dart +/Users/downy/flutter/packages/flutter/lib/src/material/curves.dart +/Users/downy/flutter/packages/flutter/lib/src/material/data_table.dart +/Users/downy/flutter/packages/flutter/lib/src/material/data_table_source.dart +/Users/downy/flutter/packages/flutter/lib/src/material/data_table_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/date.dart +/Users/downy/flutter/packages/flutter/lib/src/material/date_picker.dart +/Users/downy/flutter/packages/flutter/lib/src/material/date_picker_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection.dart +/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/desktop_text_selection_toolbar_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/dialog.dart +/Users/downy/flutter/packages/flutter/lib/src/material/dialog_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/divider.dart +/Users/downy/flutter/packages/flutter/lib/src/material/divider_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/drawer.dart +/Users/downy/flutter/packages/flutter/lib/src/material/drawer_header.dart +/Users/downy/flutter/packages/flutter/lib/src/material/drawer_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/dropdown.dart +/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu.dart +/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_form_field.dart +/Users/downy/flutter/packages/flutter/lib/src/material/dropdown_menu_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/elevated_button_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/elevation_overlay.dart +/Users/downy/flutter/packages/flutter/lib/src/material/expand_icon.dart +/Users/downy/flutter/packages/flutter/lib/src/material/expansion_panel.dart +/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile.dart +/Users/downy/flutter/packages/flutter/lib/src/material/expansion_tile_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/filled_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/filled_button_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/filter_chip.dart +/Users/downy/flutter/packages/flutter/lib/src/material/flexible_space_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_location.dart +/Users/downy/flutter/packages/flutter/lib/src/material/floating_action_button_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile.dart +/Users/downy/flutter/packages/flutter/lib/src/material/grid_tile_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/icon_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/icon_button_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/icons.dart +/Users/downy/flutter/packages/flutter/lib/src/material/ink_decoration.dart +/Users/downy/flutter/packages/flutter/lib/src/material/ink_highlight.dart +/Users/downy/flutter/packages/flutter/lib/src/material/ink_ripple.dart +/Users/downy/flutter/packages/flutter/lib/src/material/ink_sparkle.dart +/Users/downy/flutter/packages/flutter/lib/src/material/ink_splash.dart +/Users/downy/flutter/packages/flutter/lib/src/material/ink_well.dart +/Users/downy/flutter/packages/flutter/lib/src/material/input_border.dart +/Users/downy/flutter/packages/flutter/lib/src/material/input_chip.dart +/Users/downy/flutter/packages/flutter/lib/src/material/input_date_picker_form_field.dart +/Users/downy/flutter/packages/flutter/lib/src/material/input_decorator.dart +/Users/downy/flutter/packages/flutter/lib/src/material/list_tile.dart +/Users/downy/flutter/packages/flutter/lib/src/material/list_tile_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/magnifier.dart +/Users/downy/flutter/packages/flutter/lib/src/material/material.dart +/Users/downy/flutter/packages/flutter/lib/src/material/material_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/material_localizations.dart +/Users/downy/flutter/packages/flutter/lib/src/material/material_state.dart +/Users/downy/flutter/packages/flutter/lib/src/material/material_state_mixin.dart +/Users/downy/flutter/packages/flutter/lib/src/material/menu_anchor.dart +/Users/downy/flutter/packages/flutter/lib/src/material/menu_bar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/menu_button_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/menu_style.dart +/Users/downy/flutter/packages/flutter/lib/src/material/menu_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/mergeable_material.dart +/Users/downy/flutter/packages/flutter/lib/src/material/motion.dart +/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/navigation_bar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer.dart +/Users/downy/flutter/packages/flutter/lib/src/material/navigation_drawer_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail.dart +/Users/downy/flutter/packages/flutter/lib/src/material/navigation_rail_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/no_splash.dart +/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/outlined_button_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/page.dart +/Users/downy/flutter/packages/flutter/lib/src/material/page_transitions_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/paginated_data_table.dart +/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu.dart +/Users/downy/flutter/packages/flutter/lib/src/material/popup_menu_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/predictive_back_page_transitions_builder.dart +/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator.dart +/Users/downy/flutter/packages/flutter/lib/src/material/progress_indicator_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/radio.dart +/Users/downy/flutter/packages/flutter/lib/src/material/radio_list_tile.dart +/Users/downy/flutter/packages/flutter/lib/src/material/radio_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/range_slider.dart +/Users/downy/flutter/packages/flutter/lib/src/material/range_slider_parts.dart +/Users/downy/flutter/packages/flutter/lib/src/material/refresh_indicator.dart +/Users/downy/flutter/packages/flutter/lib/src/material/reorderable_list.dart +/Users/downy/flutter/packages/flutter/lib/src/material/scaffold.dart +/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/scrollbar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/search.dart +/Users/downy/flutter/packages/flutter/lib/src/material/search_anchor.dart +/Users/downy/flutter/packages/flutter/lib/src/material/search_bar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/search_view_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/segmented_button_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/selectable_text.dart +/Users/downy/flutter/packages/flutter/lib/src/material/selection_area.dart +/Users/downy/flutter/packages/flutter/lib/src/material/shaders/ink_sparkle.frag +/Users/downy/flutter/packages/flutter/lib/src/material/shadows.dart +/Users/downy/flutter/packages/flutter/lib/src/material/slider.dart +/Users/downy/flutter/packages/flutter/lib/src/material/slider_parts.dart +/Users/downy/flutter/packages/flutter/lib/src/material/slider_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/slider_value_indicator_shape.dart +/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/snack_bar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/spell_check_suggestions_toolbar_layout_delegate.dart +/Users/downy/flutter/packages/flutter/lib/src/material/stepper.dart +/Users/downy/flutter/packages/flutter/lib/src/material/switch.dart +/Users/downy/flutter/packages/flutter/lib/src/material/switch_list_tile.dart +/Users/downy/flutter/packages/flutter/lib/src/material/switch_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/tab_bar_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/tab_controller.dart +/Users/downy/flutter/packages/flutter/lib/src/material/tab_indicator.dart +/Users/downy/flutter/packages/flutter/lib/src/material/tabs.dart +/Users/downy/flutter/packages/flutter/lib/src/material/text_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/text_button_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/text_field.dart +/Users/downy/flutter/packages/flutter/lib/src/material/text_form_field.dart +/Users/downy/flutter/packages/flutter/lib/src/material/text_selection.dart +/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar.dart +/Users/downy/flutter/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart +/Users/downy/flutter/packages/flutter/lib/src/material/text_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/theme_data.dart +/Users/downy/flutter/packages/flutter/lib/src/material/time.dart +/Users/downy/flutter/packages/flutter/lib/src/material/time_picker.dart +/Users/downy/flutter/packages/flutter/lib/src/material/time_picker_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons.dart +/Users/downy/flutter/packages/flutter/lib/src/material/toggle_buttons_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/tooltip.dart +/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/material/tooltip_visibility.dart +/Users/downy/flutter/packages/flutter/lib/src/material/typography.dart +/Users/downy/flutter/packages/flutter/lib/src/material/user_accounts_drawer_header.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/_network_image_io.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/_web_image_info_io.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/alignment.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/basic_types.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/beveled_rectangle_border.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/binding.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/border_radius.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/borders.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/box_border.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/box_decoration.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/box_fit.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/box_shadow.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/circle_border.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/clip.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/colors.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/continuous_rectangle_border.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/decoration.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/decoration_image.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/edge_insets.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/flutter_logo.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/fractional_offset.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/geometry.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/gradient.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/image_cache.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/image_decoder.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/image_provider.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/image_resolution.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/image_stream.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/inline_span.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/linear_border.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/matrix_utils.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/notched_shapes.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/oval_border.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/paint_utilities.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/placeholder_span.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/rounded_rectangle_border.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/shader_warm_up.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/shape_decoration.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/stadium_border.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/star_border.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/strut_style.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/text_painter.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/text_scaler.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/text_span.dart +/Users/downy/flutter/packages/flutter/lib/src/painting/text_style.dart +/Users/downy/flutter/packages/flutter/lib/src/physics/clamped_simulation.dart +/Users/downy/flutter/packages/flutter/lib/src/physics/friction_simulation.dart +/Users/downy/flutter/packages/flutter/lib/src/physics/gravity_simulation.dart +/Users/downy/flutter/packages/flutter/lib/src/physics/simulation.dart +/Users/downy/flutter/packages/flutter/lib/src/physics/spring_simulation.dart +/Users/downy/flutter/packages/flutter/lib/src/physics/tolerance.dart +/Users/downy/flutter/packages/flutter/lib/src/physics/utils.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/animated_size.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/binding.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/box.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_layout.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/custom_paint.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/decorated_sliver.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/editable.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/error.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/flex.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/flow.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/image.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/layer.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/layout_helper.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/list_body.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/list_wheel_viewport.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/mouse_tracker.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/object.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/paragraph.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/performance_overlay.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/platform_view.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_box.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/proxy_sliver.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/rotated_box.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/selection.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/service_extensions.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/shifted_box.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fill.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_grid.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_group.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_list.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_padding.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_persistent_header.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/sliver_tree.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/stack.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/table.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/table_border.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/texture.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/tweens.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/view.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/viewport_offset.dart +/Users/downy/flutter/packages/flutter/lib/src/rendering/wrap.dart +/Users/downy/flutter/packages/flutter/lib/src/scheduler/binding.dart +/Users/downy/flutter/packages/flutter/lib/src/scheduler/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/scheduler/priority.dart +/Users/downy/flutter/packages/flutter/lib/src/scheduler/service_extensions.dart +/Users/downy/flutter/packages/flutter/lib/src/scheduler/ticker.dart +/Users/downy/flutter/packages/flutter/lib/src/semantics/binding.dart +/Users/downy/flutter/packages/flutter/lib/src/semantics/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics.dart +/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_event.dart +/Users/downy/flutter/packages/flutter/lib/src/semantics/semantics_service.dart +/Users/downy/flutter/packages/flutter/lib/src/services/_background_isolate_binary_messenger_io.dart +/Users/downy/flutter/packages/flutter/lib/src/services/asset_bundle.dart +/Users/downy/flutter/packages/flutter/lib/src/services/asset_manifest.dart +/Users/downy/flutter/packages/flutter/lib/src/services/autofill.dart +/Users/downy/flutter/packages/flutter/lib/src/services/binary_messenger.dart +/Users/downy/flutter/packages/flutter/lib/src/services/binding.dart +/Users/downy/flutter/packages/flutter/lib/src/services/browser_context_menu.dart +/Users/downy/flutter/packages/flutter/lib/src/services/clipboard.dart +/Users/downy/flutter/packages/flutter/lib/src/services/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/services/deferred_component.dart +/Users/downy/flutter/packages/flutter/lib/src/services/flavor.dart +/Users/downy/flutter/packages/flutter/lib/src/services/flutter_version.dart +/Users/downy/flutter/packages/flutter/lib/src/services/font_loader.dart +/Users/downy/flutter/packages/flutter/lib/src/services/haptic_feedback.dart +/Users/downy/flutter/packages/flutter/lib/src/services/hardware_keyboard.dart +/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_inserted_content.dart +/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_key.g.dart +/Users/downy/flutter/packages/flutter/lib/src/services/keyboard_maps.g.dart +/Users/downy/flutter/packages/flutter/lib/src/services/live_text.dart +/Users/downy/flutter/packages/flutter/lib/src/services/message_codec.dart +/Users/downy/flutter/packages/flutter/lib/src/services/message_codecs.dart +/Users/downy/flutter/packages/flutter/lib/src/services/mouse_cursor.dart +/Users/downy/flutter/packages/flutter/lib/src/services/mouse_tracking.dart +/Users/downy/flutter/packages/flutter/lib/src/services/platform_channel.dart +/Users/downy/flutter/packages/flutter/lib/src/services/platform_views.dart +/Users/downy/flutter/packages/flutter/lib/src/services/predictive_back_event.dart +/Users/downy/flutter/packages/flutter/lib/src/services/process_text.dart +/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard.dart +/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_android.dart +/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart +/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_ios.dart +/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_linux.dart +/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_macos.dart +/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_web.dart +/Users/downy/flutter/packages/flutter/lib/src/services/raw_keyboard_windows.dart +/Users/downy/flutter/packages/flutter/lib/src/services/restoration.dart +/Users/downy/flutter/packages/flutter/lib/src/services/scribe.dart +/Users/downy/flutter/packages/flutter/lib/src/services/sensitive_content.dart +/Users/downy/flutter/packages/flutter/lib/src/services/service_extensions.dart +/Users/downy/flutter/packages/flutter/lib/src/services/spell_check.dart +/Users/downy/flutter/packages/flutter/lib/src/services/system_channels.dart +/Users/downy/flutter/packages/flutter/lib/src/services/system_chrome.dart +/Users/downy/flutter/packages/flutter/lib/src/services/system_navigator.dart +/Users/downy/flutter/packages/flutter/lib/src/services/system_sound.dart +/Users/downy/flutter/packages/flutter/lib/src/services/text_boundary.dart +/Users/downy/flutter/packages/flutter/lib/src/services/text_editing.dart +/Users/downy/flutter/packages/flutter/lib/src/services/text_editing_delta.dart +/Users/downy/flutter/packages/flutter/lib/src/services/text_formatter.dart +/Users/downy/flutter/packages/flutter/lib/src/services/text_input.dart +/Users/downy/flutter/packages/flutter/lib/src/services/text_layout_metrics.dart +/Users/downy/flutter/packages/flutter/lib/src/services/undo_manager.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/_html_element_view_io.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_io.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_browser_detection_io.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/_web_image_io.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/actions.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/adapter.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_cross_fade.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_scroll_view.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_size.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/animated_switcher.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/annotated_region.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/app.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/app_lifecycle_listener.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/async.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/autocomplete.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/autofill.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/automatic_keep_alive.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/banner.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/basic.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/binding.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/bottom_navigation_bar_item.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/color_filter.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/constants.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/container.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_button_item.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/context_menu_controller.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/debug.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/decorated_sliver.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/default_selection_style.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/default_text_editing_shortcuts.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/desktop_text_selection_toolbar_layout_delegate.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/dismissible.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/display_feature_sub_screen.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/disposable_build_context.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_boundary.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/drag_target.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/dual_transition_builder.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/editable_text.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/expansible.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/fade_in_image.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/feedback.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/flutter_logo.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_manager.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_scope.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/focus_traversal.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/form.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/framework.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/gesture_detector.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/grid_paper.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/heroes.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/icon.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_data.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/icon_theme_data.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/image.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/image_filter.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/image_icon.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/implicit_animations.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_model.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_notifier.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/inherited_theme.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/interactive_viewer.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/keyboard_listener.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/layout_builder.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/localizations.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/lookup_boundary.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/magnifier.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/media_query.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/modal_barrier.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/navigation_toolbar.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/navigator_pop_handler.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/nested_scroll_view.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/notification_listener.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/orientation_builder.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/overflow_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/overlay.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/overscroll_indicator.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/page_storage.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/page_view.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/pages.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/performance_overlay.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/pinned_header_sliver.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/placeholder.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_menu_bar.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_selectable_region_context_menu.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/platform_view.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/pop_scope.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/preferred_size.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/primary_scroll_controller.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/radio_group.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_menu_anchor.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/raw_radio.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/reorderable_list.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/restoration_properties.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/router.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/routes.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/safe_area.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_activity.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_configuration.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_context.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_delegate.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_metrics.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_notification_observer.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_physics.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_position_with_single_context.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scroll_view.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollable_helpers.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/scrollbar.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/selectable_region.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/selection_container.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/semantics_debugger.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/sensitive_content.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/service_extensions.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/shared_app_data.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/shortcuts.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/single_child_scroll_view.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/size_changed_layout_notifier.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_fill.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_floating_header.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_layout_builder.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_persistent_header.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_prototype_extent_list.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_resizing_header.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/sliver_tree.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/slotted_render_object_widget.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/snapshot_widget.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/spacer.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/spell_check.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/standard_component_type.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/status_transitions.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/system_context_menu.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/table.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/tap_region.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/text.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/text_editing_intents.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_anchors.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/text_selection_toolbar_layout_delegate.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/texture.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/ticker_provider.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/title.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/toggleable.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/transitions.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/tween_animation_builder.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_scroll_view.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/undo_history.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/unique_widget.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/value_listenable_builder.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/view.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/viewport.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/visibility.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_inspector.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_span.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/widget_state.dart +/Users/downy/flutter/packages/flutter/lib/src/widgets/will_pop_scope.dart +/Users/downy/flutter/packages/flutter/lib/widgets.dart +/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/common.dart +/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart +/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/macos.dart +/Users/downy/flutter/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart diff --git a/frontend/macos/Flutter/ephemeral/FlutterOutputs.xcfilelist b/frontend/macos/Flutter/ephemeral/FlutterOutputs.xcfilelist new file mode 100644 index 0000000..0d8ec99 --- /dev/null +++ b/frontend/macos/Flutter/ephemeral/FlutterOutputs.xcfilelist @@ -0,0 +1,14 @@ +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/App +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/Info.plist +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.bin +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.json +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/FontManifest.json +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NOTICES.Z +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/NativeAssetsManifest.json +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/fonts/MaterialIcons-Regular.otf +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/shaders/ink_sparkle.frag +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data +/Users/downy/Documents/Gradi_25Fall/frontend/build/macos/Build/Products/Debug/FlutterMacOS.framework/Versions/A/FlutterMacOS diff --git a/frontend/macos/Flutter/ephemeral/flutter_export_environment.sh b/frontend/macos/Flutter/ephemeral/flutter_export_environment.sh new file mode 100755 index 0000000..f5f8b72 --- /dev/null +++ b/frontend/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Users/downy/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/downy/Documents/Gradi_25Fall/frontend" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/frontend/macos/Flutter/ephemeral/tripwire b/frontend/macos/Flutter/ephemeral/tripwire new file mode 100644 index 0000000..e69de29 diff --git a/frontend/macos/Podfile b/frontend/macos/Podfile new file mode 100644 index 0000000..ff5ddb3 --- /dev/null +++ b/frontend/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/frontend/macos/Podfile.lock b/frontend/macos/Podfile.lock new file mode 100644 index 0000000..c6b6d12 --- /dev/null +++ b/frontend/macos/Podfile.lock @@ -0,0 +1,22 @@ +PODS: + - file_selector_macos (0.0.1): + - FlutterMacOS + - FlutterMacOS (1.0.0) + +DEPENDENCIES: + - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + +EXTERNAL SOURCES: + file_selector_macos: + :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos + FlutterMacOS: + :path: Flutter/ephemeral + +SPEC CHECKSUMS: + file_selector_macos: 9e9e068e90ebee155097d00e89ae91edb2374db7 + FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 + +PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009 + +COCOAPODS: 1.16.2 diff --git a/frontend/macos/Pods/Local Podspecs/FlutterMacOS.podspec.json b/frontend/macos/Pods/Local Podspecs/FlutterMacOS.podspec.json new file mode 100644 index 0000000..2344982 --- /dev/null +++ b/frontend/macos/Pods/Local Podspecs/FlutterMacOS.podspec.json @@ -0,0 +1,20 @@ +{ + "name": "FlutterMacOS", + "version": "1.0.0", + "summary": "A UI toolkit for beautiful and fast apps.", + "homepage": "https://flutter.dev", + "license": { + "type": "BSD" + }, + "authors": { + "Flutter Dev Team": "flutter-dev@googlegroups.com" + }, + "source": { + "git": "https://github.com/flutter/engine", + "tag": "1.0.0" + }, + "platforms": { + "osx": "10.15" + }, + "vendored_frameworks": "path/to/nothing" +} diff --git a/frontend/macos/Pods/Local Podspecs/file_selector_macos.podspec.json b/frontend/macos/Pods/Local Podspecs/file_selector_macos.podspec.json new file mode 100644 index 0000000..f3592de --- /dev/null +++ b/frontend/macos/Pods/Local Podspecs/file_selector_macos.podspec.json @@ -0,0 +1,34 @@ +{ + "name": "file_selector_macos", + "version": "0.0.1", + "summary": "macOS implementation of file_selector.", + "description": "Displays native macOS open and save panels.", + "license": { + "type": "BSD", + "file": "../LICENSE" + }, + "homepage": "https://github.com/flutter/packages/tree/main/packages/file_selector", + "authors": { + "Flutter Dev Team": "flutter-dev@googlegroups.com" + }, + "source": { + "http": "https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_macos" + }, + "source_files": "file_selector_macos/Sources/file_selector_macos/**/*.swift", + "resource_bundles": { + "file_selector_macos_privacy": [ + "file_selector_macos/Sources/file_selector_macos/Resources/PrivacyInfo.xcprivacy" + ] + }, + "dependencies": { + "FlutterMacOS": [] + }, + "platforms": { + "osx": "10.15" + }, + "pod_target_xcconfig": { + "DEFINES_MODULE": "YES" + }, + "swift_versions": "5.0", + "swift_version": "5.0" +} diff --git a/frontend/macos/Pods/Pods.xcodeproj/project.pbxproj b/frontend/macos/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1beb64c --- /dev/null +++ b/frontend/macos/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,1656 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + CA272E8348BAB4CE0B0C804FB7B818C4 /* FlutterMacOS */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 624022EE1C2EAB1C3CC38699E1368C5F /* Build configuration list for PBXAggregateTarget "FlutterMacOS" */; + buildPhases = ( + ); + dependencies = ( + ); + name = FlutterMacOS; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 03FF65672874530A3E9AE6BAB1764A4A /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE00D34B275026D4656C738BED5A001 /* Cocoa.framework */; }; + 3432DABAA7742D36C6F8F8A32D0E1488 /* Pods-Runner-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 499E3722E8DACDC2AAA6C15AD1796520 /* Pods-Runner-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 669CF01609DC4C78118A0F6701A0369A /* FileSelectorPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54FCE5405570BE17A68C42D270C472CA /* FileSelectorPlugin.swift */; }; + 75564B76FFE8703157322DE7E91ADD19 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4AD67391CCD116C3E019393C90DFDF1E /* PrivacyInfo.xcprivacy */; }; + 78045458CE38E19FA6AFEDC333B3C33B /* file_selector_macos-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 43858F74F1FB1C05D7FA6EC527F87F59 /* file_selector_macos-dummy.m */; }; + 7AF6867726D234741DE68BB1A950E138 /* Pods-Runner-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = E794494AB90477BA94C681E994ADF341 /* Pods-Runner-dummy.m */; }; + A48937410C16702A0571A02A59CE3869 /* file_selector_macos-file_selector_macos_privacy in Resources */ = {isa = PBXBuildFile; fileRef = B52BE94845C16778C6788595A182BE8D /* file_selector_macos-file_selector_macos_privacy */; }; + B375EA128E6579366091BAA390BBDD34 /* Pods-RunnerTests-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D3DB54C128E3D88C0C9C7DDEA475ED7 /* Pods-RunnerTests-dummy.m */; }; + BD04BA2A11AF101C0A0DF73CE3839352 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE00D34B275026D4656C738BED5A001 /* Cocoa.framework */; }; + D727808C1C6F611A32F6607975591ADE /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9EE00D34B275026D4656C738BED5A001 /* Cocoa.framework */; }; + EB2DC96CDCF638AB89007D2DB0F3119A /* Pods-RunnerTests-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 9E9B12BCE5540D02A80250C3EC16D399 /* Pods-RunnerTests-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EF5ADFB07D3AAAE725DBA930289E55D5 /* file_selector_macos-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 0352660B8678B8F2D53F14CDC47611E0 /* file_selector_macos-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F990C396E3316B5BCA38BD8ACB6BBF07 /* messages.g.swift in Sources */ = {isa = PBXBuildFile; fileRef = 187E8528F91943094FAC776650C63719 /* messages.g.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 05C3E3135B831A2281F143E02A90F6DF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = CA272E8348BAB4CE0B0C804FB7B818C4; + remoteInfo = FlutterMacOS; + }; + 097401D1B4A991023B00362206BFACC8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 773D4A7C7FA9CAB9B055EBF0A53821FB; + remoteInfo = file_selector_macos; + }; + 14A94EC008746C8AACE067C80352C5F5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6665E994FA6BDAD3162E29390B9D4D39; + remoteInfo = "file_selector_macos-file_selector_macos_privacy"; + }; + 955F24F47E5C2AEB7BFA453C808C4884 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = CA272E8348BAB4CE0B0C804FB7B818C4; + remoteInfo = FlutterMacOS; + }; + F4DBFFB53E6828422526E89CEBA647A5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8B74B458B450D74B75744B87BD747314; + remoteInfo = "Pods-Runner"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0352660B8678B8F2D53F14CDC47611E0 /* file_selector_macos-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "file_selector_macos-umbrella.h"; sourceTree = ""; }; + 03E8AD2E8B75443E12D3D3BD12A9900E /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 08B05A9A012C65CFF9ED5E98E221A720 /* file_selector_macos.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = file_selector_macos.release.xcconfig; sourceTree = ""; }; + 0AFB643DA4919253F749E2836A5AAFDC /* Pods-Runner-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Runner-Info.plist"; sourceTree = ""; }; + 11AA7018F95317D959D9D2E76CBB2377 /* Pods-RunnerTests-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-RunnerTests-acknowledgements.markdown"; sourceTree = ""; }; + 187E8528F91943094FAC776650C63719 /* messages.g.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = messages.g.swift; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/macos/file_selector_macos/Sources/file_selector_macos/messages.g.swift"; sourceTree = ""; }; + 1B136F41D5B5FAE96EA576E768A5771D /* Pods-Runner-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Runner-acknowledgements.plist"; sourceTree = ""; }; + 43858F74F1FB1C05D7FA6EC527F87F59 /* file_selector_macos-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "file_selector_macos-dummy.m"; sourceTree = ""; }; + 499E3722E8DACDC2AAA6C15AD1796520 /* Pods-Runner-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Runner-umbrella.h"; sourceTree = ""; }; + 4AD67391CCD116C3E019393C90DFDF1E /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = "../../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/macos/file_selector_macos/Sources/file_selector_macos/Resources/PrivacyInfo.xcprivacy"; sourceTree = ""; }; + 4D3DB54C128E3D88C0C9C7DDEA475ED7 /* Pods-RunnerTests-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-RunnerTests-dummy.m"; sourceTree = ""; }; + 54FCE5405570BE17A68C42D270C472CA /* FileSelectorPlugin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FileSelectorPlugin.swift; path = "../../../../../../../../../../../../../.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/macos/file_selector_macos/Sources/file_selector_macos/FileSelectorPlugin.swift"; sourceTree = ""; }; + 5618CC158E6CE32FA5967F2180DCABAD /* file_selector_macos.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = file_selector_macos.debug.xcconfig; sourceTree = ""; }; + 5D7BD06BD77428ACB67CC9CE8B91C787 /* FlutterMacOS.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = FlutterMacOS.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 5E38F445A54D5F8706EEB5EE6B33DC5C /* file_selector_macos-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "file_selector_macos-prefix.pch"; sourceTree = ""; }; + 669E8F25E1897672BDB80B7EB784DA24 /* Pods-Runner */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-Runner"; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6C3345B1B3CAEDF5B03B1F731FDC492E /* Pods-RunnerTests */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-RunnerTests"; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 728A5ED1DD60BAC8C8F382A87B976F84 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 72EA5874DA7E0B31AADA82D098F11099 /* FlutterMacOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FlutterMacOS.release.xcconfig; sourceTree = ""; }; + 773BFCE41424EB8EBB72EF3F6A5FB719 /* Pods-Runner-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Runner-frameworks.sh"; sourceTree = ""; }; + 79F83F4D505FA40C1CD18A8029181D59 /* Pods-RunnerTests-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-RunnerTests-acknowledgements.plist"; sourceTree = ""; }; + 9D1B8733F4E68BF1AE88EB4DD66D98BD /* file_selector_macos.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = file_selector_macos.modulemap; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9E9B12BCE5540D02A80250C3EC16D399 /* Pods-RunnerTests-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-RunnerTests-umbrella.h"; sourceTree = ""; }; + 9EE00D34B275026D4656C738BED5A001 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.0.sdk/System/Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; }; + AC8FE152530FBDCE460186B326C1A8FB /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + B00A5ECAED4CA0C16FF7C65365BC0334 /* Pods-RunnerTests-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-RunnerTests-Info.plist"; sourceTree = ""; }; + B0BD57AB3672E53828D11C2A3368023A /* Pods-RunnerTests.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-RunnerTests.modulemap"; sourceTree = ""; }; + B52BE94845C16778C6788595A182BE8D /* file_selector_macos-file_selector_macos_privacy */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = "file_selector_macos-file_selector_macos_privacy"; path = file_selector_macos_privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + B703785507B22BAF0B800737429577EC /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Runner.release.xcconfig"; sourceTree = ""; }; + B9F3ECAFADED42EADC7C2406A3B88EBA /* file_selector_macos-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "file_selector_macos-Info.plist"; sourceTree = ""; }; + BD2A7E58CC066C3548579A38C6DCE104 /* FlutterMacOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = FlutterMacOS.debug.xcconfig; sourceTree = ""; }; + C24C1A035F22D24883C6F1876F274C6F /* Pods-Runner.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Runner.modulemap"; sourceTree = ""; }; + C2A19B351EE3987102FF0AA4CD33F175 /* file_selector_macos */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = file_selector_macos; path = file_selector_macos.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C50FD10CD19FF6999637BA5ECAF1681B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + D98F06A10538A0208B66D42363EB853A /* ResourceBundle-file_selector_macos_privacy-file_selector_macos-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-file_selector_macos_privacy-file_selector_macos-Info.plist"; sourceTree = ""; }; + E736E0C9C5B73D27B8865E363E2108AC /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + E794494AB90477BA94C681E994ADF341 /* Pods-Runner-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Runner-dummy.m"; sourceTree = ""; }; + EC68A8DCDAF767E8B9C3341834225393 /* file_selector_macos.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = file_selector_macos.podspec; path = "../../../../../../../../../../.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/macos/file_selector_macos.podspec"; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + ECDF6AA713870989438BA93B395DC557 /* Pods-Runner-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Runner-acknowledgements.markdown"; sourceTree = ""; }; + F330EFE02FAE8A91E846446009ADB595 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; name = LICENSE; path = "../../../../../../../../../../.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/LICENSE"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 83714CCAFCEB20E80E4151F5BE1DE816 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D727808C1C6F611A32F6607975591ADE /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9E71D4D359BD23DAAEF32A688D978673 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + BAC60E5A744A18DB84E0533BF26F4CCE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BD04BA2A11AF101C0A0DF73CE3839352 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAC0834F7252D8143E0E41335E53F3B8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 03FF65672874530A3E9AE6BAB1764A4A /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 03ACA564CA7D42409E0C518834095D0F /* Pod */ = { + isa = PBXGroup; + children = ( + EC68A8DCDAF767E8B9C3341834225393 /* file_selector_macos.podspec */, + F330EFE02FAE8A91E846446009ADB595 /* LICENSE */, + ); + name = Pod; + sourceTree = ""; + }; + 187325704B89BE4587F3B3F1836A0776 /* file_selector_macos */ = { + isa = PBXGroup; + children = ( + 626BFF6E847A62D8ED23390EE8735904 /* Sources */, + ); + name = file_selector_macos; + path = file_selector_macos; + sourceTree = ""; + }; + 1B48A95B96A02A99557D61E84A47F9C9 /* file_selector_macos */ = { + isa = PBXGroup; + children = ( + 9E5DDA214929B04F7CB98F712BA45F94 /* .. */, + 03ACA564CA7D42409E0C518834095D0F /* Pod */, + F960A509A5AEE17113895F33C15FDC1D /* Support Files */, + ); + name = file_selector_macos; + path = ../Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos; + sourceTree = ""; + }; + 20963569C421ACF39E16D18BAD958044 /* .. */ = { + isa = PBXGroup; + children = ( + 5444B18A9DA6D558DCDA0A07861B4E55 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 2530A246D2079458FB8112C781E4B3EC /* ephemeral */ = { + isa = PBXGroup; + children = ( + 4169F8E049F344000B180BA6CA088796 /* .symlinks */, + ); + name = ephemeral; + path = ephemeral; + sourceTree = ""; + }; + 2DB8426A477BA92773F00012EBA84D53 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + E806A4F97D48F5FD3B4CA1BC617EA1F5 /* Pods-Runner */, + 537E840C4F4E30B706FD9D64B15C53A7 /* Pods-RunnerTests */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + 2F5FEE56F0E0402B12FCF972B3227807 /* frontend */ = { + isa = PBXGroup; + children = ( + D5656BD140AB5320CD03D2DDF8887D2B /* macos */, + ); + name = frontend; + path = frontend; + sourceTree = ""; + }; + 397521F5275EB079681166EAC3462374 /* .. */ = { + isa = PBXGroup; + children = ( + CE690BCA3A5BD6B2E03268A00D59F514 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 39B2DC7C000BC5485CB720A39B98094D /* file_selector_macos */ = { + isa = PBXGroup; + children = ( + B133FC212F02CB96461868BF71FF76CD /* macos */, + ); + name = file_selector_macos; + path = file_selector_macos; + sourceTree = ""; + }; + 3A402A9920A8D9AD3DAA3D2E1DDD28CC /* .. */ = { + isa = PBXGroup; + children = ( + 8797A8CDBA6A3728F399E462AB22C617 /* .. */, + 71354B55EF487268B5B45BB5AAC13CBD /* Documents */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 4169F8E049F344000B180BA6CA088796 /* .symlinks */ = { + isa = PBXGroup; + children = ( + 4A20C329357CCD5F04329DECDA83F38C /* plugins */, + ); + name = .symlinks; + path = .symlinks; + sourceTree = ""; + }; + 42CD38EBDD5E23BFE60F39945B8D56CA /* Pod */ = { + isa = PBXGroup; + children = ( + 5D7BD06BD77428ACB67CC9CE8B91C787 /* FlutterMacOS.podspec */, + ); + name = Pod; + sourceTree = ""; + }; + 43AB1DFE4370DBBBF3D5B332166744D9 /* frontend */ = { + isa = PBXGroup; + children = ( + CE134C795469A1F6B17167011C16B6F3 /* macos */, + ); + name = frontend; + path = frontend; + sourceTree = ""; + }; + 4A20C329357CCD5F04329DECDA83F38C /* plugins */ = { + isa = PBXGroup; + children = ( + C700CB78D18A5D3D3892F79CBAF6E07C /* file_selector_macos */, + ); + name = plugins; + path = plugins; + sourceTree = ""; + }; + 4FB43232589F0371FEF84E8A8FEEBD17 /* .. */ = { + isa = PBXGroup; + children = ( + 6D55F484DD739FE22AC64E0B2B2D658A /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 537E840C4F4E30B706FD9D64B15C53A7 /* Pods-RunnerTests */ = { + isa = PBXGroup; + children = ( + B0BD57AB3672E53828D11C2A3368023A /* Pods-RunnerTests.modulemap */, + 11AA7018F95317D959D9D2E76CBB2377 /* Pods-RunnerTests-acknowledgements.markdown */, + 79F83F4D505FA40C1CD18A8029181D59 /* Pods-RunnerTests-acknowledgements.plist */, + 4D3DB54C128E3D88C0C9C7DDEA475ED7 /* Pods-RunnerTests-dummy.m */, + B00A5ECAED4CA0C16FF7C65365BC0334 /* Pods-RunnerTests-Info.plist */, + 9E9B12BCE5540D02A80250C3EC16D399 /* Pods-RunnerTests-umbrella.h */, + 03E8AD2E8B75443E12D3D3BD12A9900E /* Pods-RunnerTests.debug.xcconfig */, + E736E0C9C5B73D27B8865E363E2108AC /* Pods-RunnerTests.profile.xcconfig */, + AC8FE152530FBDCE460186B326C1A8FB /* Pods-RunnerTests.release.xcconfig */, + ); + name = "Pods-RunnerTests"; + path = "Target Support Files/Pods-RunnerTests"; + sourceTree = ""; + }; + 5444B18A9DA6D558DCDA0A07861B4E55 /* .. */ = { + isa = PBXGroup; + children = ( + 397521F5275EB079681166EAC3462374 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 5D16CFC69B1F98A21C9F539C94F5B042 /* Development Pods */ = { + isa = PBXGroup; + children = ( + 1B48A95B96A02A99557D61E84A47F9C9 /* file_selector_macos */, + 80B97402D320C2FAB1AA14D9FE0306F4 /* FlutterMacOS */, + ); + name = "Development Pods"; + sourceTree = ""; + }; + 626BFF6E847A62D8ED23390EE8735904 /* Sources */ = { + isa = PBXGroup; + children = ( + EF80820629A43953B96BBE2C759405EA /* file_selector_macos */, + ); + name = Sources; + path = Sources; + sourceTree = ""; + }; + 690A10E38EBD34D8F315964A445EB1C9 /* Gradi_25Fall */ = { + isa = PBXGroup; + children = ( + 43AB1DFE4370DBBBF3D5B332166744D9 /* frontend */, + ); + name = Gradi_25Fall; + path = Gradi_25Fall; + sourceTree = ""; + }; + 6CF8013CA832F8AB5DDAE0156C97FD88 /* OS X */ = { + isa = PBXGroup; + children = ( + 9EE00D34B275026D4656C738BED5A001 /* Cocoa.framework */, + ); + name = "OS X"; + sourceTree = ""; + }; + 6D2766640A6D75393933011FD6DFBDA6 /* Sources */ = { + isa = PBXGroup; + children = ( + FD0E61A53F9AE7689E25258D86853596 /* file_selector_macos */, + ); + name = Sources; + path = Sources; + sourceTree = ""; + }; + 6D55F484DD739FE22AC64E0B2B2D658A /* .. */ = { + isa = PBXGroup; + children = ( + 20963569C421ACF39E16D18BAD958044 /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + 7015130D2205725059A78752280AF3EB /* Flutter */ = { + isa = PBXGroup; + children = ( + DFEE09FCE67DECA2E93AC74911B2F638 /* ephemeral */, + ); + name = Flutter; + path = Flutter; + sourceTree = ""; + }; + 71354B55EF487268B5B45BB5AAC13CBD /* Documents */ = { + isa = PBXGroup; + children = ( + AF695AB69D94F1343C122F5CCE1BCDBC /* Gradi_25Fall */, + ); + name = Documents; + path = Documents; + sourceTree = ""; + }; + 71C6DA71553EFC496539C8163A1785C2 /* macos */ = { + isa = PBXGroup; + children = ( + CAE59B26DBB195B6BC0A47327DEA1876 /* file_selector_macos */, + ); + name = macos; + path = macos; + sourceTree = ""; + }; + 7C43B0F52F386426A730D01E14F0C9C1 /* plugins */ = { + isa = PBXGroup; + children = ( + 39B2DC7C000BC5485CB720A39B98094D /* file_selector_macos */, + ); + name = plugins; + path = plugins; + sourceTree = ""; + }; + 80B97402D320C2FAB1AA14D9FE0306F4 /* FlutterMacOS */ = { + isa = PBXGroup; + children = ( + 42CD38EBDD5E23BFE60F39945B8D56CA /* Pod */, + FD35CE461A898AB8E3329DCA71B934C4 /* Support Files */, + ); + name = FlutterMacOS; + path = ../Flutter/ephemeral; + sourceTree = ""; + }; + 84C537CAB27AF293ECBD0150D1211683 /* Resources */ = { + isa = PBXGroup; + children = ( + 4AD67391CCD116C3E019393C90DFDF1E /* PrivacyInfo.xcprivacy */, + ); + name = Resources; + path = Resources; + sourceTree = ""; + }; + 8797A8CDBA6A3728F399E462AB22C617 /* .. */ = { + isa = PBXGroup; + children = ( + A2C0B3C8C85B8772C8E02277BB3D437B /* Documents */, + ); + name = ..; + path = .; + sourceTree = ""; + }; + 9E5DDA214929B04F7CB98F712BA45F94 /* .. */ = { + isa = PBXGroup; + children = ( + 4FB43232589F0371FEF84E8A8FEEBD17 /* .. */, + ); + name = ..; + path = "../../../../../../../../../../.pub-cache/hosted/pub.dev/file_selector_macos-0.9.4+5/macos/file_selector_macos/Sources"; + sourceTree = ""; + }; + A2C0B3C8C85B8772C8E02277BB3D437B /* Documents */ = { + isa = PBXGroup; + children = ( + 690A10E38EBD34D8F315964A445EB1C9 /* Gradi_25Fall */, + ); + name = Documents; + path = Documents; + sourceTree = ""; + }; + A7D405E030ECE703019725A4EADCA86F /* .symlinks */ = { + isa = PBXGroup; + children = ( + 7C43B0F52F386426A730D01E14F0C9C1 /* plugins */, + ); + name = .symlinks; + path = .symlinks; + sourceTree = ""; + }; + AF695AB69D94F1343C122F5CCE1BCDBC /* Gradi_25Fall */ = { + isa = PBXGroup; + children = ( + 2F5FEE56F0E0402B12FCF972B3227807 /* frontend */, + ); + name = Gradi_25Fall; + path = Gradi_25Fall; + sourceTree = ""; + }; + B133FC212F02CB96461868BF71FF76CD /* macos */ = { + isa = PBXGroup; + children = ( + 187325704B89BE4587F3B3F1836A0776 /* file_selector_macos */, + ); + name = macos; + path = macos; + sourceTree = ""; + }; + C700CB78D18A5D3D3892F79CBAF6E07C /* file_selector_macos */ = { + isa = PBXGroup; + children = ( + 71C6DA71553EFC496539C8163A1785C2 /* macos */, + ); + name = file_selector_macos; + path = file_selector_macos; + sourceTree = ""; + }; + CAE59B26DBB195B6BC0A47327DEA1876 /* file_selector_macos */ = { + isa = PBXGroup; + children = ( + 6D2766640A6D75393933011FD6DFBDA6 /* Sources */, + ); + name = file_selector_macos; + path = file_selector_macos; + sourceTree = ""; + }; + CE134C795469A1F6B17167011C16B6F3 /* macos */ = { + isa = PBXGroup; + children = ( + D21D2E1710E393DC963F0DBCEDE454D5 /* Flutter */, + ); + name = macos; + path = macos; + sourceTree = ""; + }; + CE690BCA3A5BD6B2E03268A00D59F514 /* .. */ = { + isa = PBXGroup; + children = ( + 3A402A9920A8D9AD3DAA3D2E1DDD28CC /* .. */, + ); + name = ..; + path = ..; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + 5D16CFC69B1F98A21C9F539C94F5B042 /* Development Pods */, + E0A1E60606E0BF6E2E10F1F01350DFE8 /* Frameworks */, + EEE8101C35C18D4283FF95718A26C390 /* Products */, + 2DB8426A477BA92773F00012EBA84D53 /* Targets Support Files */, + ); + sourceTree = ""; + }; + D21D2E1710E393DC963F0DBCEDE454D5 /* Flutter */ = { + isa = PBXGroup; + children = ( + 2530A246D2079458FB8112C781E4B3EC /* ephemeral */, + ); + name = Flutter; + path = Flutter; + sourceTree = ""; + }; + D5656BD140AB5320CD03D2DDF8887D2B /* macos */ = { + isa = PBXGroup; + children = ( + 7015130D2205725059A78752280AF3EB /* Flutter */, + ); + name = macos; + path = macos; + sourceTree = ""; + }; + DFEE09FCE67DECA2E93AC74911B2F638 /* ephemeral */ = { + isa = PBXGroup; + children = ( + A7D405E030ECE703019725A4EADCA86F /* .symlinks */, + ); + name = ephemeral; + path = ephemeral; + sourceTree = ""; + }; + E0A1E60606E0BF6E2E10F1F01350DFE8 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6CF8013CA832F8AB5DDAE0156C97FD88 /* OS X */, + ); + name = Frameworks; + sourceTree = ""; + }; + E806A4F97D48F5FD3B4CA1BC617EA1F5 /* Pods-Runner */ = { + isa = PBXGroup; + children = ( + C24C1A035F22D24883C6F1876F274C6F /* Pods-Runner.modulemap */, + ECDF6AA713870989438BA93B395DC557 /* Pods-Runner-acknowledgements.markdown */, + 1B136F41D5B5FAE96EA576E768A5771D /* Pods-Runner-acknowledgements.plist */, + E794494AB90477BA94C681E994ADF341 /* Pods-Runner-dummy.m */, + 773BFCE41424EB8EBB72EF3F6A5FB719 /* Pods-Runner-frameworks.sh */, + 0AFB643DA4919253F749E2836A5AAFDC /* Pods-Runner-Info.plist */, + 499E3722E8DACDC2AAA6C15AD1796520 /* Pods-Runner-umbrella.h */, + 728A5ED1DD60BAC8C8F382A87B976F84 /* Pods-Runner.debug.xcconfig */, + C50FD10CD19FF6999637BA5ECAF1681B /* Pods-Runner.profile.xcconfig */, + B703785507B22BAF0B800737429577EC /* Pods-Runner.release.xcconfig */, + ); + name = "Pods-Runner"; + path = "Target Support Files/Pods-Runner"; + sourceTree = ""; + }; + EEE8101C35C18D4283FF95718A26C390 /* Products */ = { + isa = PBXGroup; + children = ( + C2A19B351EE3987102FF0AA4CD33F175 /* file_selector_macos */, + B52BE94845C16778C6788595A182BE8D /* file_selector_macos-file_selector_macos_privacy */, + 669E8F25E1897672BDB80B7EB784DA24 /* Pods-Runner */, + 6C3345B1B3CAEDF5B03B1F731FDC492E /* Pods-RunnerTests */, + ); + name = Products; + sourceTree = ""; + }; + EF80820629A43953B96BBE2C759405EA /* file_selector_macos */ = { + isa = PBXGroup; + children = ( + 54FCE5405570BE17A68C42D270C472CA /* FileSelectorPlugin.swift */, + 187E8528F91943094FAC776650C63719 /* messages.g.swift */, + ); + name = file_selector_macos; + path = file_selector_macos; + sourceTree = ""; + }; + F960A509A5AEE17113895F33C15FDC1D /* Support Files */ = { + isa = PBXGroup; + children = ( + 9D1B8733F4E68BF1AE88EB4DD66D98BD /* file_selector_macos.modulemap */, + 43858F74F1FB1C05D7FA6EC527F87F59 /* file_selector_macos-dummy.m */, + B9F3ECAFADED42EADC7C2406A3B88EBA /* file_selector_macos-Info.plist */, + 5E38F445A54D5F8706EEB5EE6B33DC5C /* file_selector_macos-prefix.pch */, + 0352660B8678B8F2D53F14CDC47611E0 /* file_selector_macos-umbrella.h */, + 5618CC158E6CE32FA5967F2180DCABAD /* file_selector_macos.debug.xcconfig */, + 08B05A9A012C65CFF9ED5E98E221A720 /* file_selector_macos.release.xcconfig */, + D98F06A10538A0208B66D42363EB853A /* ResourceBundle-file_selector_macos_privacy-file_selector_macos-Info.plist */, + ); + name = "Support Files"; + path = "../../../../../../Pods/Target Support Files/file_selector_macos"; + sourceTree = ""; + }; + FD0E61A53F9AE7689E25258D86853596 /* file_selector_macos */ = { + isa = PBXGroup; + children = ( + 84C537CAB27AF293ECBD0150D1211683 /* Resources */, + ); + name = file_selector_macos; + path = file_selector_macos; + sourceTree = ""; + }; + FD35CE461A898AB8E3329DCA71B934C4 /* Support Files */ = { + isa = PBXGroup; + children = ( + BD2A7E58CC066C3548579A38C6DCE104 /* FlutterMacOS.debug.xcconfig */, + 72EA5874DA7E0B31AADA82D098F11099 /* FlutterMacOS.release.xcconfig */, + ); + name = "Support Files"; + path = "../../Pods/Target Support Files/FlutterMacOS"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 71B1E3CB98E56B585D57CF1EA56D158B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + EF5ADFB07D3AAAE725DBA930289E55D5 /* file_selector_macos-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A07DE36529777F9C3AE89E5470DE07D0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 3432DABAA7742D36C6F8F8A32D0E1488 /* Pods-Runner-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FC4DA9BD27A4914E75F803590E4C4B8B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + EB2DC96CDCF638AB89007D2DB0F3119A /* Pods-RunnerTests-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 3232F0C0E7C65B232832393F9ADDD8C3 /* Pods-RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = D52099AA1537D0F3745166E1889F6CA3 /* Build configuration list for PBXNativeTarget "Pods-RunnerTests" */; + buildPhases = ( + FC4DA9BD27A4914E75F803590E4C4B8B /* Headers */, + 001CCB0FEA80CD1C6BF534C6D9C6283A /* Sources */, + EAC0834F7252D8143E0E41335E53F3B8 /* Frameworks */, + 4A765108DEAFDEBF078F71CDDBE3414E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + B4DA74610A695556209EA82D098ECA82 /* PBXTargetDependency */, + ); + name = "Pods-RunnerTests"; + productName = Pods_RunnerTests; + productReference = 6C3345B1B3CAEDF5B03B1F731FDC492E /* Pods-RunnerTests */; + productType = "com.apple.product-type.framework"; + }; + 6665E994FA6BDAD3162E29390B9D4D39 /* file_selector_macos-file_selector_macos_privacy */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8407C4CDCF8EE38D111AE8CFB5114AAC /* Build configuration list for PBXNativeTarget "file_selector_macos-file_selector_macos_privacy" */; + buildPhases = ( + 8158E79BBAFAB0D2BDE57A856850A916 /* Sources */, + 9E71D4D359BD23DAAEF32A688D978673 /* Frameworks */, + D70D3753688C7800F808737A882DC5F9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "file_selector_macos-file_selector_macos_privacy"; + productName = file_selector_macos_privacy; + productReference = B52BE94845C16778C6788595A182BE8D /* file_selector_macos-file_selector_macos_privacy */; + productType = "com.apple.product-type.bundle"; + }; + 773D4A7C7FA9CAB9B055EBF0A53821FB /* file_selector_macos */ = { + isa = PBXNativeTarget; + buildConfigurationList = AA54632FC0D474C831553B09CF069DC2 /* Build configuration list for PBXNativeTarget "file_selector_macos" */; + buildPhases = ( + 71B1E3CB98E56B585D57CF1EA56D158B /* Headers */, + 01EA8AE4FEFB7938A2D3321668913119 /* Sources */, + 83714CCAFCEB20E80E4151F5BE1DE816 /* Frameworks */, + 2A44C99F3F59B811A6C857A25C88748E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0753D9C3F0184B56A4F05FA397E2641C /* PBXTargetDependency */, + A3292C3B704CF709FC3E1A26C009FFC9 /* PBXTargetDependency */, + ); + name = file_selector_macos; + productName = file_selector_macos; + productReference = C2A19B351EE3987102FF0AA4CD33F175 /* file_selector_macos */; + productType = "com.apple.product-type.framework"; + }; + 8B74B458B450D74B75744B87BD747314 /* Pods-Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 984FE60DD4CB2F27B052CF79ED9D42C6 /* Build configuration list for PBXNativeTarget "Pods-Runner" */; + buildPhases = ( + A07DE36529777F9C3AE89E5470DE07D0 /* Headers */, + 2D548E28144A900228A8D3D7FABE1E9D /* Sources */, + BAC60E5A744A18DB84E0533BF26F4CCE /* Frameworks */, + 5E24C7D3FDFD3E7C3E13E14D411EC44B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5A1EC8C26D57674C6BA6DD0B5717BDA9 /* PBXTargetDependency */, + 64B79901D9B3796B26D6C67DE2508E22 /* PBXTargetDependency */, + ); + name = "Pods-Runner"; + productName = Pods_Runner; + productReference = 669E8F25E1897672BDB80B7EB784DA24 /* Pods-Runner */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1600; + LastUpgradeCheck = 1600; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + minimizedProjectReferenceProxies = 0; + preferredProjectObjectVersion = 77; + productRefGroup = EEE8101C35C18D4283FF95718A26C390 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 773D4A7C7FA9CAB9B055EBF0A53821FB /* file_selector_macos */, + 6665E994FA6BDAD3162E29390B9D4D39 /* file_selector_macos-file_selector_macos_privacy */, + CA272E8348BAB4CE0B0C804FB7B818C4 /* FlutterMacOS */, + 8B74B458B450D74B75744B87BD747314 /* Pods-Runner */, + 3232F0C0E7C65B232832393F9ADDD8C3 /* Pods-RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2A44C99F3F59B811A6C857A25C88748E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A48937410C16702A0571A02A59CE3869 /* file_selector_macos-file_selector_macos_privacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4A765108DEAFDEBF078F71CDDBE3414E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5E24C7D3FDFD3E7C3E13E14D411EC44B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D70D3753688C7800F808737A882DC5F9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 75564B76FFE8703157322DE7E91ADD19 /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 001CCB0FEA80CD1C6BF534C6D9C6283A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B375EA128E6579366091BAA390BBDD34 /* Pods-RunnerTests-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 01EA8AE4FEFB7938A2D3321668913119 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 78045458CE38E19FA6AFEDC333B3C33B /* file_selector_macos-dummy.m in Sources */, + 669CF01609DC4C78118A0F6701A0369A /* FileSelectorPlugin.swift in Sources */, + F990C396E3316B5BCA38BD8ACB6BBF07 /* messages.g.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2D548E28144A900228A8D3D7FABE1E9D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7AF6867726D234741DE68BB1A950E138 /* Pods-Runner-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8158E79BBAFAB0D2BDE57A856850A916 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 0753D9C3F0184B56A4F05FA397E2641C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FlutterMacOS; + target = CA272E8348BAB4CE0B0C804FB7B818C4 /* FlutterMacOS */; + targetProxy = 05C3E3135B831A2281F143E02A90F6DF /* PBXContainerItemProxy */; + }; + 5A1EC8C26D57674C6BA6DD0B5717BDA9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = FlutterMacOS; + target = CA272E8348BAB4CE0B0C804FB7B818C4 /* FlutterMacOS */; + targetProxy = 955F24F47E5C2AEB7BFA453C808C4884 /* PBXContainerItemProxy */; + }; + 64B79901D9B3796B26D6C67DE2508E22 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = file_selector_macos; + target = 773D4A7C7FA9CAB9B055EBF0A53821FB /* file_selector_macos */; + targetProxy = 097401D1B4A991023B00362206BFACC8 /* PBXContainerItemProxy */; + }; + A3292C3B704CF709FC3E1A26C009FFC9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "file_selector_macos-file_selector_macos_privacy"; + target = 6665E994FA6BDAD3162E29390B9D4D39 /* file_selector_macos-file_selector_macos_privacy */; + targetProxy = 14A94EC008746C8AACE067C80352C5F5 /* PBXContainerItemProxy */; + }; + B4DA74610A695556209EA82D098ECA82 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Pods-Runner"; + target = 8B74B458B450D74B75744B87BD747314 /* Pods-Runner */; + targetProxy = F4DBFFB53E6828422526E89CEBA647A5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 07AD40A4677FB80E95DF81E94F42B5EE /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E736E0C9C5B73D27B8865E363E2108AC /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/darwin-x64-release/FlutterMacOS.xcframework/macos-arm64_x86_64\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MODULEMAP_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + 0AE172D8F2A4843BFACAD21A0ED26541 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Release; + }; + 66BBADB1C1D0AB98B5525F2B20B87E1C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 08B05A9A012C65CFF9ED5E98E221A720 /* file_selector_macos.release.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + COMBINE_HIDPI_IMAGES = YES; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/file_selector_macos"; + IBSC_MODULE = file_selector_macos; + INFOPLIST_FILE = "Target Support Files/file_selector_macos/ResourceBundle-file_selector_macos_privacy-file_selector_macos-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_NAME = file_selector_macos_privacy; + SDKROOT = macosx; + SKIP_INSTALL = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 6B38880D823BA32197D5B0D3D5514905 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5618CC158E6CE32FA5967F2180DCABAD /* file_selector_macos.debug.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/darwin-x64/FlutterMacOS.xcframework/macos-arm64_x86_64\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/file_selector_macos/file_selector_macos-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/file_selector_macos/file_selector_macos-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + MODULEMAP_FILE = "Target Support Files/file_selector_macos/file_selector_macos.modulemap"; + PRODUCT_MODULE_NAME = file_selector_macos; + PRODUCT_NAME = file_selector_macos; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 7240A8579D4E173D4895EA679806EC07 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AC8FE152530FBDCE460186B326C1A8FB /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/darwin-x64-release/FlutterMacOS.xcframework/macos-arm64_x86_64\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MODULEMAP_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 73A146472CC9628F31295209925776B4 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 72EA5874DA7E0B31AADA82D098F11099 /* FlutterMacOS.release.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + COMBINE_HIDPI_IMAGES = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + SDKROOT = macosx; + }; + name = Profile; + }; + 77A41D4F329754D77F1BF1548A6C2D38 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 728A5ED1DD60BAC8C8F382A87B976F84 /* Pods-Runner.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/darwin-x64/FlutterMacOS.xcframework/macos-arm64_x86_64\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-Runner/Pods-Runner-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MODULEMAP_FILE = "Target Support Files/Pods-Runner/Pods-Runner.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 808E544862838153672EA12FCC127D9A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 827B7CE8FA8C4E650EF6FD8924F8E935 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B703785507B22BAF0B800737429577EC /* Pods-Runner.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/darwin-x64-release/FlutterMacOS.xcframework/macos-arm64_x86_64\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-Runner/Pods-Runner-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MODULEMAP_FILE = "Target Support Files/Pods-Runner/Pods-Runner.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 856D85E724192A62CA94AB4920C2BDC2 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 08B05A9A012C65CFF9ED5E98E221A720 /* file_selector_macos.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + COMBINE_HIDPI_IMAGES = YES; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/file_selector_macos"; + IBSC_MODULE = file_selector_macos; + INFOPLIST_FILE = "Target Support Files/file_selector_macos/ResourceBundle-file_selector_macos_privacy-file_selector_macos-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_NAME = file_selector_macos_privacy; + SDKROOT = macosx; + SKIP_INSTALL = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Profile; + }; + 8717AE9D98E33F36B7BB74A77DA8AE9E /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BD2A7E58CC066C3548579A38C6DCE104 /* FlutterMacOS.debug.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + COMBINE_HIDPI_IMAGES = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + SDKROOT = macosx; + }; + name = Debug; + }; + AB009CED34DC0B38841DE6CFEF8E3177 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5618CC158E6CE32FA5967F2180DCABAD /* file_selector_macos.debug.xcconfig */; + buildSettings = { + CODE_SIGNING_ALLOWED = NO; + COMBINE_HIDPI_IMAGES = YES; + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/file_selector_macos"; + IBSC_MODULE = file_selector_macos; + INFOPLIST_FILE = "Target Support Files/file_selector_macos/ResourceBundle-file_selector_macos_privacy-file_selector_macos-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_NAME = file_selector_macos_privacy; + SDKROOT = macosx; + SKIP_INSTALL = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + AC0E25C49E1EAF24FF12C103C4D28E20 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 08B05A9A012C65CFF9ED5E98E221A720 /* file_selector_macos.release.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/darwin-x64-release/FlutterMacOS.xcframework/macos-arm64_x86_64\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/file_selector_macos/file_selector_macos-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/file_selector_macos/file_selector_macos-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + MODULEMAP_FILE = "Target Support Files/file_selector_macos/file_selector_macos.modulemap"; + PRODUCT_MODULE_NAME = file_selector_macos; + PRODUCT_NAME = file_selector_macos; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + AF5B76B31CAF4546B42C34718BA67232 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_PROFILE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Profile; + }; + BDCB11BCD1D1D245E710596B08311EF4 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 08B05A9A012C65CFF9ED5E98E221A720 /* file_selector_macos.release.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/darwin-x64-release/FlutterMacOS.xcframework/macos-arm64_x86_64\"", + "$(inherited)", + ); + GCC_PREFIX_HEADER = "Target Support Files/file_selector_macos/file_selector_macos-prefix.pch"; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = "Target Support Files/file_selector_macos/file_selector_macos-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + MODULEMAP_FILE = "Target Support Files/file_selector_macos/file_selector_macos.modulemap"; + PRODUCT_MODULE_NAME = file_selector_macos; + PRODUCT_NAME = file_selector_macos; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_INSTALL_OBJC_HEADER = YES; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + CDE37EABBB3AD6CED6958AD797BCA372 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C50FD10CD19FF6999637BA5ECAF1681B /* Pods-Runner.profile.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/darwin-x64-release/FlutterMacOS.xcframework/macos-arm64_x86_64\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-Runner/Pods-Runner-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MODULEMAP_FILE = "Target Support Files/Pods-Runner/Pods-Runner.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + CEAEF0BB86C6BBA81D6E17A5B8618EB0 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 72EA5874DA7E0B31AADA82D098F11099 /* FlutterMacOS.release.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_OBJC_WEAK = NO; + COMBINE_HIDPI_IMAGES = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 10.15; + SDKROOT = macosx; + }; + name = Release; + }; + E3492020E6C8FFFAA75EF20124A3E54A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 03E8AD2E8B75443E12D3D3BD12A9900E /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = NO; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + FRAMEWORK_SEARCH_PATHS = ( + "\"/Users/downy/flutter/bin/cache/artifacts/engine/darwin-x64/FlutterMacOS.xcframework/macos-arm64_x86_64\"", + "$(inherited)", + ); + INFOPLIST_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MACH_O_TYPE = staticlib; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MODULEMAP_FILE = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 808E544862838153672EA12FCC127D9A /* Debug */, + AF5B76B31CAF4546B42C34718BA67232 /* Profile */, + 0AE172D8F2A4843BFACAD21A0ED26541 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 624022EE1C2EAB1C3CC38699E1368C5F /* Build configuration list for PBXAggregateTarget "FlutterMacOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8717AE9D98E33F36B7BB74A77DA8AE9E /* Debug */, + 73A146472CC9628F31295209925776B4 /* Profile */, + CEAEF0BB86C6BBA81D6E17A5B8618EB0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8407C4CDCF8EE38D111AE8CFB5114AAC /* Build configuration list for PBXNativeTarget "file_selector_macos-file_selector_macos_privacy" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + AB009CED34DC0B38841DE6CFEF8E3177 /* Debug */, + 856D85E724192A62CA94AB4920C2BDC2 /* Profile */, + 66BBADB1C1D0AB98B5525F2B20B87E1C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 984FE60DD4CB2F27B052CF79ED9D42C6 /* Build configuration list for PBXNativeTarget "Pods-Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 77A41D4F329754D77F1BF1548A6C2D38 /* Debug */, + CDE37EABBB3AD6CED6958AD797BCA372 /* Profile */, + 827B7CE8FA8C4E650EF6FD8924F8E935 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + AA54632FC0D474C831553B09CF069DC2 /* Build configuration list for PBXNativeTarget "file_selector_macos" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6B38880D823BA32197D5B0D3D5514905 /* Debug */, + AC0E25C49E1EAF24FF12C103C4D28E20 /* Profile */, + BDCB11BCD1D1D245E710596B08311EF4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D52099AA1537D0F3745166E1889F6CA3 /* Build configuration list for PBXNativeTarget "Pods-RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E3492020E6C8FFFAA75EF20124A3E54A /* Debug */, + 07AD40A4677FB80E95DF81E94F42B5EE /* Profile */, + 7240A8579D4E173D4895EA679806EC07 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FlutterMacOS.xcscheme b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FlutterMacOS.xcscheme new file mode 100644 index 0000000..7c07e83 --- /dev/null +++ b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/FlutterMacOS.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-Runner.xcscheme b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-Runner.xcscheme new file mode 100644 index 0000000..2eb6216 --- /dev/null +++ b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-Runner.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-RunnerTests.xcscheme b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-RunnerTests.xcscheme new file mode 100644 index 0000000..ce8b385 --- /dev/null +++ b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/Pods-RunnerTests.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/file_selector_macos-file_selector_macos_privacy.xcscheme b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/file_selector_macos-file_selector_macos_privacy.xcscheme new file mode 100644 index 0000000..60ada53 --- /dev/null +++ b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/file_selector_macos-file_selector_macos_privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/file_selector_macos.xcscheme b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/file_selector_macos.xcscheme new file mode 100644 index 0000000..1929d7b --- /dev/null +++ b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/file_selector_macos.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/xcschememanagement.plist b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..b8c1ca0 --- /dev/null +++ b/frontend/macos/Pods/Pods.xcodeproj/xcuserdata/downy.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,36 @@ + + + + + SchemeUserState + + FlutterMacOS.xcscheme + + isShown + + + Pods-Runner.xcscheme + + isShown + + + Pods-RunnerTests.xcscheme + + isShown + + + file_selector_macos-file_selector_macos_privacy.xcscheme + + isShown + + + file_selector_macos.xcscheme + + isShown + + + + SuppressBuildableAutocreation + + + diff --git a/frontend/macos/Pods/Target Support Files/FlutterMacOS/FlutterMacOS.debug.xcconfig b/frontend/macos/Pods/Target Support Files/FlutterMacOS/FlutterMacOS.debug.xcconfig new file mode 100644 index 0000000..222fc41 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/FlutterMacOS/FlutterMacOS.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CODE_SIGN_IDENTITY = +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FlutterMacOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../Flutter/ephemeral +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Pods/Target Support Files/FlutterMacOS/FlutterMacOS.release.xcconfig b/frontend/macos/Pods/Target Support Files/FlutterMacOS/FlutterMacOS.release.xcconfig new file mode 100644 index 0000000..222fc41 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/FlutterMacOS/FlutterMacOS.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CODE_SIGN_IDENTITY = +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FlutterMacOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../Flutter/ephemeral +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-Info.plist b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-Info.plist new file mode 100644 index 0000000..19cf209 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.markdown b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.markdown new file mode 100644 index 0000000..ffe3c75 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.markdown @@ -0,0 +1,32 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## file_selector_macos + +Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Generated by CocoaPods - https://cocoapods.org diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.plist b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.plist new file mode 100644 index 0000000..e881ba3 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-acknowledgements.plist @@ -0,0 +1,64 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + License + BSD + Title + file_selector_macos + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-dummy.m b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-dummy.m new file mode 100644 index 0000000..0b73bc1 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_Runner : NSObject +@end +@implementation PodsDummy_Pods_Runner +@end diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-input-files.xcfilelist b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-input-files.xcfilelist new file mode 100644 index 0000000..15707f6 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh +${BUILT_PRODUCTS_DIR}/file_selector_macos/file_selector_macos.framework \ No newline at end of file diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-output-files.xcfilelist b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-output-files.xcfilelist new file mode 100644 index 0000000..f1bf050 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_selector_macos.framework \ No newline at end of file diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-input-files.xcfilelist b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-input-files.xcfilelist new file mode 100644 index 0000000..15707f6 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh +${BUILT_PRODUCTS_DIR}/file_selector_macos/file_selector_macos.framework \ No newline at end of file diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-output-files.xcfilelist b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-output-files.xcfilelist new file mode 100644 index 0000000..f1bf050 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Profile-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_selector_macos.framework \ No newline at end of file diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-input-files.xcfilelist b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-input-files.xcfilelist new file mode 100644 index 0000000..15707f6 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh +${BUILT_PRODUCTS_DIR}/file_selector_macos/file_selector_macos.framework \ No newline at end of file diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-output-files.xcfilelist b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-output-files.xcfilelist new file mode 100644 index 0000000..f1bf050 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Release-output-files.xcfilelist @@ -0,0 +1 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_selector_macos.framework \ No newline at end of file diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh new file mode 100755 index 0000000..5ae3ef8 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh @@ -0,0 +1,189 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then + # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy + # frameworks to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" +SWIFT_STDLIB_PATH="${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +BCSYMBOLMAP_DIR="BCSymbolMaps" + + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +# Copies and strips a vendored framework +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink -f "${source}")" + fi + + if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then + # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied + find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do + echo "Installing $f" + install_bcsymbolmap "$f" "$destination" + rm "$f" + done + rmdir "${source}/${BCSYMBOLMAP_DIR}" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + elif [ -L "${binary}" ]; then + echo "Destination binary is symlinked..." + dirname="$(dirname "${binary}")" + binary="${dirname}/$(readlink "${binary}")" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} +# Copies and strips a vendored dSYM +install_dsym() { + local source="$1" + warn_missing_arch=${2:-true} + if [ -r "$source" ]; then + # Copy the dSYM into the targets temp dir. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" + + local basename + basename="$(basename -s .dSYM "$source")" + binary_name="$(ls "$source/Contents/Resources/DWARF")" + binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" + + # Strip invalid architectures from the dSYM. + if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then + strip_invalid_archs "$binary" "$warn_missing_arch" + fi + if [[ $STRIP_BINARY_RETVAL == 0 ]]; then + # Move the stripped file into its final destination. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + else + # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. + mkdir -p "${DWARF_DSYM_FOLDER_PATH}" + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" + fi + fi +} + +# Used as a return value for each invocation of `strip_invalid_archs` function. +STRIP_BINARY_RETVAL=0 + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + warn_missing_arch=${2:-true} + # Get architectures for current target binary + binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" + # Intersect them with the architectures we are building for + intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" + # If there are no archs supported by this binary then warn the user + if [[ -z "$intersected_archs" ]]; then + if [[ "$warn_missing_arch" == "true" ]]; then + echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." + fi + STRIP_BINARY_RETVAL=1 + return + fi + stripped="" + for arch in $binary_archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi + STRIP_BINARY_RETVAL=0 +} + +# Copies the bcsymbolmap files of a vendored framework +install_bcsymbolmap() { + local bcsymbolmap_path="$1" + local destination="${BUILT_PRODUCTS_DIR}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identity + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/file_selector_macos/file_selector_macos.framework" +fi +if [[ "$CONFIGURATION" == "Profile" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/file_selector_macos/file_selector_macos.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/file_selector_macos/file_selector_macos.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-umbrella.h b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-umbrella.h new file mode 100644 index 0000000..80f15ff --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_RunnerVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_RunnerVersionString[]; + diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig new file mode 100644 index 0000000..4ee6148 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig @@ -0,0 +1,16 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos/file_selector_macos.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "file_selector_macos" +OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/FlutterMacOS" "-F${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.modulemap b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.modulemap new file mode 100644 index 0000000..d2cf6f6 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.modulemap @@ -0,0 +1,6 @@ +framework module Pods_Runner { + umbrella header "Pods-Runner-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig new file mode 100644 index 0000000..4ee6148 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig @@ -0,0 +1,16 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos/file_selector_macos.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "file_selector_macos" +OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/FlutterMacOS" "-F${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig new file mode 100644 index 0000000..4ee6148 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig @@ -0,0 +1,16 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos/file_selector_macos.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "file_selector_macos" +OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/FlutterMacOS" "-F${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist new file mode 100644 index 0000000..19cf209 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.markdown b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.markdown new file mode 100644 index 0000000..102af75 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.markdown @@ -0,0 +1,3 @@ +# Acknowledgements +This application makes use of the following third party libraries: +Generated by CocoaPods - https://cocoapods.org diff --git a/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.plist b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.plist new file mode 100644 index 0000000..7acbad1 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-acknowledgements.plist @@ -0,0 +1,29 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-dummy.m b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-dummy.m new file mode 100644 index 0000000..a664d4a --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_RunnerTests : NSObject +@end +@implementation PodsDummy_Pods_RunnerTests +@end diff --git a/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-umbrella.h b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-umbrella.h new file mode 100644 index 0000000..edfc7f8 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_RunnerTestsVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_RunnerTestsVersionString[]; + diff --git a/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig new file mode 100644 index 0000000..28deb66 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos/file_selector_macos.framework/Headers" +OTHER_LDFLAGS = $(inherited) -framework "file_selector_macos" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap new file mode 100644 index 0000000..c3d99a7 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.modulemap @@ -0,0 +1,6 @@ +framework module Pods_RunnerTests { + umbrella header "Pods-RunnerTests-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig new file mode 100644 index 0000000..28deb66 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos/file_selector_macos.framework/Headers" +OTHER_LDFLAGS = $(inherited) -framework "file_selector_macos" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig new file mode 100644 index 0000000..28deb66 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig @@ -0,0 +1,11 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos/file_selector_macos.framework/Headers" +OTHER_LDFLAGS = $(inherited) -framework "file_selector_macos" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Pods/Target Support Files/file_selector_macos/ResourceBundle-file_selector_macos_privacy-file_selector_macos-Info.plist b/frontend/macos/Pods/Target Support Files/file_selector_macos/ResourceBundle-file_selector_macos_privacy-file_selector_macos-Info.plist new file mode 100644 index 0000000..e22a9aa --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/file_selector_macos/ResourceBundle-file_selector_macos_privacy-file_selector_macos-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 0.0.1 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-Info.plist b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-Info.plist new file mode 100644 index 0000000..8928a8d --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.0.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-dummy.m b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-dummy.m new file mode 100644 index 0000000..856fff1 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_file_selector_macos : NSObject +@end +@implementation PodsDummy_file_selector_macos +@end diff --git a/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-prefix.pch b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-prefix.pch new file mode 100644 index 0000000..082f8af --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-umbrella.h b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-umbrella.h new file mode 100644 index 0000000..fc8716b --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double file_selector_macosVersionNumber; +FOUNDATION_EXPORT const unsigned char file_selector_macosVersionString[]; + diff --git a/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos.debug.xcconfig b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos.debug.xcconfig new file mode 100644 index 0000000..9873e21 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CODE_SIGN_IDENTITY = +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos +DEFINES_MODULE = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos.modulemap b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos.modulemap new file mode 100644 index 0000000..fde7a05 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos.modulemap @@ -0,0 +1,6 @@ +framework module file_selector_macos { + umbrella header "file_selector_macos-umbrella.h" + + export * + module * { export * } +} diff --git a/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos.release.xcconfig b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos.release.xcconfig new file mode 100644 index 0000000..9873e21 --- /dev/null +++ b/frontend/macos/Pods/Target Support Files/file_selector_macos/file_selector_macos.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CODE_SIGN_IDENTITY = +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/file_selector_macos +DEFINES_MODULE = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/../Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/frontend/macos/Runner.xcodeproj/project.pbxproj b/frontend/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6de2e8f --- /dev/null +++ b/frontend/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 08EDBFA5A68C57CA94D6059A /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDC52E5AC5D019F310B8FBF4 /* Pods_RunnerTests.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 81A5DA21989ABED36103675C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A4CA49938D5AEB6E7445BD0 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0A4CA49938D5AEB6E7445BD0 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* gradi_frontend.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = gradi_frontend.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 5854F0B823DCC749D0089F8F /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 728BB4969904FF8B9E6843D9 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 8C4EE3B67951AD7ADCCC85F5 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 939344BC4B0B8D812E6B52C6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + D67BDDB9F7D12FE3DEE4C88F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + DDC52E5AC5D019F310B8FBF4 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + EED1FC437379E7ECD5B43A8E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 08EDBFA5A68C57CA94D6059A /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 81A5DA21989ABED36103675C /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 946897B2109C8FE54D70DDC2 /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* gradi_frontend.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 946897B2109C8FE54D70DDC2 /* Pods */ = { + isa = PBXGroup; + children = ( + 939344BC4B0B8D812E6B52C6 /* Pods-Runner.debug.xcconfig */, + D67BDDB9F7D12FE3DEE4C88F /* Pods-Runner.release.xcconfig */, + EED1FC437379E7ECD5B43A8E /* Pods-Runner.profile.xcconfig */, + 5854F0B823DCC749D0089F8F /* Pods-RunnerTests.debug.xcconfig */, + 8C4EE3B67951AD7ADCCC85F5 /* Pods-RunnerTests.release.xcconfig */, + 728BB4969904FF8B9E6843D9 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0A4CA49938D5AEB6E7445BD0 /* Pods_Runner.framework */, + DDC52E5AC5D019F310B8FBF4 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 1C3A246C72F5663F88229C15 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 603B5F73CFD7F826452D5C58 /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 7DE2262C209214EEFAA57812 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* gradi_frontend.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 1C3A246C72F5663F88229C15 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 603B5F73CFD7F826452D5C58 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 7DE2262C209214EEFAA57812 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5854F0B823DCC749D0089F8F /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/gradi_frontend.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/gradi_frontend"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8C4EE3B67951AD7ADCCC85F5 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/gradi_frontend.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/gradi_frontend"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 728BB4969904FF8B9E6843D9 /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/gradi_frontend.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/gradi_frontend"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/frontend/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/frontend/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..d36270f --- /dev/null +++ b/frontend/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/macos/Runner.xcworkspace/contents.xcworkspacedata b/frontend/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/frontend/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/frontend/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/frontend/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/frontend/macos/Runner/AppDelegate.swift b/frontend/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..b3c1761 --- /dev/null +++ b/frontend/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a2ec33f --- /dev/null +++ b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000..82b6f9d Binary files /dev/null and b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000..13b35eb Binary files /dev/null and b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000..0a3f5fa Binary files /dev/null and b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000..bdb5722 Binary files /dev/null and b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000..f083318 Binary files /dev/null and b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000..326c0e7 Binary files /dev/null and b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000..2f1632c Binary files /dev/null and b/frontend/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/frontend/macos/Runner/Base.lproj/MainMenu.xib b/frontend/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..80e867a --- /dev/null +++ b/frontend/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/macos/Runner/Configs/AppInfo.xcconfig b/frontend/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..c28ba51 --- /dev/null +++ b/frontend/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = gradi_frontend + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.gradi.gradiFrontend + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright ยฉ 2025 com.gradi. All rights reserved. diff --git a/frontend/macos/Runner/Configs/Debug.xcconfig b/frontend/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/frontend/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/frontend/macos/Runner/Configs/Release.xcconfig b/frontend/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/frontend/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/frontend/macos/Runner/Configs/Warnings.xcconfig b/frontend/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/frontend/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/frontend/macos/Runner/DebugProfile.entitlements b/frontend/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..dddb8a3 --- /dev/null +++ b/frontend/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/frontend/macos/Runner/Info.plist b/frontend/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/frontend/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/frontend/macos/Runner/MainFlutterWindow.swift b/frontend/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..3cc05eb --- /dev/null +++ b/frontend/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/frontend/macos/Runner/Release.entitlements b/frontend/macos/Runner/Release.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/frontend/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/frontend/macos/RunnerTests/RunnerTests.swift b/frontend/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61f3bd1 --- /dev/null +++ b/frontend/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/frontend/package.json b/frontend/package.json index daa52e3..e69de29 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,32 +0,0 @@ -{ - "name": "gradi-frontend", - "version": "1.0.0", - "description": "Gradi Auto Grading Service - Frontend", - "main": "index.js", - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "next lint" - }, - "dependencies": { - "next": "^14.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "devDependencies": { - "@types/node": "^20.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "typescript": "^5.0.0", - "eslint": "^8.0.0", - "eslint-config-next": "^14.0.0" - }, - "keywords": [ - "auto-grading", - "education", - "nextjs" - ], - "author": "Gradi Team", - "license": "MIT" -} diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock new file mode 100644 index 0000000..dd04493 --- /dev/null +++ b/frontend/pubspec.lock @@ -0,0 +1,738 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _flutterfire_internals: + dependency: transitive + description: + name: _flutterfire_internals + sha256: ff0a84a2734d9e1089f8aedd5c0af0061b82fb94e95260d943404e0ef2134b11 + url: "https://pub.dev" + source: hosted + version: "1.3.59" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "88707a3bec4b988aaed3b4df5d7441ee4e987f20b286cddca5d6a8270cab23f2" + url: "https://pub.dev" + source: hosted + version: "0.9.4+5" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" + url: "https://pub.dev" + source: hosted + version: "0.9.3+4" + firebase_core: + dependency: "direct main" + description: + name: firebase_core + sha256: "7be63a3f841fc9663342f7f3a011a42aef6a61066943c90b1c434d79d5c995c5" + url: "https://pub.dev" + source: hosted + version: "3.15.2" + firebase_core_platform_interface: + dependency: transitive + description: + name: firebase_core_platform_interface + sha256: cccb4f572325dc14904c02fcc7db6323ad62ba02536833dddb5c02cac7341c64 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + firebase_core_web: + dependency: transitive + description: + name: firebase_core_web + sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" + url: "https://pub.dev" + source: hosted + version: "2.24.1" + firebase_messaging: + dependency: "direct main" + description: + name: firebase_messaging + sha256: "60be38574f8b5658e2f22b7e311ff2064bea835c248424a383783464e8e02fcc" + url: "https://pub.dev" + source: hosted + version: "15.2.10" + firebase_messaging_platform_interface: + dependency: transitive + description: + name: firebase_messaging_platform_interface + sha256: "685e1771b3d1f9c8502771ccc9f91485b376ffe16d553533f335b9183ea99754" + url: "https://pub.dev" + source: hosted + version: "4.6.10" + firebase_messaging_web: + dependency: transitive + description: + name: firebase_messaging_web + sha256: "0d1be17bc89ed3ff5001789c92df678b2e963a51b6fa2bdb467532cc9dbed390" + url: "https://pub.dev" + source: hosted + version: "3.10.10" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: ef41ae901e7529e52934feba19ed82827b11baa67336829564aeab3129460610 + url: "https://pub.dev" + source: hosted + version: "18.0.1" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: "8f685642876742c941b29c32030f6f4f6dacd0e4eaecb3efbb187d6a3812ca01" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "6c5b83c86bf819cdb177a9247a3722067dd8cc6313827ce7c77a4b238a26fd52" + url: "https://pub.dev" + source: hosted + version: "8.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "306f0596590e077338312f38837f595c04f28d6cdeeac392d3d74df2f0003687" + url: "https://pub.dev" + source: hosted + version: "2.0.32" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: b9c2ad5872518a27507ab432d1fb97e8813b05f0fc693f9d40fad06d073e0678 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: f62bcd90459e63210bbf9c35deb6a51c521f992a78de19a1fe5c11704f9530e2 + url: "https://pub.dev" + source: hosted + version: "13.0.4" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: fcb1760a50d7500deca37c9a666785c047139b5f9ee15aa5469fae7dbbe3170d + url: "https://pub.dev" + source: hosted + version: "4.6.2" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 + url: "https://pub.dev" + source: hosted + version: "2.3.13" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" + url: "https://pub.dev" + source: hosted + version: "4.2.6" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 + url: "https://pub.dev" + source: hosted + version: "4.1.3" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" + url: "https://pub.dev" + source: hosted + version: "0.2.5" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1 + url: "https://pub.dev" + source: hosted + version: "7.7.0" + http: + dependency: "direct main" + description: + name: http + sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007 + url: "https://pub.dev" + source: hosted + version: "1.5.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "58a85e6f09fe9c4484d53d18a0bd6271b72c53fce1d05e6f745ae36d8c18efca" + url: "https://pub.dev" + source: hosted + version: "0.8.13+5" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: e675c22790bcc24e9abd455deead2b7a88de4b79f7327a281812f14de1a56f58 + url: "https://pub.dev" + source: hosted + version: "0.8.13+1" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" + url: "https://pub.dev" + source: hosted + version: "0.2.2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" + url: "https://pub.dev" + source: hosted + version: "0.2.2+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" + url: "https://pub.dev" + source: hosted + version: "2.11.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae + url: "https://pub.dev" + source: hosted + version: "0.2.2" + launchdarkly_event_source_client: + dependency: "direct main" + description: + name: launchdarkly_event_source_client + sha256: "51c90efe9765bf6908772abd59ea16c193798c1a9f9381475c56299cb553e3b2" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + url: "https://pub.dev" + source: hosted + version: "11.0.2" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + url: "https://pub.dev" + source: hosted + version: "3.0.10" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + lints: + dependency: transitive + description: + name: lints + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + url: "https://pub.dev" + source: hosted + version: "5.1.1" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + url: "https://pub.dev" + source: hosted + version: "7.0.1" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "34266009473bf71d748912da4bf62d439185226c03e01e2d9687bc65bbfcb713" + url: "https://pub.dev" + source: hosted + version: "2.4.15" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "1c33a907142607c40a7542768ec9badfd16293bac51da3a4482623d15845f88b" + url: "https://pub.dev" + source: hosted + version: "2.5.5" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + url: "https://pub.dev" + source: hosted + version: "0.7.6" + timezone: + dependency: transitive + description: + name: timezone + sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 + url: "https://pub.dev" + source: hosted + version: "0.10.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + uuid: + dependency: transitive + description: + name: uuid + sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 + url: "https://pub.dev" + source: hosted + version: "4.5.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 + url: "https://pub.dev" + source: hosted + version: "1.1.19" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc + url: "https://pub.dev" + source: hosted + version: "1.1.19" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + url: "https://pub.dev" + source: hosted + version: "15.0.2" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" +sdks: + dart: ">=3.9.2 <4.0.0" + flutter: ">=3.35.0" diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml new file mode 100644 index 0000000..935c90d --- /dev/null +++ b/frontend/pubspec.yaml @@ -0,0 +1,109 @@ +name: gradi_frontend +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: "none" # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ^3.9.2 + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.8 + http: ^1.2.0 + get_it: ^7.7.0 + flutter_svg: ^2.0.10+1 + image_picker: ^1.0.7 + launchdarkly_event_source_client: ^2.0.1 + + # Firebase + firebase_core: ^3.6.0 + firebase_messaging: ^15.1.3 + + # ๋กœ์ปฌ ์•Œ๋ฆผ + flutter_local_notifications: ^18.0.1 + + # ์œ„์น˜ ์ •๋ณด + geolocator: ^13.0.1 + + # ๋กœ์ปฌ ์ €์žฅ์†Œ + shared_preferences: ^2.2.2 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^5.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/images/ + - assets/images/icons/ + - assets/images/bookcovers/ + - assets/images/social_login/ + - assets/images/temp/ + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/to/asset-from-package + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/to/font-from-package diff --git a/frontend/test/widget_test.dart b/frontend/test/widget_test.dart new file mode 100644 index 0000000..0b221cc --- /dev/null +++ b/frontend/test/widget_test.dart @@ -0,0 +1,21 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:gradi_frontend/main.dart'; + +void main() { + testWidgets('GRADI app smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const GradiApp()); + + // Verify that the login page loads + expect(find.text('GRADI'), findsOneWidget); + expect(find.text('๋กœ๊ทธ์ธ'), findsOneWidget); + }); +} diff --git a/frontend/web/favicon.png b/frontend/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/frontend/web/favicon.png differ diff --git a/frontend/web/icons/Icon-192.png b/frontend/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/frontend/web/icons/Icon-192.png differ diff --git a/frontend/web/icons/Icon-512.png b/frontend/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/frontend/web/icons/Icon-512.png differ diff --git a/frontend/web/icons/Icon-maskable-192.png b/frontend/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/frontend/web/icons/Icon-maskable-192.png differ diff --git a/frontend/web/icons/Icon-maskable-512.png b/frontend/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/frontend/web/icons/Icon-maskable-512.png differ diff --git a/frontend/web/index.html b/frontend/web/index.html new file mode 100644 index 0000000..58dbead --- /dev/null +++ b/frontend/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + gradi_frontend + + + + + + diff --git a/frontend/web/manifest.json b/frontend/web/manifest.json new file mode 100644 index 0000000..6c103e6 --- /dev/null +++ b/frontend/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "gradi_frontend", + "short_name": "gradi_frontend", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/frontend/windows/.gitignore b/frontend/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/frontend/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/frontend/windows/CMakeLists.txt b/frontend/windows/CMakeLists.txt new file mode 100644 index 0000000..8588a9b --- /dev/null +++ b/frontend/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(gradi_frontend LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "gradi_frontend") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/frontend/windows/flutter/CMakeLists.txt b/frontend/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..903f489 --- /dev/null +++ b/frontend/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/frontend/windows/flutter/ephemeral/.plugin_symlinks/file_selector_windows b/frontend/windows/flutter/ephemeral/.plugin_symlinks/file_selector_windows new file mode 120000 index 0000000..1dc8799 --- /dev/null +++ b/frontend/windows/flutter/ephemeral/.plugin_symlinks/file_selector_windows @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/file_selector_windows-0.9.3+4/ \ No newline at end of file diff --git a/frontend/windows/flutter/ephemeral/.plugin_symlinks/firebase_core b/frontend/windows/flutter/ephemeral/.plugin_symlinks/firebase_core new file mode 120000 index 0000000..9493d36 --- /dev/null +++ b/frontend/windows/flutter/ephemeral/.plugin_symlinks/firebase_core @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/firebase_core-3.15.2/ \ No newline at end of file diff --git a/frontend/windows/flutter/ephemeral/.plugin_symlinks/image_picker_windows b/frontend/windows/flutter/ephemeral/.plugin_symlinks/image_picker_windows new file mode 120000 index 0000000..667155b --- /dev/null +++ b/frontend/windows/flutter/ephemeral/.plugin_symlinks/image_picker_windows @@ -0,0 +1 @@ +/Users/downy/.pub-cache/hosted/pub.dev/image_picker_windows-0.2.2/ \ No newline at end of file diff --git a/frontend/windows/flutter/generated_plugin_registrant.cc b/frontend/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..08cddef --- /dev/null +++ b/frontend/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,20 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); + FirebaseCorePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); +} diff --git a/frontend/windows/flutter/generated_plugin_registrant.h b/frontend/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/frontend/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/frontend/windows/flutter/generated_plugins.cmake b/frontend/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..36a3440 --- /dev/null +++ b/frontend/windows/flutter/generated_plugins.cmake @@ -0,0 +1,26 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows + firebase_core + geolocator_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/frontend/windows/runner/CMakeLists.txt b/frontend/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..394917c --- /dev/null +++ b/frontend/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/frontend/windows/runner/Runner.rc b/frontend/windows/runner/Runner.rc new file mode 100644 index 0000000..2c7f0dd --- /dev/null +++ b/frontend/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.gradi" "\0" + VALUE "FileDescription", "gradi_frontend" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "gradi_frontend" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.gradi. All rights reserved." "\0" + VALUE "OriginalFilename", "gradi_frontend.exe" "\0" + VALUE "ProductName", "gradi_frontend" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/frontend/windows/runner/flutter_window.cpp b/frontend/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..955ee30 --- /dev/null +++ b/frontend/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // 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. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/frontend/windows/runner/flutter_window.h b/frontend/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/frontend/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/frontend/windows/runner/main.cpp b/frontend/windows/runner/main.cpp new file mode 100644 index 0000000..a45c619 --- /dev/null +++ b/frontend/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"gradi_frontend", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/frontend/windows/runner/resource.h b/frontend/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/frontend/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/frontend/windows/runner/resources/app_icon.ico b/frontend/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000..c04e20c Binary files /dev/null and b/frontend/windows/runner/resources/app_icon.ico differ diff --git a/frontend/windows/runner/runner.exe.manifest b/frontend/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..153653e --- /dev/null +++ b/frontend/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/frontend/windows/runner/utils.cpp b/frontend/windows/runner/utils.cpp new file mode 100644 index 0000000..3a0b465 --- /dev/null +++ b/frontend/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/frontend/windows/runner/utils.h b/frontend/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/frontend/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/frontend/windows/runner/win32_window.cpp b/frontend/windows/runner/win32_window.cpp new file mode 100644 index 0000000..60608d0 --- /dev/null +++ b/frontend/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/frontend/windows/runner/win32_window.h b/frontend/windows/runner/win32_window.h new file mode 100644 index 0000000..e901dde --- /dev/null +++ b/frontend/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_